8#if QT_CONFIG(dockwidget)
9#include "qdockarealayout_p.h"
10#include "qdockwidget.h"
11#include "qdockwidget_p.h"
14#include "qtoolbar_p.h"
16#include "qtoolbarlayout_p.h"
20#if QT_CONFIG(rubberband)
21#include "qrubberband.h"
27#include <qapplication.h>
28#if QT_CONFIG(draganddrop)
32#if QT_CONFIG(statusbar)
33#include <qstatusbar.h>
37#include <qstylepainter.h>
38#include <qvarlengtharray.h>
43#ifndef QT_NO_DEBUG_STREAM
45# include <qtextstream.h>
48#include <private/qmenu_p.h>
49#include <private/qapplication_p.h>
50#include <private/qlayoutengine_p.h>
51#include <private/qwidgetresizehandler_p.h>
53#include <QScopedValueRollback>
57using namespace Qt::StringLiterals;
62
63
65#if QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG_STREAM)
67static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent);
69static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutItem &item, QString indent)
71 qout << indent <<
"QDockAreaLayoutItem: "
72 <<
"pos: " << item.pos <<
" size:" << item.size
73 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
74 <<
" keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) <<
'\n';
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
87 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
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';
97static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent)
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
108 <<
" tabbed:" << layout.tabbed
109 <<
" tbshape:" << layout.tabBarShape
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);
121static void dumpLayout(QTextStream &qout,
const QDockAreaLayout &layout)
123 qout <<
"QDockAreaLayout: "
124 << layout.rect.left() <<
','
125 << layout.rect.top() <<
' '
126 << layout.rect.width() <<
'x'
127 << layout.rect.height() <<
'\n';
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);
139QDebug operator<<(QDebug debug,
const QDockAreaLayout &layout)
143 dumpLayout(str, layout);
148QDebug operator<<(QDebug debug,
const QMainWindowLayout *layout)
151 return std::move(debug) << layout->layoutState.dockAreaLayout;
152 return debug <<
"QMainWindowLayout(0x0)";
158static void dumpItemLists(
const QMainWindowLayout *layout,
const char *function,
const char *comment)
160 for (
int i = 0; i < QInternal::DockCount; ++i) {
161 const auto &list = layout->layoutState.dockAreaLayout.docks[i].item_list;
164 qDebug() << function << comment <<
"Dock" << i << list;
167#define DUMP(comment) dumpItemLists(this, __FUNCTION__, comment)
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
202
203
206#if QT_CONFIG(dockwidget)
207class QDockWidgetGroupLayout :
public QLayout,
208 public QMainWindowLayoutSeparatorHelper<QDockWidgetGroupLayout>
210 QWidgetResizeHandler *resizer;
212 QDockWidgetGroupLayout(QDockWidgetGroupWindow* parent) : QLayout(parent) {
213 setSizeConstraint(QLayout::SetMinAndMaxSize);
214 resizer =
new QWidgetResizeHandler(parent);
216 ~QDockWidgetGroupLayout() {
217 layoutState.deleteAllLayoutItems();
220 void addItem(QLayoutItem*) override { Q_UNREACHABLE(); }
221 int count()
const override {
return 0; }
222 QLayoutItem* itemAt(
int index)
const override
225 return layoutState.itemAt(&x, index);
227 QLayoutItem* takeAt(
int index) override
230 QLayoutItem *ret = layoutState.takeAt(&x, index);
231 if (savedState.rect.isValid() && ret->widget()) {
233 QList<
int> path = savedState.indexOf(ret->widget());
235 savedState.remove(path);
237 path = layoutState.indexOf(ret->widget());
239 layoutState.remove(path);
243 QSize sizeHint()
const override
245 int fw = frameWidth();
246 return layoutState.sizeHint() + QSize(fw, fw);
248 QSize minimumSize()
const override
250 int fw = frameWidth();
251 return layoutState.minimumSize() + QSize(fw, fw);
253 QSize maximumSize()
const override
255 int fw = frameWidth();
256 return layoutState.maximumSize() + QSize(fw, fw);
258 void setGeometry(
const QRect&r) override
260 groupWindow()->destroyOrHideIfEmpty();
261 QDockAreaLayoutInfo *li = dockAreaLayoutInfo();
264 int fw = frameWidth();
266 li->reparentWidgets(parentWidget());
268 li->rect = r.adjusted(fw, fw, -fw, -fw);
271 if (savedState.rect.isValid())
272 savedState.rect = li->rect;
273 resizer->setEnabled(!nativeWindowDeco());
276 QDockAreaLayoutInfo *dockAreaLayoutInfo() {
return &layoutState; }
278#if QT_CONFIG(toolbar)
279 QToolBarAreaLayout *toolBarAreaLayout()
285 bool nativeWindowDeco()
const
287 return groupWindow()->hasNativeDecos();
290 int frameWidth()
const
292 return nativeWindowDeco() ? 0 :
293 parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, parentWidget());
296 QDockWidgetGroupWindow *groupWindow()
const
298 return static_cast<QDockWidgetGroupWindow *>(parent());
301 QDockAreaLayoutInfo layoutState;
302 QDockAreaLayoutInfo savedState;
305bool QDockWidgetGroupWindow::event(QEvent *e)
307 auto lay =
static_cast<QDockWidgetGroupLayout *>(layout());
308 if (lay && lay->windowEvent(e))
315 if (QDockWidget *dw = activeTabbedDockWidget()) {
324 if (QDockWidget *dw = activeTabbedDockWidget())
325 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->moveEvent(
static_cast<QMoveEvent*>(e));
328 case QEvent::NonClientAreaMouseMove:
329 case QEvent::NonClientAreaMouseButtonPress:
330 case QEvent::NonClientAreaMouseButtonRelease:
331 case QEvent::NonClientAreaMouseButtonDblClick:
334 if (QDockWidget *dw = activeTabbedDockWidget())
335 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->nonClientAreaMouseEvent(
static_cast<QMouseEvent*>(e));
338 case QEvent::ChildAdded:
339 if (qobject_cast<QDockWidget *>(
static_cast<QChildEvent*>(e)->child()))
342 case QEvent::LayoutRequest:
344 destroyOrHideIfEmpty();
347 updateCurrentGapRect();
353 return QWidget::event(e);
356void QDockWidgetGroupWindow::paintEvent(QPaintEvent *)
358 QDockWidgetGroupLayout *lay =
static_cast<QDockWidgetGroupLayout *>(layout());
359 bool nativeDeco = lay->nativeWindowDeco();
362 QStyleOptionFrame framOpt;
363 framOpt.initFrom(
this);
364 QStylePainter p(
this);
365 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
369QDockAreaLayoutInfo *QDockWidgetGroupWindow::layoutInfo()
const
371 return static_cast<QDockWidgetGroupLayout *>(layout())->dockAreaLayoutInfo();
376
377
378
379
380const QDockAreaLayoutInfo *QDockWidgetGroupWindow::tabLayoutInfo()
const
382 const QDockAreaLayoutInfo *info = layoutInfo();
383 while (info && !info->tabbed) {
386 const QDockAreaLayoutInfo *next =
nullptr;
387 bool isSingle =
false;
388 for (
const auto &item : info->item_list) {
389 if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
391 if (next || isSingle)
395 else if (item.widgetItem)
406
407
408QDockWidget *QDockWidgetGroupWindow::activeTabbedDockWidget()
const
410 QDockWidget *dw =
nullptr;
411 const QDockAreaLayoutInfo *info = tabLayoutInfo();
414 if (info->tabBar && info->tabBar->currentIndex() >= 0) {
415 int i = info->tabIndexToListIndex(info->tabBar->currentIndex());
417 const QDockAreaLayoutItem &item = info->item_list.at(i);
419 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
423 for (
int i = 0; !dw && i < info->item_list.size(); ++i) {
424 const QDockAreaLayoutItem &item = info->item_list.at(i);
427 if (!item.widgetItem)
429 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
437
438
439
440void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
442 const QDockAreaLayoutInfo *info = layoutInfo();
443 if (!info->isEmpty()) {
448 if (!info->item_list.isEmpty()) {
454 const auto dockWidgetsList = dockWidgets();
455 for (QDockWidget *dw : dockWidgetsList) {
456 const bool wasFloating = dw->isFloating();
457 const bool wasHidden = dw->isHidden();
458 dw->setParent(parentWidget());
459 qCDebug(lcQpaDockWidgets) <<
"Reparented:" << dw <<
"to" << parentWidget() <<
"by" <<
this;
461 dw->setFloating(
true);
464 QMainWindowLayout *ml =
465 qt_mainwindow_layout(
static_cast<QMainWindow *>(parentWidget()));
466 Qt::DockWidgetArea area = ml->dockWidgetArea(
this);
467 if (area == Qt::NoDockWidgetArea)
468 area = Qt::LeftDockWidgetArea;
469 static_cast<QMainWindow *>(parentWidget())->addDockWidget(area, dw);
470 qCDebug(lcQpaDockWidgets) <<
"Redocked to Mainwindow:" << area << dw <<
"by" <<
this;
475 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
476 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
477 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
478 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
479 std::unique_ptr<QLayoutItem> cleanup = parentInfo.takeWidgetItem(
this);
480 parentInfo.remove(
this);
485
486
487
488
489bool QDockWidgetGroupWindow::hasVisibleDockWidgets()
const
491 const auto &children = findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
492 for (
auto child : children) {
497 if (!child->testAttribute(Qt::WA_WState_Hidden))
504
505
506void QDockWidgetGroupWindow::adjustFlags()
508 Qt::WindowFlags oldFlags = windowFlags();
509 Qt::WindowFlags flags = oldFlags;
512 QDockWidget *top = activeTabbedDockWidget();
514 QDockWidget *top =
nullptr;
518 ((oldFlags & ~Qt::FramelessWindowHint) | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
519 }
else if (
static_cast<QDockWidgetGroupLayout *>(layout())->nativeWindowDeco()) {
520 flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
521 flags.setFlag(Qt::WindowCloseButtonHint, top->features() & QDockWidget::DockWidgetClosable);
522 flags &= ~Qt::FramelessWindowHint;
524 flags &= ~(Qt::WindowCloseButtonHint | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
525 flags |= Qt::FramelessWindowHint;
528 if (oldFlags != flags) {
531 setWindowFlags(flags);
532 const bool gainedNativeDecos = (oldFlags & Qt::FramelessWindowHint) && !(flags & Qt::FramelessWindowHint);
533 const bool lostNativeDecos = !(oldFlags & Qt::FramelessWindowHint) && (flags & Qt::FramelessWindowHint);
537 if (lostNativeDecos) {
538 QRect newGeometry = geometry();
539 newGeometry.setTop(frameGeometry().top());
540 const int bottomFrame = geometry().top() - frameGeometry().top();
541 m_removedFrameSize = QSize((frameSize() - size()).width(), bottomFrame);
542 setGeometry(newGeometry);
543 }
else if (gainedNativeDecos && m_removedFrameSize.isValid()) {
544 QRect r = geometry();
545 r.adjust(-m_removedFrameSize.width() / 2, 0,
546 -m_removedFrameSize.width() / 2, -m_removedFrameSize.height());
548 m_removedFrameSize = QSize();
551 setVisible(hasVisibleDockWidgets());
554 QWidget *titleBarOf = top ? top : parentWidget();
555 setWindowTitle(titleBarOf->windowTitle());
556 setWindowIcon(titleBarOf->windowIcon());
559bool QDockWidgetGroupWindow::hasNativeDecos()
const
562 QDockWidget *dw = activeTabbedDockWidget();
566 if (!QDockWidgetLayout::wmSupportsNativeWindowDeco())
569 return dw->titleBarWidget() ==
nullptr;
576QT_WARNING_DISABLE_GCC(
"-Waggressive-loop-optimizations")
578
579
580
581
582
583
584bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem,
const QPoint &mousePos)
586 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
587 if (savedState.isEmpty())
588 savedState = *layoutInfo();
590 QMainWindow::DockOptions opts =
static_cast<QMainWindow *>(parentWidget())->dockOptions();
591 QDockAreaLayoutInfo newState = savedState;
592 bool nestingEnabled =
593 (opts & QMainWindow::AllowNestedDocks) && !(opts & QMainWindow::ForceTabbedDocks);
594 QDockAreaLayoutInfo::TabMode tabMode =
595#if !QT_CONFIG(tabbar)
596 QDockAreaLayoutInfo::NoTabs;
598 nestingEnabled ? QDockAreaLayoutInfo::AllowTabs : QDockAreaLayoutInfo::ForceTabs;
599 if (
auto group = qobject_cast<QDockWidgetGroupWindow *>(widgetItem->widget())) {
600 if (!group->tabLayoutInfo())
601 tabMode = QDockAreaLayoutInfo::NoTabs;
603 if (newState.tabbed) {
605 newState.item_list = { QDockAreaLayoutItem(
new QDockAreaLayoutInfo(newState)) };
606 newState.item_list.first().size = pick(savedState.o, savedState.rect.size());
607 newState.tabbed =
false;
608 newState.tabBar =
nullptr;
612 auto newGapPos = newState.gapIndex(mousePos, nestingEnabled, tabMode);
613 Q_ASSERT(!newGapPos.isEmpty());
617 if (newGapPos == currentGapPos || newState.hasGapItem(newGapPos))
620 currentGapPos = newGapPos;
621 newState.insertGap(currentGapPos, widgetItem);
623 *layoutInfo() = std::move(newState);
624 updateCurrentGapRect();
625 layoutInfo()->apply(opts & QMainWindow::AnimatedDocks);
630void QDockWidgetGroupWindow::updateCurrentGapRect()
632 if (!currentGapPos.isEmpty())
633 currentGapRect = layoutInfo()->info(currentGapPos)->itemRect(currentGapPos.last(),
true);
637
638
639void QDockWidgetGroupWindow::restore()
641 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
642 if (!savedState.isEmpty()) {
643 *layoutInfo() = savedState;
644 savedState = QDockAreaLayoutInfo();
646 currentGapRect = QRect();
647 currentGapPos.clear();
649 layoutInfo()->fitItems();
650 layoutInfo()->apply(
static_cast<QMainWindow *>(parentWidget())->dockOptions()
651 & QMainWindow::AnimatedDocks);
655
656
657void QDockWidgetGroupWindow::apply()
659 static_cast<QDockWidgetGroupLayout *>(layout())->savedState.clear();
660 currentGapRect = QRect();
661 layoutInfo()->plug(currentGapPos);
662 currentGapPos.clear();
664 layoutInfo()->apply(
false);
667void QDockWidgetGroupWindow::childEvent(QChildEvent *event)
669 switch (event->type()) {
670 case QEvent::ChildRemoved:
671 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
672 dockWidget->removeEventFilter(
this);
673 destroyIfSingleItemLeft();
675 case QEvent::ChildAdded:
676 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
677 dockWidget->installEventFilter(
this);
684bool QDockWidgetGroupWindow::eventFilter(QObject *obj, QEvent *event)
686 auto *dockWidget = qobject_cast<QDockWidget *>(obj);
688 return QWidget::eventFilter(obj, event);
690 switch (event->type()) {
694 reparentToMainWindow(dockWidget);
695 dockWidget->setFloating(
false);
701 if (dockWidget->isVisible())
708 return QWidget::eventFilter(obj, event);
711void QDockWidgetGroupWindow::destroyIfSingleItemLeft()
713 const auto &dockWidgets =
this->dockWidgets();
716 if (dockWidgets.count() != 1)
719 auto *lastDockWidget = dockWidgets.at(0);
724 if (layoutInfo()->indexOf(lastDockWidget).isEmpty())
727 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
728 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
729 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
732 mwLayout->unplug(lastDockWidget, QDockWidgetPrivate::DragScope::Widget);
733 const QPoint position = pos();
737 reparentToMainWindow(lastDockWidget);
741 if (lastDockWidget->isFloating())
742 lastDockWidget->move(position);
745 layoutInfo()->item_list.clear();
747 destroyOrHideIfEmpty();
750void QDockWidgetGroupWindow::reparentToMainWindow(QDockWidget *dockWidget)
756 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
757 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
758 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
760 mwLayout->widgetAnimator.abort(dockWidget);
761 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
762 dockWidget->removeEventFilter(
this);
763 parentInfo.add(dockWidget);
764 layoutInfo()->remove(dockWidget);
765 const bool wasFloating = dockWidget->isFloating();
766 const bool wasVisible = dockWidget->isVisible();
767 dockWidget->setParent(mainWindow);
768 dockWidget->setFloating(wasFloating);
769 dockWidget->setVisible(wasVisible);
774
775
779QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win)
781#if QT_CONFIG(toolbar)
782 toolBarAreaLayout(win),
784#if QT_CONFIG(dockwidget)
794QSize QMainWindowLayoutState::sizeHint()
const
799#if QT_CONFIG(dockwidget)
800 result = dockAreaLayout.sizeHint();
802 if (centralWidgetItem)
803 result = centralWidgetItem->sizeHint();
806#if QT_CONFIG(toolbar)
807 result = toolBarAreaLayout.sizeHint(result);
813QSize QMainWindowLayoutState::minimumSize()
const
817#if QT_CONFIG(dockwidget)
818 result = dockAreaLayout.minimumSize();
820 if (centralWidgetItem)
821 result = centralWidgetItem->minimumSize();
824#if QT_CONFIG(toolbar)
825 result = toolBarAreaLayout.minimumSize(result);
832
833
834
835
836bool QMainWindowLayoutState::fits()
const
838 Q_ASSERT(mainWindow);
842#if QT_CONFIG(dockwidget)
843 size = dockAreaLayout.minimumStableSize();
846#if QT_CONFIG(toolbar)
847 size.rwidth() += toolBarAreaLayout.docks[QInternal::LeftDock].rect.width();
848 size.rwidth() += toolBarAreaLayout.docks[QInternal::RightDock].rect.width();
849 size.rheight() += toolBarAreaLayout.docks[QInternal::TopDock].rect.height();
850 size.rheight() += toolBarAreaLayout.docks[QInternal::BottomDock].rect.height();
853 return size.width() <= mainWindow->width() && size.height() <= mainWindow->height();
856void QMainWindowLayoutState::apply(
bool animated)
858#if QT_CONFIG(toolbar)
859 toolBarAreaLayout.apply(animated);
862#if QT_CONFIG(dockwidget)
864 dockAreaLayout.apply(animated);
866 if (centralWidgetItem) {
867 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
869 layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, animated);
874void QMainWindowLayoutState::fitLayout()
877#if !QT_CONFIG(toolbar)
880 toolBarAreaLayout.rect = rect;
881 r = toolBarAreaLayout.fitLayout();
884#if QT_CONFIG(dockwidget)
885 dockAreaLayout.rect = r;
886 dockAreaLayout.fitLayout();
888 centralWidgetRect = r;
892void QMainWindowLayoutState::deleteAllLayoutItems()
894#if QT_CONFIG(toolbar)
895 toolBarAreaLayout.deleteAllLayoutItems();
898#if QT_CONFIG(dockwidget)
899 dockAreaLayout.deleteAllLayoutItems();
903void QMainWindowLayoutState::deleteCentralWidgetItem()
905#if QT_CONFIG(dockwidget)
906 delete dockAreaLayout.centralWidgetItem;
907 dockAreaLayout.centralWidgetItem =
nullptr;
909 delete centralWidgetItem;
910 centralWidgetItem = 0;
914QLayoutItem *QMainWindowLayoutState::itemAt(
int index,
int *x)
const
916#if QT_CONFIG(toolbar)
917 if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
921#if QT_CONFIG(dockwidget)
922 if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
925 if (centralWidgetItem && (*x)++ == index)
926 return centralWidgetItem;
932QLayoutItem *QMainWindowLayoutState::takeAt(
int index,
int *x)
934#if QT_CONFIG(toolbar)
935 if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
939#if QT_CONFIG(dockwidget)
940 if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
943 if (centralWidgetItem && (*x)++ == index) {
944 QLayoutItem *ret = centralWidgetItem;
945 centralWidgetItem =
nullptr;
953QList<
int> QMainWindowLayoutState::indexOf(QWidget *widget)
const
957#if QT_CONFIG(toolbar)
959 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
960 result = toolBarAreaLayout.indexOf(toolBar);
961 if (!result.isEmpty())
967#if QT_CONFIG(dockwidget)
969 if (qobject_cast<QDockWidget *>(widget) || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
970 result = dockAreaLayout.indexOf(widget);
971 if (!result.isEmpty())
980bool QMainWindowLayoutState::contains(QWidget *widget)
const
982#if QT_CONFIG(dockwidget)
983 if (dockAreaLayout.centralWidgetItem !=
nullptr && dockAreaLayout.centralWidgetItem->widget() == widget)
985 if (!dockAreaLayout.indexOf(widget).isEmpty())
988 if (centralWidgetItem && centralWidgetItem->widget() == widget)
992#if QT_CONFIG(toolbar)
993 if (!toolBarAreaLayout.indexOf(widget).isEmpty())
999void QMainWindowLayoutState::setCentralWidget(QWidget *widget)
1001 QLayoutItem *item =
nullptr;
1003 deleteCentralWidgetItem();
1005 if (widget !=
nullptr)
1006 item =
new QWidgetItemV2(widget);
1008#if QT_CONFIG(dockwidget)
1009 dockAreaLayout.centralWidgetItem = item;
1011 centralWidgetItem = item;
1015QWidget *QMainWindowLayoutState::centralWidget()
const
1017 QLayoutItem *item =
nullptr;
1019#if QT_CONFIG(dockwidget)
1020 item = dockAreaLayout.centralWidgetItem;
1022 item = centralWidgetItem;
1025 if (item !=
nullptr)
1026 return item->widget();
1030QList<
int> QMainWindowLayoutState::gapIndex(QWidget *widget,
1031 const QPoint &pos)
const
1035#if QT_CONFIG(toolbar)
1037 if (qobject_cast<QToolBar*>(widget) !=
nullptr) {
1038 result = toolBarAreaLayout.gapIndex(pos);
1039 if (!result.isEmpty())
1045#if QT_CONFIG(dockwidget)
1047 if (qobject_cast<QDockWidget *>(widget) !=
nullptr
1048 || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1049 bool disallowTabs =
false;
1050#if QT_CONFIG(tabbar)
1051 if (
auto *group = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1052 if (!group->tabLayoutInfo())
1053 disallowTabs =
true;
1056 result = dockAreaLayout.gapIndex(pos, disallowTabs);
1057 if (!result.isEmpty())
1066bool QMainWindowLayoutState::insertGap(
const QList<
int> &path, QLayoutItem *item)
1071 int i = path.first();
1073#if QT_CONFIG(toolbar)
1075 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) !=
nullptr);
1076 return toolBarAreaLayout.insertGap(path.mid(1), item);
1080#if QT_CONFIG(dockwidget)
1082 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) || qobject_cast<QDockWidgetGroupWindow*>(item->widget()));
1083 return dockAreaLayout.insertGap(path.mid(1), item);
1090void QMainWindowLayoutState::remove(
const QList<
int> &path)
1092 int i = path.first();
1094#if QT_CONFIG(toolbar)
1096 toolBarAreaLayout.remove(path.mid(1));
1099#if QT_CONFIG(dockwidget)
1101 dockAreaLayout.remove(path.mid(1));
1105void QMainWindowLayoutState::remove(QLayoutItem *item)
1107#if QT_CONFIG(toolbar)
1108 toolBarAreaLayout.remove(item);
1111#if QT_CONFIG(dockwidget)
1113 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
1114 QList<
int> path = dockAreaLayout.indexOf(dockWidget);
1115 if (!path.isEmpty())
1116 dockAreaLayout.remove(path);
1121void QMainWindowLayoutState::clear()
1123#if QT_CONFIG(toolbar)
1124 toolBarAreaLayout.clear();
1127#if QT_CONFIG(dockwidget)
1128 dockAreaLayout.clear();
1130 centralWidgetRect = QRect();
1136bool QMainWindowLayoutState::isValid()
const
1138 return rect.isValid();
1141QLayoutItem *QMainWindowLayoutState::item(
const QList<
int> &path)
1143 int i = path.first();
1145#if QT_CONFIG(toolbar)
1147 const QToolBarAreaLayoutItem *tbItem = toolBarAreaLayout.item(path.mid(1));
1149 return tbItem->widgetItem;
1153#if QT_CONFIG(dockwidget)
1155 return dockAreaLayout.item(path.mid(1)).widgetItem;
1161QRect QMainWindowLayoutState::itemRect(
const QList<
int> &path)
const
1163 int i = path.first();
1165#if QT_CONFIG(toolbar)
1167 return toolBarAreaLayout.itemRect(path.mid(1));
1170#if QT_CONFIG(dockwidget)
1172 return dockAreaLayout.itemRect(path.mid(1));
1178QRect QMainWindowLayoutState::gapRect(
const QList<
int> &path)
const
1180 int i = path.first();
1182#if QT_CONFIG(toolbar)
1184 return toolBarAreaLayout.itemRect(path.mid(1));
1187#if QT_CONFIG(dockwidget)
1189 return dockAreaLayout.gapRect(path.mid(1));
1195QLayoutItem *QMainWindowLayoutState::plug(
const QList<
int> &path)
1197 int i = path.first();
1199#if QT_CONFIG(toolbar)
1201 return toolBarAreaLayout.plug(path.mid(1));
1204#if QT_CONFIG(dockwidget)
1206 return dockAreaLayout.plug(path.mid(1));
1212QLayoutItem *QMainWindowLayoutState::unplug(
const QList<
int> &path, QMainWindowLayoutState *other)
1214 int i = path.first();
1216#if !QT_CONFIG(toolbar)
1220 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout :
nullptr);
1223#if QT_CONFIG(dockwidget)
1225 return dockAreaLayout.unplug(path.mid(1));
1231void QMainWindowLayoutState::saveState(QDataStream &stream)
const
1233#if QT_CONFIG(dockwidget)
1234 dockAreaLayout.saveState(stream);
1235#if QT_CONFIG(tabbar)
1236 const QList<QDockWidgetGroupWindow *> floatingTabs =
1237 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
1239 for (QDockWidgetGroupWindow *floating : floatingTabs) {
1240 if (floating->layoutInfo()->isEmpty())
1242 stream << uchar(QDockAreaLayout::FloatingDockWidgetTabMarker) << floating->geometry();
1243 floating->layoutInfo()->saveState(stream);
1247#if QT_CONFIG(toolbar)
1248 toolBarAreaLayout.saveState(stream);
1252template <
typename T>
1258 for (
int i=0; i < list.size(); ++i) {
1259 if (T t = qobject_cast<T>(list[i])) {
1267#if QT_CONFIG(dockwidget)
1268static QList<QDockWidget*> allMyDockWidgets(
const QWidget *mainWindow)
1270 QList<QDockWidget*> result;
1271 for (QObject *c : mainWindow->children()) {
1272 if (
auto *dw = qobject_cast<QDockWidget*>(c)) {
1274 }
else if (
auto *gw = qobject_cast<QDockWidgetGroupWindow*>(c)) {
1275 for (QObject *c : gw->children()) {
1276 if (
auto *dw = qobject_cast<QDockWidget*>(c))
1287bool QMainWindowLayoutState::checkFormat(QDataStream &stream)
1289 while (!stream.atEnd()) {
1294#if QT_CONFIG(toolbar)
1295 case QToolBarAreaLayout::ToolBarStateMarker:
1296 case QToolBarAreaLayout::ToolBarStateMarkerEx:
1298 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1299 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker,
true )) {
1306#if QT_CONFIG(dockwidget)
1307 case QDockAreaLayout::DockWidgetStateMarker:
1309 const auto dockWidgets = allMyDockWidgets(mainWindow);
1310 if (!dockAreaLayout.restoreState(stream, dockWidgets,
true )) {
1315#if QT_CONFIG(tabbar)
1316 case QDockAreaLayout::FloatingDockWidgetTabMarker:
1320 QDockAreaLayoutInfo info;
1321 auto dockWidgets = allMyDockWidgets(mainWindow);
1322 if (!info.restoreState(stream, dockWidgets,
true ))
1338bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
1339 const QMainWindowLayoutState &oldState)
1343 while(!_stream.atEnd()) {
1345 QByteArray ba(length,
'\0');
1346 length = _stream.readRawData(ba.data(), ba.size());
1351 QDataStream ds(copy);
1352 ds.setVersion(_stream.version());
1353 if (!checkFormat(ds))
1356 QDataStream stream(copy);
1357 stream.setVersion(_stream.version());
1359 while (!stream.atEnd()) {
1364#if QT_CONFIG(dockwidget)
1365 case QDockAreaLayout::DockWidgetStateMarker:
1367 const auto dockWidgets = allMyDockWidgets(mainWindow);
1368 if (!dockAreaLayout.restoreState(stream, dockWidgets))
1371 for (
int i = 0; i < dockWidgets.size(); ++i) {
1372 QDockWidget *w = dockWidgets.at(i);
1373 QList<
int> path = dockAreaLayout.indexOf(w);
1374 if (path.isEmpty()) {
1375 QList<
int> oldPath = oldState.dockAreaLayout.indexOf(w);
1376 if (oldPath.isEmpty()) {
1379 QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
1380 if (info ==
nullptr) {
1388#if QT_CONFIG(tabwidget)
1389 case QDockAreaLayout::FloatingDockWidgetTabMarker:
1391 auto dockWidgets = allMyDockWidgets(mainWindow);
1392 QDockWidgetGroupWindow* floatingTab = qt_mainwindow_layout(mainWindow)->createTabbedDockWindow();
1393 *floatingTab->layoutInfo() = QDockAreaLayoutInfo(
1394 &dockAreaLayout.sep, QInternal::LeftDock,
1395 Qt::Horizontal, QTabBar::RoundedSouth, mainWindow);
1398 QDockAreaLayoutInfo *info = floatingTab->layoutInfo();
1399 if (!info->restoreState(stream, dockWidgets,
false))
1401 geometry = QDockAreaLayout::constrainedRect(geometry, floatingTab);
1402 floatingTab->move(geometry.topLeft());
1403 floatingTab->resize(geometry.size());
1407 if (info->onlyHasPlaceholders())
1408 info->reparentWidgets(floatingTab);
1410 floatingTab->show();
1416#if QT_CONFIG(toolbar)
1417 case QToolBarAreaLayout::ToolBarStateMarker:
1418 case QToolBarAreaLayout::ToolBarStateMarkerEx:
1420 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1421 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker))
1424 for (
int i = 0; i < toolBars.size(); ++i) {
1425 QToolBar *w = toolBars.at(i);
1426 QList<
int> path = toolBarAreaLayout.indexOf(w);
1427 if (path.isEmpty()) {
1428 QList<
int> oldPath = oldState.toolBarAreaLayout.indexOf(w);
1429 if (oldPath.isEmpty()) {
1432 toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(
nullptr, w);
1448
1449
1451#if QT_CONFIG(toolbar)
1453static constexpr Qt::ToolBarArea validateToolBarArea(Qt::ToolBarArea area)
1456 case Qt::LeftToolBarArea:
1457 case Qt::RightToolBarArea:
1458 case Qt::TopToolBarArea:
1459 case Qt::BottomToolBarArea:
1464 return Qt::TopToolBarArea;
1467static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
1470 case Qt::LeftToolBarArea:
return QInternal::LeftDock;
1471 case Qt::RightToolBarArea:
return QInternal::RightDock;
1472 case Qt::TopToolBarArea:
return QInternal::TopDock;
1473 case Qt::BottomToolBarArea:
return QInternal::BottomDock;
1478 return QInternal::DockCount;
1481static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
1484 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1485 case QInternal::RightDock:
return Qt::RightToolBarArea;
1486 case QInternal::TopDock:
return Qt::TopToolBarArea;
1487 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1490 return Qt::NoToolBarArea;
1493static inline Qt::ToolBarArea toToolBarArea(
int pos)
1495 return toToolBarArea(
static_cast<QInternal::DockPosition>(pos));
1498void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
1500 area = validateToolBarArea(area);
1502 layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1503 if (savedState.isValid())
1504 savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1509void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
1511 layoutState.toolBarAreaLayout.insertToolBarBreak(before);
1512 if (savedState.isValid())
1513 savedState.toolBarAreaLayout.insertToolBarBreak(before);
1517void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
1519 layoutState.toolBarAreaLayout.removeToolBarBreak(before);
1520 if (savedState.isValid())
1521 savedState.toolBarAreaLayout.removeToolBarBreak(before);
1525void QMainWindowLayout::moveToolBar(QToolBar *toolbar,
int pos)
1527 layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1528 if (savedState.isValid())
1529 savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1534
1535void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
1538 QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
1539 toolbar, SLOT(_q_updateIconSize(QSize)));
1540 QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
1541 toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
1543 removeWidget(toolbar);
1548
1549
1550
1551
1554
1555
1556void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
1560 area = validateToolBarArea(area);
1562 addChildWidget(toolbar);
1563 QLayoutItem *item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
1564 if (savedState.isValid() && item) {
1566 savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
1571 toolbar->d_func()->updateWindowFlags(
false );
1575
1576
1577void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
1579 addChildWidget(toolbar);
1580 QLayoutItem *item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
1581 if (savedState.isValid() && item) {
1583 savedState.toolBarAreaLayout.insertItem(before, item);
1585 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
1586 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1587 if (!currentGapPos.isEmpty()) {
1588 currentGapPos.prepend(0);
1589 currentGapRect = layoutState.itemRect(currentGapPos);
1595Qt::ToolBarArea QMainWindowLayout::toolBarArea(
const QToolBar *toolbar)
const
1597 QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar);
1599 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1600 case QInternal::RightDock:
return Qt::RightToolBarArea;
1601 case QInternal::TopDock:
return Qt::TopToolBarArea;
1602 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1605 return Qt::NoToolBarArea;
1608bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar)
const
1610 return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
1613void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar)
const
1615 option->toolBarArea = toolBarArea(toolBar);
1616 layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
1619void QMainWindowLayout::toggleToolBarsVisible()
1621 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
1622 if (!layoutState.mainWindow->isMaximized()) {
1623 QPoint topLeft = parentWidget()->geometry().topLeft();
1624 QRect r = parentWidget()->geometry();
1625 r = layoutState.toolBarAreaLayout.rectHint(r);
1627 parentWidget()->setGeometry(r);
1636
1637
1639#if QT_CONFIG(dockwidget)
1641static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area)
1644 case Qt::LeftDockWidgetArea:
return QInternal::LeftDock;
1645 case Qt::RightDockWidgetArea:
return QInternal::RightDock;
1646 case Qt::TopDockWidgetArea:
return QInternal::TopDock;
1647 case Qt::BottomDockWidgetArea:
return QInternal::BottomDock;
1652 return QInternal::DockCount;
1655inline static Qt::DockWidgetArea toDockWidgetArea(
int pos)
1657 return QDockWidgetPrivate::toDockWidgetArea(
static_cast<QInternal::DockPosition>(pos));
1662static bool isAreaAllowed(QWidget *widget,
const QList<
int> &path)
1664 Q_ASSERT_X((path.size() > 1),
"isAreaAllowed",
"invalid path size");
1665 const Qt::DockWidgetArea area = toDockWidgetArea(path[1]);
1668 if (QDockWidget *dw = qobject_cast<QDockWidget *>(widget)) {
1669 const bool allowed = dw->isAreaAllowed(area);
1671 qCDebug(lcQpaDockWidgets) <<
"No permission for single DockWidget" << widget <<
"to dock on" << area;
1676 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1677 const QList<QDockWidget *> children = dwgw->findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly);
1679 if (children.size() == 1) {
1681 const bool allowed = children.at(0)->isAreaAllowed(area);
1683 qCDebug(lcQpaDockWidgets) <<
"No permission for DockWidgetGroupWindow" << widget <<
"to dock on" << area;
1687 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"has" << children.size() <<
"children:";
1688 qCDebug(lcQpaDockWidgets) << children;
1689 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"can dock at" << area <<
"and anywhere else.";
1693 qCDebug(lcQpaDockWidgets) <<
"Docking requested for invalid widget type (coding error)." << widget << area;
1697void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1699 if (layoutState.dockAreaLayout.corners[corner] == area)
1701 layoutState.dockAreaLayout.corners[corner] = area;
1702 if (savedState.isValid())
1703 savedState.dockAreaLayout.corners[corner] = area;
1707Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner)
const
1709 return layoutState.dockAreaLayout.corners[corner];
1715QRect QMainWindowLayout::dockWidgetAreaRect(
const Qt::DockWidgetArea area, DockWidgetAreaSize size)
const
1717 const QInternal::DockPosition dockPosition = toDockPos(area);
1720 if (dockPosition == QInternal::DockCount) {
1721 qCDebug(lcQpaDockWidgets) <<
"QMainWindowLayout::dockWidgetAreaRect called with" << area;
1725 const QDockAreaLayout dl = layoutState.dockAreaLayout;
1728 return (size == Maximum) ? dl.gapRect(dockPosition) : dl.docks[dockPosition].rect;
1732
1733
1734
1735void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1736 QDockWidget *dockwidget,
1737 Qt::Orientation orientation)
1739 addChildWidget(dockwidget);
1743 if (!movingSeparator.isEmpty())
1744 endSeparatorMove(movingSeparatorPos);
1746 layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
1750bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1752 addChildWidget(dockwidget);
1753 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1755 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1760#if QT_CONFIG(tabbar)
1761void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1763 applyRestoredState();
1764 addChildWidget(second);
1765 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1766 emit second->dockLocationChanged(dockWidgetArea(first));
1770bool QMainWindowLayout::documentMode()
const
1772 return _documentMode;
1775void QMainWindowLayout::setDocumentMode(
bool enabled)
1777 if (_documentMode == enabled)
1780 _documentMode = enabled;
1783 for (QTabBar *bar : std::as_const(usedTabBars))
1784 bar->setDocumentMode(_documentMode);
1787void QMainWindowLayout::setVerticalTabsEnabled(
bool enabled)
1789 if (verticalTabsEnabled == enabled)
1792 verticalTabsEnabled = enabled;
1794 updateTabBarShapes();
1797#if QT_CONFIG(tabwidget)
1798QTabWidget::TabShape QMainWindowLayout::tabShape()
const
1803void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1805 if (_tabShape == tabShape)
1808 _tabShape = tabShape;
1810 updateTabBarShapes();
1813QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area)
const
1815 const QInternal::DockPosition dockPos = toDockPos(area);
1816 if (dockPos < QInternal::DockCount)
1817 return tabPositions[dockPos];
1818 qWarning(
"QMainWindowLayout::tabPosition called with out-of-bounds value '%d'",
int(area));
1819 return QTabWidget::North;
1822void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1824 const Qt::DockWidgetArea dockWidgetAreas[] = {
1825 Qt::TopDockWidgetArea,
1826 Qt::LeftDockWidgetArea,
1827 Qt::BottomDockWidgetArea,
1828 Qt::RightDockWidgetArea
1830 const QInternal::DockPosition dockPositions[] = {
1832 QInternal::LeftDock,
1833 QInternal::BottomDock,
1834 QInternal::RightDock
1837 for (
int i = 0; i < QInternal::DockCount; ++i)
1838 if (areas & dockWidgetAreas[i])
1839 tabPositions[dockPositions[i]] = tabPosition;
1841 updateTabBarShapes();
1844QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
1847void QMainWindowLayout::showTabBars()
1849 const auto usedTabBarsCopy = usedTabBars;
1850 for (QTabBar *tab_bar : usedTabBarsCopy) {
1851 if (usedTabBars.contains(tab_bar))
1856void QMainWindowLayout::updateTabBarShapes()
1858#if QT_CONFIG(tabwidget)
1859 const QTabWidget::TabPosition vertical[] = {
1866 const QTabBar::Shape vertical[] = {
1867 QTabBar::RoundedWest,
1868 QTabBar::RoundedEast,
1869 QTabBar::RoundedNorth,
1870 QTabBar::RoundedSouth
1874 QDockAreaLayout &layout = layoutState.dockAreaLayout;
1876 for (
int i = 0; i < QInternal::DockCount; ++i) {
1877#if QT_CONFIG(tabwidget)
1878 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
1879 QTabBar::Shape shape = _q_tb_tabBarShapeFrom(_tabShape, pos);
1881 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
1883 layout.docks[i].setTabBarShape(shape);
1888void QMainWindowLayout::splitDockWidget(QDockWidget *after,
1889 QDockWidget *dockwidget,
1890 Qt::Orientation orientation)
1892 applyRestoredState();
1893 addChildWidget(dockwidget);
1894 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
1895 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
1899Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(
const QWidget *widget)
const
1901 const QList<
int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
1902 if (pathToWidget.isEmpty())
1903 return Qt::NoDockWidgetArea;
1904 return toDockWidgetArea(pathToWidget.first());
1907void QMainWindowLayout::keepSize(QDockWidget *w)
1909 layoutState.dockAreaLayout.keepSize(w);
1912#if QT_CONFIG(tabbar)
1915class QMainWindowTabBar :
public QTabBar
1918 QPointer<QMainWindow> mainWindow;
1919 QPointer<QDockWidget> draggingDock;
1921 QMainWindowTabBar(QMainWindow *parent);
1922 ~QMainWindowTabBar();
1923 QDockWidget *dockAt(
int index)
const;
1924 QList<QDockWidget *> dockWidgets()
const;
1925 bool contains(
const QDockWidget *dockWidget)
const;
1927 bool event(QEvent *e) override;
1928 void mouseReleaseEvent(QMouseEvent*) override;
1929 void mouseMoveEvent(QMouseEvent*) override;
1933QDebug operator<<(QDebug debug,
const QMainWindowTabBar *bar)
1936 return debug <<
"QMainWindowTabBar(0x0)";
1937 QDebugStateSaver saver(debug);
1938 debug.nospace().noquote() <<
"QMainWindowTabBar(" <<
static_cast<
const void *>(bar) <<
", ";
1939 debug.nospace().noquote() <<
"ParentWidget=(" << bar->parentWidget() <<
"), ";
1940 const auto dockWidgets = bar->dockWidgets();
1941 if (dockWidgets.isEmpty())
1942 debug.nospace().noquote() <<
"No QDockWidgets";
1944 debug.nospace().noquote() <<
"DockWidgets(" << dockWidgets <<
")";
1945 debug.nospace().noquote() <<
")";
1949QMainWindowTabBar *QMainWindowLayout::findTabBar(
const QDockWidget *dockWidget)
const
1951 for (
auto *bar : usedTabBars) {
1952 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
1953 auto *tabBar =
static_cast<QMainWindowTabBar *>(bar);
1954 if (tabBar->contains(dockWidget))
1960QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
1961 : QTabBar(parent), mainWindow(parent)
1963 setExpanding(
false);
1966QList<QDockWidget *> QMainWindowTabBar::dockWidgets()
const
1968 QList<QDockWidget *> docks;
1969 for (
int i = 0; i < count(); ++i) {
1970 if (QDockWidget *dock = dockAt(i))
1976bool QMainWindowTabBar::contains(
const QDockWidget *dockWidget)
const
1978 for (
int i = 0; i < count(); ++i) {
1979 if (dockAt(i) == dockWidget)
1990QDockWidget *QMainWindowTabBar::dockAt(
int index)
const
1992 QMainWindowTabBar *that =
const_cast<QMainWindowTabBar *>(
this);
1993 QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
1994 QDockAreaLayoutInfo *info = mlayout ? mlayout->dockInfo(that) :
nullptr;
1998 const int itemIndex = info->tabIndexToListIndex(index);
1999 if (itemIndex >= 0) {
2000 Q_ASSERT(itemIndex < info->item_list.count());
2001 const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
2002 return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) :
nullptr;
2009
2010
2011
2012
2013
2014
2015
2016
2017static void moveToUnplugPosition(QPoint mouse, QDockWidget *dockWidget)
2019 Q_ASSERT(dockWidget);
2021 if (
auto *tbWidget = dockWidget->titleBarWidget()) {
2022 dockWidget->move(mouse - tbWidget->rect().center());
2026 const bool vertical = dockWidget->features().testFlag(QDockWidget::DockWidgetVerticalTitleBar);
2027 const int deltaX = vertical ? QApplication::startDragDistance() : dockWidget->width() / 2;
2028 const int deltaY = vertical ? dockWidget->height() / 2 : QApplication::startDragDistance();
2029 dockWidget->move(mouse - QPoint(deltaX, deltaY));
2032void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
2039 QTabBarPrivate *d =
static_cast<QTabBarPrivate*>(d_ptr.data());
2040 if (!draggingDock && (mainWindow->dockOptions() & QMainWindow::GroupedDragging)) {
2041 int offset = QApplication::startDragDistance() + 1;
2043 QRect r = rect().adjusted(-offset, -offset, offset, offset);
2044 if (d->dragInProgress && !r.contains(e->position().toPoint()) && d->validIndex(d->pressedIndex)) {
2045 draggingDock = dockAt(d->pressedIndex);
2049 d->moveTabFinished(d->pressedIndex);
2050 d->pressedIndex = -1;
2052 d->movingTab->setVisible(
false);
2053 d->dragStartPosition = QPoint();
2056 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2057 QDockWidgetLayout *dwlayout =
static_cast<QDockWidgetLayout *>(draggingDock->layout());
2058 dockPriv->initDrag(dwlayout->titleArea().center(),
true);
2059 dockPriv->startDrag(QDockWidgetPrivate::DragScope::Widget);
2060 if (dockPriv->state)
2061 dockPriv->state->ctrlDrag = e->modifiers() & Qt::ControlModifier;
2067 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2068 if (dockPriv->state && dockPriv->state->dragging) {
2070 moveToUnplugPosition(e->globalPosition().toPoint(), draggingDock);
2073 QTabBar::mouseMoveEvent(e);
2076QMainWindowTabBar::~QMainWindowTabBar()
2080 if (!qobject_cast<QMainWindow *>(mainWindow) || mainWindow == parentWidget())
2085 auto *mwLayout = qt_mainwindow_layout(mainWindow);
2088 mwLayout->usedTabBars.remove(
this);
2091void QMainWindowTabBar::mouseReleaseEvent(QMouseEvent *e)
2093 if (draggingDock && e->button() == Qt::LeftButton) {
2094 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2095 if (dockPriv->state && dockPriv->state->dragging)
2096 dockPriv->endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
2098 draggingDock =
nullptr;
2100 QTabBar::mouseReleaseEvent(e);
2103bool QMainWindowTabBar::event(QEvent *e)
2107 if (e->type() != QEvent::ToolTip)
2108 return QTabBar::event(e);
2109 QSize size =
this->size();
2110 QSize hint = sizeHint();
2111 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
2112 size = size.transposed();
2113 hint = hint.transposed();
2115 if (size.width() < hint.width())
2116 return QTabBar::event(e);
2121QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(
const QDockWidget *dockWidget)
const
2123 const auto *bar = findTabBar(dockWidget);
2127 QList<QDockWidget *> buddies = bar->dockWidgets();
2130 buddies.removeOne(dockWidget);
2134bool QMainWindowLayout::isDockWidgetTabbed(
const QDockWidget *dockWidget)
const
2139 const auto *bar = findTabBar(dockWidget);
2140 return bar && bar->count() > 1;
2143void QMainWindowLayout::unuseTabBar(QTabBar *bar)
2145 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
2149QTabBar *QMainWindowLayout::getTabBar()
2151 if (!usedTabBars.isEmpty() && !isInRestoreState) {
2153
2154
2155
2156
2160 QTabBar *bar =
new QMainWindowTabBar(
static_cast<QMainWindow *>(parentWidget()));
2161 bar->setDrawBase(
true);
2162 bar->setElideMode(Qt::ElideRight);
2163 bar->setDocumentMode(_documentMode);
2164 bar->setMovable(
true);
2165 connect(bar, SIGNAL(currentChanged(
int)),
this, SLOT(tabChanged()));
2166 connect(bar, &QTabBar::tabMoved,
this, &QMainWindowLayout::tabMoved);
2168 usedTabBars.insert(bar);
2172QWidget *QMainWindowLayout::getSeparatorWidget()
2174 auto *separator =
new QWidget(parentWidget());
2175 separator->setAttribute(Qt::WA_MouseNoMask,
true);
2176 separator->setAutoFillBackground(
false);
2177 separator->setObjectName(
"qt_qmainwindow_extended_splitter"_L1);
2178 usedSeparatorWidgets.insert(separator);
2183
2184
2185
2186QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget)
2188 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
2192 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2193 for (QDockWidgetGroupWindow *dwgw : groups) {
2194 info = dwgw->layoutInfo()->info(widget);
2201void QMainWindowLayout::tabChanged()
2203 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2206 QDockAreaLayoutInfo *info = dockInfo(tb);
2207 if (info ==
nullptr)
2210 QDockWidget *activated = info->apply(
false);
2213 emit
static_cast<QMainWindow *>(parentWidget())->tabifiedDockWidgetActivated(activated);
2215 if (
auto dwgw = qobject_cast<QDockWidgetGroupWindow*>(tb->parentWidget()))
2216 dwgw->adjustFlags();
2218 if (QWidget *w = centralWidget())
2222void QMainWindowLayout::tabMoved(
int from,
int to)
2224 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2226 QDockAreaLayoutInfo *info = dockInfo(tb);
2229 info->moveTab(from, to);
2232void QMainWindowLayout::raise(QDockWidget *widget)
2234 QDockAreaLayoutInfo *info = dockInfo(widget);
2235 if (info ==
nullptr)
2239 info->setCurrentTab(widget);
2247
2248
2250int QMainWindowLayout::count()
const
2253 while (itemAt(result))
2258QLayoutItem *QMainWindowLayout::itemAt(
int index)
const
2262 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
2265 if (statusbar && x++ == index)
2271QLayoutItem *QMainWindowLayout::takeAt(
int index)
2275 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
2277 if (QWidget *w = ret->widget()) {
2278 widgetAnimator.abort(w);
2279 if (w == pluggingWidget)
2280 pluggingWidget =
nullptr;
2283 if (savedState.isValid() ) {
2285 savedState.remove(ret);
2287 layoutState.remove(ret);
2290#if QT_CONFIG(toolbar)
2291 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
2292 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
2293 if (!currentGapPos.isEmpty()) {
2294 currentGapPos.prepend(0);
2295 currentGapRect = layoutState.itemRect(currentGapPos);
2303 if (statusbar && x++ == index) {
2304 QLayoutItem *ret = statusbar;
2305 statusbar =
nullptr;
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329void QMainWindowLayout::applyRestoredState()
2331 if (restoredState) {
2332 layoutState = *restoredState;
2333 restoredState.reset();
2334 discardRestoredStateTimer.stop();
2338void QMainWindowLayout::setGeometry(
const QRect &_r)
2342 if (savedState.isValid() || (restoredState && isInApplyState))
2347 QLayout::setGeometry(r);
2350 QRect sbr(QPoint(r.left(), 0),
2351 QSize(r.width(), statusbar->heightForWidth(r.width()))
2352 .expandedTo(statusbar->minimumSize()));
2353 sbr.moveBottom(r.bottom());
2354 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
2355 statusbar->setGeometry(vr);
2356 r.setBottom(sbr.top() - 1);
2359 if (restoredState) {
2361
2362
2363
2364
2365
2366
2367 layoutState = *restoredState;
2368 if (restoredState->fits()) {
2369 restoredState.reset();
2370 discardRestoredStateTimer.stop();
2373
2374
2375
2376
2377
2378
2379
2380
2381 discardRestoredStateTimer.start(150,
this);
2385 layoutState.rect = r;
2387 layoutState.fitLayout();
2388 applyState(layoutState,
false);
2391void QMainWindowLayout::timerEvent(QTimerEvent *e)
2393 if (e->timerId() == discardRestoredStateTimer.timerId()) {
2394 discardRestoredStateTimer.stop();
2395 restoredState.reset();
2397 QLayout::timerEvent(e);
2400void QMainWindowLayout::addItem(QLayoutItem *)
2401{ qWarning(
"QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
2403QSize QMainWindowLayout::sizeHint()
const
2405 if (!szHint.isValid()) {
2406 szHint = layoutState.sizeHint();
2407 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
2408 szHint = QSize(qMax(sbHint.width(), szHint.width()),
2409 sbHint.height() + szHint.height());
2414QSize QMainWindowLayout::minimumSize()
const
2416 if (!minSize.isValid()) {
2417 minSize = layoutState.minimumSize();
2418 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
2419 minSize = QSize(qMax(sbMin.width(), minSize.width()),
2420 sbMin.height() + minSize.height());
2425void QMainWindowLayout::invalidate()
2427 QLayout::invalidate();
2428 minSize = szHint = QSize();
2431#if QT_CONFIG(dockwidget)
2432void QMainWindowLayout::setCurrentHoveredFloat(QDockWidgetGroupWindow *w)
2434 if (currentHoveredFloat != w) {
2435 if (currentHoveredFloat) {
2436 disconnect(currentHoveredFloat.data(), &QObject::destroyed,
2437 this, &QMainWindowLayout::updateGapIndicator);
2438 disconnect(currentHoveredFloat.data(), &QDockWidgetGroupWindow::resized,
2439 this, &QMainWindowLayout::updateGapIndicator);
2440 if (currentHoveredFloat)
2441 currentHoveredFloat->restore();
2446 currentHoveredFloat = w;
2449 connect(w, &QObject::destroyed,
2450 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2451 connect(w, &QDockWidgetGroupWindow::resized,
2452 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2455 updateGapIndicator();
2461
2462
2466#if QT_CONFIG(toolbar)
2467 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
2468 if (toolBar ==
nullptr)
2471 QRect oldGeo = toolBar->geometry();
2473 QInternal::DockPosition pos
2474 =
static_cast<QInternal::DockPosition>(dockPos);
2475 Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
2476 ? Qt::Horizontal : Qt::Vertical;
2477 if (o != toolBar->orientation())
2478 toolBar->setOrientation(o);
2480 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
2481 .expandedTo(toolBar->minimumSize());
2483 if (toolBar->size() != hint) {
2484 QRect newGeo(oldGeo.topLeft(), hint);
2485 if (toolBar->layoutDirection() == Qt::RightToLeft)
2486 newGeo.moveRight(oldGeo.right());
2487 toolBar->setGeometry(newGeo);
2496void QMainWindowLayout::revert(QLayoutItem *widgetItem)
2498 if (!savedState.isValid())
2501 QWidget *widget = widgetItem->widget();
2502 layoutState = savedState;
2503 currentGapPos = layoutState.indexOf(widget);
2504 if (currentGapPos.isEmpty())
2506 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2507 layoutState.unplug(currentGapPos);
2508 layoutState.fitLayout();
2509 currentGapRect = layoutState.itemRect(currentGapPos);
2514bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
2516#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) && QT_CONFIG(tabbar)
2517 if (currentHoveredFloat) {
2518 QWidget *widget = widgetItem->widget();
2519 QList<
int> previousPath = layoutState.indexOf(widget);
2520 if (!previousPath.isEmpty())
2521 layoutState.remove(previousPath);
2522 previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2525 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2526 for (QDockWidgetGroupWindow *dwgw : groups) {
2527 if (dwgw == currentHoveredFloat)
2529 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2530 if (!path.isEmpty())
2531 dwgw->layoutInfo()->remove(path);
2533 currentGapRect = QRect();
2534 currentHoveredFloat->apply();
2535 if (!previousPath.isEmpty())
2536 currentHoveredFloat->layoutInfo()->remove(previousPath);
2537 QRect globalRect = currentHoveredFloat->currentGapRect;
2538 globalRect.moveTopLeft(currentHoveredFloat->mapToGlobal(globalRect.topLeft()));
2539 pluggingWidget = widget;
2540 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2545 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
2548 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2550 QWidget *widget = widgetItem->widget();
2552#if QT_CONFIG(dockwidget)
2555 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2556 for (QDockWidgetGroupWindow *dwgw : groups) {
2557 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2558 if (!path.isEmpty())
2559 dwgw->layoutInfo()->remove(path);
2563 QList<
int> previousPath = layoutState.indexOf(widget);
2565 const QLayoutItem *it = layoutState.plug(currentGapPos);
2568 Q_ASSERT(it == widgetItem);
2569 if (!previousPath.isEmpty())
2570 layoutState.remove(previousPath);
2572 pluggingWidget = widget;
2573 QRect globalRect = currentGapRect;
2574 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
2575#if QT_CONFIG(dockwidget)
2576 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2577 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
2578 if (layout->nativeWindowDeco()) {
2579 globalRect.adjust(0, layout->titleHeight(), 0, 0);
2581 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, widget);
2582 globalRect.adjust(-fw, -fw, fw, fw);
2586 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2591void QMainWindowLayout::animationFinished(QWidget *widget)
2595#if QT_CONFIG(toolbar)
2596 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2597 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
2598 if (tbl->animating) {
2599 tbl->animating =
false;
2601 tbl->layoutActions(tb->size());
2607 if (widget == pluggingWidget) {
2609#if QT_CONFIG(dockwidget)
2610#if QT_CONFIG(tabbar)
2611 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
2615 QDockAreaLayoutInfo *srcInfo = dwgw->layoutInfo();
2616 const QDockAreaLayoutInfo *srcTabInfo = dwgw->tabLayoutInfo();
2617 QDockAreaLayoutInfo *dstParentInfo;
2620 if (currentHoveredFloat) {
2621 dstPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2622 Q_ASSERT(dstPath.size() >= 1);
2623 dstParentInfo = currentHoveredFloat->layoutInfo()->info(dstPath);
2625 dstPath = layoutState.dockAreaLayout.indexOf(widget);
2626 Q_ASSERT(dstPath.size() >= 2);
2627 dstParentInfo = layoutState.dockAreaLayout.info(dstPath);
2629 Q_ASSERT(dstParentInfo);
2630 int idx = dstPath.constLast();
2631 Q_ASSERT(dstParentInfo->item_list[idx].widgetItem->widget() == dwgw);
2632 if (dstParentInfo->tabbed && srcTabInfo) {
2634 delete dstParentInfo->item_list[idx].widgetItem;
2635 dstParentInfo->item_list.removeAt(idx);
2636 std::copy(srcTabInfo->item_list.cbegin(), srcTabInfo->item_list.cend(),
2637 std::inserter(dstParentInfo->item_list,
2638 dstParentInfo->item_list.begin() + idx));
2639 quintptr currentId = srcTabInfo->currentTabId();
2640 *srcInfo = QDockAreaLayoutInfo();
2641 dstParentInfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2643 dstParentInfo->updateTabBar();
2644 dstParentInfo->setCurrentTabId(currentId);
2646 QDockAreaLayoutItem &item = dstParentInfo->item_list[idx];
2647 Q_ASSERT(item.widgetItem->widget() == dwgw);
2648 delete item.widgetItem;
2649 item.widgetItem =
nullptr;
2650 item.subinfo =
new QDockAreaLayoutInfo(std::move(*srcInfo));
2651 *srcInfo = QDockAreaLayoutInfo();
2652 item.subinfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2654 item.subinfo->setTabBarShape(dstParentInfo->tabBarShape);
2656 dwgw->destroyOrHideIfEmpty();
2660 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2661 dw->setParent(currentHoveredFloat ? currentHoveredFloat.data() : parentWidget());
2663 dw->d_func()->plug(currentGapRect);
2666#if QT_CONFIG(toolbar)
2667 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
2668 tb->d_func()->plug(currentGapRect);
2672 currentGapPos.clear();
2673 pluggingWidget =
nullptr;
2674#if QT_CONFIG(dockwidget)
2675 setCurrentHoveredFloat(
nullptr);
2679 layoutState.apply(
false);
2681#if QT_CONFIG(dockwidget)
2682#if QT_CONFIG(tabbar)
2683 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2686 if (QDockAreaLayoutInfo *info = dockInfo(widget))
2687 info->setCurrentTab(widget);
2693 if (!widgetAnimator.animating()) {
2695#if QT_CONFIG(dockwidget)
2696 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
2697#if QT_CONFIG(tabbar)
2703 updateGapIndicator();
2706void QMainWindowLayout::restore(
bool keepSavedState)
2708 if (!savedState.isValid())
2711 layoutState = savedState;
2712 applyState(layoutState);
2713 if (!keepSavedState)
2715 currentGapPos.clear();
2716 pluggingWidget =
nullptr;
2717 updateGapIndicator();
2720QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout)
2721 : QLayout(parentLayout ?
static_cast<QWidget *>(
nullptr) : mainwindow)
2722 , layoutState(mainwindow)
2723 , savedState(mainwindow)
2724 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
2725 , statusbar(
nullptr)
2726#if QT_CONFIG(dockwidget)
2727#if QT_CONFIG(tabbar)
2728 , _documentMode(
false)
2729 , verticalTabsEnabled(
false)
2730#if QT_CONFIG(tabwidget)
2731 , _tabShape(QTabWidget::Rounded)
2735 , widgetAnimator(
this)
2736 , pluggingWidget(
nullptr)
2739 setParent(parentLayout);
2741#if QT_CONFIG(dockwidget)
2742#if QT_CONFIG(tabbar)
2743 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent,
nullptr, mainwindow);
2746#if QT_CONFIG(tabwidget)
2747 for (
int i = 0; i < QInternal::DockCount; ++i)
2748 tabPositions[i] = QTabWidget::South;
2751 pluggingWidget =
nullptr;
2753 setObjectName(mainwindow->objectName() +
"_layout"_L1);
2756QMainWindowLayout::~QMainWindowLayout()
2758 layoutState.deleteAllLayoutItems();
2759 layoutState.deleteCentralWidgetItem();
2764void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
2766 if (opts == dockOptions)
2771#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
2772 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
2778#if QT_CONFIG(statusbar)
2779QStatusBar *QMainWindowLayout::statusBar()
const
2780{
return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
2782void QMainWindowLayout::setStatusBar(QStatusBar *sb)
2787 statusbar = sb ?
new QWidgetItemV2(sb) :
nullptr;
2792QWidget *QMainWindowLayout::centralWidget()
const
2794 return layoutState.centralWidget();
2797void QMainWindowLayout::setCentralWidget(QWidget *widget)
2799 if (widget !=
nullptr)
2800 addChildWidget(widget);
2801 layoutState.setCentralWidget(widget);
2802 if (savedState.isValid()) {
2803#if QT_CONFIG(dockwidget)
2804 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
2805 savedState.dockAreaLayout.fallbackToSizeHints =
true;
2807 savedState.centralWidgetItem = layoutState.centralWidgetItem;
2813#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2815
2816
2817
2818
2819
2820
2821static bool unplugGroup(QMainWindowLayout *layout, QLayoutItem **item,
2822 QDockAreaLayoutItem &parentItem)
2824 if (!parentItem.subinfo || !parentItem.subinfo->tabbed)
2828 QDockWidgetGroupWindow *floatingTabs = layout->createTabbedDockWindow();
2829 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
2830 *info = std::move(*parentItem.subinfo);
2831 delete parentItem.subinfo;
2832 parentItem.subinfo =
nullptr;
2833 floatingTabs->setGeometry(info->rect.translated(layout->parentWidget()->pos()));
2834 floatingTabs->show();
2835 floatingTabs->raise();
2836 *item =
new QDockWidgetGroupWindowItem(floatingTabs);
2837 parentItem.widgetItem = *item;
2842#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2843static QTabBar::Shape tabwidgetPositionToTabBarShape(QWidget *w)
2845 QTabBar::Shape result = QTabBar::RoundedSouth;
2846 if (qobject_cast<QDockWidget *>(w)) {
2847 switch (
static_cast<QDockWidgetPrivate *>(qt_widget_private(w))->tabPosition) {
2848 case QTabWidget::North:
2849 result = QTabBar::RoundedNorth;
2851 case QTabWidget::South:
2852 result = QTabBar::RoundedSouth;
2854 case QTabWidget::West:
2855 result = QTabBar::RoundedWest;
2857 case QTabWidget::East:
2858 result = QTabBar::RoundedEast;
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope)
2878#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2879 auto *groupWindow = qobject_cast<
const QDockWidgetGroupWindow *>(widget->parentWidget());
2880 if (!widget->isWindow() && groupWindow) {
2881 if (scope == QDockWidgetPrivate::DragScope::Group && groupWindow->tabLayoutInfo()) {
2884 if (QDockAreaLayoutInfo *info = dockInfo(widget->parentWidget())) {
2885 QList<
int> groupWindowPath = info->indexOf(widget->parentWidget());
2886 return groupWindowPath.isEmpty() ?
nullptr : info->item(groupWindowPath).widgetItem;
2888 qCDebug(lcQpaDockWidgets) <<
"Drag only:" << widget <<
"Group:" << (scope == QDockWidgetPrivate::DragScope::Group);
2891 QList<
int> path = groupWindow->layoutInfo()->indexOf(widget);
2892 QDockAreaLayoutItem parentItem = groupWindow->layoutInfo()->item(path);
2893 QLayoutItem *item = parentItem.widgetItem;
2894 if (scope == QDockWidgetPrivate::DragScope::Group && path.size() > 1
2895 && unplugGroup(
this, &item, parentItem)) {
2896 qCDebug(lcQpaDockWidgets) <<
"Unplugging:" << widget <<
"from" << item;
2900 QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget);
2901 Q_ASSERT(dockWidget);
2902 dockWidget->d_func()->unplug(widget->geometry());
2904 qCDebug(lcQpaDockWidgets) <<
"Unplugged from floating dock:" << widget <<
"from" << parentItem.widgetItem;
2909 QList<
int> path = layoutState.indexOf(widget);
2913 QLayoutItem *item = layoutState.item(path);
2914 if (widget->isWindow())
2917 QRect r = layoutState.itemRect(path);
2918 savedState = layoutState;
2920#if QT_CONFIG(dockwidget)
2921 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2922 Q_ASSERT(path.constFirst() == 1);
2923#if QT_CONFIG(tabwidget)
2924 if (scope == QDockWidgetPrivate::DragScope::Group && (dockOptions & QMainWindow::GroupedDragging) && path.size() > 3
2925 && unplugGroup(
this, &item,
2926 layoutState.dockAreaLayout.item(path.mid(1, path.size() - 2)))) {
2928 savedState = layoutState;
2934 switch (dockWidgetArea(dw)) {
2935 case Qt::LeftDockWidgetArea:
2936 case Qt::RightDockWidgetArea:
2937 r.setHeight(r.height() - sep);
2939 case Qt::TopDockWidgetArea:
2940 case Qt::BottomDockWidgetArea:
2941 r.setWidth(r.width() - sep);
2943 case Qt::NoDockWidgetArea:
2944 case Qt::DockWidgetArea_Mask:
2952 const auto *layout = qobject_cast<QDockWidgetLayout *>(dw->layout());
2953 const bool verticalTitleBar = layout ? layout->verticalTitleBar :
false;
2954 const int tbHeight = QApplication::style()
2955 ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight,
nullptr, dw)
2957 const int minHeight = verticalTitleBar ? 2 * tbHeight : tbHeight;
2958 const int minWidth = verticalTitleBar ? tbHeight : 2 * tbHeight;
2959 r.setSize(r.size().expandedTo(QSize(minWidth, minHeight)));
2960 qCDebug(lcQpaDockWidgets) << dw <<
"will be unplugged with size" << r.size();
2962 dw->d_func()->unplug(r);
2966#if QT_CONFIG(toolbar)
2967 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2968 tb->d_func()->unplug(r);
2972#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
2976 layoutState.unplug(path ,&savedState);
2977 savedState.fitLayout();
2978 currentGapPos = path;
2980 updateGapIndicator();
2982 fixToolBarOrientation(item, currentGapPos.at(1));
2987void QMainWindowLayout::updateGapIndicator()
2989#if QT_CONFIG(rubberband)
2990 if (!widgetAnimator.animating() && (!currentGapPos.isEmpty()
2991#if QT_CONFIG(dockwidget)
2992 || currentHoveredFloat
2995 QWidget *expectedParent =
2996#if QT_CONFIG(dockwidget)
2997 currentHoveredFloat ? currentHoveredFloat.data() :
3000 if (!gapIndicator) {
3001 gapIndicator =
new QRubberBand(QRubberBand::Rectangle, expectedParent);
3003 gapIndicator->setObjectName(
"qt_rubberband"_L1);
3004 }
else if (gapIndicator->parent() != expectedParent) {
3005 gapIndicator->setParent(expectedParent);
3009 const bool sigBlockState = gapIndicator->signalsBlocked();
3010 auto resetSignals = qScopeGuard([
this, sigBlockState](){ gapIndicator->blockSignals(sigBlockState); });
3011 gapIndicator->blockSignals(
true);
3013#if QT_CONFIG(dockwidget)
3014 if (currentHoveredFloat)
3015 gapIndicator->setGeometry(currentHoveredFloat->currentGapRect);
3018 gapIndicator->setGeometry(currentGapRect);
3020 gapIndicator->show();
3021 gapIndicator->raise();
3025 }
else if (gapIndicator) {
3026 gapIndicator->hide();
3032void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
3033 const QPoint &mousePos) {
3034 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() ||
3035 pluggingWidget !=
nullptr || hoverTarget ==
nullptr)
3038 QWidget *widget = hoverTarget->widget();
3040#if QT_CONFIG(dockwidget)
3042 if ((dockOptions & QMainWindow::GroupedDragging) && (qobject_cast<QDockWidget*>(widget)
3043 || qobject_cast<QDockWidgetGroupWindow *>(widget))) {
3046 QVarLengthArray<QWidget *, 10> candidates;
3047 const auto siblings = parentWidget()->children();
3048 for (QObject *c : siblings) {
3049 QWidget *w = qobject_cast<QWidget*>(c);
3054 if (!qobject_cast<QDockWidget*>(w) && !qobject_cast<QDockWidgetGroupWindow *>(w))
3060 if (w != widget && w->isWindow() && w->isVisible() && !w->isMinimized())
3063 if (QDockWidgetGroupWindow *group = qobject_cast<QDockWidgetGroupWindow *>(w)) {
3066 const auto groupChildren = group->children();
3067 for (QObject *c : groupChildren) {
3068 if (QDockWidget *dw = qobject_cast<QDockWidget*>(c)) {
3069 if (dw != widget && dw->isFloating() && dw->isVisible() && !dw->isMinimized())
3076 for (QWidget *w : candidates) {
3077 const QScreen *screen1 = qt_widget_private(widget)->associatedScreen();
3078 const QScreen *screen2 = qt_widget_private(w)->associatedScreen();
3079 if (screen1 && screen2 && screen1 != screen2)
3081 if (!w->geometry().contains(mousePos))
3084#if QT_CONFIG(tabwidget)
3085 if (
auto dropTo = qobject_cast<QDockWidget *>(w)) {
3088 w = dropTo->widget();
3091 if (!qobject_cast<QDockWidgetGroupWindow *>(w)) {
3092 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
3093 floatingTabs->setGeometry(dropTo->geometry());
3094 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
3095 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dropTo);
3102 QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(dropTo));
3103 if (dockPosition == QInternal::DockPosition::DockCount)
3104 dockPosition = toDockPos(dockWidgetArea(widget));
3105 if (dockPosition == QInternal::DockPosition::DockCount)
3106 dockPosition = QInternal::DockPosition::RightDock;
3108 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPosition,
3109 Qt::Horizontal, shape,
3110 static_cast<QMainWindow *>(parentWidget()));
3111 info->tabBar = getTabBar();
3112 info->tabbed =
true;
3114 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[dockPosition];
3115 parentInfo.add(floatingTabs);
3116 dropTo->setParent(floatingTabs);
3117 qCDebug(lcQpaDockWidgets) <<
"Wrapping" << widget <<
"into floating tabs" << floatingTabs;
3123 qCDebug(lcQpaDockWidgets) <<
"Showing" << dropTo;
3125 qCDebug(lcQpaDockWidgets) <<
"Raising" << widget;
3128 auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(w);
3129 Q_ASSERT(groupWindow);
3130 if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) {
3131 setCurrentHoveredFloat(groupWindow);
3132 applyState(layoutState);
3140 if (currentHoveredFloat)
3141 currentHoveredFloat->destroyIfSingleItemLeft();
3143 setCurrentHoveredFloat(
nullptr);
3144 layoutState.dockAreaLayout.fallbackToSizeHints =
false;
3147 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
3149 if (!savedState.isValid())
3150 savedState = layoutState;
3152 QList<
int> path = savedState.gapIndex(widget, pos);
3154 if (!path.isEmpty()) {
3155 bool allowed =
false;
3157#if QT_CONFIG(dockwidget)
3158 allowed = isAreaAllowed(widget, path);
3160#if QT_CONFIG(toolbar)
3161 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
3162 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
3169 if (path == currentGapPos)
3172 currentGapPos = path;
3173 if (path.isEmpty()) {
3174 fixToolBarOrientation(hoverTarget, 2);
3179 fixToolBarOrientation(hoverTarget, currentGapPos.at(1));
3181 QMainWindowLayoutState newState = savedState;
3183 if (!newState.insertGap(path, hoverTarget)) {
3188 QSize min = newState.minimumSize();
3189 QSize size = newState.rect.size();
3191 if (min.width() > size.width() || min.height() > size.height()) {
3196 newState.fitLayout();
3198 currentGapRect = newState.gapRect(currentGapPos);
3200#if QT_CONFIG(dockwidget)
3201 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
3203 layoutState = std::move(newState);
3204 applyState(layoutState);
3206 updateGapIndicator();
3209#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3210QDockWidgetGroupWindow *QMainWindowLayout::createTabbedDockWindow()
3212 QDockWidgetGroupWindow* f =
new QDockWidgetGroupWindow(parentWidget(), Qt::Tool);
3213 new QDockWidgetGroupLayout(f);
3218void QMainWindowLayout::applyState(QMainWindowLayoutState &newState,
bool animate)
3225 isInApplyState =
true;
3226#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3227 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
3229 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
3230 for (QDockWidgetGroupWindow *dwgw : groups)
3231 used += dwgw->layoutInfo()->usedTabBars();
3233 const QSet<QTabBar*> retired = usedTabBars - used;
3235 for (QTabBar *tab_bar : retired) {
3236 unuseTabBar(tab_bar);
3240 const QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
3241 const QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
3242 usedSeparatorWidgets = usedSeps;
3243 for (QWidget *sepWidget : retiredSeps)
3247 for (
int i = 0; i < QInternal::DockCount; ++i)
3248 newState.dockAreaLayout.docks[i].reparentWidgets(parentWidget());
3251 newState.apply(dockOptions & QMainWindow::AnimatedDocks && animate);
3252 isInApplyState =
false;
3255void QMainWindowLayout::saveState(QDataStream &stream)
const
3257 layoutState.saveState(stream);
3260bool QMainWindowLayout::restoreState(QDataStream &stream)
3262 QScopedValueRollback<
bool> guard(isInRestoreState,
true);
3263 savedState = layoutState;
3264 layoutState.clear();
3265 layoutState.rect = savedState.rect;
3267 if (!layoutState.restoreState(stream, savedState)) {
3268 layoutState.deleteAllLayoutItems();
3269 layoutState = savedState;
3270 if (parentWidget()->isVisible())
3271 applyState(layoutState,
false);
3275 if (parentWidget()->isVisible()) {
3276 layoutState.fitLayout();
3277 applyState(layoutState,
false);
3280
3281
3282
3283
3284
3285
3286 if ((parentWidget()->windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized))
3287 && !layoutState.fits()) {
3288 restoredState.reset(
new QMainWindowLayoutState(layoutState));
3292 savedState.deleteAllLayoutItems();
3295#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
3296 if (parentWidget()->isVisible())
3303#if QT_CONFIG(draganddrop)
3304bool QMainWindowLayout::needsPlatformDrag()
3306 static const bool wayland =
3307 QGuiApplication::platformName().startsWith(
"wayland"_L1, Qt::CaseInsensitive);
3311Qt::DropAction QMainWindowLayout::performPlatformWidgetDrag(QLayoutItem *widgetItem,
3312 const QPoint &pressPosition)
3314 draggingWidget = widgetItem;
3315 QWidget *widget = widgetItem->widget();
3316 auto drag = QDrag(widget);
3317 auto mimeData =
new QMimeData();
3318 auto window = widgetItem->widget()->windowHandle();
3320 auto serialize = [](
const auto &object) {
3322 QDataStream dataStream(&data, QIODevice::WriteOnly);
3323 dataStream << object;
3326 mimeData->setData(
"application/x-qt-mainwindowdrag-window"_L1,
3327 serialize(
reinterpret_cast<qintptr>(window)));
3328 mimeData->setData(
"application/x-qt-mainwindowdrag-position"_L1, serialize(pressPosition));
3329 drag.setMimeData(mimeData);
3331 auto result = drag.exec();
3333 draggingWidget =
nullptr;
3340#include "qmainwindowlayout.moc"
3341#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