1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "qdockwidget.h"
|
---|
43 |
|
---|
44 | #ifndef QT_NO_DOCKWIDGET
|
---|
45 | #include <qaction.h>
|
---|
46 | #include <qapplication.h>
|
---|
47 | #include <qdesktopwidget.h>
|
---|
48 | #include <qdrawutil.h>
|
---|
49 | #include <qevent.h>
|
---|
50 | #include <qfontmetrics.h>
|
---|
51 | #include <qmainwindow.h>
|
---|
52 | #include <qrubberband.h>
|
---|
53 | #include <qstylepainter.h>
|
---|
54 | #include <qtoolbutton.h>
|
---|
55 | #include <qdebug.h>
|
---|
56 |
|
---|
57 | #include <private/qwidgetresizehandler_p.h>
|
---|
58 |
|
---|
59 | #include "qdockwidget_p.h"
|
---|
60 | #include "qmainwindowlayout_p.h"
|
---|
61 | #ifdef Q_WS_MAC
|
---|
62 | #include <private/qt_mac_p.h>
|
---|
63 | #include <qmacstyle_mac.h>
|
---|
64 | #endif
|
---|
65 |
|
---|
66 | QT_BEGIN_NAMESPACE
|
---|
67 |
|
---|
68 | extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*); // qwidget.cpp
|
---|
69 |
|
---|
70 | extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); // qapplication.cpp
|
---|
71 |
|
---|
72 | static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
|
---|
73 | { return (dockwidget->features() & feature) == feature; }
|
---|
74 |
|
---|
75 |
|
---|
76 | /*
|
---|
77 | A Dock Window:
|
---|
78 |
|
---|
79 | [+] is the float button
|
---|
80 | [X] is the close button
|
---|
81 |
|
---|
82 | +-------------------------------+
|
---|
83 | | Dock Window Title [+][X]|
|
---|
84 | +-------------------------------+
|
---|
85 | | |
|
---|
86 | | place to put the single |
|
---|
87 | | QDockWidget child (this space |
|
---|
88 | | does not yet have a name) |
|
---|
89 | | |
|
---|
90 | | |
|
---|
91 | | |
|
---|
92 | | |
|
---|
93 | | |
|
---|
94 | | |
|
---|
95 | | |
|
---|
96 | | |
|
---|
97 | | |
|
---|
98 | +-------------------------------+
|
---|
99 |
|
---|
100 | */
|
---|
101 |
|
---|
102 | /******************************************************************************
|
---|
103 | ** QDockWidgetTitleButton
|
---|
104 | */
|
---|
105 |
|
---|
106 | class QDockWidgetTitleButton : public QAbstractButton
|
---|
107 | {
|
---|
108 | Q_OBJECT
|
---|
109 |
|
---|
110 | public:
|
---|
111 | QDockWidgetTitleButton(QDockWidget *dockWidget);
|
---|
112 |
|
---|
113 | QSize sizeHint() const;
|
---|
114 | inline QSize minimumSizeHint() const
|
---|
115 | { return sizeHint(); }
|
---|
116 |
|
---|
117 | void enterEvent(QEvent *event);
|
---|
118 | void leaveEvent(QEvent *event);
|
---|
119 | void paintEvent(QPaintEvent *event);
|
---|
120 | };
|
---|
121 |
|
---|
122 |
|
---|
123 | QDockWidgetTitleButton::QDockWidgetTitleButton(QDockWidget *dockWidget)
|
---|
124 | : QAbstractButton(dockWidget)
|
---|
125 | {
|
---|
126 | setFocusPolicy(Qt::NoFocus);
|
---|
127 | }
|
---|
128 |
|
---|
129 | QSize QDockWidgetTitleButton::sizeHint() const
|
---|
130 | {
|
---|
131 | ensurePolished();
|
---|
132 |
|
---|
133 | int size = 2*style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, 0, this);
|
---|
134 | if (!icon().isNull()) {
|
---|
135 | int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
|
---|
136 | QSize sz = icon().actualSize(QSize(iconSize, iconSize));
|
---|
137 | size += qMax(sz.width(), sz.height());
|
---|
138 | }
|
---|
139 |
|
---|
140 | return QSize(size, size);
|
---|
141 | }
|
---|
142 |
|
---|
143 | void QDockWidgetTitleButton::enterEvent(QEvent *event)
|
---|
144 | {
|
---|
145 | if (isEnabled()) update();
|
---|
146 | QAbstractButton::enterEvent(event);
|
---|
147 | }
|
---|
148 |
|
---|
149 | void QDockWidgetTitleButton::leaveEvent(QEvent *event)
|
---|
150 | {
|
---|
151 | if (isEnabled()) update();
|
---|
152 | QAbstractButton::leaveEvent(event);
|
---|
153 | }
|
---|
154 |
|
---|
155 | void QDockWidgetTitleButton::paintEvent(QPaintEvent *)
|
---|
156 | {
|
---|
157 | QPainter p(this);
|
---|
158 |
|
---|
159 | QRect r = rect();
|
---|
160 | QStyleOptionToolButton opt;
|
---|
161 | opt.init(this);
|
---|
162 | opt.state |= QStyle::State_AutoRaise;
|
---|
163 |
|
---|
164 | if (style()->styleHint(QStyle::SH_DockWidget_ButtonsHaveFrame, 0, this))
|
---|
165 | {
|
---|
166 | if (isEnabled() && underMouse() && !isChecked() && !isDown())
|
---|
167 | opt.state |= QStyle::State_Raised;
|
---|
168 | if (isChecked())
|
---|
169 | opt.state |= QStyle::State_On;
|
---|
170 | if (isDown())
|
---|
171 | opt.state |= QStyle::State_Sunken;
|
---|
172 | style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &p, this);
|
---|
173 | }
|
---|
174 |
|
---|
175 | opt.icon = icon();
|
---|
176 | opt.subControls = 0;
|
---|
177 | opt.activeSubControls = 0;
|
---|
178 | opt.features = QStyleOptionToolButton::None;
|
---|
179 | opt.arrowType = Qt::NoArrow;
|
---|
180 | int size = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
|
---|
181 | opt.iconSize = QSize(size, size);
|
---|
182 | style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, this);
|
---|
183 | }
|
---|
184 |
|
---|
185 | /******************************************************************************
|
---|
186 | ** QDockWidgetLayout
|
---|
187 | */
|
---|
188 |
|
---|
189 | QDockWidgetLayout::QDockWidgetLayout(QWidget *parent)
|
---|
190 | : QLayout(parent), verticalTitleBar(false), item_list(RoleCount, 0)
|
---|
191 | {
|
---|
192 | }
|
---|
193 |
|
---|
194 | QDockWidgetLayout::~QDockWidgetLayout()
|
---|
195 | {
|
---|
196 | qDeleteAll(item_list);
|
---|
197 | }
|
---|
198 |
|
---|
199 | bool QDockWidgetLayout::nativeWindowDeco() const
|
---|
200 | {
|
---|
201 | return nativeWindowDeco(parentWidget()->isWindow());
|
---|
202 | }
|
---|
203 |
|
---|
204 | bool QDockWidgetLayout::nativeWindowDeco(bool floating) const
|
---|
205 | {
|
---|
206 | #if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_WINCE)
|
---|
207 | Q_UNUSED(floating);
|
---|
208 | return false;
|
---|
209 | #else
|
---|
210 | return floating && item_list[QDockWidgetLayout::TitleBar] == 0;
|
---|
211 | #endif
|
---|
212 | }
|
---|
213 |
|
---|
214 |
|
---|
215 | void QDockWidgetLayout::addItem(QLayoutItem*)
|
---|
216 | {
|
---|
217 | qWarning() << "QDockWidgetLayout::addItem(): please use QDockWidgetLayout::setWidget()";
|
---|
218 | return;
|
---|
219 | }
|
---|
220 |
|
---|
221 | QLayoutItem *QDockWidgetLayout::itemAt(int index) const
|
---|
222 | {
|
---|
223 | int cnt = 0;
|
---|
224 | foreach (QLayoutItem *item, item_list) {
|
---|
225 | if (item == 0)
|
---|
226 | continue;
|
---|
227 | if (index == cnt++)
|
---|
228 | return item;
|
---|
229 | }
|
---|
230 | return 0;
|
---|
231 | }
|
---|
232 |
|
---|
233 | QLayoutItem *QDockWidgetLayout::takeAt(int index)
|
---|
234 | {
|
---|
235 | int j = 0;
|
---|
236 | for (int i = 0; i < item_list.count(); ++i) {
|
---|
237 | QLayoutItem *item = item_list.at(i);
|
---|
238 | if (item == 0)
|
---|
239 | continue;
|
---|
240 | if (index == j) {
|
---|
241 | item_list[i] = 0;
|
---|
242 | invalidate();
|
---|
243 | return item;
|
---|
244 | }
|
---|
245 | ++j;
|
---|
246 | }
|
---|
247 | return 0;
|
---|
248 | }
|
---|
249 |
|
---|
250 | int QDockWidgetLayout::count() const
|
---|
251 | {
|
---|
252 | int result = 0;
|
---|
253 | foreach (QLayoutItem *item, item_list) {
|
---|
254 | if (item != 0)
|
---|
255 | ++result;
|
---|
256 | }
|
---|
257 | return result;
|
---|
258 | }
|
---|
259 |
|
---|
260 | QSize QDockWidgetLayout::sizeFromContent(const QSize &content, bool floating) const
|
---|
261 | {
|
---|
262 | QSize result = content;
|
---|
263 |
|
---|
264 | if (verticalTitleBar) {
|
---|
265 | result.setHeight(qMax(result.height(), minimumTitleWidth()));
|
---|
266 | result.setWidth(qMax(content.width(), 0));
|
---|
267 | } else {
|
---|
268 | result.setHeight(qMax(result.height(), 0));
|
---|
269 | result.setWidth(qMax(content.width(), minimumTitleWidth()));
|
---|
270 | }
|
---|
271 |
|
---|
272 | QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
|
---|
273 | const bool nativeDeco = nativeWindowDeco(floating);
|
---|
274 |
|
---|
275 | int fw = floating && !nativeDeco
|
---|
276 | ? w->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, w)
|
---|
277 | : 0;
|
---|
278 |
|
---|
279 | const int th = titleHeight();
|
---|
280 | if (!nativeDeco) {
|
---|
281 | if (verticalTitleBar)
|
---|
282 | result += QSize(th + 2*fw, 2*fw);
|
---|
283 | else
|
---|
284 | result += QSize(2*fw, th + 2*fw);
|
---|
285 | }
|
---|
286 |
|
---|
287 | result.setHeight(qMin(result.height(), (int) QWIDGETSIZE_MAX));
|
---|
288 | result.setWidth(qMin(result.width(), (int) QWIDGETSIZE_MAX));
|
---|
289 |
|
---|
290 | if (content.width() < 0)
|
---|
291 | result.setWidth(-1);
|
---|
292 | if (content.height() < 0)
|
---|
293 | result.setHeight(-1);
|
---|
294 |
|
---|
295 | int left, top, right, bottom;
|
---|
296 | w->getContentsMargins(&left, &top, &right, &bottom);
|
---|
297 | //we need to substract the contents margin (it will be added by the caller)
|
---|
298 | QSize min = w->minimumSize() - QSize(left + right, top + bottom);
|
---|
299 | QSize max = w->maximumSize() - QSize(left + right, top + bottom);
|
---|
300 |
|
---|
301 | /* A floating dockwidget will automatically get its minimumSize set to the layout's
|
---|
302 | minimum size + deco. We're *not* interested in this, we only take minimumSize()
|
---|
303 | into account if the user set it herself. Otherwise we end up expanding the result
|
---|
304 | of a calculation for a non-floating dock widget to a floating dock widget's
|
---|
305 | minimum size + window decorations. */
|
---|
306 |
|
---|
307 | uint explicitMin = 0;
|
---|
308 | uint explicitMax = 0;
|
---|
309 | if (w->d_func()->extra != 0) {
|
---|
310 | explicitMin = w->d_func()->extra->explicitMinSize;
|
---|
311 | explicitMax = w->d_func()->extra->explicitMaxSize;
|
---|
312 | }
|
---|
313 |
|
---|
314 | if (!(explicitMin & Qt::Horizontal) || min.width() == 0)
|
---|
315 | min.setWidth(-1);
|
---|
316 | if (!(explicitMin & Qt::Vertical) || min.height() == 0)
|
---|
317 | min.setHeight(-1);
|
---|
318 |
|
---|
319 | if (!(explicitMax & Qt::Horizontal))
|
---|
320 | max.setWidth(QWIDGETSIZE_MAX);
|
---|
321 | if (!(explicitMax & Qt::Vertical))
|
---|
322 | max.setHeight(QWIDGETSIZE_MAX);
|
---|
323 |
|
---|
324 | return result.boundedTo(max).expandedTo(min);
|
---|
325 | }
|
---|
326 |
|
---|
327 | QSize QDockWidgetLayout::sizeHint() const
|
---|
328 | {
|
---|
329 | QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
|
---|
330 |
|
---|
331 | QSize content(-1, -1);
|
---|
332 | if (item_list[Content] != 0)
|
---|
333 | content = item_list[Content]->sizeHint();
|
---|
334 |
|
---|
335 | return sizeFromContent(content, w->isFloating());
|
---|
336 | }
|
---|
337 |
|
---|
338 | QSize QDockWidgetLayout::maximumSize() const
|
---|
339 | {
|
---|
340 | if (item_list[Content] != 0) {
|
---|
341 | const QSize content = item_list[Content]->maximumSize();
|
---|
342 | return sizeFromContent(content, parentWidget()->isWindow());
|
---|
343 | } else {
|
---|
344 | return parentWidget()->maximumSize();
|
---|
345 | }
|
---|
346 |
|
---|
347 | }
|
---|
348 |
|
---|
349 | QSize QDockWidgetLayout::minimumSize() const
|
---|
350 | {
|
---|
351 | QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
|
---|
352 |
|
---|
353 | QSize content(0, 0);
|
---|
354 | if (item_list[Content] != 0)
|
---|
355 | content = item_list[Content]->minimumSize();
|
---|
356 |
|
---|
357 | return sizeFromContent(content, w->isFloating());
|
---|
358 | }
|
---|
359 |
|
---|
360 | QWidget *QDockWidgetLayout::widgetForRole(Role r) const
|
---|
361 | {
|
---|
362 | QLayoutItem *item = item_list.at(r);
|
---|
363 | return item == 0 ? 0 : item->widget();
|
---|
364 | }
|
---|
365 |
|
---|
366 | QLayoutItem *QDockWidgetLayout::itemForRole(Role r) const
|
---|
367 | {
|
---|
368 | return item_list.at(r);
|
---|
369 | }
|
---|
370 |
|
---|
371 | void QDockWidgetLayout::setWidgetForRole(Role r, QWidget *w)
|
---|
372 | {
|
---|
373 | QWidget *old = widgetForRole(r);
|
---|
374 | if (old != 0) {
|
---|
375 | old->hide();
|
---|
376 | removeWidget(old);
|
---|
377 | }
|
---|
378 |
|
---|
379 | if (w != 0) {
|
---|
380 | addChildWidget(w);
|
---|
381 | item_list[r] = new QWidgetItemV2(w);
|
---|
382 | w->show();
|
---|
383 | } else {
|
---|
384 | item_list[r] = 0;
|
---|
385 | }
|
---|
386 |
|
---|
387 | invalidate();
|
---|
388 | }
|
---|
389 |
|
---|
390 | static inline int pick(bool vertical, const QSize &size)
|
---|
391 | {
|
---|
392 | return vertical ? size.height() : size.width();
|
---|
393 | }
|
---|
394 |
|
---|
395 | static inline int perp(bool vertical, const QSize &size)
|
---|
396 | {
|
---|
397 | return vertical ? size.width() : size.height();
|
---|
398 | }
|
---|
399 |
|
---|
400 | int QDockWidgetLayout::minimumTitleWidth() const
|
---|
401 | {
|
---|
402 | QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
|
---|
403 |
|
---|
404 | if (QWidget *title = widgetForRole(TitleBar))
|
---|
405 | return pick(verticalTitleBar, title->minimumSizeHint());
|
---|
406 |
|
---|
407 | QSize closeSize(0, 0);
|
---|
408 | QSize floatSize(0, 0);
|
---|
409 | if (hasFeature(q, QDockWidget::DockWidgetClosable)) {
|
---|
410 | if (QLayoutItem *item = item_list[CloseButton])
|
---|
411 | closeSize = item->widget()->sizeHint();
|
---|
412 | }
|
---|
413 | if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
|
---|
414 | if (QLayoutItem *item = item_list[FloatButton])
|
---|
415 | floatSize = item->widget()->sizeHint();
|
---|
416 | }
|
---|
417 |
|
---|
418 | int titleHeight = this->titleHeight();
|
---|
419 |
|
---|
420 | int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
|
---|
421 | int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
|
---|
422 |
|
---|
423 | return pick(verticalTitleBar, closeSize)
|
---|
424 | + pick(verticalTitleBar, floatSize)
|
---|
425 | + titleHeight + 2*fw + 3*mw;
|
---|
426 | }
|
---|
427 |
|
---|
428 | int QDockWidgetLayout::titleHeight() const
|
---|
429 | {
|
---|
430 | QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
|
---|
431 |
|
---|
432 | if (QWidget *title = widgetForRole(TitleBar))
|
---|
433 | return perp(verticalTitleBar, title->sizeHint());
|
---|
434 |
|
---|
435 | QSize closeSize(0, 0);
|
---|
436 | QSize floatSize(0, 0);
|
---|
437 | if (QLayoutItem *item = item_list[CloseButton])
|
---|
438 | closeSize = item->widget()->sizeHint();
|
---|
439 | if (QLayoutItem *item = item_list[FloatButton])
|
---|
440 | floatSize = item->widget()->sizeHint();
|
---|
441 |
|
---|
442 | int buttonHeight = qMax(perp(verticalTitleBar, closeSize),
|
---|
443 | perp(verticalTitleBar, floatSize));
|
---|
444 |
|
---|
445 | QFontMetrics titleFontMetrics = q->fontMetrics();
|
---|
446 | #ifdef Q_WS_MAC
|
---|
447 | if (qobject_cast<QMacStyle *>(q->style())) {
|
---|
448 | //### this breaks on proxy styles. (But is this code still called?)
|
---|
449 | QFont font = qt_app_fonts_hash()->value("QToolButton", q->font());
|
---|
450 | titleFontMetrics = QFontMetrics(font);
|
---|
451 | }
|
---|
452 | #endif
|
---|
453 |
|
---|
454 | int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
|
---|
455 |
|
---|
456 | return qMax(buttonHeight + 2, titleFontMetrics.lineSpacing() + 2*mw);
|
---|
457 | }
|
---|
458 |
|
---|
459 | void QDockWidgetLayout::setGeometry(const QRect &geometry)
|
---|
460 | {
|
---|
461 | QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
|
---|
462 |
|
---|
463 | bool nativeDeco = nativeWindowDeco();
|
---|
464 |
|
---|
465 | int fw = q->isFloating() && !nativeDeco
|
---|
466 | ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q)
|
---|
467 | : 0;
|
---|
468 |
|
---|
469 | if (nativeDeco) {
|
---|
470 | if (QLayoutItem *item = item_list[Content])
|
---|
471 | item->setGeometry(geometry);
|
---|
472 | } else {
|
---|
473 | int titleHeight = this->titleHeight();
|
---|
474 |
|
---|
475 | if (verticalTitleBar) {
|
---|
476 | _titleArea = QRect(QPoint(fw, fw),
|
---|
477 | QSize(titleHeight, geometry.height() - (fw * 2)));
|
---|
478 | } else {
|
---|
479 | _titleArea = QRect(QPoint(fw, fw),
|
---|
480 | QSize(geometry.width() - (fw * 2), titleHeight));
|
---|
481 | }
|
---|
482 |
|
---|
483 | if (QLayoutItem *item = item_list[TitleBar]) {
|
---|
484 | item->setGeometry(_titleArea);
|
---|
485 | } else {
|
---|
486 | QStyleOptionDockWidgetV2 opt;
|
---|
487 | q->initStyleOption(&opt);
|
---|
488 |
|
---|
489 | if (QLayoutItem *item = item_list[CloseButton]) {
|
---|
490 | if (!item->isEmpty()) {
|
---|
491 | QRect r = q->style()
|
---|
492 | ->subElementRect(QStyle::SE_DockWidgetCloseButton,
|
---|
493 | &opt, q);
|
---|
494 | if (!r.isNull())
|
---|
495 | item->setGeometry(r);
|
---|
496 | }
|
---|
497 | }
|
---|
498 |
|
---|
499 | if (QLayoutItem *item = item_list[FloatButton]) {
|
---|
500 | if (!item->isEmpty()) {
|
---|
501 | QRect r = q->style()
|
---|
502 | ->subElementRect(QStyle::SE_DockWidgetFloatButton,
|
---|
503 | &opt, q);
|
---|
504 | if (!r.isNull())
|
---|
505 | item->setGeometry(r);
|
---|
506 | }
|
---|
507 | }
|
---|
508 | }
|
---|
509 |
|
---|
510 | if (QLayoutItem *item = item_list[Content]) {
|
---|
511 | QRect r = geometry;
|
---|
512 | if (verticalTitleBar) {
|
---|
513 | r.setLeft(_titleArea.right() + 1);
|
---|
514 | r.adjust(0, fw, -fw, -fw);
|
---|
515 | } else {
|
---|
516 | r.setTop(_titleArea.bottom() + 1);
|
---|
517 | r.adjust(fw, 0, -fw, -fw);
|
---|
518 | }
|
---|
519 | item->setGeometry(r);
|
---|
520 | }
|
---|
521 | }
|
---|
522 | }
|
---|
523 |
|
---|
524 | void QDockWidgetLayout::setVerticalTitleBar(bool b)
|
---|
525 | {
|
---|
526 | if (b == verticalTitleBar)
|
---|
527 | return;
|
---|
528 | verticalTitleBar = b;
|
---|
529 | invalidate();
|
---|
530 | parentWidget()->update();
|
---|
531 | }
|
---|
532 |
|
---|
533 | /******************************************************************************
|
---|
534 | ** QDockWidgetItem
|
---|
535 | */
|
---|
536 |
|
---|
537 | QDockWidgetItem::QDockWidgetItem(QDockWidget *dockWidget)
|
---|
538 | : QWidgetItem(dockWidget)
|
---|
539 | {
|
---|
540 | }
|
---|
541 |
|
---|
542 | QSize QDockWidgetItem::minimumSize() const
|
---|
543 | {
|
---|
544 | QSize widgetMin(0, 0);
|
---|
545 | if (QLayoutItem *item = dockWidgetChildItem())
|
---|
546 | widgetMin = item->minimumSize();
|
---|
547 | return dockWidgetLayout()->sizeFromContent(widgetMin, false);
|
---|
548 | }
|
---|
549 |
|
---|
550 | QSize QDockWidgetItem::maximumSize() const
|
---|
551 | {
|
---|
552 | if (QLayoutItem *item = dockWidgetChildItem()) {
|
---|
553 | return dockWidgetLayout()->sizeFromContent(item->maximumSize(), false);
|
---|
554 | } else {
|
---|
555 | return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
---|
556 | }
|
---|
557 | }
|
---|
558 |
|
---|
559 |
|
---|
560 | QSize QDockWidgetItem::sizeHint() const
|
---|
561 | {
|
---|
562 | if (QLayoutItem *item = dockWidgetChildItem()) {
|
---|
563 | return dockWidgetLayout()->sizeFromContent(item->sizeHint(), false);
|
---|
564 | } else {
|
---|
565 | return QWidgetItem::sizeHint();
|
---|
566 | }
|
---|
567 | }
|
---|
568 |
|
---|
569 | /******************************************************************************
|
---|
570 | ** QDockWidgetPrivate
|
---|
571 | */
|
---|
572 |
|
---|
573 | void QDockWidgetPrivate::init()
|
---|
574 | {
|
---|
575 | Q_Q(QDockWidget);
|
---|
576 |
|
---|
577 | QDockWidgetLayout *layout = new QDockWidgetLayout(q);
|
---|
578 | layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
|
---|
579 |
|
---|
580 | QAbstractButton *button = new QDockWidgetTitleButton(q);
|
---|
581 | button->setObjectName(QLatin1String("qt_dockwidget_floatbutton"));
|
---|
582 | QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_toggleTopLevel()));
|
---|
583 | layout->setWidgetForRole(QDockWidgetLayout::FloatButton, button);
|
---|
584 |
|
---|
585 | button = new QDockWidgetTitleButton(q);
|
---|
586 | button->setObjectName(QLatin1String("qt_dockwidget_closebutton"));
|
---|
587 | QObject::connect(button, SIGNAL(clicked()), q, SLOT(close()));
|
---|
588 | layout->setWidgetForRole(QDockWidgetLayout::CloseButton, button);
|
---|
589 |
|
---|
590 | resizer = new QWidgetResizeHandler(q);
|
---|
591 | resizer->setMovingEnabled(false);
|
---|
592 | resizer->setActive(false);
|
---|
593 |
|
---|
594 | #ifndef QT_NO_ACTION
|
---|
595 | toggleViewAction = new QAction(q);
|
---|
596 | toggleViewAction->setCheckable(true);
|
---|
597 | fixedWindowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
|
---|
598 | toggleViewAction->setText(fixedWindowTitle);
|
---|
599 | QObject::connect(toggleViewAction, SIGNAL(triggered(bool)),
|
---|
600 | q, SLOT(_q_toggleView(bool)));
|
---|
601 | #endif
|
---|
602 |
|
---|
603 | updateButtons();
|
---|
604 | }
|
---|
605 |
|
---|
606 | /*!
|
---|
607 | Initialize \a option with the values from this QDockWidget. This method
|
---|
608 | is useful for subclasses when they need a QStyleOptionDockWidget, but don't want
|
---|
609 | to fill in all the information themselves.
|
---|
610 |
|
---|
611 | \sa QStyleOption::initFrom()
|
---|
612 | */
|
---|
613 | void QDockWidget::initStyleOption(QStyleOptionDockWidget *option) const
|
---|
614 | {
|
---|
615 | Q_D(const QDockWidget);
|
---|
616 |
|
---|
617 | if (!option)
|
---|
618 | return;
|
---|
619 | QDockWidgetLayout *dwlayout = qobject_cast<QDockWidgetLayout*>(layout());
|
---|
620 |
|
---|
621 | option->initFrom(this);
|
---|
622 | option->rect = dwlayout->titleArea();
|
---|
623 | option->title = d->fixedWindowTitle;
|
---|
624 | option->closable = hasFeature(this, QDockWidget::DockWidgetClosable);
|
---|
625 | option->movable = hasFeature(this, QDockWidget::DockWidgetMovable);
|
---|
626 | option->floatable = hasFeature(this, QDockWidget::DockWidgetFloatable);
|
---|
627 |
|
---|
628 | QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout*>(layout());
|
---|
629 | QStyleOptionDockWidgetV2 *v2
|
---|
630 | = qstyleoption_cast<QStyleOptionDockWidgetV2*>(option);
|
---|
631 | if (v2 != 0)
|
---|
632 | v2->verticalTitleBar = l->verticalTitleBar;
|
---|
633 | }
|
---|
634 |
|
---|
635 | void QDockWidgetPrivate::_q_toggleView(bool b)
|
---|
636 | {
|
---|
637 | Q_Q(QDockWidget);
|
---|
638 | if (b == q->isHidden()) {
|
---|
639 | if (b)
|
---|
640 | q->show();
|
---|
641 | else
|
---|
642 | q->close();
|
---|
643 | }
|
---|
644 | }
|
---|
645 |
|
---|
646 | void QDockWidgetPrivate::updateButtons()
|
---|
647 | {
|
---|
648 | Q_Q(QDockWidget);
|
---|
649 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
|
---|
650 |
|
---|
651 | QStyleOptionDockWidget opt;
|
---|
652 | q->initStyleOption(&opt);
|
---|
653 |
|
---|
654 | bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
|
---|
655 | bool nativeDeco = layout->nativeWindowDeco();
|
---|
656 | bool hideButtons = nativeDeco || customTitleBar;
|
---|
657 |
|
---|
658 | bool canClose = hasFeature(q, QDockWidget::DockWidgetClosable);
|
---|
659 | bool canFloat = hasFeature(q, QDockWidget::DockWidgetFloatable);
|
---|
660 |
|
---|
661 | QAbstractButton *button
|
---|
662 | = qobject_cast<QAbstractButton*>(layout->widgetForRole(QDockWidgetLayout::FloatButton));
|
---|
663 | button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, &opt, q));
|
---|
664 | button->setVisible(canFloat && !hideButtons);
|
---|
665 |
|
---|
666 | button
|
---|
667 | = qobject_cast <QAbstractButton*>(layout->widgetForRole(QDockWidgetLayout::CloseButton));
|
---|
668 | button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, q));
|
---|
669 | button->setVisible(canClose && !hideButtons);
|
---|
670 |
|
---|
671 | q->setAttribute(Qt::WA_ContentsPropagated,
|
---|
672 | (canFloat || canClose) && !hideButtons);
|
---|
673 |
|
---|
674 | layout->invalidate();
|
---|
675 | }
|
---|
676 |
|
---|
677 | void QDockWidgetPrivate::_q_toggleTopLevel()
|
---|
678 | {
|
---|
679 | Q_Q(QDockWidget);
|
---|
680 | q->setFloating(!q->isFloating());
|
---|
681 | }
|
---|
682 |
|
---|
683 | void QDockWidgetPrivate::initDrag(const QPoint &pos, bool nca)
|
---|
684 | {
|
---|
685 | Q_Q(QDockWidget);
|
---|
686 |
|
---|
687 | if (state != 0)
|
---|
688 | return;
|
---|
689 |
|
---|
690 | QMainWindow *win = qobject_cast<QMainWindow*>(q->parentWidget());
|
---|
691 | Q_ASSERT(win != 0);
|
---|
692 | QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(win->layout());
|
---|
693 | Q_ASSERT(layout != 0);
|
---|
694 | if (layout->layoutState.indexOf(q).isEmpty()) //The dock widget has not been added into the main window
|
---|
695 | return;
|
---|
696 | if (layout->pluggingWidget != 0) // the main window is animating a docking operation
|
---|
697 | return;
|
---|
698 |
|
---|
699 | state = new QDockWidgetPrivate::DragState;
|
---|
700 | state->pressPos = pos;
|
---|
701 | state->dragging = false;
|
---|
702 | state->widgetItem = 0;
|
---|
703 | state->ownWidgetItem = false;
|
---|
704 | state->nca = nca;
|
---|
705 | state->ctrlDrag = false;
|
---|
706 | }
|
---|
707 |
|
---|
708 | void QDockWidgetPrivate::startDrag()
|
---|
709 | {
|
---|
710 | Q_Q(QDockWidget);
|
---|
711 |
|
---|
712 | if (state == 0 || state->dragging)
|
---|
713 | return;
|
---|
714 |
|
---|
715 | QMainWindowLayout *layout
|
---|
716 | = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
|
---|
717 | Q_ASSERT(layout != 0);
|
---|
718 |
|
---|
719 | state->widgetItem = layout->unplug(q);
|
---|
720 | if (state->widgetItem == 0) {
|
---|
721 | /* I have a QMainWindow parent, but I was never inserted with
|
---|
722 | QMainWindow::addDockWidget, so the QMainWindowLayout has no
|
---|
723 | widget item for me. :( I have to create it myself, and then
|
---|
724 | delete it if I don't get dropped into a dock area. */
|
---|
725 | state->widgetItem = new QDockWidgetItem(q);
|
---|
726 | state->ownWidgetItem = true;
|
---|
727 | }
|
---|
728 |
|
---|
729 | if (state->ctrlDrag)
|
---|
730 | layout->restore();
|
---|
731 |
|
---|
732 | state->dragging = true;
|
---|
733 | }
|
---|
734 |
|
---|
735 | void QDockWidgetPrivate::endDrag(bool abort)
|
---|
736 | {
|
---|
737 | Q_Q(QDockWidget);
|
---|
738 | Q_ASSERT(state != 0);
|
---|
739 |
|
---|
740 | q->releaseMouse();
|
---|
741 |
|
---|
742 | if (state->dragging) {
|
---|
743 | QMainWindowLayout *layout =
|
---|
744 | qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
|
---|
745 | Q_ASSERT(layout != 0);
|
---|
746 |
|
---|
747 | if (abort || !layout->plug(state->widgetItem)) {
|
---|
748 | if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
|
---|
749 | if (state->ownWidgetItem)
|
---|
750 | delete state->widgetItem;
|
---|
751 | layout->restore();
|
---|
752 | #ifdef Q_WS_X11
|
---|
753 | // get rid of the X11BypassWindowManager window flag and activate the resizer
|
---|
754 | Qt::WindowFlags flags = q->windowFlags();
|
---|
755 | flags &= ~Qt::X11BypassWindowManagerHint;
|
---|
756 | q->setWindowFlags(flags);
|
---|
757 | resizer->setActive(QWidgetResizeHandler::Resize, true);
|
---|
758 | q->show();
|
---|
759 | #else
|
---|
760 | QDockWidgetLayout *myLayout
|
---|
761 | = qobject_cast<QDockWidgetLayout*>(q->layout());
|
---|
762 | resizer->setActive(QWidgetResizeHandler::Resize,
|
---|
763 | myLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0);
|
---|
764 | #endif
|
---|
765 | undockedGeometry = q->geometry();
|
---|
766 | q->activateWindow();
|
---|
767 | } else {
|
---|
768 | layout->revert(state->widgetItem);
|
---|
769 | }
|
---|
770 | }
|
---|
771 | }
|
---|
772 | delete state;
|
---|
773 | state = 0;
|
---|
774 | }
|
---|
775 |
|
---|
776 | bool QDockWidgetPrivate::isAnimating() const
|
---|
777 | {
|
---|
778 | Q_Q(const QDockWidget);
|
---|
779 |
|
---|
780 | QMainWindow *mainWin = qobject_cast<QMainWindow*>(q->parentWidget());
|
---|
781 | if (mainWin == 0)
|
---|
782 | return false;
|
---|
783 |
|
---|
784 | QMainWindowLayout *mainWinLayout
|
---|
785 | = qobject_cast<QMainWindowLayout*>(mainWin->layout());
|
---|
786 | if (mainWinLayout == 0)
|
---|
787 | return false;
|
---|
788 |
|
---|
789 | return (void*)mainWinLayout->pluggingWidget == (void*)q;
|
---|
790 | }
|
---|
791 |
|
---|
792 | bool QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
|
---|
793 | {
|
---|
794 | #if !defined(QT_NO_MAINWINDOW)
|
---|
795 | Q_Q(QDockWidget);
|
---|
796 |
|
---|
797 | QDockWidgetLayout *layout
|
---|
798 | = qobject_cast<QDockWidgetLayout*>(q->layout());
|
---|
799 |
|
---|
800 | if (!layout->nativeWindowDeco()) {
|
---|
801 | QRect titleArea = layout->titleArea();
|
---|
802 |
|
---|
803 | if (event->button() != Qt::LeftButton ||
|
---|
804 | !titleArea.contains(event->pos()) ||
|
---|
805 | // check if the tool window is movable... do nothing if it
|
---|
806 | // is not (but allow moving if the window is floating)
|
---|
807 | (!hasFeature(q, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
|
---|
808 | qobject_cast<QMainWindow*>(q->parentWidget()) == 0 ||
|
---|
809 | isAnimating() || state != 0) {
|
---|
810 | return false;
|
---|
811 | }
|
---|
812 |
|
---|
813 | initDrag(event->pos(), false);
|
---|
814 |
|
---|
815 | if (state)
|
---|
816 | state->ctrlDrag = hasFeature(q, QDockWidget::DockWidgetFloatable) && event->modifiers() & Qt::ControlModifier;
|
---|
817 |
|
---|
818 | return true;
|
---|
819 | }
|
---|
820 |
|
---|
821 | #endif // !defined(QT_NO_MAINWINDOW)
|
---|
822 | return false;
|
---|
823 | }
|
---|
824 |
|
---|
825 | bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
|
---|
826 | {
|
---|
827 | Q_Q(QDockWidget);
|
---|
828 |
|
---|
829 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
|
---|
830 |
|
---|
831 | if (!layout->nativeWindowDeco()) {
|
---|
832 | QRect titleArea = layout->titleArea();
|
---|
833 |
|
---|
834 | if (event->button() == Qt::LeftButton && titleArea.contains(event->pos()) &&
|
---|
835 | hasFeature(q, QDockWidget::DockWidgetFloatable)) {
|
---|
836 | _q_toggleTopLevel();
|
---|
837 | return true;
|
---|
838 | }
|
---|
839 | }
|
---|
840 | return false;
|
---|
841 | }
|
---|
842 |
|
---|
843 | bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
|
---|
844 | {
|
---|
845 | bool ret = false;
|
---|
846 | #if !defined(QT_NO_MAINWINDOW)
|
---|
847 | Q_Q(QDockWidget);
|
---|
848 |
|
---|
849 | if (!state)
|
---|
850 | return ret;
|
---|
851 |
|
---|
852 | QDockWidgetLayout *dwlayout
|
---|
853 | = qobject_cast<QDockWidgetLayout*>(q->layout());
|
---|
854 | QMainWindowLayout *mwlayout
|
---|
855 | = qobject_cast<QMainWindowLayout*>(q->parentWidget()->layout());
|
---|
856 | if (!dwlayout->nativeWindowDeco()) {
|
---|
857 | if (!state->dragging
|
---|
858 | && mwlayout->pluggingWidget == 0
|
---|
859 | && (event->pos() - state->pressPos).manhattanLength()
|
---|
860 | > QApplication::startDragDistance()) {
|
---|
861 | startDrag();
|
---|
862 | #ifdef Q_OS_WIN
|
---|
863 | grabMouseWhileInWindow();
|
---|
864 | #else
|
---|
865 | q->grabMouse();
|
---|
866 | #endif
|
---|
867 | ret = true;
|
---|
868 | }
|
---|
869 | }
|
---|
870 |
|
---|
871 | if (state->dragging && !state->nca) {
|
---|
872 | QPoint pos = event->globalPos() - state->pressPos;
|
---|
873 | q->move(pos);
|
---|
874 |
|
---|
875 | if (!state->ctrlDrag)
|
---|
876 | mwlayout->hover(state->widgetItem, event->globalPos());
|
---|
877 |
|
---|
878 | ret = true;
|
---|
879 | }
|
---|
880 |
|
---|
881 | #endif // !defined(QT_NO_MAINWINDOW)
|
---|
882 | return ret;
|
---|
883 | }
|
---|
884 |
|
---|
885 | bool QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
|
---|
886 | {
|
---|
887 | #if !defined(QT_NO_MAINWINDOW)
|
---|
888 |
|
---|
889 | if (event->button() == Qt::LeftButton && state && !state->nca) {
|
---|
890 | endDrag();
|
---|
891 | return true; //filter out the event
|
---|
892 | }
|
---|
893 |
|
---|
894 | #endif // !defined(QT_NO_MAINWINDOW)
|
---|
895 | return false;
|
---|
896 | }
|
---|
897 |
|
---|
898 | void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
|
---|
899 | {
|
---|
900 | Q_Q(QDockWidget);
|
---|
901 |
|
---|
902 | int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
|
---|
903 |
|
---|
904 | QRect geo = q->geometry();
|
---|
905 | QRect titleRect = q->frameGeometry();
|
---|
906 | #ifdef Q_WS_MAC
|
---|
907 | if ((features & QDockWidget::DockWidgetVerticalTitleBar)) {
|
---|
908 | titleRect.setTop(geo.top());
|
---|
909 | titleRect.setBottom(geo.bottom());
|
---|
910 | titleRect.setRight(geo.left() - 1);
|
---|
911 | } else
|
---|
912 | #endif
|
---|
913 | {
|
---|
914 | titleRect.setLeft(geo.left());
|
---|
915 | titleRect.setRight(geo.right());
|
---|
916 | titleRect.setBottom(geo.top() - 1);
|
---|
917 | titleRect.adjust(0, fw, 0, 0);
|
---|
918 | }
|
---|
919 |
|
---|
920 | switch (event->type()) {
|
---|
921 | case QEvent::NonClientAreaMouseButtonPress:
|
---|
922 | if (!titleRect.contains(event->globalPos()))
|
---|
923 | break;
|
---|
924 | if (state != 0)
|
---|
925 | break;
|
---|
926 | if (qobject_cast<QMainWindow*>(q->parentWidget()) == 0)
|
---|
927 | break;
|
---|
928 | if (isAnimating())
|
---|
929 | break;
|
---|
930 | initDrag(event->pos(), true);
|
---|
931 | if (state == 0)
|
---|
932 | break;
|
---|
933 | #ifdef Q_OS_WIN
|
---|
934 | // On Windows, NCA mouse events don't contain modifier info
|
---|
935 | state->ctrlDrag = GetKeyState(VK_CONTROL) & 0x8000;
|
---|
936 | #else
|
---|
937 | state->ctrlDrag = event->modifiers() & Qt::ControlModifier;
|
---|
938 | #endif
|
---|
939 | startDrag();
|
---|
940 | break;
|
---|
941 | case QEvent::NonClientAreaMouseMove:
|
---|
942 | if (state == 0 || !state->dragging)
|
---|
943 | break;
|
---|
944 | if (state->nca) {
|
---|
945 | endDrag();
|
---|
946 | }
|
---|
947 | #ifdef Q_OS_MAC
|
---|
948 | else { // workaround for lack of mouse-grab on Mac
|
---|
949 | QMainWindowLayout *layout
|
---|
950 | = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
|
---|
951 | Q_ASSERT(layout != 0);
|
---|
952 |
|
---|
953 | q->move(event->globalPos() - state->pressPos);
|
---|
954 | if (!state->ctrlDrag)
|
---|
955 | layout->hover(state->widgetItem, event->globalPos());
|
---|
956 | }
|
---|
957 | #endif
|
---|
958 | break;
|
---|
959 | case QEvent::NonClientAreaMouseButtonRelease:
|
---|
960 | #ifdef Q_OS_MAC
|
---|
961 | if (state)
|
---|
962 | endDrag();
|
---|
963 | #endif
|
---|
964 | break;
|
---|
965 | case QEvent::NonClientAreaMouseButtonDblClick:
|
---|
966 | _q_toggleTopLevel();
|
---|
967 | break;
|
---|
968 | default:
|
---|
969 | break;
|
---|
970 | }
|
---|
971 | }
|
---|
972 |
|
---|
973 | void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
|
---|
974 | {
|
---|
975 | Q_Q(QDockWidget);
|
---|
976 |
|
---|
977 | if (state == 0 || !state->dragging || !state->nca || !q->isWindow())
|
---|
978 | return;
|
---|
979 |
|
---|
980 | // When the native window frame is being dragged, all we get is these mouse
|
---|
981 | // move events.
|
---|
982 |
|
---|
983 | if (state->ctrlDrag)
|
---|
984 | return;
|
---|
985 |
|
---|
986 | QMainWindowLayout *layout
|
---|
987 | = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
|
---|
988 | Q_ASSERT(layout != 0);
|
---|
989 |
|
---|
990 | QPoint globalMousePos = event->pos() + state->pressPos;
|
---|
991 | layout->hover(state->widgetItem, globalMousePos);
|
---|
992 | }
|
---|
993 |
|
---|
994 | void QDockWidgetPrivate::unplug(const QRect &rect)
|
---|
995 | {
|
---|
996 | Q_Q(QDockWidget);
|
---|
997 | QRect r = rect;
|
---|
998 | r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
|
---|
999 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
|
---|
1000 | if (layout->nativeWindowDeco(true))
|
---|
1001 | r.adjust(0, layout->titleHeight(), 0, 0);
|
---|
1002 | setWindowState(true, true, r);
|
---|
1003 | }
|
---|
1004 |
|
---|
1005 | void QDockWidgetPrivate::plug(const QRect &rect)
|
---|
1006 | {
|
---|
1007 | setWindowState(false, false, rect);
|
---|
1008 | }
|
---|
1009 |
|
---|
1010 | void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
|
---|
1011 | {
|
---|
1012 | Q_Q(QDockWidget);
|
---|
1013 |
|
---|
1014 | bool wasFloating = q->isFloating();
|
---|
1015 | bool hidden = q->isHidden();
|
---|
1016 |
|
---|
1017 | if (q->isVisible())
|
---|
1018 | q->hide();
|
---|
1019 |
|
---|
1020 | Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
|
---|
1021 |
|
---|
1022 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
|
---|
1023 | const bool nativeDeco = layout->nativeWindowDeco(floating);
|
---|
1024 |
|
---|
1025 | if (nativeDeco) {
|
---|
1026 | flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
|
---|
1027 | if (hasFeature(q, QDockWidget::DockWidgetClosable))
|
---|
1028 | flags |= Qt::WindowCloseButtonHint;
|
---|
1029 | } else {
|
---|
1030 | flags |= Qt::FramelessWindowHint;
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 | if (unplug)
|
---|
1034 | flags |= Qt::X11BypassWindowManagerHint;
|
---|
1035 |
|
---|
1036 | q->setWindowFlags(flags);
|
---|
1037 |
|
---|
1038 | #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
|
---|
1039 | if (floating && nativeDeco && (q->features() & QDockWidget::DockWidgetVerticalTitleBar)) {
|
---|
1040 | ChangeWindowAttributes(HIViewGetWindow(HIViewRef(q->winId())), kWindowSideTitlebarAttribute, 0);
|
---|
1041 | }
|
---|
1042 | #endif
|
---|
1043 |
|
---|
1044 | if (!rect.isNull())
|
---|
1045 | q->setGeometry(rect);
|
---|
1046 |
|
---|
1047 | updateButtons();
|
---|
1048 |
|
---|
1049 | if (!hidden)
|
---|
1050 | q->show();
|
---|
1051 |
|
---|
1052 | if (floating != wasFloating) {
|
---|
1053 | emit q->topLevelChanged(floating);
|
---|
1054 | if (!floating && q->parentWidget()) {
|
---|
1055 | QMainWindowLayout *mwlayout = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
|
---|
1056 | if (mwlayout)
|
---|
1057 | emit q->dockLocationChanged(mwlayout->dockWidgetArea(q));
|
---|
1058 | }
|
---|
1059 | }
|
---|
1060 |
|
---|
1061 | resizer->setActive(QWidgetResizeHandler::Resize, !unplug && floating && !nativeDeco);
|
---|
1062 | }
|
---|
1063 |
|
---|
1064 | /*!
|
---|
1065 | \class QDockWidget
|
---|
1066 |
|
---|
1067 | \brief The QDockWidget class provides a widget that can be docked
|
---|
1068 | inside a QMainWindow or floated as a top-level window on the
|
---|
1069 | desktop.
|
---|
1070 |
|
---|
1071 | \ingroup application
|
---|
1072 |
|
---|
1073 | QDockWidget provides the concept of dock widgets, also know as
|
---|
1074 | tool palettes or utility windows. Dock windows are secondary
|
---|
1075 | windows placed in the \e {dock widget area} around the
|
---|
1076 | \l{QMainWindow::centralWidget()}{central widget} in a
|
---|
1077 | QMainWindow.
|
---|
1078 |
|
---|
1079 | \image mainwindow-docks.png
|
---|
1080 |
|
---|
1081 | Dock windows can be moved inside their current area, moved into
|
---|
1082 | new areas and floated (e.g., undocked) by the end-user. The
|
---|
1083 | QDockWidget API allows the programmer to restrict the dock widgets
|
---|
1084 | ability to move, float and close, as well as the areas in which
|
---|
1085 | they can be placed.
|
---|
1086 |
|
---|
1087 | \section1 Appearance
|
---|
1088 |
|
---|
1089 | A QDockWidget consists of a title bar and the content area. The
|
---|
1090 | title bar displays the dock widgets \link QWidget::windowTitle()
|
---|
1091 | window title\endlink, a \e float button and a \e close button.
|
---|
1092 | Depending on the state of the QDockWidget, the \e float and \e
|
---|
1093 | close buttons may be either disabled or not shown at all.
|
---|
1094 |
|
---|
1095 | The visual appearance of the title bar and buttons is dependent
|
---|
1096 | on the \l{QStyle}{style} in use.
|
---|
1097 |
|
---|
1098 | A QDockWidget acts as a wrapper for its child widget, set with setWidget().
|
---|
1099 | Custom size hints, minimum and maximum sizes and size policies should be
|
---|
1100 | implemented in the child widget. QDockWidget will respect them, adjusting
|
---|
1101 | its own constraints to include the frame and title. Size constraints
|
---|
1102 | should not be set on the QDockWidget itself, because they change depending
|
---|
1103 | on whether it is docked; a docked QDockWidget has no frame and a smaller title
|
---|
1104 | bar.
|
---|
1105 |
|
---|
1106 | \sa QMainWindow, {Dock Widgets Example}
|
---|
1107 | */
|
---|
1108 |
|
---|
1109 | /*!
|
---|
1110 | \enum QDockWidget::DockWidgetFeature
|
---|
1111 |
|
---|
1112 | \value DockWidgetClosable The dock widget can be closed. On some systems the dock
|
---|
1113 | widget always has a close button when it's floating
|
---|
1114 | (for example on MacOS 10.5).
|
---|
1115 | \value DockWidgetMovable The dock widget can be moved between docks
|
---|
1116 | by the user.
|
---|
1117 | \value DockWidgetFloatable The dock widget can be detached from the
|
---|
1118 | main window, and floated as an independent
|
---|
1119 | window.
|
---|
1120 | \value DockWidgetVerticalTitleBar The dock widget displays a vertical title
|
---|
1121 | bar on its left side. This can be used to
|
---|
1122 | increase the amount of vertical space in
|
---|
1123 | a QMainWindow.
|
---|
1124 | \value AllDockWidgetFeatures (Deprecated) The dock widget can be closed, moved,
|
---|
1125 | and floated. Since new features might be added in future
|
---|
1126 | releases, the look and behavior of dock widgets might
|
---|
1127 | change if you use this flag. Please specify individual
|
---|
1128 | flags instead.
|
---|
1129 | \value NoDockWidgetFeatures The dock widget cannot be closed, moved,
|
---|
1130 | or floated.
|
---|
1131 |
|
---|
1132 | \omitvalue DockWidgetFeatureMask
|
---|
1133 | \omitvalue Reserved
|
---|
1134 | */
|
---|
1135 |
|
---|
1136 | /*!
|
---|
1137 | \property QDockWidget::windowTitle
|
---|
1138 | \internal
|
---|
1139 |
|
---|
1140 | By default, this property contains an empty string.
|
---|
1141 | */
|
---|
1142 |
|
---|
1143 | /*!
|
---|
1144 | Constructs a QDockWidget with parent \a parent and window flags \a
|
---|
1145 | flags. The dock widget will be placed in the left dock widget
|
---|
1146 | area.
|
---|
1147 | */
|
---|
1148 | QDockWidget::QDockWidget(QWidget *parent, Qt::WindowFlags flags)
|
---|
1149 | : QWidget(*new QDockWidgetPrivate, parent, flags)
|
---|
1150 | {
|
---|
1151 | Q_D(QDockWidget);
|
---|
1152 | d->init();
|
---|
1153 | }
|
---|
1154 |
|
---|
1155 | /*!
|
---|
1156 | Constructs a QDockWidget with parent \a parent and window flags \a
|
---|
1157 | flags. The dock widget will be placed in the left dock widget
|
---|
1158 | area.
|
---|
1159 |
|
---|
1160 | The window title is set to \a title. This title is used when the
|
---|
1161 | QDockWidget is docked and undocked. It is also used in the context
|
---|
1162 | menu provided by QMainWindow.
|
---|
1163 |
|
---|
1164 | \sa setWindowTitle()
|
---|
1165 | */
|
---|
1166 | QDockWidget::QDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags)
|
---|
1167 | : QWidget(*new QDockWidgetPrivate, parent, flags)
|
---|
1168 | {
|
---|
1169 | Q_D(QDockWidget);
|
---|
1170 | d->init();
|
---|
1171 | setWindowTitle(title);
|
---|
1172 | }
|
---|
1173 |
|
---|
1174 | /*!
|
---|
1175 | Destroys the dock widget.
|
---|
1176 | */
|
---|
1177 | QDockWidget::~QDockWidget()
|
---|
1178 | { }
|
---|
1179 |
|
---|
1180 | /*!
|
---|
1181 | Returns the widget for the dock widget. This function returns zero
|
---|
1182 | if the widget has not been set.
|
---|
1183 |
|
---|
1184 | \sa setWidget()
|
---|
1185 | */
|
---|
1186 | QWidget *QDockWidget::widget() const
|
---|
1187 | {
|
---|
1188 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1189 | return layout->widgetForRole(QDockWidgetLayout::Content);
|
---|
1190 | }
|
---|
1191 |
|
---|
1192 | /*!
|
---|
1193 | Sets the widget for the dock widget to \a widget.
|
---|
1194 |
|
---|
1195 | If the dock widget is visible when \a widget is added, you must
|
---|
1196 | \l{QWidget::}{show()} it explicitly.
|
---|
1197 |
|
---|
1198 | Note that you must add the layout of the \a widget before you call
|
---|
1199 | this function; if not, the \a widget will not be visible.
|
---|
1200 |
|
---|
1201 | \sa widget()
|
---|
1202 | */
|
---|
1203 | void QDockWidget::setWidget(QWidget *widget)
|
---|
1204 | {
|
---|
1205 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1206 | layout->setWidgetForRole(QDockWidgetLayout::Content, widget);
|
---|
1207 | }
|
---|
1208 |
|
---|
1209 | /*!
|
---|
1210 | \property QDockWidget::features
|
---|
1211 | \brief whether the dock widget is movable, closable, and floatable
|
---|
1212 |
|
---|
1213 | By default, this property is set to a combination of DockWidgetClosable,
|
---|
1214 | DockWidgetMovable and DockWidgetFloatable.
|
---|
1215 |
|
---|
1216 | \sa DockWidgetFeature
|
---|
1217 | */
|
---|
1218 |
|
---|
1219 | void QDockWidget::setFeatures(QDockWidget::DockWidgetFeatures features)
|
---|
1220 | {
|
---|
1221 | Q_D(QDockWidget);
|
---|
1222 | features &= DockWidgetFeatureMask;
|
---|
1223 | if (d->features == features)
|
---|
1224 | return;
|
---|
1225 | d->features = features;
|
---|
1226 | QDockWidgetLayout *layout
|
---|
1227 | = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1228 | layout->setVerticalTitleBar(features & DockWidgetVerticalTitleBar);
|
---|
1229 | d->updateButtons();
|
---|
1230 | d->toggleViewAction->setEnabled((d->features & DockWidgetClosable) == DockWidgetClosable);
|
---|
1231 | emit featuresChanged(d->features);
|
---|
1232 | update();
|
---|
1233 | }
|
---|
1234 |
|
---|
1235 | QDockWidget::DockWidgetFeatures QDockWidget::features() const
|
---|
1236 | {
|
---|
1237 | Q_D(const QDockWidget);
|
---|
1238 | return d->features;
|
---|
1239 | }
|
---|
1240 |
|
---|
1241 | /*!
|
---|
1242 | \property QDockWidget::floating
|
---|
1243 | \brief whether the dock widget is floating
|
---|
1244 |
|
---|
1245 | A floating dock widget is presented to the user as an independent
|
---|
1246 | window "on top" of its parent QMainWindow, instead of being
|
---|
1247 | docked in the QMainWindow.
|
---|
1248 |
|
---|
1249 | By default, this property is true.
|
---|
1250 |
|
---|
1251 | \sa isWindow()
|
---|
1252 | */
|
---|
1253 | void QDockWidget::setFloating(bool floating)
|
---|
1254 | {
|
---|
1255 | Q_D(QDockWidget);
|
---|
1256 |
|
---|
1257 | // the initial click of a double-click may have started a drag...
|
---|
1258 | if (d->state != 0)
|
---|
1259 | d->endDrag(true);
|
---|
1260 |
|
---|
1261 | QRect r = d->undockedGeometry;
|
---|
1262 |
|
---|
1263 | d->setWindowState(floating, false, floating ? r : QRect());
|
---|
1264 | if (floating && r.isNull()) {
|
---|
1265 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1266 | QRect titleArea = layout->titleArea();
|
---|
1267 | int h = layout->verticalTitleBar ? titleArea.width() : titleArea.height();
|
---|
1268 | QPoint p = mapToGlobal(QPoint(h, h));
|
---|
1269 | move(p);
|
---|
1270 | }
|
---|
1271 | }
|
---|
1272 |
|
---|
1273 | /*!
|
---|
1274 | \property QDockWidget::allowedAreas
|
---|
1275 | \brief areas where the dock widget may be placed
|
---|
1276 |
|
---|
1277 | The default is Qt::AllDockWidgetAreas.
|
---|
1278 |
|
---|
1279 | \sa Qt::DockWidgetArea
|
---|
1280 | */
|
---|
1281 |
|
---|
1282 | void QDockWidget::setAllowedAreas(Qt::DockWidgetAreas areas)
|
---|
1283 | {
|
---|
1284 | Q_D(QDockWidget);
|
---|
1285 | areas &= Qt::DockWidgetArea_Mask;
|
---|
1286 | if (areas == d->allowedAreas)
|
---|
1287 | return;
|
---|
1288 | d->allowedAreas = areas;
|
---|
1289 | emit allowedAreasChanged(d->allowedAreas);
|
---|
1290 | }
|
---|
1291 |
|
---|
1292 | Qt::DockWidgetAreas QDockWidget::allowedAreas() const
|
---|
1293 | {
|
---|
1294 | Q_D(const QDockWidget);
|
---|
1295 | return d->allowedAreas;
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | /*!
|
---|
1299 | \fn bool QDockWidget::isAreaAllowed(Qt::DockWidgetArea area) const
|
---|
1300 |
|
---|
1301 | Returns true if this dock widget can be placed in the given \a area;
|
---|
1302 | otherwise returns false.
|
---|
1303 | */
|
---|
1304 |
|
---|
1305 | /*! \reimp */
|
---|
1306 | void QDockWidget::changeEvent(QEvent *event)
|
---|
1307 | {
|
---|
1308 | Q_D(QDockWidget);
|
---|
1309 | QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1310 |
|
---|
1311 | switch (event->type()) {
|
---|
1312 | case QEvent::ModifiedChange:
|
---|
1313 | case QEvent::WindowTitleChange:
|
---|
1314 | update(layout->titleArea());
|
---|
1315 | #ifndef QT_NO_ACTION
|
---|
1316 | d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(), this);
|
---|
1317 | d->toggleViewAction->setText(d->fixedWindowTitle);
|
---|
1318 | #endif
|
---|
1319 | #ifndef QT_NO_TABBAR
|
---|
1320 | {
|
---|
1321 | QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
|
---|
1322 | if (QMainWindowLayout *winLayout =
|
---|
1323 | (win ? qobject_cast<QMainWindowLayout*>(win->layout()) : 0))
|
---|
1324 | if (QDockAreaLayoutInfo *info =
|
---|
1325 | (winLayout ? winLayout->layoutState.dockAreaLayout.info(this) : 0))
|
---|
1326 | info->updateTabBar();
|
---|
1327 | }
|
---|
1328 | #endif // QT_NO_TABBAR
|
---|
1329 | break;
|
---|
1330 | default:
|
---|
1331 | break;
|
---|
1332 | }
|
---|
1333 | QWidget::changeEvent(event);
|
---|
1334 | }
|
---|
1335 |
|
---|
1336 | /*! \reimp */
|
---|
1337 | void QDockWidget::closeEvent(QCloseEvent *event)
|
---|
1338 | {
|
---|
1339 | Q_D(QDockWidget);
|
---|
1340 | if (d->state)
|
---|
1341 | d->endDrag(true);
|
---|
1342 | QWidget::closeEvent(event);
|
---|
1343 | }
|
---|
1344 |
|
---|
1345 | /*! \reimp */
|
---|
1346 | void QDockWidget::paintEvent(QPaintEvent *event)
|
---|
1347 | {
|
---|
1348 | Q_UNUSED(event)
|
---|
1349 |
|
---|
1350 | QDockWidgetLayout *layout
|
---|
1351 | = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1352 | bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
|
---|
1353 | bool nativeDeco = layout->nativeWindowDeco();
|
---|
1354 |
|
---|
1355 | if (!nativeDeco && !customTitleBar) {
|
---|
1356 | QStylePainter p(this);
|
---|
1357 | // ### Add PixelMetric to change spacers, so style may show border
|
---|
1358 | // when not floating.
|
---|
1359 | if (isFloating()) {
|
---|
1360 | QStyleOptionFrame framOpt;
|
---|
1361 | framOpt.init(this);
|
---|
1362 | p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
|
---|
1363 | }
|
---|
1364 |
|
---|
1365 | // Title must be painted after the frame, since the areas overlap, and
|
---|
1366 | // the title may wish to extend out to all sides (eg. XP style)
|
---|
1367 | QStyleOptionDockWidgetV2 titleOpt;
|
---|
1368 | initStyleOption(&titleOpt);
|
---|
1369 | p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
|
---|
1370 | }
|
---|
1371 | }
|
---|
1372 |
|
---|
1373 | /*! \reimp */
|
---|
1374 | bool QDockWidget::event(QEvent *event)
|
---|
1375 | {
|
---|
1376 | Q_D(QDockWidget);
|
---|
1377 |
|
---|
1378 | QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
|
---|
1379 | QMainWindowLayout *layout = 0;
|
---|
1380 | if (win != 0)
|
---|
1381 | layout = qobject_cast<QMainWindowLayout*>(win->layout());
|
---|
1382 |
|
---|
1383 | switch (event->type()) {
|
---|
1384 | #ifndef QT_NO_ACTION
|
---|
1385 | case QEvent::Hide:
|
---|
1386 | if (layout != 0)
|
---|
1387 | layout->keepSize(this);
|
---|
1388 | d->toggleViewAction->setChecked(false);
|
---|
1389 | emit visibilityChanged(false);
|
---|
1390 | break;
|
---|
1391 | case QEvent::Show:
|
---|
1392 | d->toggleViewAction->setChecked(true);
|
---|
1393 | emit visibilityChanged(true);
|
---|
1394 | break;
|
---|
1395 | #endif
|
---|
1396 | case QEvent::ApplicationLayoutDirectionChange:
|
---|
1397 | case QEvent::LayoutDirectionChange:
|
---|
1398 | case QEvent::StyleChange:
|
---|
1399 | case QEvent::ParentChange:
|
---|
1400 | d->updateButtons();
|
---|
1401 | break;
|
---|
1402 | case QEvent::ZOrderChange: {
|
---|
1403 | bool onTop = false;
|
---|
1404 | if (win != 0) {
|
---|
1405 | const QObjectList &siblings = win->children();
|
---|
1406 | onTop = siblings.count() > 0 && siblings.last() == (QObject*)this;
|
---|
1407 | }
|
---|
1408 | if (!isFloating() && layout != 0 && onTop)
|
---|
1409 | layout->raise(this);
|
---|
1410 | break;
|
---|
1411 | }
|
---|
1412 | case QEvent::WindowActivate:
|
---|
1413 | case QEvent::WindowDeactivate:
|
---|
1414 | update(qobject_cast<QDockWidgetLayout *>(this->layout())->titleArea());
|
---|
1415 | break;
|
---|
1416 | case QEvent::ContextMenu:
|
---|
1417 | if (d->state) {
|
---|
1418 | event->accept();
|
---|
1419 | return true;
|
---|
1420 | }
|
---|
1421 | break;
|
---|
1422 | // return true after calling the handler since we don't want
|
---|
1423 | // them to be passed onto the default handlers
|
---|
1424 | case QEvent::MouseButtonPress:
|
---|
1425 | if (d->mousePressEvent(static_cast<QMouseEvent *>(event)))
|
---|
1426 | return true;
|
---|
1427 | break;
|
---|
1428 | case QEvent::MouseButtonDblClick:
|
---|
1429 | if (d->mouseDoubleClickEvent(static_cast<QMouseEvent *>(event)))
|
---|
1430 | return true;
|
---|
1431 | break;
|
---|
1432 | case QEvent::MouseMove:
|
---|
1433 | if (d->mouseMoveEvent(static_cast<QMouseEvent *>(event)))
|
---|
1434 | return true;
|
---|
1435 | break;
|
---|
1436 | #ifdef Q_OS_WIN
|
---|
1437 | case QEvent::Leave:
|
---|
1438 | if (d->state != 0 && d->state->dragging && !d->state->nca) {
|
---|
1439 | // This is a workaround for loosing the mouse on Vista.
|
---|
1440 | QPoint pos = QCursor::pos();
|
---|
1441 | QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
|
---|
1442 | QApplication::mouseButtons(), QApplication::keyboardModifiers());
|
---|
1443 | d->mouseMoveEvent(&fake);
|
---|
1444 | }
|
---|
1445 | break;
|
---|
1446 | #endif
|
---|
1447 | case QEvent::MouseButtonRelease:
|
---|
1448 | if (d->mouseReleaseEvent(static_cast<QMouseEvent *>(event)))
|
---|
1449 | return true;
|
---|
1450 | break;
|
---|
1451 | case QEvent::NonClientAreaMouseMove:
|
---|
1452 | case QEvent::NonClientAreaMouseButtonPress:
|
---|
1453 | case QEvent::NonClientAreaMouseButtonRelease:
|
---|
1454 | case QEvent::NonClientAreaMouseButtonDblClick:
|
---|
1455 | d->nonClientAreaMouseEvent(static_cast<QMouseEvent*>(event));
|
---|
1456 | return true;
|
---|
1457 | case QEvent::Move:
|
---|
1458 | d->moveEvent(static_cast<QMoveEvent*>(event));
|
---|
1459 | break;
|
---|
1460 | case QEvent::Resize:
|
---|
1461 | // if the mainwindow is plugging us, we don't want to update undocked geometry
|
---|
1462 | if (isFloating() && layout != 0 && layout->pluggingWidget != this)
|
---|
1463 | d->undockedGeometry = geometry();
|
---|
1464 | break;
|
---|
1465 | default:
|
---|
1466 | break;
|
---|
1467 | }
|
---|
1468 | return QWidget::event(event);
|
---|
1469 | }
|
---|
1470 |
|
---|
1471 | #ifndef QT_NO_ACTION
|
---|
1472 | /*!
|
---|
1473 | Returns a checkable action that can be used to show or close this
|
---|
1474 | dock widget.
|
---|
1475 |
|
---|
1476 | The action's text is set to the dock widget's window title.
|
---|
1477 |
|
---|
1478 | \sa QAction::text QWidget::windowTitle
|
---|
1479 | */
|
---|
1480 | QAction * QDockWidget::toggleViewAction() const
|
---|
1481 | {
|
---|
1482 | Q_D(const QDockWidget);
|
---|
1483 | return d->toggleViewAction;
|
---|
1484 | }
|
---|
1485 | #endif // QT_NO_ACTION
|
---|
1486 |
|
---|
1487 | /*!
|
---|
1488 | \fn void QDockWidget::featuresChanged(QDockWidget::DockWidgetFeatures features)
|
---|
1489 |
|
---|
1490 | This signal is emitted when the \l features property changes. The
|
---|
1491 | \a features parameter gives the new value of the property.
|
---|
1492 | */
|
---|
1493 |
|
---|
1494 | /*!
|
---|
1495 | \fn void QDockWidget::topLevelChanged(bool topLevel)
|
---|
1496 |
|
---|
1497 | This signal is emitted when the \l floating property changes.
|
---|
1498 | The \a topLevel parameter is true if the dock widget is now floating;
|
---|
1499 | otherwise it is false.
|
---|
1500 |
|
---|
1501 | \sa isWindow()
|
---|
1502 | */
|
---|
1503 |
|
---|
1504 | /*!
|
---|
1505 | \fn void QDockWidget::allowedAreasChanged(Qt::DockWidgetAreas allowedAreas)
|
---|
1506 |
|
---|
1507 | This signal is emitted when the \l allowedAreas property changes. The
|
---|
1508 | \a allowedAreas parameter gives the new value of the property.
|
---|
1509 | */
|
---|
1510 |
|
---|
1511 | /*!
|
---|
1512 | \fn void QDockWidget::visibilityChanged(bool visible)
|
---|
1513 | \since 4.3
|
---|
1514 |
|
---|
1515 | This signal is emitted when the dock widget becomes \a visible (or
|
---|
1516 | invisible). This happens when the widget is hidden or shown, as
|
---|
1517 | well as when it is docked in a tabbed dock area and its tab
|
---|
1518 | becomes selected or unselected.
|
---|
1519 | */
|
---|
1520 |
|
---|
1521 | /*!
|
---|
1522 | \fn void QDockWidget::dockLocationChanged(Qt::DockWidgetArea area)
|
---|
1523 | \since 4.3
|
---|
1524 |
|
---|
1525 | This signal is emitted when the dock widget is moved to another
|
---|
1526 | dock \a area, or is moved to a different location in its current
|
---|
1527 | dock area. This happens when the dock widget is moved
|
---|
1528 | programmatically or is dragged to a new location by the user.
|
---|
1529 | */
|
---|
1530 |
|
---|
1531 | /*!
|
---|
1532 | \since 4.3
|
---|
1533 | Sets an arbitrary \a widget as the dock widget's title bar. If \a widget
|
---|
1534 | is 0, the title bar widget is removed, but not deleted.
|
---|
1535 |
|
---|
1536 | If a title bar widget is set, QDockWidget will not use native window
|
---|
1537 | decorations when it is floated.
|
---|
1538 |
|
---|
1539 | Here are some tips for implementing custom title bars:
|
---|
1540 |
|
---|
1541 | \list
|
---|
1542 | \i Mouse events that are not explicitly handled by the title bar widget
|
---|
1543 | must be ignored by calling QMouseEvent::ignore(). These events then
|
---|
1544 | propagate to the QDockWidget parent, which handles them in the usual
|
---|
1545 | manner, moving when the title bar is dragged, docking and undocking
|
---|
1546 | when it is double-clicked, etc.
|
---|
1547 |
|
---|
1548 | \i When DockWidgetVerticalTitleBar is set on QDockWidget, the title
|
---|
1549 | bar widget is repositioned accordingly. In resizeEvent(), the title
|
---|
1550 | bar should check what orientation it should assume:
|
---|
1551 | \snippet doc/src/snippets/code/src_gui_widgets_qdockwidget.cpp 0
|
---|
1552 |
|
---|
1553 | \i The title bar widget must have a valid QWidget::sizeHint() and
|
---|
1554 | QWidget::minimumSizeHint(). These functions should take into account
|
---|
1555 | the current orientation of the title bar.
|
---|
1556 | \endlist
|
---|
1557 |
|
---|
1558 | Using qobject_cast as shown above, the title bar widget has full access
|
---|
1559 | to its parent QDockWidget. Hence it can perform such operations as docking
|
---|
1560 | and hiding in response to user actions.
|
---|
1561 |
|
---|
1562 | \sa titleBarWidget() DockWidgetVerticalTitleBar
|
---|
1563 | */
|
---|
1564 |
|
---|
1565 | void QDockWidget::setTitleBarWidget(QWidget *widget)
|
---|
1566 | {
|
---|
1567 | Q_D(QDockWidget);
|
---|
1568 | QDockWidgetLayout *layout
|
---|
1569 | = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1570 | layout->setWidgetForRole(QDockWidgetLayout::TitleBar, widget);
|
---|
1571 | d->updateButtons();
|
---|
1572 | if (isWindow()) {
|
---|
1573 | //this ensures the native decoration is drawn
|
---|
1574 | d->setWindowState(true /*floating*/, true /*unplug*/);
|
---|
1575 | }
|
---|
1576 | }
|
---|
1577 |
|
---|
1578 | /*!
|
---|
1579 | \since 4.3
|
---|
1580 | Returns the custom title bar widget set on the QDockWidget, or 0 if no
|
---|
1581 | custom title bar has been set.
|
---|
1582 |
|
---|
1583 | \sa setTitleBarWidget()
|
---|
1584 | */
|
---|
1585 |
|
---|
1586 | QWidget *QDockWidget::titleBarWidget() const
|
---|
1587 | {
|
---|
1588 | QDockWidgetLayout *layout
|
---|
1589 | = qobject_cast<QDockWidgetLayout*>(this->layout());
|
---|
1590 | return layout->widgetForRole(QDockWidgetLayout::TitleBar);
|
---|
1591 | }
|
---|
1592 |
|
---|
1593 | QT_END_NAMESPACE
|
---|
1594 |
|
---|
1595 | #include "qdockwidget.moc"
|
---|
1596 | #include "moc_qdockwidget.cpp"
|
---|
1597 |
|
---|
1598 | #endif // QT_NO_DOCKWIDGET
|
---|