7#if QT_CONFIG(dockwidget)
8#include "qdockarealayout_p.h"
9#include "qdockwidget.h"
10#include "qdockwidget_p.h"
13#include "qtoolbar_p.h"
15#include "qtoolbarlayout_p.h"
19#if QT_CONFIG(rubberband)
20#include "qrubberband.h"
26#include <qapplication.h>
27#if QT_CONFIG(draganddrop)
31#if QT_CONFIG(statusbar)
32#include <qstatusbar.h>
36#include <qstylepainter.h>
37#include <qvarlengtharray.h>
42#ifndef QT_NO_DEBUG_STREAM
44# include <qtextstream.h>
47#include <private/qmenu_p.h>
48#include <private/qapplication_p.h>
49#include <private/qlayoutengine_p.h>
50#include <private/qwidgetresizehandler_p.h>
52#include <QScopedValueRollback>
56using namespace Qt::StringLiterals;
61
62
64#if QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG_STREAM)
66static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent);
68static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutItem &item, QString indent)
70 qout << indent <<
"QDockAreaLayoutItem: "
71 <<
"pos: " << item.pos <<
" size:" << item.size
72 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
73 <<
" keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) <<
'\n';
75 if (item.widgetItem !=
nullptr) {
76 qout << indent <<
"widget: "
77 << item.widgetItem->widget()->metaObject()->className()
78 <<
" \"" << item.widgetItem->widget()->windowTitle() <<
"\"\n";
79 }
else if (item.subinfo !=
nullptr) {
80 qout << indent <<
"subinfo:\n";
81 dumpLayout(qout, *item.subinfo, indent +
" "_L1);
82 }
else if (item.placeHolderItem !=
nullptr) {
83 QRect r = item.placeHolderItem->topLevelRect;
84 qout << indent <<
"placeHolder: "
85 <<
"pos: " << item.pos <<
" size:" << item.size
86 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
87 <<
" keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize)
88 <<
" objectName:" << item.placeHolderItem->objectName
89 <<
" hidden:" << item.placeHolderItem->hidden
90 <<
" window:" << item.placeHolderItem->window
91 <<
" rect:" << r.x() <<
',' << r.y() <<
' '
92 << r.width() <<
'x' << r.height() <<
'\n';
96static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent)
98 const QSize minSize = layout.minimumSize();
99 qout << indent <<
"QDockAreaLayoutInfo: "
100 << layout.rect.left() <<
','
101 << layout.rect.top() <<
' '
102 << layout.rect.width() <<
'x'
103 << layout.rect.height()
104 <<
" min size: " << minSize.width() <<
',' << minSize.height()
105 <<
" orient:" << layout.o
107 <<
" tabbed:" << layout.tabbed
108 <<
" tbshape:" << layout.tabBarShape
114 for (
int i = 0; i < layout.item_list.size(); ++i) {
115 qout << indent <<
"Item: " << i <<
'\n';
116 dumpLayout(qout, layout.item_list.at(i), indent +
" "_L1);
120static void dumpLayout(QTextStream &qout,
const QDockAreaLayout &layout)
122 qout <<
"QDockAreaLayout: "
123 << layout.rect.left() <<
','
124 << layout.rect.top() <<
' '
125 << layout.rect.width() <<
'x'
126 << layout.rect.height() <<
'\n';
128 qout <<
"TopDockArea:\n";
129 dumpLayout(qout, layout.docks[QInternal::TopDock],
" "_L1);
130 qout <<
"LeftDockArea:\n";
131 dumpLayout(qout, layout.docks[QInternal::LeftDock],
" "_L1);
132 qout <<
"RightDockArea:\n";
133 dumpLayout(qout, layout.docks[QInternal::RightDock],
" "_L1);
134 qout <<
"BottomDockArea:\n";
135 dumpLayout(qout, layout.docks[QInternal::BottomDock],
" "_L1);
138QDebug operator<<(QDebug debug,
const QDockAreaLayout &layout)
142 dumpLayout(str, layout);
147QDebug operator<<(QDebug debug,
const QMainWindowLayout *layout)
149 debug << layout->layoutState.dockAreaLayout;
156static void dumpItemLists(
const QMainWindowLayout *layout,
const char *function,
const char *comment)
158 for (
int i = 0; i < QInternal::DockCount; ++i) {
159 const auto &list = layout->layoutState.dockAreaLayout.docks[i].item_list;
162 qDebug() << function << comment <<
"Dock" << i << list;
165#define DUMP(comment) dumpItemLists(this, __FUNCTION__, comment)
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
204#if QT_CONFIG(dockwidget)
205class QDockWidgetGroupLayout :
public QLayout,
206 public QMainWindowLayoutSeparatorHelper<QDockWidgetGroupLayout>
208 QWidgetResizeHandler *resizer;
210 QDockWidgetGroupLayout(QDockWidgetGroupWindow* parent) : QLayout(parent) {
211 setSizeConstraint(QLayout::SetMinAndMaxSize);
212 resizer =
new QWidgetResizeHandler(parent);
214 ~QDockWidgetGroupLayout() {
215 layoutState.deleteAllLayoutItems();
218 void addItem(QLayoutItem*) override { Q_UNREACHABLE(); }
219 int count()
const override {
return 0; }
220 QLayoutItem* itemAt(
int index)
const override
223 return layoutState.itemAt(&x, index);
225 QLayoutItem* takeAt(
int index) override
228 QLayoutItem *ret = layoutState.takeAt(&x, index);
229 if (savedState.rect.isValid() && ret->widget()) {
231 QList<
int> path = savedState.indexOf(ret->widget());
233 savedState.remove(path);
235 path = layoutState.indexOf(ret->widget());
237 layoutState.remove(path);
241 QSize sizeHint()
const override
243 int fw = frameWidth();
244 return layoutState.sizeHint() + QSize(fw, fw);
246 QSize minimumSize()
const override
248 int fw = frameWidth();
249 return layoutState.minimumSize() + QSize(fw, fw);
251 QSize maximumSize()
const override
253 int fw = frameWidth();
254 return layoutState.maximumSize() + QSize(fw, fw);
256 void setGeometry(
const QRect&r) override
258 groupWindow()->destroyOrHideIfEmpty();
259 QDockAreaLayoutInfo *li = dockAreaLayoutInfo();
262 int fw = frameWidth();
264 li->reparentWidgets(parentWidget());
266 li->rect = r.adjusted(fw, fw, -fw, -fw);
269 if (savedState.rect.isValid())
270 savedState.rect = li->rect;
271 resizer->setEnabled(!nativeWindowDeco());
274 QDockAreaLayoutInfo *dockAreaLayoutInfo() {
return &layoutState; }
276#if QT_CONFIG(toolbar)
277 QToolBarAreaLayout *toolBarAreaLayout()
283 bool nativeWindowDeco()
const
285 return groupWindow()->hasNativeDecos();
288 int frameWidth()
const
290 return nativeWindowDeco() ? 0 :
291 parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, parentWidget());
294 QDockWidgetGroupWindow *groupWindow()
const
296 return static_cast<QDockWidgetGroupWindow *>(parent());
299 QDockAreaLayoutInfo layoutState;
300 QDockAreaLayoutInfo savedState;
303bool QDockWidgetGroupWindow::event(QEvent *e)
305 auto lay =
static_cast<QDockWidgetGroupLayout *>(layout());
306 if (lay && lay->windowEvent(e))
313 if (QDockWidget *dw = activeTabbedDockWidget()) {
322 if (QDockWidget *dw = activeTabbedDockWidget())
323 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->moveEvent(
static_cast<QMoveEvent*>(e));
326 case QEvent::NonClientAreaMouseMove:
327 case QEvent::NonClientAreaMouseButtonPress:
328 case QEvent::NonClientAreaMouseButtonRelease:
329 case QEvent::NonClientAreaMouseButtonDblClick:
332 if (QDockWidget *dw = activeTabbedDockWidget())
333 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->nonClientAreaMouseEvent(
static_cast<QMouseEvent*>(e));
336 case QEvent::ChildAdded:
337 if (qobject_cast<QDockWidget *>(
static_cast<QChildEvent*>(e)->child()))
340 case QEvent::LayoutRequest:
342 destroyOrHideIfEmpty();
345 updateCurrentGapRect();
351 return QWidget::event(e);
354void QDockWidgetGroupWindow::paintEvent(QPaintEvent *)
356 QDockWidgetGroupLayout *lay =
static_cast<QDockWidgetGroupLayout *>(layout());
357 bool nativeDeco = lay->nativeWindowDeco();
360 QStyleOptionFrame framOpt;
361 framOpt.initFrom(
this);
362 QStylePainter p(
this);
363 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
367QDockAreaLayoutInfo *QDockWidgetGroupWindow::layoutInfo()
const
369 return static_cast<QDockWidgetGroupLayout *>(layout())->dockAreaLayoutInfo();
374
375
376
377
378const QDockAreaLayoutInfo *QDockWidgetGroupWindow::tabLayoutInfo()
const
380 const QDockAreaLayoutInfo *info = layoutInfo();
381 while (info && !info->tabbed) {
384 const QDockAreaLayoutInfo *next =
nullptr;
385 bool isSingle =
false;
386 for (
const auto &item : info->item_list) {
387 if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
389 if (next || isSingle)
393 else if (item.widgetItem)
404
405
406QDockWidget *QDockWidgetGroupWindow::activeTabbedDockWidget()
const
408 QDockWidget *dw =
nullptr;
409 const QDockAreaLayoutInfo *info = tabLayoutInfo();
412 if (info->tabBar && info->tabBar->currentIndex() >= 0) {
413 int i = info->tabIndexToListIndex(info->tabBar->currentIndex());
415 const QDockAreaLayoutItem &item = info->item_list.at(i);
417 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
421 for (
int i = 0; !dw && i < info->item_list.size(); ++i) {
422 const QDockAreaLayoutItem &item = info->item_list.at(i);
425 if (!item.widgetItem)
427 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
435
436
437
438void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
440 const QDockAreaLayoutInfo *info = layoutInfo();
441 if (!info->isEmpty()) {
446 if (!info->item_list.isEmpty()) {
452 const auto dockWidgetsList = dockWidgets();
453 for (QDockWidget *dw : dockWidgetsList) {
454 const bool wasFloating = dw->isFloating();
455 const bool wasHidden = dw->isHidden();
456 dw->setParent(parentWidget());
457 qCDebug(lcQpaDockWidgets) <<
"Reparented:" << dw <<
"to" << parentWidget() <<
"by" <<
this;
459 dw->setFloating(
true);
462 QMainWindowLayout *ml =
463 qt_mainwindow_layout(
static_cast<QMainWindow *>(parentWidget()));
464 Qt::DockWidgetArea area = ml->dockWidgetArea(
this);
465 if (area == Qt::NoDockWidgetArea)
466 area = Qt::LeftDockWidgetArea;
467 static_cast<QMainWindow *>(parentWidget())->addDockWidget(area, dw);
468 qCDebug(lcQpaDockWidgets) <<
"Redocked to Mainwindow:" << area << dw <<
"by" <<
this;
477
478
479
480
481bool QDockWidgetGroupWindow::hasVisibleDockWidgets()
const
483 const auto &children = findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
484 for (
auto child : children) {
489 if (!child->testAttribute(Qt::WA_WState_Hidden))
496
497
498void QDockWidgetGroupWindow::adjustFlags()
500 Qt::WindowFlags oldFlags = windowFlags();
501 Qt::WindowFlags flags = oldFlags;
504 QDockWidget *top = activeTabbedDockWidget();
506 QDockWidget *top =
nullptr;
510 ((oldFlags & ~Qt::FramelessWindowHint) | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
511 }
else if (
static_cast<QDockWidgetGroupLayout *>(layout())->nativeWindowDeco()) {
512 flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
513 flags.setFlag(Qt::WindowCloseButtonHint, top->features() & QDockWidget::DockWidgetClosable);
514 flags &= ~Qt::FramelessWindowHint;
516 flags &= ~(Qt::WindowCloseButtonHint | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
517 flags |= Qt::FramelessWindowHint;
520 if (oldFlags != flags) {
523 setWindowFlags(flags);
524 const bool gainedNativeDecos = (oldFlags & Qt::FramelessWindowHint) && !(flags & Qt::FramelessWindowHint);
525 const bool lostNativeDecos = !(oldFlags & Qt::FramelessWindowHint) && (flags & Qt::FramelessWindowHint);
529 if (lostNativeDecos) {
530 QRect newGeometry = geometry();
531 newGeometry.setTop(frameGeometry().top());
532 const int bottomFrame = geometry().top() - frameGeometry().top();
533 m_removedFrameSize = QSize((frameSize() - size()).width(), bottomFrame);
534 setGeometry(newGeometry);
535 }
else if (gainedNativeDecos && m_removedFrameSize.isValid()) {
536 QRect r = geometry();
537 r.adjust(-m_removedFrameSize.width() / 2, 0,
538 -m_removedFrameSize.width() / 2, -m_removedFrameSize.height());
540 m_removedFrameSize = QSize();
543 setVisible(hasVisibleDockWidgets());
546 QWidget *titleBarOf = top ? top : parentWidget();
547 setWindowTitle(titleBarOf->windowTitle());
548 setWindowIcon(titleBarOf->windowIcon());
551bool QDockWidgetGroupWindow::hasNativeDecos()
const
554 QDockWidget *dw = activeTabbedDockWidget();
558 if (!QDockWidgetLayout::wmSupportsNativeWindowDeco())
561 return dw->titleBarWidget() ==
nullptr;
568
569
570
571
572
573
574bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem,
const QPoint &mousePos)
576 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
577 if (savedState.isEmpty())
578 savedState = *layoutInfo();
580 QMainWindow::DockOptions opts =
static_cast<QMainWindow *>(parentWidget())->dockOptions();
581 QDockAreaLayoutInfo newState = savedState;
582 bool nestingEnabled =
583 (opts & QMainWindow::AllowNestedDocks) && !(opts & QMainWindow::ForceTabbedDocks);
584 QDockAreaLayoutInfo::TabMode tabMode =
585#if !QT_CONFIG(tabbar)
586 QDockAreaLayoutInfo::NoTabs;
588 nestingEnabled ? QDockAreaLayoutInfo::AllowTabs : QDockAreaLayoutInfo::ForceTabs;
589 if (
auto group = qobject_cast<QDockWidgetGroupWindow *>(widgetItem->widget())) {
590 if (!group->tabLayoutInfo())
591 tabMode = QDockAreaLayoutInfo::NoTabs;
593 if (newState.tabbed) {
595 newState.item_list = { QDockAreaLayoutItem(
new QDockAreaLayoutInfo(newState)) };
596 newState.item_list.first().size = pick(savedState.o, savedState.rect.size());
597 newState.tabbed =
false;
598 newState.tabBar =
nullptr;
602 auto newGapPos = newState.gapIndex(mousePos, nestingEnabled, tabMode);
603 Q_ASSERT(!newGapPos.isEmpty());
607 if (newGapPos == currentGapPos || newState.hasGapItem(newGapPos))
610 currentGapPos = newGapPos;
611 newState.insertGap(currentGapPos, widgetItem);
613 *layoutInfo() = std::move(newState);
614 updateCurrentGapRect();
615 layoutInfo()->apply(opts & QMainWindow::AnimatedDocks);
619void QDockWidgetGroupWindow::updateCurrentGapRect()
621 if (!currentGapPos.isEmpty())
622 currentGapRect = layoutInfo()->info(currentGapPos)->itemRect(currentGapPos.last(),
true);
626
627
628void QDockWidgetGroupWindow::restore()
630 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
631 if (!savedState.isEmpty()) {
632 *layoutInfo() = savedState;
633 savedState = QDockAreaLayoutInfo();
635 currentGapRect = QRect();
636 currentGapPos.clear();
638 layoutInfo()->fitItems();
639 layoutInfo()->apply(
static_cast<QMainWindow *>(parentWidget())->dockOptions()
640 & QMainWindow::AnimatedDocks);
644
645
646void QDockWidgetGroupWindow::apply()
648 static_cast<QDockWidgetGroupLayout *>(layout())->savedState.clear();
649 currentGapRect = QRect();
650 layoutInfo()->plug(currentGapPos);
651 currentGapPos.clear();
653 layoutInfo()->apply(
false);
656void QDockWidgetGroupWindow::childEvent(QChildEvent *event)
658 switch (event->type()) {
659 case QEvent::ChildRemoved:
660 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
661 dockWidget->removeEventFilter(
this);
662 destroyIfSingleItemLeft();
664 case QEvent::ChildAdded:
665 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
666 dockWidget->installEventFilter(
this);
673bool QDockWidgetGroupWindow::eventFilter(QObject *obj, QEvent *event)
675 auto *dockWidget = qobject_cast<QDockWidget *>(obj);
677 return QWidget::eventFilter(obj, event);
679 switch (event->type()) {
683 reparent(dockWidget);
684 dockWidget->setFloating(
false);
690 if (dockWidget->isVisible())
697 return QWidget::eventFilter(obj, event);
700void QDockWidgetGroupWindow::destroyIfSingleItemLeft()
702 const auto &dockWidgets =
this->dockWidgets();
705 if (dockWidgets.count() != 1)
708 auto *lastDockWidget = dockWidgets.at(0);
713 if (layoutInfo()->indexOf(lastDockWidget).isEmpty())
716 auto *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
717 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
720 mwLayout->unplug(lastDockWidget, QDockWidgetPrivate::DragScope::Widget);
721 lastDockWidget->setGeometry(geometry());
725 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
728 reparent(lastDockWidget);
731 layoutInfo()->item_list.clear();
734 parentInfo.remove(
this);
735 destroyOrHideIfEmpty();
738void QDockWidgetGroupWindow::reparent(QDockWidget *dockWidget)
744 auto *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
745 Q_ASSERT(mainWindow);
746 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
748 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
749 dockWidget->removeEventFilter(
this);
750 parentInfo.add(dockWidget);
751 layoutInfo()->remove(dockWidget);
752 const bool wasFloating = dockWidget->isFloating();
753 const bool wasVisible = dockWidget->isVisible();
754 dockWidget->setParent(mainWindow);
755 dockWidget->setFloating(wasFloating);
756 dockWidget->setVisible(wasVisible);
761
762
766QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win)
768#if QT_CONFIG(toolbar)
769 toolBarAreaLayout(win),
771#if QT_CONFIG(dockwidget)
781QSize QMainWindowLayoutState::sizeHint()
const
786#if QT_CONFIG(dockwidget)
787 result = dockAreaLayout.sizeHint();
789 if (centralWidgetItem)
790 result = centralWidgetItem->sizeHint();
793#if QT_CONFIG(toolbar)
794 result = toolBarAreaLayout.sizeHint(result);
800QSize QMainWindowLayoutState::minimumSize()
const
804#if QT_CONFIG(dockwidget)
805 result = dockAreaLayout.minimumSize();
807 if (centralWidgetItem)
808 result = centralWidgetItem->minimumSize();
811#if QT_CONFIG(toolbar)
812 result = toolBarAreaLayout.minimumSize(result);
819
820
821
822
823bool QMainWindowLayoutState::fits()
const
825 Q_ASSERT(mainWindow);
829#if QT_CONFIG(dockwidget)
830 size = dockAreaLayout.minimumStableSize();
833#if QT_CONFIG(toolbar)
834 size.rwidth() += toolBarAreaLayout.docks[QInternal::LeftDock].rect.width();
835 size.rwidth() += toolBarAreaLayout.docks[QInternal::RightDock].rect.width();
836 size.rheight() += toolBarAreaLayout.docks[QInternal::TopDock].rect.height();
837 size.rheight() += toolBarAreaLayout.docks[QInternal::BottomDock].rect.height();
840 return size.width() <= mainWindow->width() && size.height() <= mainWindow->height();
843void QMainWindowLayoutState::apply(
bool animated)
845#if QT_CONFIG(toolbar)
846 toolBarAreaLayout.apply(animated);
849#if QT_CONFIG(dockwidget)
851 dockAreaLayout.apply(animated);
853 if (centralWidgetItem) {
854 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
856 layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, animated);
861void QMainWindowLayoutState::fitLayout()
864#if !QT_CONFIG(toolbar)
867 toolBarAreaLayout.rect = rect;
868 r = toolBarAreaLayout.fitLayout();
871#if QT_CONFIG(dockwidget)
872 dockAreaLayout.rect = r;
873 dockAreaLayout.fitLayout();
875 centralWidgetRect = r;
879void QMainWindowLayoutState::deleteAllLayoutItems()
881#if QT_CONFIG(toolbar)
882 toolBarAreaLayout.deleteAllLayoutItems();
885#if QT_CONFIG(dockwidget)
886 dockAreaLayout.deleteAllLayoutItems();
890void QMainWindowLayoutState::deleteCentralWidgetItem()
892#if QT_CONFIG(dockwidget)
893 delete dockAreaLayout.centralWidgetItem;
894 dockAreaLayout.centralWidgetItem =
nullptr;
896 delete centralWidgetItem;
897 centralWidgetItem = 0;
901QLayoutItem *QMainWindowLayoutState::itemAt(
int index,
int *x)
const
903#if QT_CONFIG(toolbar)
904 if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
908#if QT_CONFIG(dockwidget)
909 if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
912 if (centralWidgetItem && (*x)++ == index)
913 return centralWidgetItem;
919QLayoutItem *QMainWindowLayoutState::takeAt(
int index,
int *x)
921#if QT_CONFIG(toolbar)
922 if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
926#if QT_CONFIG(dockwidget)
927 if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
930 if (centralWidgetItem && (*x)++ == index) {
931 QLayoutItem *ret = centralWidgetItem;
932 centralWidgetItem =
nullptr;
940QList<
int> QMainWindowLayoutState::indexOf(QWidget *widget)
const
944#if QT_CONFIG(toolbar)
946 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
947 result = toolBarAreaLayout.indexOf(toolBar);
948 if (!result.isEmpty())
954#if QT_CONFIG(dockwidget)
956 if (qobject_cast<QDockWidget *>(widget) || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
957 result = dockAreaLayout.indexOf(widget);
958 if (!result.isEmpty())
967bool QMainWindowLayoutState::contains(QWidget *widget)
const
969#if QT_CONFIG(dockwidget)
970 if (dockAreaLayout.centralWidgetItem !=
nullptr && dockAreaLayout.centralWidgetItem->widget() == widget)
972 if (!dockAreaLayout.indexOf(widget).isEmpty())
975 if (centralWidgetItem && centralWidgetItem->widget() == widget)
979#if QT_CONFIG(toolbar)
980 if (!toolBarAreaLayout.indexOf(widget).isEmpty())
986void QMainWindowLayoutState::setCentralWidget(QWidget *widget)
988 QLayoutItem *item =
nullptr;
990 deleteCentralWidgetItem();
992 if (widget !=
nullptr)
993 item =
new QWidgetItemV2(widget);
995#if QT_CONFIG(dockwidget)
996 dockAreaLayout.centralWidgetItem = item;
998 centralWidgetItem = item;
1002QWidget *QMainWindowLayoutState::centralWidget()
const
1004 QLayoutItem *item =
nullptr;
1006#if QT_CONFIG(dockwidget)
1007 item = dockAreaLayout.centralWidgetItem;
1009 item = centralWidgetItem;
1012 if (item !=
nullptr)
1013 return item->widget();
1017QList<
int> QMainWindowLayoutState::gapIndex(QWidget *widget,
1018 const QPoint &pos)
const
1022#if QT_CONFIG(toolbar)
1024 if (qobject_cast<QToolBar*>(widget) !=
nullptr) {
1025 result = toolBarAreaLayout.gapIndex(pos);
1026 if (!result.isEmpty())
1032#if QT_CONFIG(dockwidget)
1034 if (qobject_cast<QDockWidget *>(widget) !=
nullptr
1035 || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1036 bool disallowTabs =
false;
1037#if QT_CONFIG(tabbar)
1038 if (
auto *group = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1039 if (!group->tabLayoutInfo())
1040 disallowTabs =
true;
1043 result = dockAreaLayout.gapIndex(pos, disallowTabs);
1044 if (!result.isEmpty())
1053bool QMainWindowLayoutState::insertGap(
const QList<
int> &path, QLayoutItem *item)
1058 int i = path.first();
1060#if QT_CONFIG(toolbar)
1062 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) !=
nullptr);
1063 return toolBarAreaLayout.insertGap(path.mid(1), item);
1067#if QT_CONFIG(dockwidget)
1069 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) || qobject_cast<QDockWidgetGroupWindow*>(item->widget()));
1070 return dockAreaLayout.insertGap(path.mid(1), item);
1077void QMainWindowLayoutState::remove(
const QList<
int> &path)
1079 int i = path.first();
1081#if QT_CONFIG(toolbar)
1083 toolBarAreaLayout.remove(path.mid(1));
1086#if QT_CONFIG(dockwidget)
1088 dockAreaLayout.remove(path.mid(1));
1092void QMainWindowLayoutState::remove(QLayoutItem *item)
1094#if QT_CONFIG(toolbar)
1095 toolBarAreaLayout.remove(item);
1098#if QT_CONFIG(dockwidget)
1100 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
1101 QList<
int> path = dockAreaLayout.indexOf(dockWidget);
1102 if (!path.isEmpty())
1103 dockAreaLayout.remove(path);
1108void QMainWindowLayoutState::clear()
1110#if QT_CONFIG(toolbar)
1111 toolBarAreaLayout.clear();
1114#if QT_CONFIG(dockwidget)
1115 dockAreaLayout.clear();
1117 centralWidgetRect = QRect();
1123bool QMainWindowLayoutState::isValid()
const
1125 return rect.isValid();
1128QLayoutItem *QMainWindowLayoutState::item(
const QList<
int> &path)
1130 int i = path.first();
1132#if QT_CONFIG(toolbar)
1134 const QToolBarAreaLayoutItem *tbItem = toolBarAreaLayout.item(path.mid(1));
1136 return tbItem->widgetItem;
1140#if QT_CONFIG(dockwidget)
1142 return dockAreaLayout.item(path.mid(1)).widgetItem;
1148QRect QMainWindowLayoutState::itemRect(
const QList<
int> &path)
const
1150 int i = path.first();
1152#if QT_CONFIG(toolbar)
1154 return toolBarAreaLayout.itemRect(path.mid(1));
1157#if QT_CONFIG(dockwidget)
1159 return dockAreaLayout.itemRect(path.mid(1));
1165QRect QMainWindowLayoutState::gapRect(
const QList<
int> &path)
const
1167 int i = path.first();
1169#if QT_CONFIG(toolbar)
1171 return toolBarAreaLayout.itemRect(path.mid(1));
1174#if QT_CONFIG(dockwidget)
1176 return dockAreaLayout.gapRect(path.mid(1));
1182QLayoutItem *QMainWindowLayoutState::plug(
const QList<
int> &path)
1184 int i = path.first();
1186#if QT_CONFIG(toolbar)
1188 return toolBarAreaLayout.plug(path.mid(1));
1191#if QT_CONFIG(dockwidget)
1193 return dockAreaLayout.plug(path.mid(1));
1199QLayoutItem *QMainWindowLayoutState::unplug(
const QList<
int> &path, QMainWindowLayoutState *other)
1201 int i = path.first();
1203#if !QT_CONFIG(toolbar)
1207 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout :
nullptr);
1210#if QT_CONFIG(dockwidget)
1212 return dockAreaLayout.unplug(path.mid(1));
1218void QMainWindowLayoutState::saveState(QDataStream &stream)
const
1220#if QT_CONFIG(dockwidget)
1221 dockAreaLayout.saveState(stream);
1222#if QT_CONFIG(tabbar)
1223 const QList<QDockWidgetGroupWindow *> floatingTabs =
1224 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
1226 for (QDockWidgetGroupWindow *floating : floatingTabs) {
1227 if (floating->layoutInfo()->isEmpty())
1229 stream << uchar(QDockAreaLayout::FloatingDockWidgetTabMarker) << floating->geometry();
1230 floating->layoutInfo()->saveState(stream);
1234#if QT_CONFIG(toolbar)
1235 toolBarAreaLayout.saveState(stream);
1239template <
typename T>
1245 for (
int i=0; i < list.size(); ++i) {
1246 if (T t = qobject_cast<T>(list[i])) {
1254#if QT_CONFIG(dockwidget)
1255static QList<QDockWidget*> allMyDockWidgets(
const QWidget *mainWindow)
1257 QList<QDockWidget*> result;
1258 for (QObject *c : mainWindow->children()) {
1259 if (
auto *dw = qobject_cast<QDockWidget*>(c)) {
1261 }
else if (
auto *gw = qobject_cast<QDockWidgetGroupWindow*>(c)) {
1262 for (QObject *c : gw->children()) {
1263 if (
auto *dw = qobject_cast<QDockWidget*>(c))
1274bool QMainWindowLayoutState::checkFormat(QDataStream &stream)
1276 while (!stream.atEnd()) {
1281#if QT_CONFIG(toolbar)
1282 case QToolBarAreaLayout::ToolBarStateMarker:
1283 case QToolBarAreaLayout::ToolBarStateMarkerEx:
1285 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1286 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker,
true )) {
1293#if QT_CONFIG(dockwidget)
1294 case QDockAreaLayout::DockWidgetStateMarker:
1296 const auto dockWidgets = allMyDockWidgets(mainWindow);
1297 if (!dockAreaLayout.restoreState(stream, dockWidgets,
true )) {
1302#if QT_CONFIG(tabbar)
1303 case QDockAreaLayout::FloatingDockWidgetTabMarker:
1307 QDockAreaLayoutInfo info;
1308 auto dockWidgets = allMyDockWidgets(mainWindow);
1309 if (!info.restoreState(stream, dockWidgets,
true ))
1325bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
1326 const QMainWindowLayoutState &oldState)
1330 while(!_stream.atEnd()) {
1332 QByteArray ba(length,
'\0');
1333 length = _stream.readRawData(ba.data(), ba.size());
1338 QDataStream ds(copy);
1339 ds.setVersion(_stream.version());
1340 if (!checkFormat(ds))
1343 QDataStream stream(copy);
1344 stream.setVersion(_stream.version());
1346 while (!stream.atEnd()) {
1351#if QT_CONFIG(dockwidget)
1352 case QDockAreaLayout::DockWidgetStateMarker:
1354 const auto dockWidgets = allMyDockWidgets(mainWindow);
1355 if (!dockAreaLayout.restoreState(stream, dockWidgets))
1358 for (
int i = 0; i < dockWidgets.size(); ++i) {
1359 QDockWidget *w = dockWidgets.at(i);
1360 QList<
int> path = dockAreaLayout.indexOf(w);
1361 if (path.isEmpty()) {
1362 QList<
int> oldPath = oldState.dockAreaLayout.indexOf(w);
1363 if (oldPath.isEmpty()) {
1366 QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
1367 if (info ==
nullptr) {
1375#if QT_CONFIG(tabwidget)
1376 case QDockAreaLayout::FloatingDockWidgetTabMarker:
1378 auto dockWidgets = allMyDockWidgets(mainWindow);
1379 QDockWidgetGroupWindow* floatingTab = qt_mainwindow_layout(mainWindow)->createTabbedDockWindow();
1380 *floatingTab->layoutInfo() = QDockAreaLayoutInfo(
1381 &dockAreaLayout.sep, QInternal::LeftDock,
1382 Qt::Horizontal, QTabBar::RoundedSouth, mainWindow);
1385 QDockAreaLayoutInfo *info = floatingTab->layoutInfo();
1386 if (!info->restoreState(stream, dockWidgets,
false))
1388 geometry = QDockAreaLayout::constrainedRect(geometry, floatingTab);
1389 floatingTab->move(geometry.topLeft());
1390 floatingTab->resize(geometry.size());
1394 if (info->onlyHasPlaceholders())
1395 info->reparentWidgets(floatingTab);
1397 floatingTab->show();
1403#if QT_CONFIG(toolbar)
1404 case QToolBarAreaLayout::ToolBarStateMarker:
1405 case QToolBarAreaLayout::ToolBarStateMarkerEx:
1407 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1408 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker))
1411 for (
int i = 0; i < toolBars.size(); ++i) {
1412 QToolBar *w = toolBars.at(i);
1413 QList<
int> path = toolBarAreaLayout.indexOf(w);
1414 if (path.isEmpty()) {
1415 QList<
int> oldPath = oldState.toolBarAreaLayout.indexOf(w);
1416 if (oldPath.isEmpty()) {
1419 toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(
nullptr, w);
1435
1436
1438#if QT_CONFIG(toolbar)
1440static constexpr Qt::ToolBarArea validateToolBarArea(Qt::ToolBarArea area)
1443 case Qt::LeftToolBarArea:
1444 case Qt::RightToolBarArea:
1445 case Qt::TopToolBarArea:
1446 case Qt::BottomToolBarArea:
1451 return Qt::TopToolBarArea;
1454static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
1457 case Qt::LeftToolBarArea:
return QInternal::LeftDock;
1458 case Qt::RightToolBarArea:
return QInternal::RightDock;
1459 case Qt::TopToolBarArea:
return QInternal::TopDock;
1460 case Qt::BottomToolBarArea:
return QInternal::BottomDock;
1465 return QInternal::DockCount;
1468static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
1471 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1472 case QInternal::RightDock:
return Qt::RightToolBarArea;
1473 case QInternal::TopDock:
return Qt::TopToolBarArea;
1474 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1477 return Qt::NoToolBarArea;
1480static inline Qt::ToolBarArea toToolBarArea(
int pos)
1482 return toToolBarArea(
static_cast<QInternal::DockPosition>(pos));
1485void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
1487 area = validateToolBarArea(area);
1489 layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1490 if (savedState.isValid())
1491 savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1496void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
1498 layoutState.toolBarAreaLayout.insertToolBarBreak(before);
1499 if (savedState.isValid())
1500 savedState.toolBarAreaLayout.insertToolBarBreak(before);
1504void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
1506 layoutState.toolBarAreaLayout.removeToolBarBreak(before);
1507 if (savedState.isValid())
1508 savedState.toolBarAreaLayout.removeToolBarBreak(before);
1512void QMainWindowLayout::moveToolBar(QToolBar *toolbar,
int pos)
1514 layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1515 if (savedState.isValid())
1516 savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1521
1522void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
1525 QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
1526 toolbar, SLOT(_q_updateIconSize(QSize)));
1527 QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
1528 toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
1530 removeWidget(toolbar);
1535
1536
1537void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
1541 area = validateToolBarArea(area);
1543 addChildWidget(toolbar);
1544 QLayoutItem *item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
1545 if (savedState.isValid() && item) {
1547 savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
1552 toolbar->d_func()->updateWindowFlags(
false );
1556
1557
1558void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
1560 addChildWidget(toolbar);
1561 QLayoutItem *item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
1562 if (savedState.isValid() && item) {
1564 savedState.toolBarAreaLayout.insertItem(before, item);
1566 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
1567 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1568 if (!currentGapPos.isEmpty()) {
1569 currentGapPos.prepend(0);
1570 currentGapRect = layoutState.itemRect(currentGapPos);
1576Qt::ToolBarArea QMainWindowLayout::toolBarArea(
const QToolBar *toolbar)
const
1578 QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar);
1580 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1581 case QInternal::RightDock:
return Qt::RightToolBarArea;
1582 case QInternal::TopDock:
return Qt::TopToolBarArea;
1583 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1586 return Qt::NoToolBarArea;
1589bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar)
const
1591 return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
1594void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar)
const
1596 option->toolBarArea = toolBarArea(toolBar);
1597 layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
1600void QMainWindowLayout::toggleToolBarsVisible()
1602 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
1603 if (!layoutState.mainWindow->isMaximized()) {
1604 QPoint topLeft = parentWidget()->geometry().topLeft();
1605 QRect r = parentWidget()->geometry();
1606 r = layoutState.toolBarAreaLayout.rectHint(r);
1608 parentWidget()->setGeometry(r);
1617
1618
1620#if QT_CONFIG(dockwidget)
1622static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area)
1625 case Qt::LeftDockWidgetArea:
return QInternal::LeftDock;
1626 case Qt::RightDockWidgetArea:
return QInternal::RightDock;
1627 case Qt::TopDockWidgetArea:
return QInternal::TopDock;
1628 case Qt::BottomDockWidgetArea:
return QInternal::BottomDock;
1633 return QInternal::DockCount;
1636inline static Qt::DockWidgetArea toDockWidgetArea(
int pos)
1638 return QDockWidgetPrivate::toDockWidgetArea(
static_cast<QInternal::DockPosition>(pos));
1643static bool isAreaAllowed(QWidget *widget,
const QList<
int> &path)
1645 Q_ASSERT_X((path.size() > 1),
"isAreaAllowed",
"invalid path size");
1646 const Qt::DockWidgetArea area = toDockWidgetArea(path[1]);
1649 if (QDockWidget *dw = qobject_cast<QDockWidget *>(widget)) {
1650 const bool allowed = dw->isAreaAllowed(area);
1652 qCDebug(lcQpaDockWidgets) <<
"No permission for single DockWidget" << widget <<
"to dock on" << area;
1657 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1658 const QList<QDockWidget *> children = dwgw->findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly);
1660 if (children.size() == 1) {
1662 const bool allowed = children.at(0)->isAreaAllowed(area);
1664 qCDebug(lcQpaDockWidgets) <<
"No permission for DockWidgetGroupWindow" << widget <<
"to dock on" << area;
1668 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"has" << children.size() <<
"children:";
1669 qCDebug(lcQpaDockWidgets) << children;
1670 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"can dock at" << area <<
"and anywhere else.";
1674 qCDebug(lcQpaDockWidgets) <<
"Docking requested for invalid widget type (coding error)." << widget << area;
1678void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1680 if (layoutState.dockAreaLayout.corners[corner] == area)
1682 layoutState.dockAreaLayout.corners[corner] = area;
1683 if (savedState.isValid())
1684 savedState.dockAreaLayout.corners[corner] = area;
1688Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner)
const
1690 return layoutState.dockAreaLayout.corners[corner];
1696QRect QMainWindowLayout::dockWidgetAreaRect(
const Qt::DockWidgetArea area, DockWidgetAreaSize size)
const
1698 const QInternal::DockPosition dockPosition = toDockPos(area);
1701 if (dockPosition == QInternal::DockCount) {
1702 qCDebug(lcQpaDockWidgets) <<
"QMainWindowLayout::dockWidgetAreaRect called with" << area;
1706 const QDockAreaLayout dl = layoutState.dockAreaLayout;
1709 return (size == Maximum) ? dl.gapRect(dockPosition) : dl.docks[dockPosition].rect;
1713
1714
1715
1716void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1717 QDockWidget *dockwidget,
1718 Qt::Orientation orientation)
1720 addChildWidget(dockwidget);
1724 if (!movingSeparator.isEmpty())
1725 endSeparatorMove(movingSeparatorPos);
1727 layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
1731bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1733 addChildWidget(dockwidget);
1734 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1736 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1741#if QT_CONFIG(tabbar)
1742void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1744 applyRestoredState();
1745 addChildWidget(second);
1746 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1747 emit second->dockLocationChanged(dockWidgetArea(first));
1751bool QMainWindowLayout::documentMode()
const
1753 return _documentMode;
1756void QMainWindowLayout::setDocumentMode(
bool enabled)
1758 if (_documentMode == enabled)
1761 _documentMode = enabled;
1764 for (QTabBar *bar : std::as_const(usedTabBars))
1765 bar->setDocumentMode(_documentMode);
1766 for (QTabBar *bar : std::as_const(unusedTabBars))
1767 bar->setDocumentMode(_documentMode);
1770void QMainWindowLayout::setVerticalTabsEnabled(
bool enabled)
1772 if (verticalTabsEnabled == enabled)
1775 verticalTabsEnabled = enabled;
1777 updateTabBarShapes();
1780#if QT_CONFIG(tabwidget)
1781QTabWidget::TabShape QMainWindowLayout::tabShape()
const
1786void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1788 if (_tabShape == tabShape)
1791 _tabShape = tabShape;
1793 updateTabBarShapes();
1796QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area)
const
1798 const QInternal::DockPosition dockPos = toDockPos(area);
1799 if (dockPos < QInternal::DockCount)
1800 return tabPositions[dockPos];
1801 qWarning(
"QMainWindowLayout::tabPosition called with out-of-bounds value '%d'",
int(area));
1802 return QTabWidget::North;
1805void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1807 const Qt::DockWidgetArea dockWidgetAreas[] = {
1808 Qt::TopDockWidgetArea,
1809 Qt::LeftDockWidgetArea,
1810 Qt::BottomDockWidgetArea,
1811 Qt::RightDockWidgetArea
1813 const QInternal::DockPosition dockPositions[] = {
1815 QInternal::LeftDock,
1816 QInternal::BottomDock,
1817 QInternal::RightDock
1820 for (
int i = 0; i < QInternal::DockCount; ++i)
1821 if (areas & dockWidgetAreas[i])
1822 tabPositions[dockPositions[i]] = tabPosition;
1824 updateTabBarShapes();
1827QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
1830void QMainWindowLayout::updateTabBarShapes()
1832#if QT_CONFIG(tabwidget)
1833 const QTabWidget::TabPosition vertical[] = {
1840 const QTabBar::Shape vertical[] = {
1841 QTabBar::RoundedWest,
1842 QTabBar::RoundedEast,
1843 QTabBar::RoundedNorth,
1844 QTabBar::RoundedSouth
1848 QDockAreaLayout &layout = layoutState.dockAreaLayout;
1850 for (
int i = 0; i < QInternal::DockCount; ++i) {
1851#if QT_CONFIG(tabwidget)
1852 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
1853 QTabBar::Shape shape = _q_tb_tabBarShapeFrom(_tabShape, pos);
1855 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
1857 layout.docks[i].setTabBarShape(shape);
1862void QMainWindowLayout::splitDockWidget(QDockWidget *after,
1863 QDockWidget *dockwidget,
1864 Qt::Orientation orientation)
1866 applyRestoredState();
1867 addChildWidget(dockwidget);
1868 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
1869 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
1873Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(
const QWidget *widget)
const
1875 const QList<
int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
1876 if (pathToWidget.isEmpty())
1877 return Qt::NoDockWidgetArea;
1878 return toDockWidgetArea(pathToWidget.first());
1881void QMainWindowLayout::keepSize(QDockWidget *w)
1883 layoutState.dockAreaLayout.keepSize(w);
1886#if QT_CONFIG(tabbar)
1889class QMainWindowTabBar :
public QTabBar
1892 QMainWindow *mainWindow;
1893 QPointer<QDockWidget> draggingDock;
1895 QMainWindowTabBar(QMainWindow *parent);
1896 ~QMainWindowTabBar();
1897 QDockWidget *dockAt(
int index)
const;
1898 QList<QDockWidget *> dockWidgets()
const;
1899 bool contains(
const QDockWidget *dockWidget)
const;
1901 bool event(QEvent *e) override;
1902 void mouseReleaseEvent(QMouseEvent*) override;
1903 void mouseMoveEvent(QMouseEvent*) override;
1907QMainWindowTabBar *QMainWindowLayout::findTabBar(
const QDockWidget *dockWidget)
const
1909 for (
auto *bar : usedTabBars) {
1910 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
1911 auto *tabBar =
static_cast<QMainWindowTabBar *>(bar);
1912 if (tabBar->contains(dockWidget))
1918QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
1919 : QTabBar(parent), mainWindow(parent)
1921 setExpanding(
false);
1924QList<QDockWidget *> QMainWindowTabBar::dockWidgets()
const
1926 QList<QDockWidget *> docks;
1927 for (
int i = 0; i < count(); ++i) {
1928 if (QDockWidget *dock = dockAt(i))
1934bool QMainWindowTabBar::contains(
const QDockWidget *dockWidget)
const
1936 for (
int i = 0; i < count(); ++i) {
1937 if (dockAt(i) == dockWidget)
1948QDockWidget *QMainWindowTabBar::dockAt(
int index)
const
1950 QMainWindowTabBar *that =
const_cast<QMainWindowTabBar *>(
this);
1951 QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
1952 QDockAreaLayoutInfo *info = mlayout->dockInfo(that);
1956 const int itemIndex = info->tabIndexToListIndex(index);
1957 if (itemIndex >= 0) {
1958 Q_ASSERT(itemIndex < info->item_list.count());
1959 const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
1960 return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) :
nullptr;
1967
1968
1969
1970
1971
1972
1973
1974
1975static void moveToUnplugPosition(QPoint mouse, QDockWidget *dockWidget)
1977 Q_ASSERT(dockWidget);
1979 if (
auto *tbWidget = dockWidget->titleBarWidget()) {
1980 dockWidget->move(mouse - tbWidget->rect().center());
1984 const bool vertical = dockWidget->features().testFlag(QDockWidget::DockWidgetVerticalTitleBar);
1985 const int deltaX = vertical ? QApplication::startDragDistance() : dockWidget->width() / 2;
1986 const int deltaY = vertical ? dockWidget->height() / 2 : QApplication::startDragDistance();
1987 dockWidget->move(mouse - QPoint(deltaX, deltaY));
1990void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
1997 QTabBarPrivate *d =
static_cast<QTabBarPrivate*>(d_ptr.data());
1998 if (!draggingDock && (mainWindow->dockOptions() & QMainWindow::GroupedDragging)) {
1999 int offset = QApplication::startDragDistance() + 1;
2001 QRect r = rect().adjusted(-offset, -offset, offset, offset);
2002 if (d->dragInProgress && !r.contains(e->position().toPoint()) && d->validIndex(d->pressedIndex)) {
2003 draggingDock = dockAt(d->pressedIndex);
2007 d->moveTabFinished(d->pressedIndex);
2008 d->pressedIndex = -1;
2010 d->movingTab->setVisible(
false);
2011 d->dragStartPosition = QPoint();
2014 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2015 QDockWidgetLayout *dwlayout =
static_cast<QDockWidgetLayout *>(draggingDock->layout());
2016 dockPriv->initDrag(dwlayout->titleArea().center(),
true);
2017 dockPriv->startDrag(QDockWidgetPrivate::DragScope::Widget);
2018 if (dockPriv->state)
2019 dockPriv->state->ctrlDrag = e->modifiers() & Qt::ControlModifier;
2025 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2026 if (dockPriv->state && dockPriv->state->dragging) {
2028 moveToUnplugPosition(e->globalPosition().toPoint(), draggingDock);
2031 QTabBar::mouseMoveEvent(e);
2034QMainWindowTabBar::~QMainWindowTabBar()
2036 if (!mainWindow || mainWindow == parentWidget())
2042 auto *mwLayout = qt_mainwindow_layout(mainWindow);
2045 mwLayout->unusedTabBars.removeOne(
this);
2046 mwLayout->usedTabBars.remove(
this);
2049void QMainWindowTabBar::mouseReleaseEvent(QMouseEvent *e)
2051 if (draggingDock && e->button() == Qt::LeftButton) {
2052 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2053 if (dockPriv->state && dockPriv->state->dragging)
2054 dockPriv->endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
2056 draggingDock =
nullptr;
2058 QTabBar::mouseReleaseEvent(e);
2061bool QMainWindowTabBar::event(QEvent *e)
2065 if (e->type() != QEvent::ToolTip)
2066 return QTabBar::event(e);
2067 QSize size =
this->size();
2068 QSize hint = sizeHint();
2069 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
2070 size = size.transposed();
2071 hint = hint.transposed();
2073 if (size.width() < hint.width())
2074 return QTabBar::event(e);
2079QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(
const QDockWidget *dockWidget)
const
2081 const auto *bar = findTabBar(dockWidget);
2085 QList<QDockWidget *> buddies = bar->dockWidgets();
2088 buddies.removeOne(dockWidget);
2092bool QMainWindowLayout::isDockWidgetTabbed(
const QDockWidget *dockWidget)
const
2097 const auto *bar = findTabBar(dockWidget);
2098 return bar && bar->count() > 1;
2101QTabBar *QMainWindowLayout::getTabBar()
2103 if (!usedTabBars.isEmpty() && !isInRestoreState) {
2105
2106
2107
2108
2112 QTabBar *result =
nullptr;
2113 if (!unusedTabBars.isEmpty()) {
2114 result = unusedTabBars.takeLast();
2116 result =
new QMainWindowTabBar(
static_cast<QMainWindow *>(parentWidget()));
2117 result->setDrawBase(
true);
2118 result->setElideMode(Qt::ElideRight);
2119 result->setDocumentMode(_documentMode);
2120 result->setMovable(
true);
2121 connect(result, SIGNAL(currentChanged(
int)),
this, SLOT(tabChanged()));
2122 connect(result, &QTabBar::tabMoved,
this, &QMainWindowLayout::tabMoved);
2125 usedTabBars.insert(result);
2130QWidget *QMainWindowLayout::getSeparatorWidget()
2132 QWidget *result =
nullptr;
2133 if (!unusedSeparatorWidgets.isEmpty()) {
2134 result = unusedSeparatorWidgets.takeLast();
2136 result =
new QWidget(parentWidget());
2137 result->setAttribute(Qt::WA_MouseNoMask,
true);
2138 result->setAutoFillBackground(
false);
2139 result->setObjectName(
"qt_qmainwindow_extended_splitter"_L1);
2141 usedSeparatorWidgets.insert(result);
2146
2147
2148
2149QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget)
2151 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
2155 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2156 for (QDockWidgetGroupWindow *dwgw : groups) {
2157 info = dwgw->layoutInfo()->info(widget);
2164void QMainWindowLayout::tabChanged()
2166 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2169 QDockAreaLayoutInfo *info = dockInfo(tb);
2170 if (info ==
nullptr)
2173 QDockWidget *activated = info->apply(
false);
2176 emit
static_cast<QMainWindow *>(parentWidget())->tabifiedDockWidgetActivated(activated);
2178 if (
auto dwgw = qobject_cast<QDockWidgetGroupWindow*>(tb->parentWidget()))
2179 dwgw->adjustFlags();
2181 if (QWidget *w = centralWidget())
2185void QMainWindowLayout::tabMoved(
int from,
int to)
2187 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2189 QDockAreaLayoutInfo *info = dockInfo(tb);
2192 info->moveTab(from, to);
2195void QMainWindowLayout::raise(QDockWidget *widget)
2197 QDockAreaLayoutInfo *info = dockInfo(widget);
2198 if (info ==
nullptr)
2202 info->setCurrentTab(widget);
2210
2211
2213int QMainWindowLayout::count()
const
2216 while (itemAt(result))
2221QLayoutItem *QMainWindowLayout::itemAt(
int index)
const
2225 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
2228 if (statusbar && x++ == index)
2234QLayoutItem *QMainWindowLayout::takeAt(
int index)
2238 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
2240 if (QWidget *w = ret->widget()) {
2241 widgetAnimator.abort(w);
2242 if (w == pluggingWidget)
2243 pluggingWidget =
nullptr;
2246 if (savedState.isValid() ) {
2248 savedState.remove(ret);
2250 layoutState.remove(ret);
2253#if QT_CONFIG(toolbar)
2254 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
2255 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
2256 if (!currentGapPos.isEmpty()) {
2257 currentGapPos.prepend(0);
2258 currentGapRect = layoutState.itemRect(currentGapPos);
2266 if (statusbar && x++ == index) {
2267 QLayoutItem *ret = statusbar;
2268 statusbar =
nullptr;
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292void QMainWindowLayout::applyRestoredState()
2294 if (restoredState) {
2295 layoutState = *restoredState;
2296 restoredState.reset();
2297 discardRestoredStateTimer.stop();
2301void QMainWindowLayout::setGeometry(
const QRect &_r)
2305 if (savedState.isValid() || (restoredState && isInApplyState))
2310 QLayout::setGeometry(r);
2313 QRect sbr(QPoint(r.left(), 0),
2314 QSize(r.width(), statusbar->heightForWidth(r.width()))
2315 .expandedTo(statusbar->minimumSize()));
2316 sbr.moveBottom(r.bottom());
2317 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
2318 statusbar->setGeometry(vr);
2319 r.setBottom(sbr.top() - 1);
2322 if (restoredState) {
2324
2325
2326
2327
2328
2329
2330 layoutState = *restoredState;
2331 if (restoredState->fits()) {
2332 restoredState.reset();
2333 discardRestoredStateTimer.stop();
2336
2337
2338
2339
2340
2341
2342
2343
2344 discardRestoredStateTimer.start(150,
this);
2348 layoutState.rect = r;
2350 layoutState.fitLayout();
2351 applyState(layoutState,
false);
2354void QMainWindowLayout::timerEvent(QTimerEvent *e)
2356 if (e->timerId() == discardRestoredStateTimer.timerId()) {
2357 discardRestoredStateTimer.stop();
2358 restoredState.reset();
2360 QLayout::timerEvent(e);
2363void QMainWindowLayout::addItem(QLayoutItem *)
2364{ qWarning(
"QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
2366QSize QMainWindowLayout::sizeHint()
const
2368 if (!szHint.isValid()) {
2369 szHint = layoutState.sizeHint();
2370 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
2371 szHint = QSize(qMax(sbHint.width(), szHint.width()),
2372 sbHint.height() + szHint.height());
2377QSize QMainWindowLayout::minimumSize()
const
2379 if (!minSize.isValid()) {
2380 minSize = layoutState.minimumSize();
2381 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
2382 minSize = QSize(qMax(sbMin.width(), minSize.width()),
2383 sbMin.height() + minSize.height());
2388void QMainWindowLayout::invalidate()
2390 QLayout::invalidate();
2391 minSize = szHint = QSize();
2394#if QT_CONFIG(dockwidget)
2395void QMainWindowLayout::setCurrentHoveredFloat(QDockWidgetGroupWindow *w)
2397 if (currentHoveredFloat != w) {
2398 if (currentHoveredFloat) {
2399 disconnect(currentHoveredFloat.data(), &QObject::destroyed,
2400 this, &QMainWindowLayout::updateGapIndicator);
2401 disconnect(currentHoveredFloat.data(), &QDockWidgetGroupWindow::resized,
2402 this, &QMainWindowLayout::updateGapIndicator);
2403 if (currentHoveredFloat)
2404 currentHoveredFloat->restore();
2409 currentHoveredFloat = w;
2412 connect(w, &QObject::destroyed,
2413 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2414 connect(w, &QDockWidgetGroupWindow::resized,
2415 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2418 updateGapIndicator();
2424
2425
2429#if QT_CONFIG(toolbar)
2430 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
2431 if (toolBar ==
nullptr)
2434 QRect oldGeo = toolBar->geometry();
2436 QInternal::DockPosition pos
2437 =
static_cast<QInternal::DockPosition>(dockPos);
2438 Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
2439 ? Qt::Horizontal : Qt::Vertical;
2440 if (o != toolBar->orientation())
2441 toolBar->setOrientation(o);
2443 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
2444 .expandedTo(toolBar->minimumSize());
2446 if (toolBar->size() != hint) {
2447 QRect newGeo(oldGeo.topLeft(), hint);
2448 if (toolBar->layoutDirection() == Qt::RightToLeft)
2449 newGeo.moveRight(oldGeo.right());
2450 toolBar->setGeometry(newGeo);
2459void QMainWindowLayout::revert(QLayoutItem *widgetItem)
2461 if (!savedState.isValid())
2464 QWidget *widget = widgetItem->widget();
2465 layoutState = savedState;
2466 currentGapPos = layoutState.indexOf(widget);
2467 if (currentGapPos.isEmpty())
2469 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2470 layoutState.unplug(currentGapPos);
2471 layoutState.fitLayout();
2472 currentGapRect = layoutState.itemRect(currentGapPos);
2477bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
2479#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) && QT_CONFIG(tabbar)
2480 if (currentHoveredFloat) {
2481 QWidget *widget = widgetItem->widget();
2482 QList<
int> previousPath = layoutState.indexOf(widget);
2483 if (!previousPath.isEmpty())
2484 layoutState.remove(previousPath);
2485 previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2488 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2489 for (QDockWidgetGroupWindow *dwgw : groups) {
2490 if (dwgw == currentHoveredFloat)
2492 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2493 if (!path.isEmpty())
2494 dwgw->layoutInfo()->remove(path);
2496 currentGapRect = QRect();
2497 currentHoveredFloat->apply();
2498 if (!previousPath.isEmpty())
2499 currentHoveredFloat->layoutInfo()->remove(previousPath);
2500 QRect globalRect = currentHoveredFloat->currentGapRect;
2501 globalRect.moveTopLeft(currentHoveredFloat->mapToGlobal(globalRect.topLeft()));
2502 pluggingWidget = widget;
2503 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2508 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
2511 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2513 QWidget *widget = widgetItem->widget();
2515#if QT_CONFIG(dockwidget)
2518 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2519 for (QDockWidgetGroupWindow *dwgw : groups) {
2520 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2521 if (!path.isEmpty())
2522 dwgw->layoutInfo()->remove(path);
2526 QList<
int> previousPath = layoutState.indexOf(widget);
2528 const QLayoutItem *it = layoutState.plug(currentGapPos);
2531 Q_ASSERT(it == widgetItem);
2532 if (!previousPath.isEmpty())
2533 layoutState.remove(previousPath);
2535 pluggingWidget = widget;
2536 QRect globalRect = currentGapRect;
2537 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
2538#if QT_CONFIG(dockwidget)
2539 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2540 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
2541 if (layout->nativeWindowDeco()) {
2542 globalRect.adjust(0, layout->titleHeight(), 0, 0);
2544 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, widget);
2545 globalRect.adjust(-fw, -fw, fw, fw);
2549 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2554void QMainWindowLayout::animationFinished(QWidget *widget)
2558#if QT_CONFIG(toolbar)
2559 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2560 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
2561 if (tbl->animating) {
2562 tbl->animating =
false;
2564 tbl->layoutActions(tb->size());
2570 if (widget == pluggingWidget) {
2572#if QT_CONFIG(dockwidget)
2573#if QT_CONFIG(tabbar)
2574 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
2578 QDockAreaLayoutInfo *srcInfo = dwgw->layoutInfo();
2579 const QDockAreaLayoutInfo *srcTabInfo = dwgw->tabLayoutInfo();
2580 QDockAreaLayoutInfo *dstParentInfo;
2583 if (currentHoveredFloat) {
2584 dstPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2585 Q_ASSERT(dstPath.size() >= 1);
2586 dstParentInfo = currentHoveredFloat->layoutInfo()->info(dstPath);
2588 dstPath = layoutState.dockAreaLayout.indexOf(widget);
2589 Q_ASSERT(dstPath.size() >= 2);
2590 dstParentInfo = layoutState.dockAreaLayout.info(dstPath);
2592 Q_ASSERT(dstParentInfo);
2593 int idx = dstPath.constLast();
2594 Q_ASSERT(dstParentInfo->item_list[idx].widgetItem->widget() == dwgw);
2595 if (dstParentInfo->tabbed && srcTabInfo) {
2597 delete dstParentInfo->item_list[idx].widgetItem;
2598 dstParentInfo->item_list.removeAt(idx);
2599 std::copy(srcTabInfo->item_list.cbegin(), srcTabInfo->item_list.cend(),
2600 std::inserter(dstParentInfo->item_list,
2601 dstParentInfo->item_list.begin() + idx));
2602 quintptr currentId = srcTabInfo->currentTabId();
2603 *srcInfo = QDockAreaLayoutInfo();
2604 dstParentInfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2606 dstParentInfo->updateTabBar();
2607 dstParentInfo->setCurrentTabId(currentId);
2609 QDockAreaLayoutItem &item = dstParentInfo->item_list[idx];
2610 Q_ASSERT(item.widgetItem->widget() == dwgw);
2611 delete item.widgetItem;
2612 item.widgetItem =
nullptr;
2613 item.subinfo =
new QDockAreaLayoutInfo(std::move(*srcInfo));
2614 *srcInfo = QDockAreaLayoutInfo();
2615 item.subinfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2617 item.subinfo->setTabBarShape(dstParentInfo->tabBarShape);
2619 dwgw->destroyOrHideIfEmpty();
2623 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2624 dw->setParent(currentHoveredFloat ? currentHoveredFloat.data() : parentWidget());
2626 dw->d_func()->plug(currentGapRect);
2629#if QT_CONFIG(toolbar)
2630 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
2631 tb->d_func()->plug(currentGapRect);
2635 currentGapPos.clear();
2636 pluggingWidget =
nullptr;
2637#if QT_CONFIG(dockwidget)
2638 setCurrentHoveredFloat(
nullptr);
2642 layoutState.apply(
false);
2644#if QT_CONFIG(dockwidget)
2645#if QT_CONFIG(tabbar)
2646 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2649 if (QDockAreaLayoutInfo *info = dockInfo(widget))
2650 info->setCurrentTab(widget);
2656 if (!widgetAnimator.animating()) {
2658#if QT_CONFIG(dockwidget)
2659 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
2660#if QT_CONFIG(tabbar)
2661 const auto usedTabBarsCopy = usedTabBars;
2662 for (QTabBar *tab_bar : usedTabBarsCopy)
2668 updateGapIndicator();
2671void QMainWindowLayout::restore(
bool keepSavedState)
2673 if (!savedState.isValid())
2676 layoutState = savedState;
2677 applyState(layoutState);
2678 if (!keepSavedState)
2680 currentGapPos.clear();
2681 pluggingWidget =
nullptr;
2682 updateGapIndicator();
2685QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout)
2686 : QLayout(parentLayout ?
static_cast<QWidget *>(
nullptr) : mainwindow)
2687 , layoutState(mainwindow)
2688 , savedState(mainwindow)
2689 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
2690 , statusbar(
nullptr)
2691#if QT_CONFIG(dockwidget)
2692#if QT_CONFIG(tabbar)
2693 , _documentMode(
false)
2694 , verticalTabsEnabled(
false)
2695#if QT_CONFIG(tabwidget)
2696 , _tabShape(QTabWidget::Rounded)
2700 , widgetAnimator(
this)
2701 , pluggingWidget(
nullptr)
2704 setParent(parentLayout);
2706#if QT_CONFIG(dockwidget)
2707#if QT_CONFIG(tabbar)
2708 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent,
nullptr, mainwindow);
2711#if QT_CONFIG(tabwidget)
2712 for (
int i = 0; i < QInternal::DockCount; ++i)
2713 tabPositions[i] = QTabWidget::South;
2716 pluggingWidget =
nullptr;
2718 setObjectName(mainwindow->objectName() +
"_layout"_L1);
2721QMainWindowLayout::~QMainWindowLayout()
2723 layoutState.deleteAllLayoutItems();
2724 layoutState.deleteCentralWidgetItem();
2729void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
2731 if (opts == dockOptions)
2736#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
2737 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
2743#if QT_CONFIG(statusbar)
2744QStatusBar *QMainWindowLayout::statusBar()
const
2745{
return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
2747void QMainWindowLayout::setStatusBar(QStatusBar *sb)
2752 statusbar = sb ?
new QWidgetItemV2(sb) :
nullptr;
2757QWidget *QMainWindowLayout::centralWidget()
const
2759 return layoutState.centralWidget();
2762void QMainWindowLayout::setCentralWidget(QWidget *widget)
2764 if (widget !=
nullptr)
2765 addChildWidget(widget);
2766 layoutState.setCentralWidget(widget);
2767 if (savedState.isValid()) {
2768#if QT_CONFIG(dockwidget)
2769 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
2770 savedState.dockAreaLayout.fallbackToSizeHints =
true;
2772 savedState.centralWidgetItem = layoutState.centralWidgetItem;
2778#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2780
2781
2782
2783
2784
2785
2786static bool unplugGroup(QMainWindowLayout *layout, QLayoutItem **item,
2787 QDockAreaLayoutItem &parentItem)
2789 if (!parentItem.subinfo || !parentItem.subinfo->tabbed)
2793 QDockWidgetGroupWindow *floatingTabs = layout->createTabbedDockWindow();
2794 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
2795 *info = std::move(*parentItem.subinfo);
2796 delete parentItem.subinfo;
2797 parentItem.subinfo =
nullptr;
2798 floatingTabs->setGeometry(info->rect.translated(layout->parentWidget()->pos()));
2799 floatingTabs->show();
2800 floatingTabs->raise();
2801 *item =
new QDockWidgetGroupWindowItem(floatingTabs);
2802 parentItem.widgetItem = *item;
2807#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2808static QTabBar::Shape tabwidgetPositionToTabBarShape(QWidget *w)
2810 QTabBar::Shape result = QTabBar::RoundedSouth;
2811 if (qobject_cast<QDockWidget *>(w)) {
2812 switch (
static_cast<QDockWidgetPrivate *>(qt_widget_private(w))->tabPosition) {
2813 case QTabWidget::North:
2814 result = QTabBar::RoundedNorth;
2816 case QTabWidget::South:
2817 result = QTabBar::RoundedSouth;
2819 case QTabWidget::West:
2820 result = QTabBar::RoundedWest;
2822 case QTabWidget::East:
2823 result = QTabBar::RoundedEast;
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope)
2843#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2844 auto *groupWindow = qobject_cast<
const QDockWidgetGroupWindow *>(widget->parentWidget());
2845 if (!widget->isWindow() && groupWindow) {
2846 if (scope == QDockWidgetPrivate::DragScope::Group && groupWindow->tabLayoutInfo()) {
2849 if (QDockAreaLayoutInfo *info = dockInfo(widget->parentWidget())) {
2850 QList<
int> groupWindowPath = info->indexOf(widget->parentWidget());
2851 return groupWindowPath.isEmpty() ?
nullptr : info->item(groupWindowPath).widgetItem;
2853 qCDebug(lcQpaDockWidgets) <<
"Drag only:" << widget <<
"Group:" << (scope == QDockWidgetPrivate::DragScope::Group);
2856 QList<
int> path = groupWindow->layoutInfo()->indexOf(widget);
2857 QDockAreaLayoutItem parentItem = groupWindow->layoutInfo()->item(path);
2858 QLayoutItem *item = parentItem.widgetItem;
2859 if (scope == QDockWidgetPrivate::DragScope::Group && path.size() > 1
2860 && unplugGroup(
this, &item, parentItem)) {
2861 qCDebug(lcQpaDockWidgets) <<
"Unplugging:" << widget <<
"from" << item;
2865 QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget);
2866 Q_ASSERT(dockWidget);
2867 dockWidget->d_func()->unplug(widget->geometry());
2869 qCDebug(lcQpaDockWidgets) <<
"Unplugged from floating dock:" << widget <<
"from" << parentItem.widgetItem;
2874 QList<
int> path = layoutState.indexOf(widget);
2878 QLayoutItem *item = layoutState.item(path);
2879 if (widget->isWindow())
2882 QRect r = layoutState.itemRect(path);
2883 savedState = layoutState;
2885#if QT_CONFIG(dockwidget)
2886 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2887 Q_ASSERT(path.constFirst() == 1);
2888#if QT_CONFIG(tabwidget)
2889 if (scope == QDockWidgetPrivate::DragScope::Group && (dockOptions & QMainWindow::GroupedDragging) && path.size() > 3
2890 && unplugGroup(
this, &item,
2891 layoutState.dockAreaLayout.item(path.mid(1, path.size() - 2)))) {
2893 savedState = layoutState;
2899 switch (dockWidgetArea(dw)) {
2900 case Qt::LeftDockWidgetArea:
2901 case Qt::RightDockWidgetArea:
2902 r.setHeight(r.height() - sep);
2904 case Qt::TopDockWidgetArea:
2905 case Qt::BottomDockWidgetArea:
2906 r.setWidth(r.width() - sep);
2908 case Qt::NoDockWidgetArea:
2909 case Qt::DockWidgetArea_Mask:
2917 const auto *layout = qobject_cast<QDockWidgetLayout *>(dw->layout());
2918 const bool verticalTitleBar = layout ? layout->verticalTitleBar :
false;
2919 const int tbHeight = QApplication::style()
2920 ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight,
nullptr, dw)
2922 const int minHeight = verticalTitleBar ? 2 * tbHeight : tbHeight;
2923 const int minWidth = verticalTitleBar ? tbHeight : 2 * tbHeight;
2924 r.setSize(r.size().expandedTo(QSize(minWidth, minHeight)));
2925 qCDebug(lcQpaDockWidgets) << dw <<
"will be unplugged with size" << r.size();
2927 dw->d_func()->unplug(r);
2931#if QT_CONFIG(toolbar)
2932 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2933 tb->d_func()->unplug(r);
2937#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
2941 layoutState.unplug(path ,&savedState);
2942 savedState.fitLayout();
2943 currentGapPos = path;
2945 updateGapIndicator();
2947 fixToolBarOrientation(item, currentGapPos.at(1));
2952void QMainWindowLayout::updateGapIndicator()
2954#if QT_CONFIG(rubberband)
2955 if (!widgetAnimator.animating() && (!currentGapPos.isEmpty()
2956#if QT_CONFIG(dockwidget)
2957 || currentHoveredFloat
2960 QWidget *expectedParent =
2961#if QT_CONFIG(dockwidget)
2962 currentHoveredFloat ? currentHoveredFloat.data() :
2965 if (!gapIndicator) {
2966 gapIndicator =
new QRubberBand(QRubberBand::Rectangle, expectedParent);
2968 gapIndicator->setObjectName(
"qt_rubberband"_L1);
2969 }
else if (gapIndicator->parent() != expectedParent) {
2970 gapIndicator->setParent(expectedParent);
2974 const bool sigBlockState = gapIndicator->signalsBlocked();
2975 auto resetSignals = qScopeGuard([
this, sigBlockState](){ gapIndicator->blockSignals(sigBlockState); });
2976 gapIndicator->blockSignals(
true);
2978#if QT_CONFIG(dockwidget)
2979 if (currentHoveredFloat)
2980 gapIndicator->setGeometry(currentHoveredFloat->currentGapRect);
2983 gapIndicator->setGeometry(currentGapRect);
2985 gapIndicator->show();
2986 gapIndicator->raise();
2990 }
else if (gapIndicator) {
2991 gapIndicator->hide();
2997void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
2998 const QPoint &mousePos) {
2999 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() ||
3000 pluggingWidget !=
nullptr || hoverTarget ==
nullptr)
3003 QWidget *widget = hoverTarget->widget();
3005#if QT_CONFIG(dockwidget)
3007 if ((dockOptions & QMainWindow::GroupedDragging) && (qobject_cast<QDockWidget*>(widget)
3008 || qobject_cast<QDockWidgetGroupWindow *>(widget))) {
3011 QVarLengthArray<QWidget *, 10> candidates;
3012 const auto siblings = parentWidget()->children();
3013 for (QObject *c : siblings) {
3014 QWidget *w = qobject_cast<QWidget*>(c);
3019 if (!qobject_cast<QDockWidget*>(w) && !qobject_cast<QDockWidgetGroupWindow *>(w))
3025 if (w != widget && w->isWindow() && w->isVisible() && !w->isMinimized())
3028 if (QDockWidgetGroupWindow *group = qobject_cast<QDockWidgetGroupWindow *>(w)) {
3031 const auto groupChildren = group->children();
3032 for (QObject *c : groupChildren) {
3033 if (QDockWidget *dw = qobject_cast<QDockWidget*>(c)) {
3034 if (dw != widget && dw->isFloating() && dw->isVisible() && !dw->isMinimized())
3041 for (QWidget *w : candidates) {
3042 const QScreen *screen1 = qt_widget_private(widget)->associatedScreen();
3043 const QScreen *screen2 = qt_widget_private(w)->associatedScreen();
3044 if (screen1 && screen2 && screen1 != screen2)
3046 if (!w->geometry().contains(mousePos))
3049#if QT_CONFIG(tabwidget)
3050 if (
auto dropTo = qobject_cast<QDockWidget *>(w)) {
3053 w = dropTo->widget();
3056 if (!qobject_cast<QDockWidgetGroupWindow *>(w)) {
3057 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
3058 floatingTabs->setGeometry(dropTo->geometry());
3059 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
3060 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dropTo);
3067 QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(dropTo));
3068 if (dockPosition == QInternal::DockPosition::DockCount)
3069 dockPosition = toDockPos(dockWidgetArea(widget));
3070 if (dockPosition == QInternal::DockPosition::DockCount)
3071 dockPosition = QInternal::DockPosition::RightDock;
3073 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPosition,
3074 Qt::Horizontal, shape,
3075 static_cast<QMainWindow *>(parentWidget()));
3076 info->tabBar = getTabBar();
3077 info->tabbed =
true;
3079 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[dockPosition];
3080 parentInfo.add(floatingTabs);
3081 dropTo->setParent(floatingTabs);
3082 qCDebug(lcQpaDockWidgets) <<
"Wrapping" << widget <<
"into floating tabs" << floatingTabs;
3088 qCDebug(lcQpaDockWidgets) <<
"Showing" << dropTo;
3090 qCDebug(lcQpaDockWidgets) <<
"Raising" << widget;
3093 auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(w);
3094 Q_ASSERT(groupWindow);
3095 if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) {
3096 setCurrentHoveredFloat(groupWindow);
3097 applyState(layoutState);
3105 if (currentHoveredFloat)
3106 currentHoveredFloat->destroyIfSingleItemLeft();
3108 setCurrentHoveredFloat(
nullptr);
3109 layoutState.dockAreaLayout.fallbackToSizeHints =
false;
3112 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
3114 if (!savedState.isValid())
3115 savedState = layoutState;
3117 QList<
int> path = savedState.gapIndex(widget, pos);
3119 if (!path.isEmpty()) {
3120 bool allowed =
false;
3122#if QT_CONFIG(dockwidget)
3123 allowed = isAreaAllowed(widget, path);
3125#if QT_CONFIG(toolbar)
3126 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
3127 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
3134 if (path == currentGapPos)
3137 currentGapPos = path;
3138 if (path.isEmpty()) {
3139 fixToolBarOrientation(hoverTarget, 2);
3144 fixToolBarOrientation(hoverTarget, currentGapPos.at(1));
3146 QMainWindowLayoutState newState = savedState;
3148 if (!newState.insertGap(path, hoverTarget)) {
3153 QSize min = newState.minimumSize();
3154 QSize size = newState.rect.size();
3156 if (min.width() > size.width() || min.height() > size.height()) {
3161 newState.fitLayout();
3163 currentGapRect = newState.gapRect(currentGapPos);
3165#if QT_CONFIG(dockwidget)
3166 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
3168 layoutState = std::move(newState);
3169 applyState(layoutState);
3171 updateGapIndicator();
3174#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3175QDockWidgetGroupWindow *QMainWindowLayout::createTabbedDockWindow()
3177 QDockWidgetGroupWindow* f =
new QDockWidgetGroupWindow(parentWidget(), Qt::Tool);
3178 new QDockWidgetGroupLayout(f);
3183void QMainWindowLayout::applyState(QMainWindowLayoutState &newState,
bool animate)
3190 isInApplyState =
true;
3191#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3192 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
3194 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
3195 for (QDockWidgetGroupWindow *dwgw : groups)
3196 used += dwgw->layoutInfo()->usedTabBars();
3198 const QSet<QTabBar*> retired = usedTabBars - used;
3200 for (QTabBar *tab_bar : retired) {
3202 while (tab_bar->count() > 0)
3203 tab_bar->removeTab(0);
3204 unusedTabBars.append(tab_bar);
3208 const QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
3209 const QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
3210 usedSeparatorWidgets = usedSeps;
3211 for (QWidget *sepWidget : retiredSeps) {
3212 unusedSeparatorWidgets.append(sepWidget);
3217 for (
int i = 0; i < QInternal::DockCount; ++i)
3218 newState.dockAreaLayout.docks[i].reparentWidgets(parentWidget());
3221 newState.apply(dockOptions & QMainWindow::AnimatedDocks && animate);
3222 isInApplyState =
false;
3225void QMainWindowLayout::saveState(QDataStream &stream)
const
3227 layoutState.saveState(stream);
3230bool QMainWindowLayout::restoreState(QDataStream &stream)
3232 QScopedValueRollback<
bool> guard(isInRestoreState,
true);
3233 savedState = layoutState;
3234 layoutState.clear();
3235 layoutState.rect = savedState.rect;
3237 if (!layoutState.restoreState(stream, savedState)) {
3238 layoutState.deleteAllLayoutItems();
3239 layoutState = savedState;
3240 if (parentWidget()->isVisible())
3241 applyState(layoutState,
false);
3245 if (parentWidget()->isVisible()) {
3246 layoutState.fitLayout();
3247 applyState(layoutState,
false);
3250
3251
3252
3253
3254
3255
3256 if ((parentWidget()->windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized))
3257 && !layoutState.fits()) {
3258 restoredState.reset(
new QMainWindowLayoutState(layoutState));
3262 savedState.deleteAllLayoutItems();
3265#if QT_CONFIG(dockwidget)
3266 if (parentWidget()->isVisible()) {
3267#if QT_CONFIG(tabbar)
3268 for (QTabBar *tab_bar : std::as_const(usedTabBars))
3278#if QT_CONFIG(draganddrop)
3279bool QMainWindowLayout::needsPlatformDrag()
3281 static const bool wayland =
3282 QGuiApplication::platformName().startsWith(
"wayland"_L1, Qt::CaseInsensitive);
3286Qt::DropAction QMainWindowLayout::performPlatformWidgetDrag(QLayoutItem *widgetItem,
3287 const QPoint &pressPosition)
3289 draggingWidget = widgetItem;
3290 QWidget *widget = widgetItem->widget();
3291 auto drag = QDrag(widget);
3292 auto mimeData =
new QMimeData();
3293 auto window = widgetItem->widget()->windowHandle();
3295 auto serialize = [](
const auto &object) {
3297 QDataStream dataStream(&data, QIODevice::WriteOnly);
3298 dataStream << object;
3301 mimeData->setData(
"application/x-qt-mainwindowdrag-window"_L1,
3302 serialize(
reinterpret_cast<qintptr>(window)));
3303 mimeData->setData(
"application/x-qt-mainwindowdrag-position"_L1, serialize(pressPosition));
3304 drag.setMimeData(mimeData);
3306 auto result = drag.exec();
3308 draggingWidget =
nullptr;
3315#include "qmainwindowlayout.moc"
3316#include "moc_qmainwindowlayout_p.cpp"
Combined button and popup list for selecting options.
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *mainWindow)
static void fixToolBarOrientation(QLayoutItem *item, int dockPos)
static QList< T > findChildrenHelper(const QObject *o)
QList< QObject * > QObjectList