Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qmainwindowlayout.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
6
7#if QT_CONFIG(dockwidget)
8#include "qdockarealayout_p.h"
9#include "qdockwidget.h"
10#include "qdockwidget_p.h"
11#endif
12#if QT_CONFIG(toolbar)
13#include "qtoolbar_p.h"
14#include "qtoolbar.h"
15#include "qtoolbarlayout_p.h"
16#endif
17#include "qmainwindow.h"
18#include "qwidgetanimator_p.h"
19#if QT_CONFIG(rubberband)
20#include "qrubberband.h"
21#endif
22#if QT_CONFIG(tabbar)
23#include "qtabbar_p.h"
24#endif
25
26#include <qapplication.h>
27#if QT_CONFIG(draganddrop)
28#include <qdrag.h>
29#endif
30#include <qmimedata.h>
31#if QT_CONFIG(statusbar)
32#include <qstatusbar.h>
33#endif
34#include <qstring.h>
35#include <qstyle.h>
36#include <qstylepainter.h>
37#include <qvarlengtharray.h>
38#include <qstack.h>
39#include <qmap.h>
40#include <qtimer.h>
41#include <qpointer.h>
42
43#ifndef QT_NO_DEBUG_STREAM
44# include <qdebug.h>
45# include <qtextstream.h>
46#endif
47
48#include <private/qmenu_p.h>
49#include <private/qapplication_p.h>
50#include <private/qlayoutengine_p.h>
51#include <private/qwidgetresizehandler_p.h>
52
53#include <QScopedValueRollback>
54
56
57using namespace Qt::StringLiterals;
58
60
61/******************************************************************************
62** debug
63*/
64
65#if QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG_STREAM)
66
67static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent);
68
69static void dumpLayout(QTextStream &qout, const QDockAreaLayoutItem &item, QString indent)
70{
71 qout << indent << "QDockAreaLayoutItem: "
72 << "pos: " << item.pos << " size:" << item.size
74 << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) << '\n';
75 indent += " "_L1;
76 if (item.widgetItem != nullptr) {
77 qout << indent << "widget: "
78 << item.widgetItem->widget()->metaObject()->className()
79 << " \"" << item.widgetItem->widget()->windowTitle() << "\"\n";
80 } else if (item.subinfo != nullptr) {
81 qout << indent << "subinfo:\n";
82 dumpLayout(qout, *item.subinfo, indent + " "_L1);
83 } else if (item.placeHolderItem != nullptr) {
84 QRect r = item.placeHolderItem->topLevelRect;
85 qout << indent << "placeHolder: "
86 << "pos: " << item.pos << " size:" << item.size
88 << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize)
89 << " objectName:" << item.placeHolderItem->objectName
90 << " hidden:" << item.placeHolderItem->hidden
91 << " window:" << item.placeHolderItem->window
92 << " rect:" << r.x() << ',' << r.y() << ' '
93 << r.width() << 'x' << r.height() << '\n';
94 }
95}
96
97static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent)
98{
99 const QSize minSize = layout.minimumSize();
100 qout << indent << "QDockAreaLayoutInfo: "
101 << layout.rect.left() << ','
102 << layout.rect.top() << ' '
103 << layout.rect.width() << 'x'
104 << layout.rect.height()
105 << " min size: " << minSize.width() << ',' << minSize.height()
106 << " orient:" << layout.o
107#if QT_CONFIG(tabbar)
108 << " tabbed:" << layout.tabbed
109 << " tbshape:" << layout.tabBarShape
110#endif
111 << '\n';
112
113 indent += " "_L1;
114
115 for (int i = 0; i < layout.item_list.size(); ++i) {
116 qout << indent << "Item: " << i << '\n';
117 dumpLayout(qout, layout.item_list.at(i), indent + " "_L1);
118 }
119}
120
121static void dumpLayout(QTextStream &qout, const QDockAreaLayout &layout)
122{
123 qout << "QDockAreaLayout: "
124 << layout.rect.left() << ','
125 << layout.rect.top() << ' '
126 << layout.rect.width() << 'x'
127 << layout.rect.height() << '\n';
128
129 qout << "TopDockArea:\n";
130 dumpLayout(qout, layout.docks[QInternal::TopDock], " "_L1);
131 qout << "LeftDockArea:\n";
132 dumpLayout(qout, layout.docks[QInternal::LeftDock], " "_L1);
133 qout << "RightDockArea:\n";
134 dumpLayout(qout, layout.docks[QInternal::RightDock], " "_L1);
135 qout << "BottomDockArea:\n";
136 dumpLayout(qout, layout.docks[QInternal::BottomDock], " "_L1);
137}
138
140{
141 QString s;
142 QTextStream str(&s);
143 dumpLayout(str, layout);
144 debug << s;
145 return debug;
146}
147
149{
150 debug << layout->layoutState.dockAreaLayout;
151 return debug;
152}
153
154// Use this to dump item lists of all populated main window docks.
155// Use DUMP macro inside QMainWindowLayout
156#if 0
157static void dumpItemLists(const QMainWindowLayout *layout, const char *function, const char *comment)
158{
159 for (int i = 0; i < QInternal::DockCount; ++i) {
160 const auto &list = layout->layoutState.dockAreaLayout.docks[i].item_list;
161 if (list.isEmpty())
162 continue;
163 qDebug() << function << comment << "Dock" << i << list;
164 }
165}
166#define DUMP(comment) dumpItemLists(this, __FUNCTION__, comment)
167#endif // 0
168
169#endif // QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG)
170
171
205#if QT_CONFIG(dockwidget)
206class QDockWidgetGroupLayout : public QLayout,
207 public QMainWindowLayoutSeparatorHelper<QDockWidgetGroupLayout>
208{
209 QWidgetResizeHandler *resizer;
210public:
211 QDockWidgetGroupLayout(QDockWidgetGroupWindow* parent) : QLayout(parent) {
212 setSizeConstraint(QLayout::SetMinAndMaxSize);
213 resizer = new QWidgetResizeHandler(parent);
214 }
215 ~QDockWidgetGroupLayout() {
216 layoutState.deleteAllLayoutItems();
217 }
218
219 void addItem(QLayoutItem*) override { Q_UNREACHABLE(); }
220 int count() const override { return 0; }
221 QLayoutItem* itemAt(int index) const override
222 {
223 int x = 0;
224 return layoutState.itemAt(&x, index);
225 }
226 QLayoutItem* takeAt(int index) override
227 {
228 int x = 0;
229 QLayoutItem *ret = layoutState.takeAt(&x, index);
230 if (savedState.rect.isValid() && ret->widget()) {
231 // we need to remove the item also from the saved state to prevent crash
232 QList<int> path = savedState.indexOf(ret->widget());
233 if (!path.isEmpty())
234 savedState.remove(path);
235 // Also, the item may be contained several times as a gap item.
236 path = layoutState.indexOf(ret->widget());
237 if (!path.isEmpty())
238 layoutState.remove(path);
239 }
240 return ret;
241 }
242 QSize sizeHint() const override
243 {
244 int fw = frameWidth();
245 return layoutState.sizeHint() + QSize(fw, fw);
246 }
247 QSize minimumSize() const override
248 {
249 int fw = frameWidth();
250 return layoutState.minimumSize() + QSize(fw, fw);
251 }
252 QSize maximumSize() const override
253 {
254 int fw = frameWidth();
255 return layoutState.maximumSize() + QSize(fw, fw);
256 }
257 void setGeometry(const QRect&r) override
258 {
259 groupWindow()->destroyOrHideIfEmpty();
260 QDockAreaLayoutInfo *li = dockAreaLayoutInfo();
261 if (li->isEmpty())
262 return;
263 int fw = frameWidth();
264#if QT_CONFIG(tabbar)
265 li->reparentWidgets(parentWidget());
266#endif
267 li->rect = r.adjusted(fw, fw, -fw, -fw);
268 li->fitItems();
269 li->apply(false);
270 if (savedState.rect.isValid())
271 savedState.rect = li->rect;
272 resizer->setEnabled(!nativeWindowDeco());
273 }
274
275 QDockAreaLayoutInfo *dockAreaLayoutInfo() { return &layoutState; }
276
277 bool nativeWindowDeco() const
278 {
279 return groupWindow()->hasNativeDecos();
280 }
281
282 int frameWidth() const
283 {
284 return nativeWindowDeco() ? 0 :
285 parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, nullptr, parentWidget());
286 }
287
288 QDockWidgetGroupWindow *groupWindow() const
289 {
290 return static_cast<QDockWidgetGroupWindow *>(parent());
291 }
292
293 QDockAreaLayoutInfo layoutState;
294 QDockAreaLayoutInfo savedState;
295};
296
297bool QDockWidgetGroupWindow::event(QEvent *e)
298{
299 auto lay = static_cast<QDockWidgetGroupLayout *>(layout());
300 if (lay && lay->windowEvent(e))
301 return true;
302
303 switch (e->type()) {
304 case QEvent::Close:
305#if QT_CONFIG(tabbar)
306 // Forward the close to the QDockWidget just as if its close button was pressed
307 if (QDockWidget *dw = activeTabbedDockWidget()) {
308 dw->close();
309 adjustFlags();
310 }
311#endif
312 return true;
313 case QEvent::Move:
314#if QT_CONFIG(tabbar)
315 // Let QDockWidgetPrivate::moseEvent handle the dragging
316 if (QDockWidget *dw = activeTabbedDockWidget())
317 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->moveEvent(static_cast<QMoveEvent*>(e));
318#endif
319 return true;
324#if QT_CONFIG(tabbar)
325 // Let the QDockWidgetPrivate of the currently visible dock widget handle the drag and drop
326 if (QDockWidget *dw = activeTabbedDockWidget())
327 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->nonClientAreaMouseEvent(static_cast<QMouseEvent*>(e));
328#endif
329 return true;
331 if (qobject_cast<QDockWidget *>(static_cast<QChildEvent*>(e)->child()))
332 adjustFlags();
333 break;
335 // We might need to show the widget again
336 destroyOrHideIfEmpty();
337 break;
338 case QEvent::Resize:
339 updateCurrentGapRect();
340 emit resized();
341 break;
342 default:
343 break;
344 }
345 return QWidget::event(e);
346}
347
348void QDockWidgetGroupWindow::paintEvent(QPaintEvent *)
349{
350 QDockWidgetGroupLayout *lay = static_cast<QDockWidgetGroupLayout *>(layout());
351 bool nativeDeco = lay->nativeWindowDeco();
352
353 if (!nativeDeco) {
354 QStyleOptionFrame framOpt;
355 framOpt.initFrom(this);
356 QStylePainter p(this);
357 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
358 }
359}
360
361QDockAreaLayoutInfo *QDockWidgetGroupWindow::layoutInfo() const
362{
363 return static_cast<QDockWidgetGroupLayout *>(layout())->dockAreaLayoutInfo();
364}
365
366#if QT_CONFIG(tabbar)
372const QDockAreaLayoutInfo *QDockWidgetGroupWindow::tabLayoutInfo() const
373{
374 const QDockAreaLayoutInfo *info = layoutInfo();
375 while (info && !info->tabbed) {
376 // There should be only one tabbed subinfo otherwise we are not a floating tab but a real
377 // window
378 const QDockAreaLayoutInfo *next = nullptr;
379 bool isSingle = false;
380 for (const auto &item : info->item_list) {
382 continue;
383 if (next || isSingle) // Two visible things
384 return nullptr;
385 if (item.subinfo)
386 next = item.subinfo;
387 else if (item.widgetItem)
388 isSingle = true;
389 }
390 if (isSingle)
391 return info;
392 info = next;
393 }
394 return info;
395}
396
400QDockWidget *QDockWidgetGroupWindow::activeTabbedDockWidget() const
401{
402 QDockWidget *dw = nullptr;
403 const QDockAreaLayoutInfo *info = tabLayoutInfo();
404 if (!info)
405 return nullptr;
406 if (info->tabBar && info->tabBar->currentIndex() >= 0) {
407 int i = info->tabIndexToListIndex(info->tabBar->currentIndex());
408 if (i >= 0) {
409 const QDockAreaLayoutItem &item = info->item_list.at(i);
410 if (item.widgetItem)
411 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
412 }
413 }
414 if (!dw) {
415 for (int i = 0; !dw && i < info->item_list.size(); ++i) {
416 const QDockAreaLayoutItem &item = info->item_list.at(i);
417 if (item.skip())
418 continue;
419 if (!item.widgetItem)
420 continue;
421 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
422 }
423 }
424 return dw;
425}
426#endif // QT_CONFIG(tabbar)
427
432void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
433{
434 const QDockAreaLayoutInfo *info = layoutInfo();
435 if (!info->isEmpty()) {
436 show(); // It might have been hidden,
437 return;
438 }
439 // There might still be placeholders
440 if (!info->item_list.isEmpty()) {
441 hide();
442 return;
443 }
444
445 // Make sure to reparent the possibly floating or hidden QDockWidgets to the parent
446 const auto dockWidgetsList = dockWidgets();
447 for (QDockWidget *dw : dockWidgetsList) {
448 const bool wasFloating = dw->isFloating();
449 const bool wasHidden = dw->isHidden();
450 dw->setParent(parentWidget());
451 qCDebug(lcQpaDockWidgets) << "Reparented:" << dw << "to" << parentWidget() << "by" << this;
452 if (wasFloating) {
453 dw->setFloating(true);
454 } else {
455 // maybe it was hidden, we still have to put it back in the main layout.
457 qt_mainwindow_layout(static_cast<QMainWindow *>(parentWidget()));
458 Qt::DockWidgetArea area = ml->dockWidgetArea(this);
460 area = Qt::LeftDockWidgetArea; // FIXME: DockWidget doesn't save original docking area
461 static_cast<QMainWindow *>(parentWidget())->addDockWidget(area, dw);
462 qCDebug(lcQpaDockWidgets) << "Redocked to Mainwindow:" << area << dw << "by" << this;
463 }
464 if (!wasHidden)
465 dw->show();
466 }
467 deleteLater();
468}
469
475bool QDockWidgetGroupWindow::hasVisibleDockWidgets() const
476{
477 const auto &children = findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
478 for (auto child : children) {
479 // WA_WState_Visible is set on the dock widget, associated to the active tab
480 // and unset on all others.
481 // WA_WState_Hidden is set if the dock widgets have been explicitly hidden.
482 // This is the relevant information to check (equivalent to !child->isHidden()).
483 if (!child->testAttribute(Qt::WA_WState_Hidden))
484 return true;
485 }
486 return false;
487}
488
492void QDockWidgetGroupWindow::adjustFlags()
493{
494 Qt::WindowFlags oldFlags = windowFlags();
495 Qt::WindowFlags flags = oldFlags;
496
497#if QT_CONFIG(tabbar)
498 QDockWidget *top = activeTabbedDockWidget();
499#else
500 QDockWidget *top = nullptr;
501#endif
502 if (!top) { // nested tabs, show window decoration
503 flags =
504 ((oldFlags & ~Qt::FramelessWindowHint) | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
505 } else if (static_cast<QDockWidgetGroupLayout *>(layout())->nativeWindowDeco()) {
508 flags &= ~Qt::FramelessWindowHint;
509 } else {
512 }
513
514 if (oldFlags != flags) {
515 if (!windowHandle())
516 create(); // The desired geometry is forgotten if we call setWindowFlags before having a window
517 setWindowFlags(flags);
518 const bool gainedNativeDecos = (oldFlags & Qt::FramelessWindowHint) && !(flags & Qt::FramelessWindowHint);
519 const bool lostNativeDecos = !(oldFlags & Qt::FramelessWindowHint) && (flags & Qt::FramelessWindowHint);
520
521 // Adjust the geometry after gaining/losing decos, so that the client area appears always
522 // at the same place when tabbing
523 if (lostNativeDecos) {
524 QRect newGeometry = geometry();
525 newGeometry.setTop(frameGeometry().top());
526 const int bottomFrame = geometry().top() - frameGeometry().top();
527 m_removedFrameSize = QSize((frameSize() - size()).width(), bottomFrame);
528 setGeometry(newGeometry);
529 } else if (gainedNativeDecos && m_removedFrameSize.isValid()) {
530 QRect r = geometry();
531 r.adjust(-m_removedFrameSize.width() / 2, 0,
532 -m_removedFrameSize.width() / 2, -m_removedFrameSize.height());
533 setGeometry(r);
534 m_removedFrameSize = QSize();
535 }
536
537 setVisible(hasVisibleDockWidgets());
538 }
539
540 QWidget *titleBarOf = top ? top : parentWidget();
541 setWindowTitle(titleBarOf->windowTitle());
542 setWindowIcon(titleBarOf->windowIcon());
543}
544
545bool QDockWidgetGroupWindow::hasNativeDecos() const
546{
547#if QT_CONFIG(tabbar)
548 QDockWidget *dw = activeTabbedDockWidget();
549 if (!dw) // We have a group of nested QDockWidgets (not just floating tabs)
550 return true;
551
553 return false;
554
555 return dw->titleBarWidget() == nullptr;
556#else
557 return true;
558#endif
559}
560
561/*
562 The given widget is hovered over this floating group.
563 This function will save the state and create a gap in the actual state.
564 currentGapRect and currentGapPos will be set.
565 One must call restore() or apply() after this function.
566 Returns true if there was any change in the currentGapPos
567 */
568bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem, const QPoint &mousePos)
569{
570 QDockAreaLayoutInfo &savedState = static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
571 if (savedState.isEmpty())
572 savedState = *layoutInfo();
573
574 QMainWindow::DockOptions opts = static_cast<QMainWindow *>(parentWidget())->dockOptions();
575 QDockAreaLayoutInfo newState = savedState;
576 bool nestingEnabled =
579#if !QT_CONFIG(tabbar)
581#else
583 if (auto group = qobject_cast<QDockWidgetGroupWindow *>(widgetItem->widget())) {
584 if (!group->tabLayoutInfo())
586 }
587 if (newState.tabbed) {
588 // insertion into a top-level tab
590 newState.item_list.first().size = pick(savedState.o, savedState.rect.size());
591 newState.tabbed = false;
592 newState.tabBar = nullptr;
593 }
594#endif
595
596 auto newGapPos = newState.gapIndex(mousePos, nestingEnabled, tabMode);
597 Q_ASSERT(!newGapPos.isEmpty());
598
599 // Do not insert a new gap item, if the current position already is a gap,
600 // or if the group window contains one
601 if (newGapPos == currentGapPos || newState.hasGapItem(newGapPos))
602 return false;
603
604 currentGapPos = newGapPos;
605 newState.insertGap(currentGapPos, widgetItem);
606 newState.fitItems();
607 *layoutInfo() = std::move(newState);
608 updateCurrentGapRect();
609 layoutInfo()->apply(opts & QMainWindow::AnimatedDocks);
610 return true;
611}
612
613void QDockWidgetGroupWindow::updateCurrentGapRect()
614{
615 if (!currentGapPos.isEmpty())
616 currentGapRect = layoutInfo()->info(currentGapPos)->itemRect(currentGapPos.last(), true);
617}
618
619/*
620 Remove the gap that was created by hover()
621 */
622void QDockWidgetGroupWindow::restore()
623{
624 QDockAreaLayoutInfo &savedState = static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
625 if (!savedState.isEmpty()) {
626 *layoutInfo() = savedState;
627 savedState = QDockAreaLayoutInfo();
628 }
629 currentGapRect = QRect();
630 currentGapPos.clear();
631 adjustFlags();
632 layoutInfo()->fitItems();
633 layoutInfo()->apply(static_cast<QMainWindow *>(parentWidget())->dockOptions()
635}
636
637/*
638 Apply the state that was created by hover
639 */
640void QDockWidgetGroupWindow::apply()
641{
642 static_cast<QDockWidgetGroupLayout *>(layout())->savedState.clear();
643 currentGapRect = QRect();
644 layoutInfo()->plug(currentGapPos);
645 currentGapPos.clear();
646 adjustFlags();
647 layoutInfo()->apply(false);
648}
649
650void QDockWidgetGroupWindow::childEvent(QChildEvent *event)
651{
652 switch (event->type()) {
654 if (auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
656 destroyIfSingleItemLeft();
657 break;
659 if (auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
661 break;
662 default:
663 break;
664 }
665}
666
667bool QDockWidgetGroupWindow::eventFilter(QObject *obj, QEvent *event)
668{
669 auto *dockWidget = qobject_cast<QDockWidget *>(obj);
670 if (!dockWidget)
672
673 switch (event->type()) {
674 case QEvent::Close:
675 // We don't want closed dock widgets in a floating tab
676 // => dock it to the main dock, before closing;
677 reparent(dockWidget);
678 dockWidget->setFloating(false);
679 break;
680
681 case QEvent::Hide:
682 // if the dock widget is not an active tab, it is hidden anyway.
683 // if it is the active tab, hide the whole group.
684 if (dockWidget->isVisible())
685 hide();
686 break;
687
688 default:
689 break;
690 }
692}
693
694void QDockWidgetGroupWindow::destroyIfSingleItemLeft()
695{
696 const auto &dockWidgets = this->dockWidgets();
697
698 // Handle only the last dock
699 if (dockWidgets.count() != 1)
700 return;
701
702 auto *lastDockWidget = dockWidgets.at(0);
703
704 // If the last remaining dock widget is not in the group window's item_list,
705 // a group window is being docked on a main window docking area.
706 // => don't interfere
707 if (layoutInfo()->indexOf(lastDockWidget).isEmpty())
708 return;
709
710 auto *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
711 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
712
713 // Unplug the last remaining dock widget and hide the group window, to avoid flickering
714 mwLayout->unplug(lastDockWidget, QDockWidgetPrivate::DragScope::Widget);
715 lastDockWidget->setGeometry(geometry());
716 hide();
717
718 // Get the layout info for the main window dock, where dock widgets need to go
719 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
720
721 // Re-parent last dock widget
722 reparent(lastDockWidget);
723
724 // the group window could still have placeholder items => clear everything
725 layoutInfo()->item_list.clear();
726
727 // remove the group window and the dock's item_list pointing to it.
728 parentInfo.remove(this);
729 destroyOrHideIfEmpty();
730}
731
732void QDockWidgetGroupWindow::reparent(QDockWidget *dockWidget)
733{
734 // reparent a dockWidget to the main window
735 // - remove it from the floating dock's layout info
736 // - insert it to the main dock's layout info
737 // Finally, set draggingDock to nullptr, since the drag is finished.
738 auto *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
739 Q_ASSERT(mainWindow);
740 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
741 Q_ASSERT(mwLayout);
742 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
744 parentInfo.add(dockWidget);
745 layoutInfo()->remove(dockWidget);
746 const bool wasFloating = dockWidget->isFloating();
747 const bool wasVisible = dockWidget->isVisible();
748 dockWidget->setParent(mainWindow);
749 dockWidget->setFloating(wasFloating);
750 dockWidget->setVisible(wasVisible);
751}
752#endif
753
754/******************************************************************************
755** QMainWindowLayoutState
756*/
757
758// we deal with all the #ifndefferry here so QMainWindowLayout code is clean
759
761 :
762#if QT_CONFIG(toolbar)
763 toolBarAreaLayout(win),
764#endif
765#if QT_CONFIG(dockwidget)
766 dockAreaLayout(win)
767#else
768 centralWidgetItem(0)
769#endif
770
771{
772 mainWindow = win;
773}
774
776{
777
778 QSize result(0, 0);
779
780#if QT_CONFIG(dockwidget)
781 result = dockAreaLayout.sizeHint();
782#else
785#endif
786
787#if QT_CONFIG(toolbar)
788 result = toolBarAreaLayout.sizeHint(result);
789#endif // QT_CONFIG(toolbar)
790
791 return result;
792}
793
795{
796 QSize result(0, 0);
797
798#if QT_CONFIG(dockwidget)
799 result = dockAreaLayout.minimumSize();
800#else
803#endif
804
805#if QT_CONFIG(toolbar)
806 result = toolBarAreaLayout.minimumSize(result);
807#endif // QT_CONFIG(toolbar)
808
809 return result;
810}
811
818{
820
821 QSize size;
822
823#if QT_CONFIG(dockwidget)
824 size = dockAreaLayout.minimumStableSize();
825#endif
826
827#if QT_CONFIG(toolbar)
828 size.rwidth() += toolBarAreaLayout.docks[QInternal::LeftDock].rect.width();
829 size.rwidth() += toolBarAreaLayout.docks[QInternal::RightDock].rect.width();
830 size.rheight() += toolBarAreaLayout.docks[QInternal::TopDock].rect.height();
831 size.rheight() += toolBarAreaLayout.docks[QInternal::BottomDock].rect.height();
832#endif
833
834 return size.width() <= mainWindow->width() && size.height() <= mainWindow->height();
835}
836
838{
839#if QT_CONFIG(toolbar)
840 toolBarAreaLayout.apply(animated);
841#endif
842
843#if QT_CONFIG(dockwidget)
844// dumpLayout(dockAreaLayout, QString());
845 dockAreaLayout.apply(animated);
846#else
847 if (centralWidgetItem) {
850 layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, animated);
851 }
852#endif
853}
854
856{
857 QRect r;
858#if !QT_CONFIG(toolbar)
859 r = rect;
860#else
861 toolBarAreaLayout.rect = rect;
862 r = toolBarAreaLayout.fitLayout();
863#endif // QT_CONFIG(toolbar)
864
865#if QT_CONFIG(dockwidget)
866 dockAreaLayout.rect = r;
867 dockAreaLayout.fitLayout();
868#else
870#endif
871}
872
874{
875#if QT_CONFIG(toolbar)
876 toolBarAreaLayout.deleteAllLayoutItems();
877#endif
878
879#if QT_CONFIG(dockwidget)
880 dockAreaLayout.deleteAllLayoutItems();
881#endif
882}
883
885{
886#if QT_CONFIG(dockwidget)
887 delete dockAreaLayout.centralWidgetItem;
888 dockAreaLayout.centralWidgetItem = nullptr;
889#else
890 delete centralWidgetItem;
892#endif
893}
894
896{
897#if QT_CONFIG(toolbar)
898 if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
899 return ret;
900#endif
901
902#if QT_CONFIG(dockwidget)
903 if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
904 return ret;
905#else
906 if (centralWidgetItem && (*x)++ == index)
907 return centralWidgetItem;
908#endif
909
910 return nullptr;
911}
912
914{
915#if QT_CONFIG(toolbar)
916 if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
917 return ret;
918#endif
919
920#if QT_CONFIG(dockwidget)
921 if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
922 return ret;
923#else
924 if (centralWidgetItem && (*x)++ == index) {
926 centralWidgetItem = nullptr;
927 return ret;
928 }
929#endif
930
931 return nullptr;
932}
933
935{
936 QList<int> result;
937
938#if QT_CONFIG(toolbar)
939 // is it a toolbar?
940 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
941 result = toolBarAreaLayout.indexOf(toolBar);
942 if (!result.isEmpty())
943 result.prepend(0);
944 return result;
945 }
946#endif
947
948#if QT_CONFIG(dockwidget)
949 // is it a dock widget?
950 if (qobject_cast<QDockWidget *>(widget) || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
951 result = dockAreaLayout.indexOf(widget);
952 if (!result.isEmpty())
953 result.prepend(1);
954 return result;
955 }
956#endif // QT_CONFIG(dockwidget)
957
958 return result;
959}
960
962{
963#if QT_CONFIG(dockwidget)
964 if (dockAreaLayout.centralWidgetItem != nullptr && dockAreaLayout.centralWidgetItem->widget() == widget)
965 return true;
966 if (!dockAreaLayout.indexOf(widget).isEmpty())
967 return true;
968#else
970 return true;
971#endif
972
973#if QT_CONFIG(toolbar)
974 if (!toolBarAreaLayout.indexOf(widget).isEmpty())
975 return true;
976#endif
977 return false;
978}
979
981{
982 QLayoutItem *item = nullptr;
983 //make sure we remove the widget
985
986 if (widget != nullptr)
988
989#if QT_CONFIG(dockwidget)
990 dockAreaLayout.centralWidgetItem = item;
991#else
993#endif
994}
995
997{
998 QLayoutItem *item = nullptr;
999
1000#if QT_CONFIG(dockwidget)
1001 item = dockAreaLayout.centralWidgetItem;
1002#else
1004#endif
1005
1006 if (item != nullptr)
1007 return item->widget();
1008 return nullptr;
1009}
1010
1012 const QPoint &pos) const
1013{
1014 QList<int> result;
1015
1016#if QT_CONFIG(toolbar)
1017 // is it a toolbar?
1018 if (qobject_cast<QToolBar*>(widget) != nullptr) {
1019 result = toolBarAreaLayout.gapIndex(pos);
1020 if (!result.isEmpty())
1021 result.prepend(0);
1022 return result;
1023 }
1024#endif
1025
1026#if QT_CONFIG(dockwidget)
1027 // is it a dock widget?
1028 if (qobject_cast<QDockWidget *>(widget) != nullptr
1029 || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1030 bool disallowTabs = false;
1031#if QT_CONFIG(tabbar)
1032 if (auto *group = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1033 if (!group->tabLayoutInfo()) // Disallow to drop nested docks as a tab
1034 disallowTabs = true;
1035 }
1036#endif
1037 result = dockAreaLayout.gapIndex(pos, disallowTabs);
1038 if (!result.isEmpty())
1039 result.prepend(1);
1040 return result;
1041 }
1042#endif // QT_CONFIG(dockwidget)
1043
1044 return result;
1045}
1046
1048{
1049 if (path.isEmpty())
1050 return false;
1051
1052 int i = path.first();
1053
1054#if QT_CONFIG(toolbar)
1055 if (i == 0) {
1056 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) != nullptr);
1057 return toolBarAreaLayout.insertGap(path.mid(1), item);
1058 }
1059#endif
1060
1061#if QT_CONFIG(dockwidget)
1062 if (i == 1) {
1063 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) || qobject_cast<QDockWidgetGroupWindow*>(item->widget()));
1064 return dockAreaLayout.insertGap(path.mid(1), item);
1065 }
1066#endif // QT_CONFIG(dockwidget)
1067
1068 return false;
1069}
1070
1072{
1073 int i = path.first();
1074
1075#if QT_CONFIG(toolbar)
1076 if (i == 0)
1077 toolBarAreaLayout.remove(path.mid(1));
1078#endif
1079
1080#if QT_CONFIG(dockwidget)
1081 if (i == 1)
1082 dockAreaLayout.remove(path.mid(1));
1083#endif // QT_CONFIG(dockwidget)
1084}
1085
1087{
1088#if QT_CONFIG(toolbar)
1089 toolBarAreaLayout.remove(item);
1090#endif
1091
1092#if QT_CONFIG(dockwidget)
1093 // is it a dock widget?
1094 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
1095 QList<int> path = dockAreaLayout.indexOf(dockWidget);
1096 if (!path.isEmpty())
1097 dockAreaLayout.remove(path);
1098 }
1099#endif // QT_CONFIG(dockwidget)
1100}
1101
1103{
1104#if QT_CONFIG(toolbar)
1105 toolBarAreaLayout.clear();
1106#endif
1107
1108#if QT_CONFIG(dockwidget)
1109 dockAreaLayout.clear();
1110#else
1112#endif
1113
1114 rect = QRect();
1115}
1116
1118{
1119 return rect.isValid();
1120}
1121
1123{
1124 int i = path.first();
1125
1126#if QT_CONFIG(toolbar)
1127 if (i == 0) {
1128 const QToolBarAreaLayoutItem *tbItem = toolBarAreaLayout.item(path.mid(1));
1129 Q_ASSERT(tbItem);
1130 return tbItem->widgetItem;
1131 }
1132#endif
1133
1134#if QT_CONFIG(dockwidget)
1135 if (i == 1)
1136 return dockAreaLayout.item(path.mid(1)).widgetItem;
1137#endif // QT_CONFIG(dockwidget)
1138
1139 return nullptr;
1140}
1141
1143{
1144 int i = path.first();
1145
1146#if QT_CONFIG(toolbar)
1147 if (i == 0)
1148 return toolBarAreaLayout.itemRect(path.mid(1));
1149#endif
1150
1151#if QT_CONFIG(dockwidget)
1152 if (i == 1)
1153 return dockAreaLayout.itemRect(path.mid(1));
1154#endif // QT_CONFIG(dockwidget)
1155
1156 return QRect();
1157}
1158
1160{
1161 int i = path.first();
1162
1163#if QT_CONFIG(toolbar)
1164 if (i == 0)
1165 return toolBarAreaLayout.itemRect(path.mid(1));
1166#endif
1167
1168#if QT_CONFIG(dockwidget)
1169 if (i == 1)
1170 return dockAreaLayout.gapRect(path.mid(1));
1171#endif // QT_CONFIG(dockwidget)
1172
1173 return QRect();
1174}
1175
1177{
1178 int i = path.first();
1179
1180#if QT_CONFIG(toolbar)
1181 if (i == 0)
1182 return toolBarAreaLayout.plug(path.mid(1));
1183#endif
1184
1185#if QT_CONFIG(dockwidget)
1186 if (i == 1)
1187 return dockAreaLayout.plug(path.mid(1));
1188#endif // QT_CONFIG(dockwidget)
1189
1190 return nullptr;
1191}
1192
1194{
1195 int i = path.first();
1196
1197#if !QT_CONFIG(toolbar)
1198 Q_UNUSED(other);
1199#else
1200 if (i == 0)
1201 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout : nullptr);
1202#endif
1203
1204#if QT_CONFIG(dockwidget)
1205 if (i == 1)
1206 return dockAreaLayout.unplug(path.mid(1));
1207#endif // QT_CONFIG(dockwidget)
1208
1209 return nullptr;
1210}
1211
1213{
1214#if QT_CONFIG(dockwidget)
1215 dockAreaLayout.saveState(stream);
1216#if QT_CONFIG(tabbar)
1217 const QList<QDockWidgetGroupWindow *> floatingTabs =
1218 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
1219
1220 for (QDockWidgetGroupWindow *floating : floatingTabs) {
1221 if (floating->layoutInfo()->isEmpty())
1222 continue;
1223 stream << uchar(QDockAreaLayout::FloatingDockWidgetTabMarker) << floating->geometry();
1224 floating->layoutInfo()->saveState(stream);
1225 }
1226#endif
1227#endif
1228#if QT_CONFIG(toolbar)
1229 toolBarAreaLayout.saveState(stream);
1230#endif
1231}
1232
1233template <typename T>
1234static QList<T> findChildrenHelper(const QObject *o)
1235{
1236 const QObjectList &list = o->children();
1237 QList<T> result;
1238
1239 for (int i=0; i < list.size(); ++i) {
1240 if (T t = qobject_cast<T>(list[i])) {
1241 result.append(t);
1242 }
1243 }
1244
1245 return result;
1246}
1247
1248#if QT_CONFIG(dockwidget)
1249static QList<QDockWidget*> allMyDockWidgets(const QWidget *mainWindow)
1250{
1251 QList<QDockWidget*> result;
1252 for (QObject *c : mainWindow->children()) {
1253 if (auto *dw = qobject_cast<QDockWidget*>(c)) {
1254 result.append(dw);
1255 } else if (auto *gw = qobject_cast<QDockWidgetGroupWindow*>(c)) {
1256 for (QObject *c : gw->children()) {
1257 if (auto *dw = qobject_cast<QDockWidget*>(c))
1258 result.append(dw);
1259 }
1260 }
1261 }
1262
1263 return result;
1264}
1265#endif // QT_CONFIG(dockwidget)
1266
1267//pre4.3 tests the format that was used before 4.3
1269{
1270 while (!stream.atEnd()) {
1271 uchar marker;
1272 stream >> marker;
1273 switch(marker)
1274 {
1275#if QT_CONFIG(toolbar)
1278 {
1279 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1280 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, true /*testing*/)) {
1281 return false;
1282 }
1283 }
1284 break;
1285#endif // QT_CONFIG(toolbar)
1286
1287#if QT_CONFIG(dockwidget)
1289 {
1290 const auto dockWidgets = allMyDockWidgets(mainWindow);
1291 if (!dockAreaLayout.restoreState(stream, dockWidgets, true /*testing*/)) {
1292 return false;
1293 }
1294 }
1295 break;
1296#if QT_CONFIG(tabbar)
1298 {
1299 QRect geom;
1300 stream >> geom;
1302 auto dockWidgets = allMyDockWidgets(mainWindow);
1303 if (!info.restoreState(stream, dockWidgets, true /* testing*/))
1304 return false;
1305 }
1306 break;
1307#endif // QT_CONFIG(tabbar)
1308#endif // QT_CONFIG(dockwidget)
1309 default:
1310 //there was an error during the parsing
1311 return false;
1312 }// switch
1313 } //while
1314
1315 //everything went fine: it must be a pre-4.3 saved state
1316 return true;
1317}
1318
1320 const QMainWindowLayoutState &oldState)
1321{
1322 //make a copy of the data so that we can read it more than once
1324 while(!_stream.atEnd()) {
1325 int length = 1024;
1326 QByteArray ba(length, '\0');
1327 length = _stream.readRawData(ba.data(), ba.size());
1328 ba.resize(length);
1329 copy += ba;
1330 }
1331
1332 QDataStream ds(copy);
1333 ds.setVersion(_stream.version());
1334 if (!checkFormat(ds))
1335 return false;
1336
1338 stream.setVersion(_stream.version());
1339
1340 while (!stream.atEnd()) {
1341 uchar marker;
1342 stream >> marker;
1343 switch(marker)
1344 {
1345#if QT_CONFIG(dockwidget)
1347 {
1348 const auto dockWidgets = allMyDockWidgets(mainWindow);
1349 if (!dockAreaLayout.restoreState(stream, dockWidgets))
1350 return false;
1351
1352 for (int i = 0; i < dockWidgets.size(); ++i) {
1353 QDockWidget *w = dockWidgets.at(i);
1354 QList<int> path = dockAreaLayout.indexOf(w);
1355 if (path.isEmpty()) {
1356 QList<int> oldPath = oldState.dockAreaLayout.indexOf(w);
1357 if (oldPath.isEmpty()) {
1358 continue;
1359 }
1360 QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
1361 if (info == nullptr) {
1362 continue;
1363 }
1364 info->add(w);
1365 }
1366 }
1367 }
1368 break;
1369#if QT_CONFIG(tabwidget)
1371 {
1372 auto dockWidgets = allMyDockWidgets(mainWindow);
1373 QDockWidgetGroupWindow* floatingTab = qt_mainwindow_layout(mainWindow)->createTabbedDockWindow();
1374 *floatingTab->layoutInfo() = QDockAreaLayoutInfo(
1375 &dockAreaLayout.sep, QInternal::LeftDock, // FIXME: DockWidget doesn't save original docking area
1377 QRect geometry;
1378 stream >> geometry;
1379 QDockAreaLayoutInfo *info = floatingTab->layoutInfo();
1380 if (!info->restoreState(stream, dockWidgets, false))
1381 return false;
1382 geometry = QDockAreaLayout::constrainedRect(geometry, floatingTab);
1383 floatingTab->move(geometry.topLeft());
1384 floatingTab->resize(geometry.size());
1385
1386 // Don't show an empty QDockWidgetGroupWindow if no dock widget is available yet.
1387 // reparentWidgets() would be triggered by show(), so do it explicitly here.
1388 if (info->onlyHasPlaceholders())
1389 info->reparentWidgets(floatingTab);
1390 else
1391 floatingTab->show();
1392 }
1393 break;
1394#endif // QT_CONFIG(tabwidget)
1395#endif // QT_CONFIG(dockwidget)
1396
1397#if QT_CONFIG(toolbar)
1400 {
1401 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1402 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker))
1403 return false;
1404
1405 for (int i = 0; i < toolBars.size(); ++i) {
1406 QToolBar *w = toolBars.at(i);
1407 QList<int> path = toolBarAreaLayout.indexOf(w);
1408 if (path.isEmpty()) {
1409 QList<int> oldPath = oldState.toolBarAreaLayout.indexOf(w);
1410 if (oldPath.isEmpty()) {
1411 continue;
1412 }
1413 toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(nullptr, w);
1414 }
1415 }
1416 }
1417 break;
1418#endif // QT_CONFIG(toolbar)
1419 default:
1420 return false;
1421 }// switch
1422 } //while
1423
1424
1425 return true;
1426}
1427
1428/******************************************************************************
1429** QMainWindowLayoutState - toolbars
1430*/
1431
1432#if QT_CONFIG(toolbar)
1433
1434static constexpr Qt::ToolBarArea validateToolBarArea(Qt::ToolBarArea area)
1435{
1436 switch (area) {
1439 case Qt::TopToolBarArea:
1441 return area;
1442 default:
1443 break;
1444 }
1445 return Qt::TopToolBarArea;
1446}
1447
1449{
1450 switch (area) {
1455 default:
1456 break;
1457 }
1458
1459 return QInternal::DockCount;
1460}
1461
1462static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
1463{
1464 switch (pos) {
1469 default: break;
1470 }
1471 return Qt::NoToolBarArea;
1472}
1473
1474static inline Qt::ToolBarArea toToolBarArea(int pos)
1475{
1476 return toToolBarArea(static_cast<QInternal::DockPosition>(pos));
1477}
1478
1479void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
1480{
1481 area = validateToolBarArea(area);
1482
1483 layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1484 if (savedState.isValid())
1485 savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1486
1487 invalidate();
1488}
1489
1490void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
1491{
1492 layoutState.toolBarAreaLayout.insertToolBarBreak(before);
1493 if (savedState.isValid())
1494 savedState.toolBarAreaLayout.insertToolBarBreak(before);
1495 invalidate();
1496}
1497
1498void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
1499{
1500 layoutState.toolBarAreaLayout.removeToolBarBreak(before);
1501 if (savedState.isValid())
1502 savedState.toolBarAreaLayout.removeToolBarBreak(before);
1503 invalidate();
1504}
1505
1506void QMainWindowLayout::moveToolBar(QToolBar *toolbar, int pos)
1507{
1508 layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1509 if (savedState.isValid())
1510 savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1511 invalidate();
1512}
1513
1514/* Removes the toolbar from the mainwindow so that it can be added again. Does not
1515 explicitly hide the toolbar. */
1516void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
1517{
1518 if (toolbar) {
1519 QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
1520 toolbar, SLOT(_q_updateIconSize(QSize)));
1521 QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
1522 toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
1523
1524 removeWidget(toolbar);
1525 }
1526}
1527
1531void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
1532 QToolBar *toolbar,
1533 bool)
1534{
1535 area = validateToolBarArea(area);
1536 // let's add the toolbar to the layout
1537 addChildWidget(toolbar);
1538 QLayoutItem *item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
1539 if (savedState.isValid() && item) {
1540 // copy the toolbar also in the saved state
1541 savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
1542 }
1543 invalidate();
1544
1545 // this ensures that the toolbar has the right window flags (not floating any more)
1546 toolbar->d_func()->updateWindowFlags(false /*floating*/);
1547}
1548
1552void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
1553{
1554 addChildWidget(toolbar);
1555 QLayoutItem *item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
1556 if (savedState.isValid() && item) {
1557 // copy the toolbar also in the saved state
1558 savedState.toolBarAreaLayout.insertItem(before, item);
1559 }
1560 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
1561 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1562 if (!currentGapPos.isEmpty()) {
1565 }
1566 }
1567 invalidate();
1568}
1569
1570Qt::ToolBarArea QMainWindowLayout::toolBarArea(const QToolBar *toolbar) const
1571{
1572 QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar);
1573 switch (pos) {
1578 default: break;
1579 }
1580 return Qt::NoToolBarArea;
1581}
1582
1583bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar) const
1584{
1585 return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
1586}
1587
1588void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
1589{
1590 option->toolBarArea = toolBarArea(toolBar);
1591 layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
1592}
1593
1594void QMainWindowLayout::toggleToolBarsVisible()
1595{
1596 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
1598 QPoint topLeft = parentWidget()->geometry().topLeft();
1600 r = layoutState.toolBarAreaLayout.rectHint(r);
1601 r.moveTo(topLeft);
1603 } else {
1604 update();
1605 }
1606}
1607
1608#endif // QT_CONFIG(toolbar)
1609
1610/******************************************************************************
1611** QMainWindowLayoutState - dock areas
1612*/
1613
1614#if QT_CONFIG(dockwidget)
1615
1617{
1618 switch (area) {
1623 default:
1624 break;
1625 }
1626
1627 return QInternal::DockCount;
1628}
1629
1630inline static Qt::DockWidgetArea toDockWidgetArea(int pos)
1631{
1633}
1634
1635// Checks if QDockWidgetGroupWindow or QDockWidget can be plugged the area indicated by path.
1636// Returns false if called with invalid widget type or if compiled without dockwidget support.
1637static bool isAreaAllowed(QWidget *widget, const QList<int> &path)
1638{
1639 Q_ASSERT_X((path.size() > 1), "isAreaAllowed", "invalid path size");
1641
1642 // Read permissions directly from a single dock widget
1643 if (QDockWidget *dw = qobject_cast<QDockWidget *>(widget)) {
1644 const bool allowed = dw->isAreaAllowed(area);
1645 if (!allowed)
1646 qCDebug(lcQpaDockWidgets) << "No permission for single DockWidget" << widget << "to dock on" << area;
1647 return allowed;
1648 }
1649
1650 // Read permissions from a DockWidgetGroupWindow depending on its DockWidget children
1651 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1652 const QList<QDockWidget *> children = dwgw->findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly);
1653
1654 if (children.size() == 1) {
1655 // Group window has a single child => read its permissions
1656 const bool allowed = children.at(0)->isAreaAllowed(area);
1657 if (!allowed)
1658 qCDebug(lcQpaDockWidgets) << "No permission for DockWidgetGroupWindow" << widget << "to dock on" << area;
1659 return allowed;
1660 } else {
1661 // Group window has more than one or no children => dock it anywhere
1662 qCDebug(lcQpaDockWidgets) << "DockWidgetGroupWindow" << widget << "has" << children.size() << "children:";
1663 qCDebug(lcQpaDockWidgets) << children;
1664 qCDebug(lcQpaDockWidgets) << "DockWidgetGroupWindow" << widget << "can dock at" << area << "and anywhere else.";
1665 return true;
1666 }
1667 }
1668 qCDebug(lcQpaDockWidgets) << "Docking requested for invalid widget type (coding error)." << widget << area;
1669 return false;
1670}
1671
1672void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1673{
1674 if (layoutState.dockAreaLayout.corners[corner] == area)
1675 return;
1676 layoutState.dockAreaLayout.corners[corner] = area;
1677 if (savedState.isValid())
1678 savedState.dockAreaLayout.corners[corner] = area;
1679 invalidate();
1680}
1681
1682Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner) const
1683{
1684 return layoutState.dockAreaLayout.corners[corner];
1685}
1686
1687// Returns the rectangle of a dockWidgetArea
1688// if max is true, the maximum possible rectangle for dropping is returned
1689// the current visible rectangle otherwise
1690QRect QMainWindowLayout::dockWidgetAreaRect(const Qt::DockWidgetArea area, DockWidgetAreaSize size) const
1691{
1692 const QInternal::DockPosition dockPosition = toDockPos(area);
1693
1694 // Called with invalid dock widget area
1695 if (dockPosition == QInternal::DockCount) {
1696 qCDebug(lcQpaDockWidgets) << "QMainWindowLayout::dockWidgetAreaRect called with" << area;
1697 return QRect();
1698 }
1699
1700 const QDockAreaLayout dl = layoutState.dockAreaLayout;
1701
1702 // Return maximum or visible rectangle
1703 return (size == Maximum) ? dl.gapRect(dockPosition) : dl.docks[dockPosition].rect;
1704}
1705
1706void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1707 QDockWidget *dockwidget,
1708 Qt::Orientation orientation)
1709{
1710 addChildWidget(dockwidget);
1711
1712 // If we are currently moving a separator, then we need to abort the move, since each
1713 // time we move the mouse layoutState is replaced by savedState modified by the move.
1714 if (!movingSeparator.isEmpty())
1715 endSeparatorMove(movingSeparatorPos);
1716
1717 layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
1718 emit dockwidget->dockLocationChanged(area);
1719 invalidate();
1720}
1721
1722bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1723{
1724 addChildWidget(dockwidget);
1725 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1726 return false;
1727 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1728 invalidate();
1729 return true;
1730}
1731
1732#if QT_CONFIG(tabbar)
1733void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1734{
1736 addChildWidget(second);
1737 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1739 invalidate();
1740}
1741
1742bool QMainWindowLayout::documentMode() const
1743{
1744 return _documentMode;
1745}
1746
1747void QMainWindowLayout::setDocumentMode(bool enabled)
1748{
1749 if (_documentMode == enabled)
1750 return;
1751
1752 _documentMode = enabled;
1753
1754 // Update the document mode for all tab bars
1755 for (QTabBar *bar : std::as_const(usedTabBars))
1756 bar->setDocumentMode(_documentMode);
1757 for (QTabBar *bar : std::as_const(unusedTabBars))
1758 bar->setDocumentMode(_documentMode);
1759}
1760
1761void QMainWindowLayout::setVerticalTabsEnabled(bool enabled)
1762{
1763 if (verticalTabsEnabled == enabled)
1764 return;
1765
1766 verticalTabsEnabled = enabled;
1767
1768 updateTabBarShapes();
1769}
1770
1771#if QT_CONFIG(tabwidget)
1772QTabWidget::TabShape QMainWindowLayout::tabShape() const
1773{
1774 return _tabShape;
1775}
1776
1777void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1778{
1779 if (_tabShape == tabShape)
1780 return;
1781
1782 _tabShape = tabShape;
1783
1784 updateTabBarShapes();
1785}
1786
1787QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area) const
1788{
1789 const QInternal::DockPosition dockPos = toDockPos(area);
1790 if (dockPos < QInternal::DockCount)
1791 return tabPositions[dockPos];
1792 qWarning("QMainWindowLayout::tabPosition called with out-of-bounds value '%d'", int(area));
1793 return QTabWidget::North;
1794}
1795
1796void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1797{
1798 const Qt::DockWidgetArea dockWidgetAreas[] = {
1803 };
1804 const QInternal::DockPosition dockPositions[] = {
1809 };
1810
1811 for (int i = 0; i < QInternal::DockCount; ++i)
1812 if (areas & dockWidgetAreas[i])
1813 tabPositions[dockPositions[i]] = tabPosition;
1814
1815 updateTabBarShapes();
1816}
1817
1819#endif // QT_CONFIG(tabwidget)
1820
1821void QMainWindowLayout::updateTabBarShapes()
1822{
1823#if QT_CONFIG(tabwidget)
1824 const QTabWidget::TabPosition vertical[] = {
1829 };
1830#else
1831 const QTabBar::Shape vertical[] = {
1836 };
1837#endif
1838
1839 QDockAreaLayout &layout = layoutState.dockAreaLayout;
1840
1841 for (int i = 0; i < QInternal::DockCount; ++i) {
1842#if QT_CONFIG(tabwidget)
1843 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
1844 QTabBar::Shape shape = _q_tb_tabBarShapeFrom(_tabShape, pos);
1845#else
1846 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
1847#endif
1848 layout.docks[i].setTabBarShape(shape);
1849 }
1850}
1851#endif // QT_CONFIG(tabbar)
1852
1853void QMainWindowLayout::splitDockWidget(QDockWidget *after,
1854 QDockWidget *dockwidget,
1855 Qt::Orientation orientation)
1856{
1858 addChildWidget(dockwidget);
1859 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
1860 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
1861 invalidate();
1862}
1863
1864Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(QWidget *widget) const
1865{
1866 const QList<int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
1867 if (pathToWidget.isEmpty())
1868 return Qt::NoDockWidgetArea;
1869 return toDockWidgetArea(pathToWidget.first());
1870}
1871
1872void QMainWindowLayout::keepSize(QDockWidget *w)
1873{
1874 layoutState.dockAreaLayout.keepSize(w);
1875}
1876
1877#if QT_CONFIG(tabbar)
1878
1879// Handle custom tooltip, and allow to drag tabs away.
1880class QMainWindowTabBar : public QTabBar
1881{
1882 Q_OBJECT
1884 QPointer<QDockWidget> draggingDock; // Currently dragging (detached) dock widget
1885public:
1886 QMainWindowTabBar(QMainWindow *parent);
1887 ~QMainWindowTabBar();
1888 QDockWidget *dockAt(int index) const;
1889 QList<QDockWidget *> dockWidgets() const;
1890 bool contains(const QDockWidget *dockWidget) const;
1891protected:
1892 bool event(QEvent *e) override;
1893 void mouseReleaseEvent(QMouseEvent*) override;
1894 void mouseMoveEvent(QMouseEvent*) override;
1895
1896};
1897
1898QMainWindowTabBar *QMainWindowLayout::findTabBar(const QDockWidget *dockWidget) const
1899{
1900 for (auto *bar : usedTabBars) {
1901 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
1902 auto *tabBar = static_cast<QMainWindowTabBar *>(bar);
1903 if (tabBar->contains(dockWidget))
1904 return tabBar;
1905 }
1906 return nullptr;
1907}
1908
1909QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
1910 : QTabBar(parent), mainWindow(parent)
1911{
1912 setExpanding(false);
1913}
1914
1915QList<QDockWidget *> QMainWindowTabBar::dockWidgets() const
1916{
1917 QList<QDockWidget *> docks;
1918 for (int i = 0; i < count(); ++i) {
1919 if (QDockWidget *dock = dockAt(i))
1920 docks << dock;
1921 }
1922 return docks;
1923}
1924
1925bool QMainWindowTabBar::contains(const QDockWidget *dockWidget) const
1926{
1927 for (int i = 0; i < count(); ++i) {
1928 if (dockAt(i) == dockWidget)
1929 return true;
1930 }
1931 return false;
1932}
1933
1934// When a dock widget is removed from a floating tab,
1935// Events need to be processed for the tab bar to realize that the dock widget is gone.
1936// In this case count() counts the dock widget in transition and accesses dockAt
1937// with an out-of-bounds index.
1938// => return nullptr in contrast to other xxxxxAt() functions
1939QDockWidget *QMainWindowTabBar::dockAt(int index) const
1940{
1941 QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this);
1942 QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
1943 QDockAreaLayoutInfo *info = mlayout->dockInfo(that);
1944 if (!info)
1945 return nullptr;
1946
1947 const int itemIndex = info->tabIndexToListIndex(index);
1948 if (itemIndex >= 0) {
1949 Q_ASSERT(itemIndex < info->item_list.count());
1950 const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
1951 return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
1952 }
1953
1954 return nullptr;
1955}
1956
1957void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
1958{
1959 // The QTabBar handles the moving (reordering) of tabs.
1960 // When QTabBarPrivate::dragInProgress is true, and that the mouse is outside of a region
1961 // around the QTabBar, we will consider the user wants to drag that QDockWidget away from this
1962 // tab area.
1963
1964 QTabBarPrivate *d = static_cast<QTabBarPrivate*>(d_ptr.data());
1965 if (!draggingDock && (mainWindow->dockOptions() & QMainWindow::GroupedDragging)) {
1967 offset *= 3;
1969 if (d->dragInProgress && !r.contains(e->position().toPoint()) && d->validIndex(d->pressedIndex)) {
1970 draggingDock = dockAt(d->pressedIndex);
1971 if (draggingDock) {
1972 // We should drag this QDockWidget away by unpluging it.
1973 // First cancel the QTabBar's internal move
1974 d->moveTabFinished(d->pressedIndex);
1975 d->pressedIndex = -1;
1976 if (d->movingTab)
1977 d->movingTab->setVisible(false);
1978 d->dragStartPosition = QPoint();
1979
1980 // Then starts the drag using QDockWidgetPrivate's API
1981 QDockWidgetPrivate *dockPriv = static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
1982 QDockWidgetLayout *dwlayout = static_cast<QDockWidgetLayout *>(draggingDock->layout());
1983 dockPriv->initDrag(dwlayout->titleArea().center(), true);
1984 dockPriv->startDrag(QDockWidgetPrivate::DragScope::Widget);
1985 if (dockPriv->state)
1986 dockPriv->state->ctrlDrag = e->modifiers() & Qt::ControlModifier;
1987 }
1988 }
1989 }
1990
1991 if (draggingDock) {
1992 QDockWidgetPrivate *dockPriv = static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
1993 if (dockPriv->state && dockPriv->state->dragging) {
1994 QPoint pos = e->globalPosition().toPoint() - dockPriv->state->pressPos;
1995 draggingDock->move(pos);
1996 // move will call QMainWindowLayout::hover
1997 }
1998 }
2000}
2001
2002QMainWindowTabBar::~QMainWindowTabBar()
2003{
2004 if (!mainWindow || mainWindow == parentWidget())
2005 return;
2006
2007 // tab bar is not parented to the main window
2008 // => can only be a dock widget group window
2009 // => remove itself from used and unused tab bar containers
2010 auto *mwLayout = qt_mainwindow_layout(mainWindow);
2011 if (!mwLayout)
2012 return;
2013 mwLayout->unusedTabBars.removeOne(this);
2014 mwLayout->usedTabBars.remove(this);
2015}
2016
2017void QMainWindowTabBar::mouseReleaseEvent(QMouseEvent *e)
2018{
2019 if (draggingDock && e->button() == Qt::LeftButton) {
2020 QDockWidgetPrivate *dockPriv = static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2021 if (dockPriv->state && dockPriv->state->dragging)
2023
2024 draggingDock = nullptr;
2025 }
2027}
2028
2029bool QMainWindowTabBar::event(QEvent *e)
2030{
2031 // show the tooltip if tab is too small to fit label
2032
2033 if (e->type() != QEvent::ToolTip)
2034 return QTabBar::event(e);
2035 QSize size = this->size();
2036 QSize hint = sizeHint();
2037 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
2038 size = size.transposed();
2039 hint = hint.transposed();
2040 }
2041 if (size.width() < hint.width())
2042 return QTabBar::event(e);
2043 e->accept();
2044 return true;
2045}
2046
2047QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(const QDockWidget *dockWidget) const
2048{
2049 const auto *bar = findTabBar(dockWidget);
2050 if (!bar)
2051 return {};
2052
2053 QList<QDockWidget *> buddies = bar->dockWidgets();
2054 // Return only other dock widgets associated with dockWidget in a tab bar.
2055 // If dockWidget is alone in a tab bar, return an empty list.
2056 buddies.removeOne(dockWidget);
2057 return buddies;
2058}
2059
2060bool QMainWindowLayout::isDockWidgetTabbed(const QDockWidget *dockWidget) const
2061{
2062 // A single dock widget in a tab bar is not considered to be tabbed.
2063 // This is to make sure, we don't drag an empty QDockWidgetGroupWindow around.
2064 // => only consider tab bars with two or more tabs.
2065 const auto *bar = findTabBar(dockWidget);
2066 return bar && bar->count() > 1;
2067}
2068
2069QTabBar *QMainWindowLayout::getTabBar()
2070{
2071 if (!usedTabBars.isEmpty() && !isInRestoreState) {
2072 /*
2073 If dock widgets have been removed and added while the main window was
2074 hidden, then the layout hasn't been activated yet, and tab bars from empty
2075 docking areas haven't been put in the cache yet.
2076 */
2077 activate();
2078 }
2079
2080 QTabBar *result = nullptr;
2081 if (!unusedTabBars.isEmpty()) {
2082 result = unusedTabBars.takeLast();
2083 } else {
2084 result = new QMainWindowTabBar(static_cast<QMainWindow *>(parentWidget()));
2085 result->setDrawBase(true);
2086 result->setElideMode(Qt::ElideRight);
2087 result->setDocumentMode(_documentMode);
2088 result->setMovable(true);
2089 connect(result, SIGNAL(currentChanged(int)), this, SLOT(tabChanged()));
2090 connect(result, &QTabBar::tabMoved, this, &QMainWindowLayout::tabMoved);
2091 }
2092
2093 usedTabBars.insert(result);
2094 return result;
2095}
2096
2097// Allocates a new separator widget if needed
2098QWidget *QMainWindowLayout::getSeparatorWidget()
2099{
2100 QWidget *result = nullptr;
2101 if (!unusedSeparatorWidgets.isEmpty()) {
2102 result = unusedSeparatorWidgets.takeLast();
2103 } else {
2104 result = new QWidget(parentWidget());
2105 result->setAttribute(Qt::WA_MouseNoMask, true);
2106 result->setAutoFillBackground(false);
2107 result->setObjectName("qt_qmainwindow_extended_splitter"_L1);
2108 }
2109 usedSeparatorWidgets.insert(result);
2110 return result;
2111}
2112
2117QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget)
2118{
2119 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
2120 if (info)
2121 return info;
2122 const auto groups =
2123 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2124 for (QDockWidgetGroupWindow *dwgw : groups) {
2125 info = dwgw->layoutInfo()->info(widget);
2126 if (info)
2127 return info;
2128 }
2129 return nullptr;
2130}
2131
2132void QMainWindowLayout::tabChanged()
2133{
2134 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2135 if (tb == nullptr)
2136 return;
2137 QDockAreaLayoutInfo *info = dockInfo(tb);
2138 if (info == nullptr)
2139 return;
2140
2141 QDockWidget *activated = info->apply(false);
2142
2143 if (activated)
2144 emit static_cast<QMainWindow *>(parentWidget())->tabifiedDockWidgetActivated(activated);
2145
2146 if (auto dwgw = qobject_cast<QDockWidgetGroupWindow*>(tb->parentWidget()))
2147 dwgw->adjustFlags();
2148
2149 if (QWidget *w = centralWidget())
2150 w->raise();
2151}
2152
2153void QMainWindowLayout::tabMoved(int from, int to)
2154{
2155 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2156 Q_ASSERT(tb);
2157 QDockAreaLayoutInfo *info = dockInfo(tb);
2158 Q_ASSERT(info);
2159
2160 info->moveTab(from, to);
2161}
2162
2163void QMainWindowLayout::raise(QDockWidget *widget)
2164{
2165 QDockAreaLayoutInfo *info = dockInfo(widget);
2166 if (info == nullptr)
2167 return;
2168 if (!info->tabbed)
2169 return;
2170 info->setCurrentTab(widget);
2171}
2172#endif // QT_CONFIG(tabbar)
2173
2174#endif // QT_CONFIG(dockwidget)
2175
2176
2177/******************************************************************************
2178** QMainWindowLayoutState - layout interface
2179*/
2180
2182{
2183 int result = 0;
2184 while (itemAt(result))
2185 ++result;
2186 return result;
2187}
2188
2190{
2191 int x = 0;
2192
2193 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
2194 return ret;
2195
2196 if (statusbar && x++ == index)
2197 return statusbar;
2198
2199 return nullptr;
2200}
2201
2203{
2204 int x = 0;
2205
2206 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
2207 // the widget might in fact have been destroyed by now
2208 if (QWidget *w = ret->widget()) {
2209 widgetAnimator.abort(w);
2210 if (w == pluggingWidget)
2211 pluggingWidget = nullptr;
2212 }
2213
2214 if (savedState.isValid() ) {
2215 //we need to remove the item also from the saved state to prevent crash
2216 savedState.remove(ret);
2217 //Also, the item may be contained several times as a gap item.
2218 layoutState.remove(ret);
2219 }
2220
2221#if QT_CONFIG(toolbar)
2222 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
2223 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
2224 if (!currentGapPos.isEmpty()) {
2225 currentGapPos.prepend(0);
2226 currentGapRect = layoutState.itemRect(currentGapPos);
2227 }
2228 }
2229#endif
2230
2231 return ret;
2232 }
2233
2234 if (statusbar && x++ == index) {
2235 QLayoutItem *ret = statusbar;
2236 statusbar = nullptr;
2237 return ret;
2238 }
2239
2240 return nullptr;
2241}
2242
2243
2261{
2262 if (restoredState) {
2263 layoutState = *restoredState;
2264 restoredState.reset();
2265 discardRestoredStateTimer.stop();
2266 }
2267}
2268
2270{
2271 // Check if the state is valid, and avoid replacing it again if it is currently used
2272 // in applyState
2273 if (savedState.isValid() || (restoredState && isInApplyState))
2274 return;
2275
2276 QRect r = _r;
2277
2279
2280 if (statusbar) {
2281 QRect sbr(QPoint(r.left(), 0),
2282 QSize(r.width(), statusbar->heightForWidth(r.width()))
2283 .expandedTo(statusbar->minimumSize()));
2284 sbr.moveBottom(r.bottom());
2285 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
2286 statusbar->setGeometry(vr);
2287 r.setBottom(sbr.top() - 1);
2288 }
2289
2290 if (restoredState) {
2291 /*
2292 The main window was hidden and was going to be maximized or full-screened when
2293 the state was restored. The state might have been for a larger window size than
2294 the current size (in _r), and the window might still be in the process of being
2295 shown and transitioning to the final size (there's no reliable way of knowing
2296 this across different platforms). Try again with the restored state.
2297 */
2298 layoutState = *restoredState;
2299 if (restoredState->fits()) {
2300 restoredState.reset();
2301 discardRestoredStateTimer.stop();
2302 } else {
2303 /*
2304 Try again in the next setGeometry call, but discard the restored state
2305 after 150ms without any further tries. That's a reasonably short amount of
2306 time during which we can expect the windowing system to either have completed
2307 showing the window, or resized the window once more (which then restarts the
2308 timer in timerEvent).
2309 If the windowing system is done, then the user won't have had a chance to
2310 change the layout interactively AND trigger another resize.
2311 */
2312 discardRestoredStateTimer.start(150, this);
2313 }
2314 }
2315
2316 layoutState.rect = r;
2317
2318 layoutState.fitLayout();
2319 applyState(layoutState, false);
2320}
2321
2323{
2324 if (e->timerId() == discardRestoredStateTimer.timerId()) {
2325 discardRestoredStateTimer.stop();
2326 restoredState.reset();
2327 }
2329}
2330
2332{ qWarning("QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
2333
2335{
2336 if (!szHint.isValid()) {
2337 szHint = layoutState.sizeHint();
2338 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
2339 szHint = QSize(qMax(sbHint.width(), szHint.width()),
2340 sbHint.height() + szHint.height());
2341 }
2342 return szHint;
2343}
2344
2346{
2347 if (!minSize.isValid()) {
2348 minSize = layoutState.minimumSize();
2349 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
2350 minSize = QSize(qMax(sbMin.width(), minSize.width()),
2351 sbMin.height() + minSize.height());
2352 }
2353 return minSize;
2354}
2355
2357{
2359 minSize = szHint = QSize();
2360}
2361
2362#if QT_CONFIG(dockwidget)
2363void QMainWindowLayout::setCurrentHoveredFloat(QDockWidgetGroupWindow *w)
2364{
2365 if (currentHoveredFloat != w) {
2366 if (currentHoveredFloat) {
2367 disconnect(currentHoveredFloat.data(), &QObject::destroyed,
2368 this, &QMainWindowLayout::updateGapIndicator);
2369 disconnect(currentHoveredFloat.data(), &QDockWidgetGroupWindow::resized,
2370 this, &QMainWindowLayout::updateGapIndicator);
2371 if (currentHoveredFloat)
2372 currentHoveredFloat->restore();
2373 } else if (w) {
2374 restore(true);
2375 }
2376
2377 currentHoveredFloat = w;
2378
2379 if (w) {
2381 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2382 connect(w, &QDockWidgetGroupWindow::resized,
2383 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2384 }
2385
2386 updateGapIndicator();
2387 }
2388}
2389#endif // QT_CONFIG(dockwidget)
2390
2391/******************************************************************************
2392** QMainWindowLayout - remaining stuff
2393*/
2394
2395static void fixToolBarOrientation(QLayoutItem *item, int dockPos)
2396{
2397#if QT_CONFIG(toolbar)
2398 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
2399 if (toolBar == nullptr)
2400 return;
2401
2402 QRect oldGeo = toolBar->geometry();
2403
2405 = static_cast<QInternal::DockPosition>(dockPos);
2408 if (o != toolBar->orientation())
2409 toolBar->setOrientation(o);
2410
2411 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
2412 .expandedTo(toolBar->minimumSize());
2413
2414 if (toolBar->size() != hint) {
2415 QRect newGeo(oldGeo.topLeft(), hint);
2416 if (toolBar->layoutDirection() == Qt::RightToLeft)
2417 newGeo.moveRight(oldGeo.right());
2418 toolBar->setGeometry(newGeo);
2419 }
2420
2421#else
2422 Q_UNUSED(item);
2423 Q_UNUSED(dockPos);
2424#endif
2425}
2426
2428{
2429 if (!savedState.isValid())
2430 return;
2431
2432 QWidget *widget = widgetItem->widget();
2433 layoutState = savedState;
2434 currentGapPos = layoutState.indexOf(widget);
2435 if (currentGapPos.isEmpty())
2436 return;
2437 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2438 layoutState.unplug(currentGapPos);
2439 layoutState.fitLayout();
2440 currentGapRect = layoutState.itemRect(currentGapPos);
2441
2442 plug(widgetItem);
2443}
2444
2446{
2447#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) && QT_CONFIG(tabbar)
2448 if (currentHoveredFloat) {
2449 QWidget *widget = widgetItem->widget();
2450 QList<int> previousPath = layoutState.indexOf(widget);
2451 if (!previousPath.isEmpty())
2452 layoutState.remove(previousPath);
2453 previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2454 // Let's remove the widget from any possible group window
2455 const auto groups =
2456 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2457 for (QDockWidgetGroupWindow *dwgw : groups) {
2458 if (dwgw == currentHoveredFloat)
2459 continue;
2460 QList<int> path = dwgw->layoutInfo()->indexOf(widget);
2461 if (!path.isEmpty())
2462 dwgw->layoutInfo()->remove(path);
2463 }
2464 currentGapRect = QRect();
2465 currentHoveredFloat->apply();
2466 if (!previousPath.isEmpty())
2467 currentHoveredFloat->layoutInfo()->remove(previousPath);
2468 QRect globalRect = currentHoveredFloat->currentGapRect;
2469 globalRect.moveTopLeft(currentHoveredFloat->mapToGlobal(globalRect.topLeft()));
2470 pluggingWidget = widget;
2471 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2472 return true;
2473 }
2474#endif
2475
2476 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
2477 return false;
2478
2479 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2480
2481 QWidget *widget = widgetItem->widget();
2482
2483#if QT_CONFIG(dockwidget)
2484 // Let's remove the widget from any possible group window
2485 const auto groups =
2486 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2487 for (QDockWidgetGroupWindow *dwgw : groups) {
2488 QList<int> path = dwgw->layoutInfo()->indexOf(widget);
2489 if (!path.isEmpty())
2490 dwgw->layoutInfo()->remove(path);
2491 }
2492#endif
2493
2494 QList<int> previousPath = layoutState.indexOf(widget);
2495
2496 const QLayoutItem *it = layoutState.plug(currentGapPos);
2497 if (!it)
2498 return false;
2499 Q_ASSERT(it == widgetItem);
2500 if (!previousPath.isEmpty())
2501 layoutState.remove(previousPath);
2502
2503 pluggingWidget = widget;
2504 QRect globalRect = currentGapRect;
2505 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
2506#if QT_CONFIG(dockwidget)
2507 if (qobject_cast<QDockWidget*>(widget) != nullptr) {
2508 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
2509 if (layout->nativeWindowDeco()) {
2510 globalRect.adjust(0, layout->titleHeight(), 0, 0);
2511 } else {
2513 globalRect.adjust(-fw, -fw, fw, fw);
2514 }
2515 }
2516#endif
2517 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2518
2519 return true;
2520}
2521
2523{
2524 //this function is called from within the Widget Animator whenever an animation is finished
2525 //on a certain widget
2526#if QT_CONFIG(toolbar)
2527 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2528 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
2529 if (tbl->animating) {
2530 tbl->animating = false;
2531 if (tbl->expanded)
2532 tbl->layoutActions(tb->size());
2533 tb->update();
2534 }
2535 }
2536#endif
2537
2538 if (widget == pluggingWidget) {
2539
2540#if QT_CONFIG(dockwidget)
2541#if QT_CONFIG(tabbar)
2542 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
2543 // When the animated widget was a QDockWidgetGroupWindow, it means each of the
2544 // embedded QDockWidget needs to be plugged back into the QMainWindow layout.
2545 savedState.clear();
2546 QDockAreaLayoutInfo *srcInfo = dwgw->layoutInfo();
2547 const QDockAreaLayoutInfo *srcTabInfo = dwgw->tabLayoutInfo();
2548 QDockAreaLayoutInfo *dstParentInfo;
2549 QList<int> dstPath;
2550
2551 if (currentHoveredFloat) {
2552 dstPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2553 Q_ASSERT(dstPath.size() >= 1);
2554 dstParentInfo = currentHoveredFloat->layoutInfo()->info(dstPath);
2555 } else {
2556 dstPath = layoutState.dockAreaLayout.indexOf(widget);
2557 Q_ASSERT(dstPath.size() >= 2);
2558 dstParentInfo = layoutState.dockAreaLayout.info(dstPath);
2559 }
2560 Q_ASSERT(dstParentInfo);
2561 int idx = dstPath.constLast();
2562 Q_ASSERT(dstParentInfo->item_list[idx].widgetItem->widget() == dwgw);
2563 if (dstParentInfo->tabbed && srcTabInfo) {
2564 // merge the two tab widgets
2565 delete dstParentInfo->item_list[idx].widgetItem;
2566 dstParentInfo->item_list.removeAt(idx);
2567 std::copy(srcTabInfo->item_list.cbegin(), srcTabInfo->item_list.cend(),
2568 std::inserter(dstParentInfo->item_list,
2569 dstParentInfo->item_list.begin() + idx));
2570 quintptr currentId = srcTabInfo->currentTabId();
2571 *srcInfo = QDockAreaLayoutInfo();
2572 dstParentInfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2573 : parentWidget());
2574 dstParentInfo->updateTabBar();
2575 dstParentInfo->setCurrentTabId(currentId);
2576 } else {
2577 QDockAreaLayoutItem &item = dstParentInfo->item_list[idx];
2578 Q_ASSERT(item.widgetItem->widget() == dwgw);
2579 delete item.widgetItem;
2580 item.widgetItem = nullptr;
2581 item.subinfo = new QDockAreaLayoutInfo(std::move(*srcInfo));
2582 *srcInfo = QDockAreaLayoutInfo();
2583 item.subinfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2584 : parentWidget());
2585 item.subinfo->setTabBarShape(dstParentInfo->tabBarShape);
2586 }
2587 dwgw->destroyOrHideIfEmpty();
2588 }
2589#endif
2590
2591 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2592 dw->setParent(currentHoveredFloat ? currentHoveredFloat.data() : parentWidget());
2593 dw->show();
2594 dw->d_func()->plug(currentGapRect);
2595 }
2596#endif
2597#if QT_CONFIG(toolbar)
2598 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
2599 tb->d_func()->plug(currentGapRect);
2600#endif
2601
2602 savedState.clear();
2603 currentGapPos.clear();
2604 pluggingWidget = nullptr;
2605#if QT_CONFIG(dockwidget)
2606 setCurrentHoveredFloat(nullptr);
2607#endif
2608 //applying the state will make sure that the currentGap is updated correctly
2609 //and all the geometries (especially the one from the central widget) is correct
2610 layoutState.apply(false);
2611
2612#if QT_CONFIG(dockwidget)
2613#if QT_CONFIG(tabbar)
2614 if (qobject_cast<QDockWidget*>(widget) != nullptr) {
2615 // info() might return null if the widget is destroyed while
2616 // animating but before the animationFinished signal is received.
2617 if (QDockAreaLayoutInfo *info = dockInfo(widget))
2618 info->setCurrentTab(widget);
2619 }
2620#endif
2621#endif
2622 }
2623
2624 if (!widgetAnimator.animating()) {
2625 //all animations are finished
2626#if QT_CONFIG(dockwidget)
2627 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
2628#if QT_CONFIG(tabbar)
2629 const auto usedTabBarsCopy = usedTabBars; // list potentially modified by animations
2630 for (QTabBar *tab_bar : usedTabBarsCopy)
2631 tab_bar->show();
2632#endif // QT_CONFIG(tabbar)
2633#endif // QT_CONFIG(dockwidget)
2634 }
2635
2636 updateGapIndicator();
2637}
2638
2639void QMainWindowLayout::restore(bool keepSavedState)
2640{
2641 if (!savedState.isValid())
2642 return;
2643
2644 layoutState = savedState;
2645 applyState(layoutState);
2646 if (!keepSavedState)
2647 savedState.clear();
2648 currentGapPos.clear();
2649 pluggingWidget = nullptr;
2650 updateGapIndicator();
2651}
2652
2654 : QLayout(parentLayout ? static_cast<QWidget *>(nullptr) : mainwindow)
2655 , layoutState(mainwindow)
2656 , savedState(mainwindow)
2657 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
2658 , statusbar(nullptr)
2659#if QT_CONFIG(dockwidget)
2660#if QT_CONFIG(tabbar)
2661 , _documentMode(false)
2662 , verticalTabsEnabled(false)
2663#if QT_CONFIG(tabwidget)
2664 , _tabShape(QTabWidget::Rounded)
2665#endif
2666#endif
2667#endif // QT_CONFIG(dockwidget)
2668 , widgetAnimator(this)
2669 , pluggingWidget(nullptr)
2670{
2671 if (parentLayout)
2672 setParent(parentLayout);
2673
2674#if QT_CONFIG(dockwidget)
2675#if QT_CONFIG(tabbar)
2676 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, nullptr, mainwindow);
2677#endif
2678
2679#if QT_CONFIG(tabwidget)
2680 for (int i = 0; i < QInternal::DockCount; ++i)
2681 tabPositions[i] = QTabWidget::South;
2682#endif
2683#endif // QT_CONFIG(dockwidget)
2684 pluggingWidget = nullptr;
2685
2686 setObjectName(mainwindow->objectName() + "_layout"_L1);
2687}
2688
2696
2697void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
2698{
2699 if (opts == dockOptions)
2700 return;
2701
2702 dockOptions = opts;
2703
2704#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
2705 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
2706#endif
2707
2708 invalidate();
2709}
2710
2711#if QT_CONFIG(statusbar)
2712QStatusBar *QMainWindowLayout::statusBar() const
2713{ return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
2714
2715void QMainWindowLayout::setStatusBar(QStatusBar *sb)
2716{
2717 if (sb)
2718 addChildWidget(sb);
2719 delete statusbar;
2720 statusbar = sb ? new QWidgetItemV2(sb) : nullptr;
2721 invalidate();
2722}
2723#endif // QT_CONFIG(statusbar)
2724
2729
2731{
2732 if (widget != nullptr)
2735 if (savedState.isValid()) {
2736#if QT_CONFIG(dockwidget)
2737 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
2738 savedState.dockAreaLayout.fallbackToSizeHints = true;
2739#else
2741#endif
2742 }
2743 invalidate();
2744}
2745
2746#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2754static bool unplugGroup(QMainWindowLayout *layout, QLayoutItem **item,
2755 QDockAreaLayoutItem &parentItem)
2756{
2757 if (!parentItem.subinfo || !parentItem.subinfo->tabbed)
2758 return false;
2759
2760 // The QDockWidget is part of a group of tab and we need to unplug them all.
2761 QDockWidgetGroupWindow *floatingTabs = layout->createTabbedDockWindow();
2762 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
2763 *info = std::move(*parentItem.subinfo);
2764 delete parentItem.subinfo;
2765 parentItem.subinfo = nullptr;
2766 floatingTabs->setGeometry(info->rect.translated(layout->parentWidget()->pos()));
2767 floatingTabs->show();
2768 floatingTabs->raise();
2769 *item = new QDockWidgetGroupWindowItem(floatingTabs);
2770 parentItem.widgetItem = *item;
2771 return true;
2772}
2773#endif
2774
2775#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2776static QTabBar::Shape tabwidgetPositionToTabBarShape(QWidget *w)
2777{
2779 if (qobject_cast<QDockWidget *>(w)) {
2780 switch (static_cast<QDockWidgetPrivate *>(qt_widget_private(w))->tabPosition) {
2781 case QTabWidget::North:
2783 break;
2784 case QTabWidget::South:
2786 break;
2787 case QTabWidget::West:
2789 break;
2790 case QTabWidget::East:
2792 break;
2793 }
2794 }
2795 return result;
2796}
2797#endif // QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2798
2810{
2811#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2812 auto *groupWindow = qobject_cast<const QDockWidgetGroupWindow *>(widget->parentWidget());
2813 if (!widget->isWindow() && groupWindow) {
2814 if (scope == QDockWidgetPrivate::DragScope::Group && groupWindow->tabLayoutInfo()) {
2815 // We are just dragging a floating window as it, not need to do anything, we just have to
2816 // look up the corresponding QWidgetItem* if it exists
2817 if (QDockAreaLayoutInfo *info = dockInfo(widget->parentWidget())) {
2818 QList<int> groupWindowPath = info->indexOf(widget->parentWidget());
2819 return groupWindowPath.isEmpty() ? nullptr : info->item(groupWindowPath).widgetItem;
2820 }
2821 qCDebug(lcQpaDockWidgets) << "Drag only:" << widget << "Group:" << (scope == QDockWidgetPrivate::DragScope::Group);
2822 return nullptr;
2823 }
2824 QList<int> path = groupWindow->layoutInfo()->indexOf(widget);
2825 QDockAreaLayoutItem parentItem = groupWindow->layoutInfo()->item(path);
2826 QLayoutItem *item = parentItem.widgetItem;
2827 if (scope == QDockWidgetPrivate::DragScope::Group && path.size() > 1
2828 && unplugGroup(this, &item, parentItem)) {
2829 qCDebug(lcQpaDockWidgets) << "Unplugging:" << widget << "from" << item;
2830 return item;
2831 } else {
2832 // We are unplugging a single dock widget from a floating window.
2833 QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget);
2834 Q_ASSERT(dockWidget); // cannot be a QDockWidgetGroupWindow because it's not floating.
2835 dockWidget->d_func()->unplug(widget->geometry());
2836
2837 qCDebug(lcQpaDockWidgets) << "Unplugged from floating dock:" << widget << "from" << parentItem.widgetItem;
2838 return item;
2839 }
2840 }
2841#endif
2842 QList<int> path = layoutState.indexOf(widget);
2843 if (path.isEmpty())
2844 return nullptr;
2845
2847 if (widget->isWindow())
2848 return item;
2849
2852
2853#if QT_CONFIG(dockwidget)
2854 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2855 Q_ASSERT(path.constFirst() == 1);
2856#if QT_CONFIG(tabwidget)
2858 && unplugGroup(this, &item,
2859 layoutState.dockAreaLayout.item(path.mid(1, path.size() - 2)))) {
2860 path.removeLast();
2862 } else
2863#endif // QT_CONFIG(tabwidget)
2864 {
2865 // Dock widget is unplugged from a main window dock
2866 // => height or width need to be decreased by separator size
2867 switch (dockWidgetArea(dw)) {
2870 r.setHeight(r.height() - sep);
2871 break;
2874 r.setWidth(r.width() - sep);
2875 break;
2878 break;
2879 }
2880
2881 // Depending on the title bar layout (vertical / horizontal),
2882 // width and height have to provide minimum space for window handles
2883 // and mouse dragging.
2884 // Assuming horizontal title bar, if the dock widget does not have a layout.
2885 const auto *layout = qobject_cast<QDockWidgetLayout *>(dw->layout());
2886 const bool verticalTitleBar = layout ? layout->verticalTitleBar : false;
2887 const int tbHeight = QApplication::style()
2888 ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight, nullptr, dw)
2889 : 20;
2890 const int minHeight = verticalTitleBar ? 2 * tbHeight : tbHeight;
2891 const int minWidth = verticalTitleBar ? tbHeight : 2 * tbHeight;
2892 r.setSize(r.size().expandedTo(QSize(minWidth, minHeight)));
2893 qCDebug(lcQpaDockWidgets) << dw << "will be unplugged with size" << r.size();
2894
2895 dw->d_func()->unplug(r);
2896 }
2897 }
2898#endif // QT_CONFIG(dockwidget)
2899#if QT_CONFIG(toolbar)
2900 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2901 tb->d_func()->unplug(r);
2902 }
2903#endif
2904
2905#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
2906 Q_UNUSED(scope);
2907#endif
2908
2912 currentGapRect = r;
2913 updateGapIndicator();
2914
2916
2917 return item;
2918}
2919
2920void QMainWindowLayout::updateGapIndicator()
2921{
2922#if QT_CONFIG(rubberband)
2924#if QT_CONFIG(dockwidget)
2925 || currentHoveredFloat
2926#endif
2927 )) {
2928 QWidget *expectedParent =
2929#if QT_CONFIG(dockwidget)
2930 currentHoveredFloat ? currentHoveredFloat.data() :
2931#endif
2932 parentWidget();
2933 if (!gapIndicator) {
2934 gapIndicator = new QRubberBand(QRubberBand::Rectangle, expectedParent);
2935 // For accessibility to identify this special widget.
2936 gapIndicator->setObjectName("qt_rubberband"_L1);
2937 } else if (gapIndicator->parent() != expectedParent) {
2938 gapIndicator->setParent(expectedParent);
2939 }
2940
2941 // Prevent re-entry in case of size change
2942 const bool sigBlockState = gapIndicator->signalsBlocked();
2943 auto resetSignals = qScopeGuard([this, sigBlockState](){ gapIndicator->blockSignals(sigBlockState); });
2944 gapIndicator->blockSignals(true);
2945
2946#if QT_CONFIG(dockwidget)
2947 if (currentHoveredFloat)
2948 gapIndicator->setGeometry(currentHoveredFloat->currentGapRect);
2949 else
2950#endif
2951 gapIndicator->setGeometry(currentGapRect);
2952
2953 gapIndicator->show();
2954 gapIndicator->raise();
2955
2956 // Reset signal state
2957
2958 } else if (gapIndicator) {
2959 gapIndicator->hide();
2960 }
2961
2962#endif // QT_CONFIG(rubberband)
2963}
2964
2966 const QPoint &mousePos) {
2967 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() ||
2968 pluggingWidget != nullptr || hoverTarget == nullptr)
2969 return;
2970
2971 QWidget *widget = hoverTarget->widget();
2972
2973#if QT_CONFIG(dockwidget)
2974 widget->raise();
2975 if ((dockOptions & QMainWindow::GroupedDragging) && (qobject_cast<QDockWidget*>(widget)
2976 || qobject_cast<QDockWidgetGroupWindow *>(widget))) {
2977
2978 // Check if we are over another floating dock widget
2979 QVarLengthArray<QWidget *, 10> candidates;
2980 const auto siblings = parentWidget()->children();
2981 for (QObject *c : siblings) {
2983 if (!w)
2984 continue;
2985
2986 // Handle only dock widgets and group windows
2987 if (!qobject_cast<QDockWidget*>(w) && !qobject_cast<QDockWidgetGroupWindow *>(w))
2988 continue;
2989
2990 // Check permission to dock on another dock widget or floating dock
2991 // FIXME in Qt 7
2992
2993 if (w != widget && w->isWindow() && w->isVisible() && !w->isMinimized())
2994 candidates << w;
2995
2996 if (QDockWidgetGroupWindow *group = qobject_cast<QDockWidgetGroupWindow *>(w)) {
2997 // floating QDockWidgets have a QDockWidgetGroupWindow as a parent,
2998 // if they have been hovered over
2999 const auto groupChildren = group->children();
3000 for (QObject *c : groupChildren) {
3001 if (QDockWidget *dw = qobject_cast<QDockWidget*>(c)) {
3002 if (dw != widget && dw->isFloating() && dw->isVisible() && !dw->isMinimized())
3003 candidates << dw;
3004 }
3005 }
3006 }
3007 }
3008
3009 for (QWidget *w : candidates) {
3010 const QScreen *screen1 = qt_widget_private(widget)->associatedScreen();
3011 const QScreen *screen2 = qt_widget_private(w)->associatedScreen();
3012 if (screen1 && screen2 && screen1 != screen2)
3013 continue;
3014 if (!w->geometry().contains(mousePos))
3015 continue;
3016
3017#if QT_CONFIG(tabwidget)
3018 if (auto dropTo = qobject_cast<QDockWidget *>(w)) {
3019
3020 // w is the drop target's widget
3021 w = dropTo->widget();
3022
3023 // Create a floating tab, unless already existing
3024 if (!qobject_cast<QDockWidgetGroupWindow *>(w)) {
3025 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
3026 floatingTabs->setGeometry(dropTo->geometry());
3027 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
3028 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dropTo);
3029
3030 // dropTo and widget may be in a state where they transition
3031 // from being a group window child to a single floating dock widget.
3032 // In that case, their path to a main window dock may not have been
3033 // updated yet.
3034 // => ask both and fall back to dock 1 (right dock)
3035 QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(dropTo));
3036 if (dockPosition == QInternal::DockPosition::DockCount)
3037 dockPosition = toDockPos(dockWidgetArea(widget));
3038 if (dockPosition == QInternal::DockPosition::DockCount)
3040
3041 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPosition,
3042 Qt::Horizontal, shape,
3043 static_cast<QMainWindow *>(parentWidget()));
3044 info->tabBar = getTabBar();
3045 info->tabbed = true;
3046 info->add(dropTo);
3047 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[dockPosition];
3048 parentInfo.add(floatingTabs);
3049 dropTo->setParent(floatingTabs);
3050 qCDebug(lcQpaDockWidgets) << "Wrapping" << widget << "into floating tabs" << floatingTabs;
3051 w = floatingTabs;
3052 }
3053
3054 // Show the drop target and raise widget to foreground
3055 dropTo->show();
3056 qCDebug(lcQpaDockWidgets) << "Showing" << dropTo;
3057 widget->raise();
3058 qCDebug(lcQpaDockWidgets) << "Raising" << widget;
3059 }
3060#endif
3061 auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(w);
3062 Q_ASSERT(groupWindow);
3063 if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) {
3064 setCurrentHoveredFloat(groupWindow);
3065 applyState(layoutState); // update the tabbars
3066 }
3067 return;
3068 }
3069 }
3070
3071 // If a temporary group window has been created during a hover,
3072 // remove it, if it has only one dockwidget child
3073 if (currentHoveredFloat)
3074 currentHoveredFloat->destroyIfSingleItemLeft();
3075
3076 setCurrentHoveredFloat(nullptr);
3077 layoutState.dockAreaLayout.fallbackToSizeHints = false;
3078#endif // QT_CONFIG(dockwidget)
3079
3080 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
3081
3082 if (!savedState.isValid())
3084
3085 QList<int> path = savedState.gapIndex(widget, pos);
3086
3087 if (!path.isEmpty()) {
3088 bool allowed = false;
3089
3090#if QT_CONFIG(dockwidget)
3091 allowed = isAreaAllowed(widget, path);
3092#endif
3093#if QT_CONFIG(toolbar)
3094 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
3095 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
3096#endif
3097
3098 if (!allowed)
3099 path.clear();
3100 }
3101
3102 if (path == currentGapPos)
3103 return; // the gap is already there
3104
3106 if (path.isEmpty()) {
3107 fixToolBarOrientation(hoverTarget, 2); // 2 = top dock, ie. horizontal
3108 restore(true);
3109 return;
3110 }
3111
3112 fixToolBarOrientation(hoverTarget, currentGapPos.at(1));
3113
3115
3116 if (!newState.insertGap(path, hoverTarget)) {
3117 restore(true); // not enough space
3118 return;
3119 }
3120
3121 QSize min = newState.minimumSize();
3122 QSize size = newState.rect.size();
3123
3124 if (min.width() > size.width() || min.height() > size.height()) {
3125 restore(true);
3126 return;
3127 }
3128
3129 newState.fitLayout();
3130
3132
3133#if QT_CONFIG(dockwidget)
3134 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
3135#endif
3136 layoutState = std::move(newState);
3138
3139 updateGapIndicator();
3140}
3141
3142#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3143QDockWidgetGroupWindow *QMainWindowLayout::createTabbedDockWindow()
3144{
3145 QDockWidgetGroupWindow* f = new QDockWidgetGroupWindow(parentWidget(), Qt::Tool);
3146 new QDockWidgetGroupLayout(f);
3147 return f;
3148}
3149#endif
3150
3152{
3153 // applying the state can lead to showing separator widgets, which would lead to a re-layout
3154 // (even though the separator widgets are not really part of the layout)
3155 // break the loop
3156 if (isInApplyState)
3157 return;
3158 isInApplyState = true;
3159#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3160 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
3161 const auto groups =
3162 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
3163 for (QDockWidgetGroupWindow *dwgw : groups)
3164 used += dwgw->layoutInfo()->usedTabBars();
3165
3166 const QSet<QTabBar*> retired = usedTabBars - used;
3167 usedTabBars = used;
3168 for (QTabBar *tab_bar : retired) {
3169 tab_bar->hide();
3170 while (tab_bar->count() > 0)
3171 tab_bar->removeTab(0);
3172 unusedTabBars.append(tab_bar);
3173 }
3174
3175 if (sep == 1) {
3176 const QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
3177 const QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
3178 usedSeparatorWidgets = usedSeps;
3179 for (QWidget *sepWidget : retiredSeps) {
3180 unusedSeparatorWidgets.append(sepWidget);
3181 sepWidget->hide();
3182 }
3183 }
3184
3185 for (int i = 0; i < QInternal::DockCount; ++i)
3186 newState.dockAreaLayout.docks[i].reparentWidgets(parentWidget());
3187
3188#endif // QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3190 isInApplyState = false;
3191}
3192
3197
3199{
3200 QScopedValueRollback<bool> guard(isInRestoreState, true);
3204
3208 if (parentWidget()->isVisible())
3209 applyState(layoutState, false); // hides tabBars allocated by newState
3210 return false;
3211 }
3212
3213 if (parentWidget()->isVisible()) {
3215 applyState(layoutState, false);
3216 } else {
3217 /*
3218 The state might not fit into the size of the widget as it gets shown, but
3219 if the window is expected to be maximized or full screened, then we might
3220 get several resizes as part of that transition, at the end of which the
3221 state might fit. So keep the restored state around for now and try again
3222 later in setGeometry.
3223 */
3224 if ((parentWidget()->windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized))
3225 && !layoutState.fits()) {
3227 }
3228 }
3229
3231 savedState.clear();
3232
3233#if QT_CONFIG(dockwidget)
3234 if (parentWidget()->isVisible()) {
3235#if QT_CONFIG(tabbar)
3236 for (QTabBar *tab_bar : std::as_const(usedTabBars))
3237 tab_bar->show();
3238
3239#endif
3240 }
3241#endif // QT_CONFIG(dockwidget)
3242
3243 return true;
3244}
3245
3246#if QT_CONFIG(draganddrop)
3247bool QMainWindowLayout::needsPlatformDrag()
3248{
3249 static const bool wayland =
3251 return wayland;
3252}
3253
3254Qt::DropAction QMainWindowLayout::performPlatformWidgetDrag(QLayoutItem *widgetItem,
3255 const QPoint &pressPosition)
3256{
3257 draggingWidget = widgetItem;
3258 QWidget *widget = widgetItem->widget();
3259 auto drag = QDrag(widget);
3260 auto mimeData = new QMimeData();
3261 auto window = widgetItem->widget()->windowHandle();
3262
3263 auto serialize = [](const auto &object) {
3266 dataStream << object;
3267 return data;
3268 };
3269 mimeData->setData("application/x-qt-mainwindowdrag-window"_L1,
3270 serialize(reinterpret_cast<qintptr>(window)));
3271 mimeData->setData("application/x-qt-mainwindowdrag-position"_L1, serialize(pressPosition));
3272 drag.setMimeData(mimeData);
3273
3274 auto result = drag.exec();
3275
3276 draggingWidget = nullptr;
3277 return result;
3278}
3279#endif
3280
3282
3283#include "qmainwindowlayout.moc"
3284#include "moc_qmainwindowlayout_p.cpp"
static QStyle * style()
Returns the application's style object.
int startDragDistance
the minimum distance required for a drag and drop operation to start.
QSize minimumSize() const override
\reimp
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
\inmodule QtCore
Definition qcoreevent.h:379
\inmodule QtCore\reentrant
Definition qdatastream.h:46
void setVersion(int)
Sets the version number of the data serialization format to v, a value of the \l Version enum.
\inmodule QtCore
QList< int > indexOf(QWidget *widget) const
QList< QDockAreaLayoutItem > item_list
void remove(const QList< int > &path)
static QRect constrainedRect(QRect rect, QWidget *widget)
static bool wmSupportsNativeWindowDeco()
static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
void endDrag(EndDragMode mode)
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-l...
Definition qdockwidget.h:20
bool isFloating() const
Definition qdockwidget.h:56
void dockLocationChanged(Qt::DockWidgetArea area)
void setFloating(bool floating)
\inmodule QtGui
Definition qdrag.h:22
\inmodule QtCore
Definition qcoreevent.h:45
@ NonClientAreaMouseButtonDblClick
Definition qcoreevent.h:215
@ ChildRemoved
Definition qcoreevent.h:108
@ LayoutRequest
Definition qcoreevent.h:112
@ NonClientAreaMouseMove
Definition qcoreevent.h:212
@ NonClientAreaMouseButtonRelease
Definition qcoreevent.h:214
@ NonClientAreaMouseButtonPress
Definition qcoreevent.h:213
@ ChildAdded
Definition qcoreevent.h:106
Type type() const
Returns the event type.
Definition qcoreevent.h:304
void accept()
Sets the accept flag of the event object, the equivalent of calling setAccepted(true).
Definition qcoreevent.h:310
void show()
Shows the item (items are visible by default).
QPointF pos() const
Returns the position of the item in parent coordinates.
QGraphicsWidget * window() const
GraphicsItemFlags flags() const
Returns this item's flags.
qreal x
the x position of the item
QString platformName
The name of the underlying platform plugin.
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately before the event occurred.
Definition qevent.h:56
The QLayoutItem class provides an abstract item that a QLayout manipulates.
Definition qlayoutitem.h:25
virtual QSize minimumSize() const =0
Implemented in subclasses to return the minimum size of this item.
virtual QWidget * widget() const
If this item manages a QWidget, returns that widget.
virtual QSize sizeHint() const =0
Implemented in subclasses to return the preferred size of this item.
The QLayout class is the base class of geometry managers.
Definition qlayout.h:26
void removeWidget(QWidget *w)
Removes the widget widget from the layout.
Definition qlayout.cpp:1323
void addChildWidget(QWidget *w)
This function is called from addWidget() functions in subclasses to add w as a managed widget of a la...
Definition qlayout.cpp:837
void update()
Updates the layout for parentWidget().
Definition qlayout.cpp:971
@ SetMinAndMaxSize
Definition qlayout.h:41
void invalidate() override
\reimp
Definition qlayout.cpp:469
QWidget * parentWidget() const
Returns the parent widget of this layout, or \nullptr if this layout is not installed on any widget.
Definition qlayout.cpp:399
virtual void setGeometry(const QRect &) override
\reimp
Definition qlayout.cpp:451
QLayout * layout() override
\reimp
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void prepend(rvalue_ref t)
Definition qlist.h:473
const T & constFirst() const noexcept
Definition qlist.h:647
QLayoutItem * takeAt(int index, int *x)
void setCentralWidget(QWidget *widget)
bool insertGap(const QList< int > &path, QLayoutItem *item)
QList< int > indexOf(QWidget *widget) const
QRect gapRect(const QList< int > &path) const
QLayoutItem * item(const QList< int > &path)
QRect itemRect(const QList< int > &path) const
bool restoreState(QDataStream &stream, const QMainWindowLayoutState &oldState)
void saveState(QDataStream &stream) const
void remove(const QList< int > &path)
QLayoutItem * itemAt(int index, int *x) const
QWidget * centralWidget() const
void apply(bool animated)
bool checkFormat(QDataStream &stream)
QMainWindowLayoutState(QMainWindow *win)
QLayoutItem * unplug(const QList< int > &path, QMainWindowLayoutState *savedState=nullptr)
QList< int > gapIndex(QWidget *widget, const QPoint &pos) const
QLayoutItem * plug(const QList< int > &path)
bool contains(QWidget *widget) const
void setCentralWidget(QWidget *cw)
void timerEvent(QTimerEvent *e) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
void hover(QLayoutItem *hoverTarget, const QPoint &mousePos)
void revert(QLayoutItem *widgetItem)
QSize sizeHint() const override
Implemented in subclasses to return the preferred size of this item.
QMainWindowLayoutState savedState
QLayoutItem * itemAt(int index) const override
Must be implemented in subclasses to return the layout item at index.
void setDockOptions(QMainWindow::DockOptions opts)
QLayoutItem * unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope)
void invalidate() override
\reimp
void restore(bool keepSavedState=false)
void addItem(QLayoutItem *item) override
Implemented in subclasses to add an item.
QSize minimumSize() const override
Returns the minimum size of this layout.
QWidget * centralWidget() const
QWidgetAnimator widgetAnimator
bool plug(QLayoutItem *widgetItem)
QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout)
int count() const override
Must be implemented in subclasses to return the number of items in the layout.
std::unique_ptr< QMainWindowLayoutState > restoredState
void saveState(QDataStream &stream) const
QMainWindow::DockOptions dockOptions
void setGeometry(const QRect &r) override
\reimp
QLayoutItem * takeAt(int index) override
Must be implemented in subclasses to remove the layout item at index from the layout,...
void applyState(QMainWindowLayoutState &newState, bool animate=true)
bool restoreState(QDataStream &stream)
QMainWindowLayoutState layoutState
void animationFinished(QWidget *widget)
The QMainWindow class provides a main application window.
Definition qmainwindow.h:25
\inmodule QtCore
Definition qmimedata.h:16
void setData(const QString &mimetype, const QByteArray &data)
Sets the data associated with the MIME type given by mimeType to the specified data.
\inmodule QtGui
Definition qevent.h:196
The QMoveEvent class contains event parameters for move events.
Definition qevent.h:502
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2339
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
void setParent(QObject *parent)
Makes the object a child of parent.
Definition qobject.cpp:2195
virtual bool eventFilter(QObject *watched, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object.
Definition qobject.cpp:1555
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void removeEventFilter(QObject *obj)
Removes an event filter object obj from this object.
Definition qobject.cpp:2370
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
Definition qobject.cpp:1470
QList< T > findChildren(QAnyStringView aName, Qt::FindChildOptions options=Qt::FindChildrenRecursively) const
Returns all children of this object with the given name that can be cast to type T,...
Definition qobject.h:164
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:127
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:486
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:404
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr void moveTopLeft(const QPoint &p) noexcept
Moves the rectangle, leaving the top-left corner at the given position.
Definition qrect.h:304
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:170
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr void setTop(int pos) noexcept
Sets the top edge of the rectangle to the given y coordinate.
Definition qrect.h:194
The QRubberBand class provides a rectangle or line that can indicate a selection or a boundary.
Definition qrubberband.h:18
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
QPointF globalPosition() const
Returns the position of the point in this event on the screen or virtual desktop.
Definition qevent.h:123
QPointF position() const
Returns the position of the point in this event, relative to the widget or item that received the eve...
Definition qevent.h:119
Qt::MouseButton button() const
Returns the button that caused the event.
Definition qevent.h:116
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr QSize expandedTo(const QSize &) const noexcept
Returns a size holding the maximum width and height of this size and the given otherSize.
Definition qsize.h:192
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
The QStatusBar class provides a horizontal bar suitable for presenting status information.
Definition qstatusbar.h:17
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
\variable QStyleOptionFocusRect::backgroundColor
void initFrom(const QWidget *w)
The QStylePainter class is a convenience class for drawing QStyle elements inside a widget.
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Returns the given logicalRectangle converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2143
@ PM_DockWidgetFrameWidth
Definition qstyle.h:437
@ PM_TitleBarHeight
Definition qstyle.h:448
@ PM_DockWidgetSeparatorExtent
Definition qstyle.h:435
@ PE_FrameDockWidget
Definition qstyle.h:105
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
Returns the value of the given pixel metric.
The QTabBar class provides a tab bar, e.g.
Definition qtabbar.h:19
bool event(QEvent *) override
\reimp
Definition qtabbar.cpp:1672
void mouseReleaseEvent(QMouseEvent *) override
\reimp
Definition qtabbar.cpp:2312
void mouseMoveEvent(QMouseEvent *) override
\reimp
Definition qtabbar.cpp:2160
void tabMoved(int from, int to)
Shape
This enum type lists the built-in shapes supported by QTabBar.
Definition qtabbar.h:42
@ RoundedSouth
Definition qtabbar.h:42
@ RoundedNorth
Definition qtabbar.h:42
@ RoundedWest
Definition qtabbar.h:42
@ RoundedEast
Definition qtabbar.h:42
The QTabWidget class provides a stack of tabbed widgets.
Definition qtabwidget.h:20
TabPosition
This enum type defines where QTabWidget draws the tab row:
Definition qtabwidget.h:74
TabShape
This enum type defines the shape of the tabs: \value Rounded The tabs are drawn with a rounded look.
Definition qtabwidget.h:85
\inmodule QtCore
\inmodule QtCore
Definition qcoreevent.h:366
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition qcoreevent.h:370
The QToolBar class provides a movable panel that contains a set of controls.
Definition qtoolbar.h:23
bool animating() const
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setGeometry(int x, int y, int w, int h)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:886
void setParent(QWidget *parent)
Sets the parent of the widget to parent, and resets the window flags.
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition qwidget.h:106
QLayout * layout() const
Returns the layout manager that is installed on this widget, or \nullptr if no layout manager is inst...
int width
the width of the widget excluding any window frame
Definition qwidget.h:114
QPoint pos
the position of the widget within its parent widget
Definition qwidget.h:111
bool isMaximized() const
Definition qwidget.cpp:2876
int height
the height of the widget excluding any window frame
Definition qwidget.h:115
virtual void setVisible(bool visible)
Definition qwidget.cpp:8255
void update()
Updates the widget unless updates are disabled or the widget is hidden.
bool event(QEvent *event) override
This is the main event handler; it handles event event.
Definition qwidget.cpp:8866
QStyle * style() const
Definition qwidget.cpp:2600
bool isVisible() const
Definition qwidget.h:874
QPointF mapFromGlobal(const QPointF &) const
Translates the global screen coordinate pos to widget coordinates.
#define this
Definition dialogs.cpp:9
QOpenGLWidget * widget
[1]
QString str
[2]
QSet< QString >::iterator it
rect
[4]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
short next
Definition keywords.cpp:445
QTextStream & qout()
Definition lalr.cpp:26
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ WindowFullScreen
Definition qnamespace.h:255
@ WindowMaximized
Definition qnamespace.h:254
DockWidgetArea
@ BottomDockWidgetArea
@ DockWidgetArea_Mask
@ NoDockWidgetArea
@ RightDockWidgetArea
@ LeftDockWidgetArea
@ TopDockWidgetArea
@ LeftButton
Definition qnamespace.h:58
@ WA_WState_Hidden
Definition qnamespace.h:297
@ WA_MouseNoMask
Definition qnamespace.h:338
ToolBarArea
@ LeftToolBarArea
@ BottomToolBarArea
@ TopToolBarArea
@ NoToolBarArea
@ RightToolBarArea
@ RightToLeft
Orientation
Definition qnamespace.h:98
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
@ FindDirectChildrenOnly
@ FindChildrenRecursively
@ ControlModifier
@ CaseInsensitive
DropAction
@ UniqueConnection
@ CustomizeWindowHint
Definition qnamespace.h:239
@ FramelessWindowHint
Definition qnamespace.h:225
@ Tool
Definition qnamespace.h:212
@ WindowTitleHint
Definition qnamespace.h:226
@ WindowCloseButtonHint
Definition qnamespace.h:241
@ ElideRight
Definition qnamespace.h:190
ToolButtonStyle
QLatin1StringView dockWidgetArea(int v)
Definition language.cpp:139
static jboolean copy(JNIEnv *, jobject)
static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)
static int pick(bool vertical, const QSize &size)
EGLStreamKHR stream
static int area(const QSize &s)
Definition qicon.cpp:153
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
return ret
static void fixToolBarOrientation(QLayoutItem *item, int dockPos)
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)
static QList< T > findChildrenHelper(const QObject *o)
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLint GLint GLint GLint GLint x
[0]
GLsizei GLuint * groups
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLenum GLuint GLenum GLsizei length
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLint GLsizei width
GLboolean GLuint group
GLbitfield flags
GLenum GLuint GLintptr offset
const GLchar * marker
GLint first
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLuint GLenum option
static constexpr QSize frameSize(const T &frame)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
static constexpr QChar sep
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
#define QT_CONFIG(feature)
#define Q_OBJECT
#define emit
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
size_t quintptr
Definition qtypes.h:167
ptrdiff_t qintptr
Definition qtypes.h:166
Q_WIDGETS_EXPORT QWidgetPrivate * qt_widget_private(QWidget *widget)
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
#define enabled
static QRect frameGeometry(HWND hwnd, bool topLevel)
QWidget * win
Definition settings.cpp:6
view show()
[18] //! [19]
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
QByteArray ba
[0]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QDataStream & operator<<(QDataStream &out, const MyClass &myObj)
[4]
QMimeData * mimeData
QObject::connect nullptr
QVBoxLayout * layout
myObject disconnect()
[26]
list indexOf("B")
QSharedPointer< T > other(t)
[5]
scene addItem(form)
QGraphicsItem * item
edit hide()
edit isVisible()
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QDockWidget * dockWidget
[0]
QHostInfo info
[0]
view create()
QDockAreaLayoutInfo * subinfo