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;
576
577
578
579
580
581
582bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem,
const QPoint &mousePos)
584 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
585 if (savedState.isEmpty())
586 savedState = *layoutInfo();
588 QMainWindow::DockOptions opts =
static_cast<QMainWindow *>(parentWidget())->dockOptions();
589 QDockAreaLayoutInfo newState = savedState;
590 bool nestingEnabled =
591 (opts & QMainWindow::AllowNestedDocks) && !(opts & QMainWindow::ForceTabbedDocks);
592 QDockAreaLayoutInfo::TabMode tabMode =
593#if !QT_CONFIG(tabbar)
594 QDockAreaLayoutInfo::NoTabs;
596 nestingEnabled ? QDockAreaLayoutInfo::AllowTabs : QDockAreaLayoutInfo::ForceTabs;
597 if (
auto group = qobject_cast<QDockWidgetGroupWindow *>(widgetItem->widget())) {
598 if (!group->tabLayoutInfo())
599 tabMode = QDockAreaLayoutInfo::NoTabs;
601 if (newState.tabbed) {
603 newState.item_list = { QDockAreaLayoutItem(
new QDockAreaLayoutInfo(newState)) };
604 newState.item_list.first().size = pick(savedState.o, savedState.rect.size());
605 newState.tabbed =
false;
606 newState.tabBar =
nullptr;
610 auto newGapPos = newState.gapIndex(mousePos, nestingEnabled, tabMode);
611 Q_ASSERT(!newGapPos.isEmpty());
615 if (newGapPos == currentGapPos || newState.hasGapItem(newGapPos))
618 currentGapPos = newGapPos;
619 newState.insertGap(currentGapPos, widgetItem);
621 *layoutInfo() = std::move(newState);
622 updateCurrentGapRect();
623 layoutInfo()->apply(opts & QMainWindow::AnimatedDocks);
627void QDockWidgetGroupWindow::updateCurrentGapRect()
629 if (!currentGapPos.isEmpty())
630 currentGapRect = layoutInfo()->info(currentGapPos)->itemRect(currentGapPos.last(),
true);
634
635
636void QDockWidgetGroupWindow::restore()
638 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
639 if (!savedState.isEmpty()) {
640 *layoutInfo() = savedState;
641 savedState = QDockAreaLayoutInfo();
643 currentGapRect = QRect();
644 currentGapPos.clear();
646 layoutInfo()->fitItems();
647 layoutInfo()->apply(
static_cast<QMainWindow *>(parentWidget())->dockOptions()
648 & QMainWindow::AnimatedDocks);
652
653
654void QDockWidgetGroupWindow::apply()
656 static_cast<QDockWidgetGroupLayout *>(layout())->savedState.clear();
657 currentGapRect = QRect();
658 layoutInfo()->plug(currentGapPos);
659 currentGapPos.clear();
661 layoutInfo()->apply(
false);
664void QDockWidgetGroupWindow::childEvent(QChildEvent *event)
666 switch (event->type()) {
667 case QEvent::ChildRemoved:
668 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
669 dockWidget->removeEventFilter(
this);
670 destroyIfSingleItemLeft();
672 case QEvent::ChildAdded:
673 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
674 dockWidget->installEventFilter(
this);
681bool QDockWidgetGroupWindow::eventFilter(QObject *obj, QEvent *event)
683 auto *dockWidget = qobject_cast<QDockWidget *>(obj);
685 return QWidget::eventFilter(obj, event);
687 switch (event->type()) {
691 reparentToMainWindow(dockWidget);
692 dockWidget->setFloating(
false);
698 if (dockWidget->isVisible())
705 return QWidget::eventFilter(obj, event);
708void QDockWidgetGroupWindow::destroyIfSingleItemLeft()
710 const auto &dockWidgets =
this->dockWidgets();
713 if (dockWidgets.count() != 1)
716 auto *lastDockWidget = dockWidgets.at(0);
721 if (layoutInfo()->indexOf(lastDockWidget).isEmpty())
724 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
725 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
726 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
729 mwLayout->unplug(lastDockWidget, QDockWidgetPrivate::DragScope::Widget);
730 lastDockWidget->setGeometry(geometry());
734 reparentToMainWindow(lastDockWidget);
737 layoutInfo()->deleteAllLayoutItems();
738 layoutInfo()->item_list.clear();
740 destroyOrHideIfEmpty();
743void QDockWidgetGroupWindow::reparentToMainWindow(QDockWidget *dockWidget)
749 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
750 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
751 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
753 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
754 dockWidget->removeEventFilter(
this);
755 parentInfo.add(dockWidget);
756 std::unique_ptr<QLayoutItem> cleanup = layoutInfo()->takeWidgetItem(dockWidget);
757 layoutInfo()->remove(dockWidget);
758 const bool wasFloating = dockWidget->isFloating();
759 const bool wasVisible = dockWidget->isVisible();
760 dockWidget->setParent(mainWindow);
761 dockWidget->setFloating(wasFloating);
762 dockWidget->setVisible(wasVisible);
767
768
772QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win)
774#if QT_CONFIG(toolbar)
775 toolBarAreaLayout(win),
777#if QT_CONFIG(dockwidget)
787QSize QMainWindowLayoutState::sizeHint()
const
792#if QT_CONFIG(dockwidget)
793 result = dockAreaLayout.sizeHint();
795 if (centralWidgetItem)
796 result = centralWidgetItem->sizeHint();
799#if QT_CONFIG(toolbar)
800 result = toolBarAreaLayout.sizeHint(result);
806QSize QMainWindowLayoutState::minimumSize()
const
810#if QT_CONFIG(dockwidget)
811 result = dockAreaLayout.minimumSize();
813 if (centralWidgetItem)
814 result = centralWidgetItem->minimumSize();
817#if QT_CONFIG(toolbar)
818 result = toolBarAreaLayout.minimumSize(result);
825
826
827
828
829bool QMainWindowLayoutState::fits()
const
831 Q_ASSERT(mainWindow);
835#if QT_CONFIG(dockwidget)
836 size = dockAreaLayout.minimumStableSize();
839#if QT_CONFIG(toolbar)
840 size.rwidth() += toolBarAreaLayout.docks[QInternal::LeftDock].rect.width();
841 size.rwidth() += toolBarAreaLayout.docks[QInternal::RightDock].rect.width();
842 size.rheight() += toolBarAreaLayout.docks[QInternal::TopDock].rect.height();
843 size.rheight() += toolBarAreaLayout.docks[QInternal::BottomDock].rect.height();
846 return size.width() <= mainWindow->width() && size.height() <= mainWindow->height();
849void QMainWindowLayoutState::apply(
bool animated)
851#if QT_CONFIG(toolbar)
852 toolBarAreaLayout.apply(animated);
855#if QT_CONFIG(dockwidget)
857 dockAreaLayout.apply(animated);
859 if (centralWidgetItem) {
860 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
862 layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, animated);
867void QMainWindowLayoutState::fitLayout()
870#if !QT_CONFIG(toolbar)
873 toolBarAreaLayout.rect = rect;
874 r = toolBarAreaLayout.fitLayout();
877#if QT_CONFIG(dockwidget)
878 dockAreaLayout.rect = r;
879 dockAreaLayout.fitLayout();
881 centralWidgetRect = r;
885void QMainWindowLayoutState::deleteAllLayoutItems()
887#if QT_CONFIG(toolbar)
888 toolBarAreaLayout.deleteAllLayoutItems();
891#if QT_CONFIG(dockwidget)
892 dockAreaLayout.deleteAllLayoutItems();
896void QMainWindowLayoutState::deleteCentralWidgetItem()
898#if QT_CONFIG(dockwidget)
899 delete dockAreaLayout.centralWidgetItem;
900 dockAreaLayout.centralWidgetItem =
nullptr;
902 delete centralWidgetItem;
903 centralWidgetItem = 0;
907QLayoutItem *QMainWindowLayoutState::itemAt(
int index,
int *x)
const
909#if QT_CONFIG(toolbar)
910 if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
914#if QT_CONFIG(dockwidget)
915 if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
918 if (centralWidgetItem && (*x)++ == index)
919 return centralWidgetItem;
925QLayoutItem *QMainWindowLayoutState::takeAt(
int index,
int *x)
927#if QT_CONFIG(toolbar)
928 if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
932#if QT_CONFIG(dockwidget)
933 if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
936 if (centralWidgetItem && (*x)++ == index) {
937 QLayoutItem *ret = centralWidgetItem;
938 centralWidgetItem =
nullptr;
946QList<
int> QMainWindowLayoutState::indexOf(QWidget *widget)
const
950#if QT_CONFIG(toolbar)
952 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
953 result = toolBarAreaLayout.indexOf(toolBar);
954 if (!result.isEmpty())
960#if QT_CONFIG(dockwidget)
962 if (qobject_cast<QDockWidget *>(widget) || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
963 result = dockAreaLayout.indexOf(widget);
964 if (!result.isEmpty())
973bool QMainWindowLayoutState::contains(QWidget *widget)
const
975#if QT_CONFIG(dockwidget)
976 if (dockAreaLayout.centralWidgetItem !=
nullptr && dockAreaLayout.centralWidgetItem->widget() == widget)
978 if (!dockAreaLayout.indexOf(widget).isEmpty())
981 if (centralWidgetItem && centralWidgetItem->widget() == widget)
985#if QT_CONFIG(toolbar)
986 if (!toolBarAreaLayout.indexOf(widget).isEmpty())
992void QMainWindowLayoutState::setCentralWidget(QWidget *widget)
994 QLayoutItem *item =
nullptr;
996 deleteCentralWidgetItem();
998 if (widget !=
nullptr)
999 item =
new QWidgetItemV2(widget);
1001#if QT_CONFIG(dockwidget)
1002 dockAreaLayout.centralWidgetItem = item;
1004 centralWidgetItem = item;
1008QWidget *QMainWindowLayoutState::centralWidget()
const
1010 QLayoutItem *item =
nullptr;
1012#if QT_CONFIG(dockwidget)
1013 item = dockAreaLayout.centralWidgetItem;
1015 item = centralWidgetItem;
1018 if (item !=
nullptr)
1019 return item->widget();
1023QList<
int> QMainWindowLayoutState::gapIndex(QWidget *widget,
1024 const QPoint &pos)
const
1028#if QT_CONFIG(toolbar)
1030 if (qobject_cast<QToolBar*>(widget) !=
nullptr) {
1031 result = toolBarAreaLayout.gapIndex(pos);
1032 if (!result.isEmpty())
1038#if QT_CONFIG(dockwidget)
1040 if (qobject_cast<QDockWidget *>(widget) !=
nullptr
1041 || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1042 bool disallowTabs =
false;
1043#if QT_CONFIG(tabbar)
1044 if (
auto *group = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1045 if (!group->tabLayoutInfo())
1046 disallowTabs =
true;
1049 result = dockAreaLayout.gapIndex(pos, disallowTabs);
1050 if (!result.isEmpty())
1059bool QMainWindowLayoutState::insertGap(
const QList<
int> &path, QLayoutItem *item)
1064 int i = path.first();
1066#if QT_CONFIG(toolbar)
1068 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) !=
nullptr);
1069 return toolBarAreaLayout.insertGap(path.mid(1), item);
1073#if QT_CONFIG(dockwidget)
1075 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) || qobject_cast<QDockWidgetGroupWindow*>(item->widget()));
1076 return dockAreaLayout.insertGap(path.mid(1), item);
1083void QMainWindowLayoutState::remove(
const QList<
int> &path)
1085 int i = path.first();
1087#if QT_CONFIG(toolbar)
1089 toolBarAreaLayout.remove(path.mid(1));
1092#if QT_CONFIG(dockwidget)
1094 dockAreaLayout.remove(path.mid(1));
1098void QMainWindowLayoutState::remove(QLayoutItem *item)
1100#if QT_CONFIG(toolbar)
1101 toolBarAreaLayout.remove(item);
1104#if QT_CONFIG(dockwidget)
1106 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
1107 QList<
int> path = dockAreaLayout.indexOf(dockWidget);
1108 if (!path.isEmpty())
1109 dockAreaLayout.remove(path);
1114void QMainWindowLayoutState::clear()
1116#if QT_CONFIG(toolbar)
1117 toolBarAreaLayout.clear();
1120#if QT_CONFIG(dockwidget)
1121 dockAreaLayout.clear();
1123 centralWidgetRect = QRect();
1129bool QMainWindowLayoutState::isValid()
const
1131 return rect.isValid();
1134QLayoutItem *QMainWindowLayoutState::item(
const QList<
int> &path)
1136 int i = path.first();
1138#if QT_CONFIG(toolbar)
1140 const QToolBarAreaLayoutItem *tbItem = toolBarAreaLayout.item(path.mid(1));
1142 return tbItem->widgetItem;
1146#if QT_CONFIG(dockwidget)
1148 return dockAreaLayout.item(path.mid(1)).widgetItem;
1154QRect QMainWindowLayoutState::itemRect(
const QList<
int> &path)
const
1156 int i = path.first();
1158#if QT_CONFIG(toolbar)
1160 return toolBarAreaLayout.itemRect(path.mid(1));
1163#if QT_CONFIG(dockwidget)
1165 return dockAreaLayout.itemRect(path.mid(1));
1171QRect QMainWindowLayoutState::gapRect(
const QList<
int> &path)
const
1173 int i = path.first();
1175#if QT_CONFIG(toolbar)
1177 return toolBarAreaLayout.itemRect(path.mid(1));
1180#if QT_CONFIG(dockwidget)
1182 return dockAreaLayout.gapRect(path.mid(1));
1188QLayoutItem *QMainWindowLayoutState::plug(
const QList<
int> &path)
1190 int i = path.first();
1192#if QT_CONFIG(toolbar)
1194 return toolBarAreaLayout.plug(path.mid(1));
1197#if QT_CONFIG(dockwidget)
1199 return dockAreaLayout.plug(path.mid(1));
1205QLayoutItem *QMainWindowLayoutState::unplug(
const QList<
int> &path, QMainWindowLayoutState *other)
1207 int i = path.first();
1209#if !QT_CONFIG(toolbar)
1213 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout :
nullptr);
1216#if QT_CONFIG(dockwidget)
1218 return dockAreaLayout.unplug(path.mid(1));
1224void QMainWindowLayoutState::saveState(QDataStream &stream)
const
1226#if QT_CONFIG(dockwidget)
1227 dockAreaLayout.saveState(stream);
1228#if QT_CONFIG(tabbar)
1229 const QList<QDockWidgetGroupWindow *> floatingTabs =
1230 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
1232 for (QDockWidgetGroupWindow *floating : floatingTabs) {
1233 if (floating->layoutInfo()->isEmpty())
1235 stream << uchar(QDockAreaLayout::FloatingDockWidgetTabMarker) << floating->geometry();
1236 floating->layoutInfo()->saveState(stream);
1240#if QT_CONFIG(toolbar)
1241 toolBarAreaLayout.saveState(stream);
1245template <
typename T>
1251 for (
int i=0; i < list.size(); ++i) {
1252 if (T t = qobject_cast<T>(list[i])) {
1260#if QT_CONFIG(dockwidget)
1261static QList<QDockWidget*> allMyDockWidgets(
const QWidget *mainWindow)
1263 QList<QDockWidget*> result;
1264 for (QObject *c : mainWindow->children()) {
1265 if (
auto *dw = qobject_cast<QDockWidget*>(c)) {
1267 }
else if (
auto *gw = qobject_cast<QDockWidgetGroupWindow*>(c)) {
1268 for (QObject *c : gw->children()) {
1269 if (
auto *dw = qobject_cast<QDockWidget*>(c))
1280bool QMainWindowLayoutState::checkFormat(QDataStream &stream)
1282 while (!stream.atEnd()) {
1287#if QT_CONFIG(toolbar)
1288 case QToolBarAreaLayout::ToolBarStateMarker:
1289 case QToolBarAreaLayout::ToolBarStateMarkerEx:
1291 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1292 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker,
true )) {
1299#if QT_CONFIG(dockwidget)
1300 case QDockAreaLayout::DockWidgetStateMarker:
1302 const auto dockWidgets = allMyDockWidgets(mainWindow);
1303 if (!dockAreaLayout.restoreState(stream, dockWidgets,
true )) {
1308#if QT_CONFIG(tabbar)
1309 case QDockAreaLayout::FloatingDockWidgetTabMarker:
1313 QDockAreaLayoutInfo info;
1314 auto dockWidgets = allMyDockWidgets(mainWindow);
1315 if (!info.restoreState(stream, dockWidgets,
true ))
1331bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
1332 const QMainWindowLayoutState &oldState)
1336 while(!_stream.atEnd()) {
1338 QByteArray ba(length,
'\0');
1339 length = _stream.readRawData(ba.data(), ba.size());
1344 QDataStream ds(copy);
1345 ds.setVersion(_stream.version());
1346 if (!checkFormat(ds))
1349 QDataStream stream(copy);
1350 stream.setVersion(_stream.version());
1352 while (!stream.atEnd()) {
1357#if QT_CONFIG(dockwidget)
1358 case QDockAreaLayout::DockWidgetStateMarker:
1360 const auto dockWidgets = allMyDockWidgets(mainWindow);
1361 if (!dockAreaLayout.restoreState(stream, dockWidgets))
1364 for (
int i = 0; i < dockWidgets.size(); ++i) {
1365 QDockWidget *w = dockWidgets.at(i);
1366 QList<
int> path = dockAreaLayout.indexOf(w);
1367 if (path.isEmpty()) {
1368 QList<
int> oldPath = oldState.dockAreaLayout.indexOf(w);
1369 if (oldPath.isEmpty()) {
1372 QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
1373 if (info ==
nullptr) {
1381#if QT_CONFIG(tabwidget)
1382 case QDockAreaLayout::FloatingDockWidgetTabMarker:
1384 auto dockWidgets = allMyDockWidgets(mainWindow);
1385 QDockWidgetGroupWindow* floatingTab = qt_mainwindow_layout(mainWindow)->createTabbedDockWindow();
1386 *floatingTab->layoutInfo() = QDockAreaLayoutInfo(
1387 &dockAreaLayout.sep, QInternal::LeftDock,
1388 Qt::Horizontal, QTabBar::RoundedSouth, mainWindow);
1391 QDockAreaLayoutInfo *info = floatingTab->layoutInfo();
1392 if (!info->restoreState(stream, dockWidgets,
false))
1394 geometry = QDockAreaLayout::constrainedRect(geometry, floatingTab);
1395 floatingTab->move(geometry.topLeft());
1396 floatingTab->resize(geometry.size());
1400 if (info->onlyHasPlaceholders())
1401 info->reparentWidgets(floatingTab);
1403 floatingTab->show();
1409#if QT_CONFIG(toolbar)
1410 case QToolBarAreaLayout::ToolBarStateMarker:
1411 case QToolBarAreaLayout::ToolBarStateMarkerEx:
1413 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
1414 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker))
1417 for (
int i = 0; i < toolBars.size(); ++i) {
1418 QToolBar *w = toolBars.at(i);
1419 QList<
int> path = toolBarAreaLayout.indexOf(w);
1420 if (path.isEmpty()) {
1421 QList<
int> oldPath = oldState.toolBarAreaLayout.indexOf(w);
1422 if (oldPath.isEmpty()) {
1425 toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(
nullptr, w);
1441
1442
1444#if QT_CONFIG(toolbar)
1446static constexpr Qt::ToolBarArea validateToolBarArea(Qt::ToolBarArea area)
1449 case Qt::LeftToolBarArea:
1450 case Qt::RightToolBarArea:
1451 case Qt::TopToolBarArea:
1452 case Qt::BottomToolBarArea:
1457 return Qt::TopToolBarArea;
1460static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
1463 case Qt::LeftToolBarArea:
return QInternal::LeftDock;
1464 case Qt::RightToolBarArea:
return QInternal::RightDock;
1465 case Qt::TopToolBarArea:
return QInternal::TopDock;
1466 case Qt::BottomToolBarArea:
return QInternal::BottomDock;
1471 return QInternal::DockCount;
1474static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
1477 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1478 case QInternal::RightDock:
return Qt::RightToolBarArea;
1479 case QInternal::TopDock:
return Qt::TopToolBarArea;
1480 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1483 return Qt::NoToolBarArea;
1486static inline Qt::ToolBarArea toToolBarArea(
int pos)
1488 return toToolBarArea(
static_cast<QInternal::DockPosition>(pos));
1491void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
1493 area = validateToolBarArea(area);
1495 layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1496 if (savedState.isValid())
1497 savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1502void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
1504 layoutState.toolBarAreaLayout.insertToolBarBreak(before);
1505 if (savedState.isValid())
1506 savedState.toolBarAreaLayout.insertToolBarBreak(before);
1510void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
1512 layoutState.toolBarAreaLayout.removeToolBarBreak(before);
1513 if (savedState.isValid())
1514 savedState.toolBarAreaLayout.removeToolBarBreak(before);
1518void QMainWindowLayout::moveToolBar(QToolBar *toolbar,
int pos)
1520 layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1521 if (savedState.isValid())
1522 savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1527
1528void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
1531 QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
1532 toolbar, SLOT(_q_updateIconSize(QSize)));
1533 QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
1534 toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
1536 removeWidget(toolbar);
1541
1542
1543void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
1547 area = validateToolBarArea(area);
1549 addChildWidget(toolbar);
1550 QLayoutItem *item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
1551 if (savedState.isValid() && item) {
1553 savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
1558 toolbar->d_func()->updateWindowFlags(
false );
1562
1563
1564void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
1566 addChildWidget(toolbar);
1567 QLayoutItem *item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
1568 if (savedState.isValid() && item) {
1570 savedState.toolBarAreaLayout.insertItem(before, item);
1572 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
1573 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1574 if (!currentGapPos.isEmpty()) {
1575 currentGapPos.prepend(0);
1576 currentGapRect = layoutState.itemRect(currentGapPos);
1582Qt::ToolBarArea QMainWindowLayout::toolBarArea(
const QToolBar *toolbar)
const
1584 QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar);
1586 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1587 case QInternal::RightDock:
return Qt::RightToolBarArea;
1588 case QInternal::TopDock:
return Qt::TopToolBarArea;
1589 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1592 return Qt::NoToolBarArea;
1595bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar)
const
1597 return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
1600void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar)
const
1602 option->toolBarArea = toolBarArea(toolBar);
1603 layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
1606void QMainWindowLayout::toggleToolBarsVisible()
1608 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
1609 if (!layoutState.mainWindow->isMaximized()) {
1610 QPoint topLeft = parentWidget()->geometry().topLeft();
1611 QRect r = parentWidget()->geometry();
1612 r = layoutState.toolBarAreaLayout.rectHint(r);
1614 parentWidget()->setGeometry(r);
1623
1624
1626#if QT_CONFIG(dockwidget)
1628static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area)
1631 case Qt::LeftDockWidgetArea:
return QInternal::LeftDock;
1632 case Qt::RightDockWidgetArea:
return QInternal::RightDock;
1633 case Qt::TopDockWidgetArea:
return QInternal::TopDock;
1634 case Qt::BottomDockWidgetArea:
return QInternal::BottomDock;
1639 return QInternal::DockCount;
1642inline static Qt::DockWidgetArea toDockWidgetArea(
int pos)
1644 return QDockWidgetPrivate::toDockWidgetArea(
static_cast<QInternal::DockPosition>(pos));
1649static bool isAreaAllowed(QWidget *widget,
const QList<
int> &path)
1651 Q_ASSERT_X((path.size() > 1),
"isAreaAllowed",
"invalid path size");
1652 const Qt::DockWidgetArea area = toDockWidgetArea(path[1]);
1655 if (QDockWidget *dw = qobject_cast<QDockWidget *>(widget)) {
1656 const bool allowed = dw->isAreaAllowed(area);
1658 qCDebug(lcQpaDockWidgets) <<
"No permission for single DockWidget" << widget <<
"to dock on" << area;
1663 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1664 const QList<QDockWidget *> children = dwgw->findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly);
1666 if (children.size() == 1) {
1668 const bool allowed = children.at(0)->isAreaAllowed(area);
1670 qCDebug(lcQpaDockWidgets) <<
"No permission for DockWidgetGroupWindow" << widget <<
"to dock on" << area;
1674 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"has" << children.size() <<
"children:";
1675 qCDebug(lcQpaDockWidgets) << children;
1676 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"can dock at" << area <<
"and anywhere else.";
1680 qCDebug(lcQpaDockWidgets) <<
"Docking requested for invalid widget type (coding error)." << widget << area;
1684void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1686 if (layoutState.dockAreaLayout.corners[corner] == area)
1688 layoutState.dockAreaLayout.corners[corner] = area;
1689 if (savedState.isValid())
1690 savedState.dockAreaLayout.corners[corner] = area;
1694Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner)
const
1696 return layoutState.dockAreaLayout.corners[corner];
1702QRect QMainWindowLayout::dockWidgetAreaRect(
const Qt::DockWidgetArea area, DockWidgetAreaSize size)
const
1704 const QInternal::DockPosition dockPosition = toDockPos(area);
1707 if (dockPosition == QInternal::DockCount) {
1708 qCDebug(lcQpaDockWidgets) <<
"QMainWindowLayout::dockWidgetAreaRect called with" << area;
1712 const QDockAreaLayout dl = layoutState.dockAreaLayout;
1715 return (size == Maximum) ? dl.gapRect(dockPosition) : dl.docks[dockPosition].rect;
1719
1720
1721
1722void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1723 QDockWidget *dockwidget,
1724 Qt::Orientation orientation)
1726 addChildWidget(dockwidget);
1730 if (!movingSeparator.isEmpty())
1731 endSeparatorMove(movingSeparatorPos);
1733 layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
1737bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1739 addChildWidget(dockwidget);
1740 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1742 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1747#if QT_CONFIG(tabbar)
1748void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1750 applyRestoredState();
1751 addChildWidget(second);
1752 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1753 emit second->dockLocationChanged(dockWidgetArea(first));
1757bool QMainWindowLayout::documentMode()
const
1759 return _documentMode;
1762void QMainWindowLayout::setDocumentMode(
bool enabled)
1764 if (_documentMode == enabled)
1767 _documentMode = enabled;
1770 for (QTabBar *bar : std::as_const(usedTabBars))
1771 bar->setDocumentMode(_documentMode);
1774void QMainWindowLayout::setVerticalTabsEnabled(
bool enabled)
1776 if (verticalTabsEnabled == enabled)
1779 verticalTabsEnabled = enabled;
1781 updateTabBarShapes();
1784#if QT_CONFIG(tabwidget)
1785QTabWidget::TabShape QMainWindowLayout::tabShape()
const
1790void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1792 if (_tabShape == tabShape)
1795 _tabShape = tabShape;
1797 updateTabBarShapes();
1800QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area)
const
1802 const QInternal::DockPosition dockPos = toDockPos(area);
1803 if (dockPos < QInternal::DockCount)
1804 return tabPositions[dockPos];
1805 qWarning(
"QMainWindowLayout::tabPosition called with out-of-bounds value '%d'",
int(area));
1806 return QTabWidget::North;
1809void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1811 const Qt::DockWidgetArea dockWidgetAreas[] = {
1812 Qt::TopDockWidgetArea,
1813 Qt::LeftDockWidgetArea,
1814 Qt::BottomDockWidgetArea,
1815 Qt::RightDockWidgetArea
1817 const QInternal::DockPosition dockPositions[] = {
1819 QInternal::LeftDock,
1820 QInternal::BottomDock,
1821 QInternal::RightDock
1824 for (
int i = 0; i < QInternal::DockCount; ++i)
1825 if (areas & dockWidgetAreas[i])
1826 tabPositions[dockPositions[i]] = tabPosition;
1828 updateTabBarShapes();
1831QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
1834void QMainWindowLayout::showTabBars()
1836 const auto usedTabBarsCopy = usedTabBars;
1837 for (QTabBar *tab_bar : usedTabBarsCopy) {
1838 if (usedTabBars.contains(tab_bar))
1843void QMainWindowLayout::updateTabBarShapes()
1845#if QT_CONFIG(tabwidget)
1846 const QTabWidget::TabPosition vertical[] = {
1853 const QTabBar::Shape vertical[] = {
1854 QTabBar::RoundedWest,
1855 QTabBar::RoundedEast,
1856 QTabBar::RoundedNorth,
1857 QTabBar::RoundedSouth
1861 QDockAreaLayout &layout = layoutState.dockAreaLayout;
1863 for (
int i = 0; i < QInternal::DockCount; ++i) {
1864#if QT_CONFIG(tabwidget)
1865 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
1866 QTabBar::Shape shape = _q_tb_tabBarShapeFrom(_tabShape, pos);
1868 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
1870 layout.docks[i].setTabBarShape(shape);
1875void QMainWindowLayout::splitDockWidget(QDockWidget *after,
1876 QDockWidget *dockwidget,
1877 Qt::Orientation orientation)
1879 applyRestoredState();
1880 addChildWidget(dockwidget);
1881 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
1882 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
1886Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(
const QWidget *widget)
const
1888 const QList<
int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
1889 if (pathToWidget.isEmpty())
1890 return Qt::NoDockWidgetArea;
1891 return toDockWidgetArea(pathToWidget.first());
1894void QMainWindowLayout::keepSize(QDockWidget *w)
1896 layoutState.dockAreaLayout.keepSize(w);
1899#if QT_CONFIG(tabbar)
1902class QMainWindowTabBar :
public QTabBar
1905 QPointer<QMainWindow> mainWindow;
1906 QPointer<QDockWidget> draggingDock;
1908 QMainWindowTabBar(QMainWindow *parent);
1909 ~QMainWindowTabBar();
1910 QDockWidget *dockAt(
int index)
const;
1911 QList<QDockWidget *> dockWidgets()
const;
1912 bool contains(
const QDockWidget *dockWidget)
const;
1914 bool event(QEvent *e) override;
1915 void mouseReleaseEvent(QMouseEvent*) override;
1916 void mouseMoveEvent(QMouseEvent*) override;
1920QDebug operator<<(QDebug debug,
const QMainWindowTabBar *bar)
1923 return debug <<
"QMainWindowTabBar(0x0)";
1924 QDebugStateSaver saver(debug);
1925 debug.nospace().noquote() <<
"QMainWindowTabBar(" <<
static_cast<
const void *>(bar) <<
", ";
1926 debug.nospace().noquote() <<
"ParentWidget=(" << bar->parentWidget() <<
"), ";
1927 const auto dockWidgets = bar->dockWidgets();
1928 if (dockWidgets.isEmpty())
1929 debug.nospace().noquote() <<
"No QDockWidgets";
1931 debug.nospace().noquote() <<
"DockWidgets(" << dockWidgets <<
")";
1932 debug.nospace().noquote() <<
")";
1936QMainWindowTabBar *QMainWindowLayout::findTabBar(
const QDockWidget *dockWidget)
const
1938 for (
auto *bar : usedTabBars) {
1939 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
1940 auto *tabBar =
static_cast<QMainWindowTabBar *>(bar);
1941 if (tabBar->contains(dockWidget))
1947QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
1948 : QTabBar(parent), mainWindow(parent)
1950 setExpanding(
false);
1953QList<QDockWidget *> QMainWindowTabBar::dockWidgets()
const
1955 QList<QDockWidget *> docks;
1956 for (
int i = 0; i < count(); ++i) {
1957 if (QDockWidget *dock = dockAt(i))
1963bool QMainWindowTabBar::contains(
const QDockWidget *dockWidget)
const
1965 for (
int i = 0; i < count(); ++i) {
1966 if (dockAt(i) == dockWidget)
1977QDockWidget *QMainWindowTabBar::dockAt(
int index)
const
1979 QMainWindowTabBar *that =
const_cast<QMainWindowTabBar *>(
this);
1980 QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
1981 QDockAreaLayoutInfo *info = mlayout ? mlayout->dockInfo(that) :
nullptr;
1985 const int itemIndex = info->tabIndexToListIndex(index);
1986 if (itemIndex >= 0) {
1987 Q_ASSERT(itemIndex < info->item_list.count());
1988 const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
1989 return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) :
nullptr;
1996
1997
1998
1999
2000
2001
2002
2003
2004static void moveToUnplugPosition(QPoint mouse, QDockWidget *dockWidget)
2006 Q_ASSERT(dockWidget);
2008 if (
auto *tbWidget = dockWidget->titleBarWidget()) {
2009 dockWidget->move(mouse - tbWidget->rect().center());
2013 const bool vertical = dockWidget->features().testFlag(QDockWidget::DockWidgetVerticalTitleBar);
2014 const int deltaX = vertical ? QApplication::startDragDistance() : dockWidget->width() / 2;
2015 const int deltaY = vertical ? dockWidget->height() / 2 : QApplication::startDragDistance();
2016 dockWidget->move(mouse - QPoint(deltaX, deltaY));
2019void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
2026 QTabBarPrivate *d =
static_cast<QTabBarPrivate*>(d_ptr.data());
2027 if (!draggingDock && (mainWindow->dockOptions() & QMainWindow::GroupedDragging)) {
2028 int offset = QApplication::startDragDistance() + 1;
2030 QRect r = rect().adjusted(-offset, -offset, offset, offset);
2031 if (d->dragInProgress && !r.contains(e->position().toPoint()) && d->validIndex(d->pressedIndex)) {
2032 draggingDock = dockAt(d->pressedIndex);
2036 d->moveTabFinished(d->pressedIndex);
2037 d->pressedIndex = -1;
2039 d->movingTab->setVisible(
false);
2040 d->dragStartPosition = QPoint();
2043 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2044 QDockWidgetLayout *dwlayout =
static_cast<QDockWidgetLayout *>(draggingDock->layout());
2045 dockPriv->initDrag(dwlayout->titleArea().center(),
true);
2046 dockPriv->startDrag(QDockWidgetPrivate::DragScope::Widget);
2047 if (dockPriv->state)
2048 dockPriv->state->ctrlDrag = e->modifiers() & Qt::ControlModifier;
2054 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2055 if (dockPriv->state && dockPriv->state->dragging) {
2057 moveToUnplugPosition(e->globalPosition().toPoint(), draggingDock);
2060 QTabBar::mouseMoveEvent(e);
2063QMainWindowTabBar::~QMainWindowTabBar()
2067 if (!qobject_cast<QMainWindow *>(mainWindow) || mainWindow == parentWidget())
2072 auto *mwLayout = qt_mainwindow_layout(mainWindow);
2075 mwLayout->usedTabBars.remove(
this);
2078void QMainWindowTabBar::mouseReleaseEvent(QMouseEvent *e)
2080 if (draggingDock && e->button() == Qt::LeftButton) {
2081 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2082 if (dockPriv->state && dockPriv->state->dragging)
2083 dockPriv->endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
2085 draggingDock =
nullptr;
2087 QTabBar::mouseReleaseEvent(e);
2090bool QMainWindowTabBar::event(QEvent *e)
2094 if (e->type() != QEvent::ToolTip)
2095 return QTabBar::event(e);
2096 QSize size =
this->size();
2097 QSize hint = sizeHint();
2098 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
2099 size = size.transposed();
2100 hint = hint.transposed();
2102 if (size.width() < hint.width())
2103 return QTabBar::event(e);
2108QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(
const QDockWidget *dockWidget)
const
2110 const auto *bar = findTabBar(dockWidget);
2114 QList<QDockWidget *> buddies = bar->dockWidgets();
2117 buddies.removeOne(dockWidget);
2121bool QMainWindowLayout::isDockWidgetTabbed(
const QDockWidget *dockWidget)
const
2126 const auto *bar = findTabBar(dockWidget);
2127 return bar && bar->count() > 1;
2130void QMainWindowLayout::unuseTabBar(QTabBar *bar)
2132 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
2136QTabBar *QMainWindowLayout::getTabBar()
2138 if (!usedTabBars.isEmpty() && !isInRestoreState) {
2140
2141
2142
2143
2147 QTabBar *bar =
new QMainWindowTabBar(
static_cast<QMainWindow *>(parentWidget()));
2148 bar->setDrawBase(
true);
2149 bar->setElideMode(Qt::ElideRight);
2150 bar->setDocumentMode(_documentMode);
2151 bar->setMovable(
true);
2152 connect(bar, SIGNAL(currentChanged(
int)),
this, SLOT(tabChanged()));
2153 connect(bar, &QTabBar::tabMoved,
this, &QMainWindowLayout::tabMoved);
2155 usedTabBars.insert(bar);
2159QWidget *QMainWindowLayout::getSeparatorWidget()
2161 auto *separator =
new QWidget(parentWidget());
2162 separator->setAttribute(Qt::WA_MouseNoMask,
true);
2163 separator->setAutoFillBackground(
false);
2164 separator->setObjectName(
"qt_qmainwindow_extended_splitter"_L1);
2165 usedSeparatorWidgets.insert(separator);
2170
2171
2172
2173QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget)
2175 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
2179 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2180 for (QDockWidgetGroupWindow *dwgw : groups) {
2181 info = dwgw->layoutInfo()->info(widget);
2188void QMainWindowLayout::tabChanged()
2190 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2193 QDockAreaLayoutInfo *info = dockInfo(tb);
2194 if (info ==
nullptr)
2197 QDockWidget *activated = info->apply(
false);
2200 emit
static_cast<QMainWindow *>(parentWidget())->tabifiedDockWidgetActivated(activated);
2202 if (
auto dwgw = qobject_cast<QDockWidgetGroupWindow*>(tb->parentWidget()))
2203 dwgw->adjustFlags();
2205 if (QWidget *w = centralWidget())
2209void QMainWindowLayout::tabMoved(
int from,
int to)
2211 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2213 QDockAreaLayoutInfo *info = dockInfo(tb);
2216 info->moveTab(from, to);
2219void QMainWindowLayout::raise(QDockWidget *widget)
2221 QDockAreaLayoutInfo *info = dockInfo(widget);
2222 if (info ==
nullptr)
2226 info->setCurrentTab(widget);
2234
2235
2237int QMainWindowLayout::count()
const
2240 while (itemAt(result))
2245QLayoutItem *QMainWindowLayout::itemAt(
int index)
const
2249 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
2252 if (statusbar && x++ == index)
2258QLayoutItem *QMainWindowLayout::takeAt(
int index)
2262 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
2264 if (QWidget *w = ret->widget()) {
2265 widgetAnimator.abort(w);
2266 if (w == pluggingWidget)
2267 pluggingWidget =
nullptr;
2270 if (savedState.isValid() ) {
2272 savedState.remove(ret);
2274 layoutState.remove(ret);
2277#if QT_CONFIG(toolbar)
2278 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
2279 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
2280 if (!currentGapPos.isEmpty()) {
2281 currentGapPos.prepend(0);
2282 currentGapRect = layoutState.itemRect(currentGapPos);
2290 if (statusbar && x++ == index) {
2291 QLayoutItem *ret = statusbar;
2292 statusbar =
nullptr;
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316void QMainWindowLayout::applyRestoredState()
2318 if (restoredState) {
2319 layoutState = *restoredState;
2320 restoredState.reset();
2321 discardRestoredStateTimer.stop();
2325void QMainWindowLayout::setGeometry(
const QRect &_r)
2329 if (savedState.isValid() || (restoredState && isInApplyState))
2334 QLayout::setGeometry(r);
2337 QRect sbr(QPoint(r.left(), 0),
2338 QSize(r.width(), statusbar->heightForWidth(r.width()))
2339 .expandedTo(statusbar->minimumSize()));
2340 sbr.moveBottom(r.bottom());
2341 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
2342 statusbar->setGeometry(vr);
2343 r.setBottom(sbr.top() - 1);
2346 if (restoredState) {
2348
2349
2350
2351
2352
2353
2354 layoutState = *restoredState;
2355 if (restoredState->fits()) {
2356 restoredState.reset();
2357 discardRestoredStateTimer.stop();
2360
2361
2362
2363
2364
2365
2366
2367
2368 discardRestoredStateTimer.start(150,
this);
2372 layoutState.rect = r;
2374 layoutState.fitLayout();
2375 applyState(layoutState,
false);
2378void QMainWindowLayout::timerEvent(QTimerEvent *e)
2380 if (e->timerId() == discardRestoredStateTimer.timerId()) {
2381 discardRestoredStateTimer.stop();
2382 restoredState.reset();
2384 QLayout::timerEvent(e);
2387void QMainWindowLayout::addItem(QLayoutItem *)
2388{ qWarning(
"QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
2390QSize QMainWindowLayout::sizeHint()
const
2392 if (!szHint.isValid()) {
2393 szHint = layoutState.sizeHint();
2394 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
2395 szHint = QSize(qMax(sbHint.width(), szHint.width()),
2396 sbHint.height() + szHint.height());
2401QSize QMainWindowLayout::minimumSize()
const
2403 if (!minSize.isValid()) {
2404 minSize = layoutState.minimumSize();
2405 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
2406 minSize = QSize(qMax(sbMin.width(), minSize.width()),
2407 sbMin.height() + minSize.height());
2412void QMainWindowLayout::invalidate()
2414 QLayout::invalidate();
2415 minSize = szHint = QSize();
2418#if QT_CONFIG(dockwidget)
2419void QMainWindowLayout::setCurrentHoveredFloat(QDockWidgetGroupWindow *w)
2421 if (currentHoveredFloat != w) {
2422 if (currentHoveredFloat) {
2423 disconnect(currentHoveredFloat.data(), &QObject::destroyed,
2424 this, &QMainWindowLayout::updateGapIndicator);
2425 disconnect(currentHoveredFloat.data(), &QDockWidgetGroupWindow::resized,
2426 this, &QMainWindowLayout::updateGapIndicator);
2427 if (currentHoveredFloat)
2428 currentHoveredFloat->restore();
2433 currentHoveredFloat = w;
2436 connect(w, &QObject::destroyed,
2437 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2438 connect(w, &QDockWidgetGroupWindow::resized,
2439 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2442 updateGapIndicator();
2448
2449
2453#if QT_CONFIG(toolbar)
2454 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
2455 if (toolBar ==
nullptr)
2458 QRect oldGeo = toolBar->geometry();
2460 QInternal::DockPosition pos
2461 =
static_cast<QInternal::DockPosition>(dockPos);
2462 Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
2463 ? Qt::Horizontal : Qt::Vertical;
2464 if (o != toolBar->orientation())
2465 toolBar->setOrientation(o);
2467 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
2468 .expandedTo(toolBar->minimumSize());
2470 if (toolBar->size() != hint) {
2471 QRect newGeo(oldGeo.topLeft(), hint);
2472 if (toolBar->layoutDirection() == Qt::RightToLeft)
2473 newGeo.moveRight(oldGeo.right());
2474 toolBar->setGeometry(newGeo);
2483void QMainWindowLayout::revert(QLayoutItem *widgetItem)
2485 if (!savedState.isValid())
2488 QWidget *widget = widgetItem->widget();
2489 layoutState = savedState;
2490 currentGapPos = layoutState.indexOf(widget);
2491 if (currentGapPos.isEmpty())
2493 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2494 layoutState.unplug(currentGapPos);
2495 layoutState.fitLayout();
2496 currentGapRect = layoutState.itemRect(currentGapPos);
2501bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
2503#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) && QT_CONFIG(tabbar)
2504 if (currentHoveredFloat) {
2505 QWidget *widget = widgetItem->widget();
2506 QList<
int> previousPath = layoutState.indexOf(widget);
2507 if (!previousPath.isEmpty())
2508 layoutState.remove(previousPath);
2509 previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2512 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2513 for (QDockWidgetGroupWindow *dwgw : groups) {
2514 if (dwgw == currentHoveredFloat)
2516 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2517 if (!path.isEmpty())
2518 dwgw->layoutInfo()->remove(path);
2520 currentGapRect = QRect();
2521 currentHoveredFloat->apply();
2522 if (!previousPath.isEmpty())
2523 currentHoveredFloat->layoutInfo()->remove(previousPath);
2524 QRect globalRect = currentHoveredFloat->currentGapRect;
2525 globalRect.moveTopLeft(currentHoveredFloat->mapToGlobal(globalRect.topLeft()));
2526 pluggingWidget = widget;
2527 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2532 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
2535 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2537 QWidget *widget = widgetItem->widget();
2539#if QT_CONFIG(dockwidget)
2542 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2543 for (QDockWidgetGroupWindow *dwgw : groups) {
2544 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2545 if (!path.isEmpty())
2546 dwgw->layoutInfo()->remove(path);
2550 QList<
int> previousPath = layoutState.indexOf(widget);
2552 const QLayoutItem *it = layoutState.plug(currentGapPos);
2555 Q_ASSERT(it == widgetItem);
2556 if (!previousPath.isEmpty())
2557 layoutState.remove(previousPath);
2559 pluggingWidget = widget;
2560 QRect globalRect = currentGapRect;
2561 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
2562#if QT_CONFIG(dockwidget)
2563 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2564 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
2565 if (layout->nativeWindowDeco()) {
2566 globalRect.adjust(0, layout->titleHeight(), 0, 0);
2568 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, widget);
2569 globalRect.adjust(-fw, -fw, fw, fw);
2573 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
2578void QMainWindowLayout::animationFinished(QWidget *widget)
2582#if QT_CONFIG(toolbar)
2583 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2584 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
2585 if (tbl->animating) {
2586 tbl->animating =
false;
2588 tbl->layoutActions(tb->size());
2594 if (widget == pluggingWidget) {
2596#if QT_CONFIG(dockwidget)
2597#if QT_CONFIG(tabbar)
2598 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
2602 QDockAreaLayoutInfo *srcInfo = dwgw->layoutInfo();
2603 const QDockAreaLayoutInfo *srcTabInfo = dwgw->tabLayoutInfo();
2604 QDockAreaLayoutInfo *dstParentInfo;
2607 if (currentHoveredFloat) {
2608 dstPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2609 Q_ASSERT(dstPath.size() >= 1);
2610 dstParentInfo = currentHoveredFloat->layoutInfo()->info(dstPath);
2612 dstPath = layoutState.dockAreaLayout.indexOf(widget);
2613 Q_ASSERT(dstPath.size() >= 2);
2614 dstParentInfo = layoutState.dockAreaLayout.info(dstPath);
2616 Q_ASSERT(dstParentInfo);
2617 int idx = dstPath.constLast();
2618 Q_ASSERT(dstParentInfo->item_list[idx].widgetItem->widget() == dwgw);
2619 if (dstParentInfo->tabbed && srcTabInfo) {
2621 delete dstParentInfo->item_list[idx].widgetItem;
2622 dstParentInfo->item_list.removeAt(idx);
2623 std::copy(srcTabInfo->item_list.cbegin(), srcTabInfo->item_list.cend(),
2624 std::inserter(dstParentInfo->item_list,
2625 dstParentInfo->item_list.begin() + idx));
2626 quintptr currentId = srcTabInfo->currentTabId();
2627 *srcInfo = QDockAreaLayoutInfo();
2628 dstParentInfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2630 dstParentInfo->updateTabBar();
2631 dstParentInfo->setCurrentTabId(currentId);
2633 QDockAreaLayoutItem &item = dstParentInfo->item_list[idx];
2634 Q_ASSERT(item.widgetItem->widget() == dwgw);
2635 delete item.widgetItem;
2636 item.widgetItem =
nullptr;
2637 item.subinfo =
new QDockAreaLayoutInfo(std::move(*srcInfo));
2638 *srcInfo = QDockAreaLayoutInfo();
2639 item.subinfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2641 item.subinfo->setTabBarShape(dstParentInfo->tabBarShape);
2643 dwgw->destroyOrHideIfEmpty();
2647 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2648 dw->setParent(currentHoveredFloat ? currentHoveredFloat.data() : parentWidget());
2650 dw->d_func()->plug(currentGapRect);
2653#if QT_CONFIG(toolbar)
2654 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
2655 tb->d_func()->plug(currentGapRect);
2659 currentGapPos.clear();
2660 pluggingWidget =
nullptr;
2661#if QT_CONFIG(dockwidget)
2662 setCurrentHoveredFloat(
nullptr);
2666 layoutState.apply(
false);
2668#if QT_CONFIG(dockwidget)
2669#if QT_CONFIG(tabbar)
2670 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2673 if (QDockAreaLayoutInfo *info = dockInfo(widget))
2674 info->setCurrentTab(widget);
2680 if (!widgetAnimator.animating()) {
2682#if QT_CONFIG(dockwidget)
2683 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
2684#if QT_CONFIG(tabbar)
2690 updateGapIndicator();
2693void QMainWindowLayout::restore(
bool keepSavedState)
2695 if (!savedState.isValid())
2698 layoutState = savedState;
2699 applyState(layoutState);
2700 if (!keepSavedState)
2702 currentGapPos.clear();
2703 pluggingWidget =
nullptr;
2704 updateGapIndicator();
2707QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout)
2708 : QLayout(parentLayout ?
static_cast<QWidget *>(
nullptr) : mainwindow)
2709 , layoutState(mainwindow)
2710 , savedState(mainwindow)
2711 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
2712 , statusbar(
nullptr)
2713#if QT_CONFIG(dockwidget)
2714#if QT_CONFIG(tabbar)
2715 , _documentMode(
false)
2716 , verticalTabsEnabled(
false)
2717#if QT_CONFIG(tabwidget)
2718 , _tabShape(QTabWidget::Rounded)
2722 , widgetAnimator(
this)
2723 , pluggingWidget(
nullptr)
2726 setParent(parentLayout);
2728#if QT_CONFIG(dockwidget)
2729#if QT_CONFIG(tabbar)
2730 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent,
nullptr, mainwindow);
2733#if QT_CONFIG(tabwidget)
2734 for (
int i = 0; i < QInternal::DockCount; ++i)
2735 tabPositions[i] = QTabWidget::South;
2738 pluggingWidget =
nullptr;
2740 setObjectName(mainwindow->objectName() +
"_layout"_L1);
2743QMainWindowLayout::~QMainWindowLayout()
2745 layoutState.deleteAllLayoutItems();
2746 layoutState.deleteCentralWidgetItem();
2751void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
2753 if (opts == dockOptions)
2758#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
2759 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
2765#if QT_CONFIG(statusbar)
2766QStatusBar *QMainWindowLayout::statusBar()
const
2767{
return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
2769void QMainWindowLayout::setStatusBar(QStatusBar *sb)
2774 statusbar = sb ?
new QWidgetItemV2(sb) :
nullptr;
2779QWidget *QMainWindowLayout::centralWidget()
const
2781 return layoutState.centralWidget();
2784void QMainWindowLayout::setCentralWidget(QWidget *widget)
2786 if (widget !=
nullptr)
2787 addChildWidget(widget);
2788 layoutState.setCentralWidget(widget);
2789 if (savedState.isValid()) {
2790#if QT_CONFIG(dockwidget)
2791 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
2792 savedState.dockAreaLayout.fallbackToSizeHints =
true;
2794 savedState.centralWidgetItem = layoutState.centralWidgetItem;
2800#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2802
2803
2804
2805
2806
2807
2808static bool unplugGroup(QMainWindowLayout *layout, QLayoutItem **item,
2809 QDockAreaLayoutItem &parentItem)
2811 if (!parentItem.subinfo || !parentItem.subinfo->tabbed)
2815 QDockWidgetGroupWindow *floatingTabs = layout->createTabbedDockWindow();
2816 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
2817 *info = std::move(*parentItem.subinfo);
2818 delete parentItem.subinfo;
2819 parentItem.subinfo =
nullptr;
2820 floatingTabs->setGeometry(info->rect.translated(layout->parentWidget()->pos()));
2821 floatingTabs->show();
2822 floatingTabs->raise();
2823 *item =
new QDockWidgetGroupWindowItem(floatingTabs);
2824 parentItem.widgetItem = *item;
2829#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2830static QTabBar::Shape tabwidgetPositionToTabBarShape(QWidget *w)
2832 QTabBar::Shape result = QTabBar::RoundedSouth;
2833 if (qobject_cast<QDockWidget *>(w)) {
2834 switch (
static_cast<QDockWidgetPrivate *>(qt_widget_private(w))->tabPosition) {
2835 case QTabWidget::North:
2836 result = QTabBar::RoundedNorth;
2838 case QTabWidget::South:
2839 result = QTabBar::RoundedSouth;
2841 case QTabWidget::West:
2842 result = QTabBar::RoundedWest;
2844 case QTabWidget::East:
2845 result = QTabBar::RoundedEast;
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope)
2865#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2866 auto *groupWindow = qobject_cast<
const QDockWidgetGroupWindow *>(widget->parentWidget());
2867 if (!widget->isWindow() && groupWindow) {
2868 if (scope == QDockWidgetPrivate::DragScope::Group && groupWindow->tabLayoutInfo()) {
2871 if (QDockAreaLayoutInfo *info = dockInfo(widget->parentWidget())) {
2872 QList<
int> groupWindowPath = info->indexOf(widget->parentWidget());
2873 return groupWindowPath.isEmpty() ?
nullptr : info->item(groupWindowPath).widgetItem;
2875 qCDebug(lcQpaDockWidgets) <<
"Drag only:" << widget <<
"Group:" << (scope == QDockWidgetPrivate::DragScope::Group);
2878 QList<
int> path = groupWindow->layoutInfo()->indexOf(widget);
2879 QDockAreaLayoutItem parentItem = groupWindow->layoutInfo()->item(path);
2880 QLayoutItem *item = parentItem.widgetItem;
2881 if (scope == QDockWidgetPrivate::DragScope::Group && path.size() > 1
2882 && unplugGroup(
this, &item, parentItem)) {
2883 qCDebug(lcQpaDockWidgets) <<
"Unplugging:" << widget <<
"from" << item;
2887 QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget);
2888 Q_ASSERT(dockWidget);
2889 dockWidget->d_func()->unplug(widget->geometry());
2891 qCDebug(lcQpaDockWidgets) <<
"Unplugged from floating dock:" << widget <<
"from" << parentItem.widgetItem;
2896 QList<
int> path = layoutState.indexOf(widget);
2900 QLayoutItem *item = layoutState.item(path);
2901 if (widget->isWindow())
2904 QRect r = layoutState.itemRect(path);
2905 savedState = layoutState;
2907#if QT_CONFIG(dockwidget)
2908 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2909 Q_ASSERT(path.constFirst() == 1);
2910#if QT_CONFIG(tabwidget)
2911 if (scope == QDockWidgetPrivate::DragScope::Group && (dockOptions & QMainWindow::GroupedDragging) && path.size() > 3
2912 && unplugGroup(
this, &item,
2913 layoutState.dockAreaLayout.item(path.mid(1, path.size() - 2)))) {
2915 savedState = layoutState;
2921 switch (dockWidgetArea(dw)) {
2922 case Qt::LeftDockWidgetArea:
2923 case Qt::RightDockWidgetArea:
2924 r.setHeight(r.height() - sep);
2926 case Qt::TopDockWidgetArea:
2927 case Qt::BottomDockWidgetArea:
2928 r.setWidth(r.width() - sep);
2930 case Qt::NoDockWidgetArea:
2931 case Qt::DockWidgetArea_Mask:
2939 const auto *layout = qobject_cast<QDockWidgetLayout *>(dw->layout());
2940 const bool verticalTitleBar = layout ? layout->verticalTitleBar :
false;
2941 const int tbHeight = QApplication::style()
2942 ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight,
nullptr, dw)
2944 const int minHeight = verticalTitleBar ? 2 * tbHeight : tbHeight;
2945 const int minWidth = verticalTitleBar ? tbHeight : 2 * tbHeight;
2946 r.setSize(r.size().expandedTo(QSize(minWidth, minHeight)));
2947 qCDebug(lcQpaDockWidgets) << dw <<
"will be unplugged with size" << r.size();
2949 dw->d_func()->unplug(r);
2953#if QT_CONFIG(toolbar)
2954 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2955 tb->d_func()->unplug(r);
2959#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
2963 layoutState.unplug(path ,&savedState);
2964 savedState.fitLayout();
2965 currentGapPos = path;
2967 updateGapIndicator();
2969 fixToolBarOrientation(item, currentGapPos.at(1));
2974void QMainWindowLayout::updateGapIndicator()
2976#if QT_CONFIG(rubberband)
2977 if (!widgetAnimator.animating() && (!currentGapPos.isEmpty()
2978#if QT_CONFIG(dockwidget)
2979 || currentHoveredFloat
2982 QWidget *expectedParent =
2983#if QT_CONFIG(dockwidget)
2984 currentHoveredFloat ? currentHoveredFloat.data() :
2987 if (!gapIndicator) {
2988 gapIndicator =
new QRubberBand(QRubberBand::Rectangle, expectedParent);
2990 gapIndicator->setObjectName(
"qt_rubberband"_L1);
2991 }
else if (gapIndicator->parent() != expectedParent) {
2992 gapIndicator->setParent(expectedParent);
2996 const bool sigBlockState = gapIndicator->signalsBlocked();
2997 auto resetSignals = qScopeGuard([
this, sigBlockState](){ gapIndicator->blockSignals(sigBlockState); });
2998 gapIndicator->blockSignals(
true);
3000#if QT_CONFIG(dockwidget)
3001 if (currentHoveredFloat)
3002 gapIndicator->setGeometry(currentHoveredFloat->currentGapRect);
3005 gapIndicator->setGeometry(currentGapRect);
3007 gapIndicator->show();
3008 gapIndicator->raise();
3012 }
else if (gapIndicator) {
3013 gapIndicator->hide();
3019void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
3020 const QPoint &mousePos) {
3021 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() ||
3022 pluggingWidget !=
nullptr || hoverTarget ==
nullptr)
3025 QWidget *widget = hoverTarget->widget();
3027#if QT_CONFIG(dockwidget)
3029 if ((dockOptions & QMainWindow::GroupedDragging) && (qobject_cast<QDockWidget*>(widget)
3030 || qobject_cast<QDockWidgetGroupWindow *>(widget))) {
3033 QVarLengthArray<QWidget *, 10> candidates;
3034 const auto siblings = parentWidget()->children();
3035 for (QObject *c : siblings) {
3036 QWidget *w = qobject_cast<QWidget*>(c);
3041 if (!qobject_cast<QDockWidget*>(w) && !qobject_cast<QDockWidgetGroupWindow *>(w))
3047 if (w != widget && w->isWindow() && w->isVisible() && !w->isMinimized())
3050 if (QDockWidgetGroupWindow *group = qobject_cast<QDockWidgetGroupWindow *>(w)) {
3053 const auto groupChildren = group->children();
3054 for (QObject *c : groupChildren) {
3055 if (QDockWidget *dw = qobject_cast<QDockWidget*>(c)) {
3056 if (dw != widget && dw->isFloating() && dw->isVisible() && !dw->isMinimized())
3063 for (QWidget *w : candidates) {
3064 const QScreen *screen1 = qt_widget_private(widget)->associatedScreen();
3065 const QScreen *screen2 = qt_widget_private(w)->associatedScreen();
3066 if (screen1 && screen2 && screen1 != screen2)
3068 if (!w->geometry().contains(mousePos))
3071#if QT_CONFIG(tabwidget)
3072 if (
auto dropTo = qobject_cast<QDockWidget *>(w)) {
3075 w = dropTo->widget();
3078 if (!qobject_cast<QDockWidgetGroupWindow *>(w)) {
3079 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
3080 floatingTabs->setGeometry(dropTo->geometry());
3081 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
3082 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dropTo);
3089 QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(dropTo));
3090 if (dockPosition == QInternal::DockPosition::DockCount)
3091 dockPosition = toDockPos(dockWidgetArea(widget));
3092 if (dockPosition == QInternal::DockPosition::DockCount)
3093 dockPosition = QInternal::DockPosition::RightDock;
3095 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPosition,
3096 Qt::Horizontal, shape,
3097 static_cast<QMainWindow *>(parentWidget()));
3098 info->tabBar = getTabBar();
3099 info->tabbed =
true;
3101 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[dockPosition];
3102 parentInfo.add(floatingTabs);
3103 dropTo->setParent(floatingTabs);
3104 qCDebug(lcQpaDockWidgets) <<
"Wrapping" << widget <<
"into floating tabs" << floatingTabs;
3110 qCDebug(lcQpaDockWidgets) <<
"Showing" << dropTo;
3112 qCDebug(lcQpaDockWidgets) <<
"Raising" << widget;
3115 auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(w);
3116 Q_ASSERT(groupWindow);
3117 if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) {
3118 setCurrentHoveredFloat(groupWindow);
3119 applyState(layoutState);
3127 if (currentHoveredFloat)
3128 currentHoveredFloat->destroyIfSingleItemLeft();
3130 setCurrentHoveredFloat(
nullptr);
3131 layoutState.dockAreaLayout.fallbackToSizeHints =
false;
3134 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
3136 if (!savedState.isValid())
3137 savedState = layoutState;
3139 QList<
int> path = savedState.gapIndex(widget, pos);
3141 if (!path.isEmpty()) {
3142 bool allowed =
false;
3144#if QT_CONFIG(dockwidget)
3145 allowed = isAreaAllowed(widget, path);
3147#if QT_CONFIG(toolbar)
3148 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
3149 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
3156 if (path == currentGapPos)
3159 currentGapPos = path;
3160 if (path.isEmpty()) {
3161 fixToolBarOrientation(hoverTarget, 2);
3166 fixToolBarOrientation(hoverTarget, currentGapPos.at(1));
3168 QMainWindowLayoutState newState = savedState;
3170 if (!newState.insertGap(path, hoverTarget)) {
3175 QSize min = newState.minimumSize();
3176 QSize size = newState.rect.size();
3178 if (min.width() > size.width() || min.height() > size.height()) {
3183 newState.fitLayout();
3185 currentGapRect = newState.gapRect(currentGapPos);
3187#if QT_CONFIG(dockwidget)
3188 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
3190 layoutState = std::move(newState);
3191 applyState(layoutState);
3193 updateGapIndicator();
3196#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3197QDockWidgetGroupWindow *QMainWindowLayout::createTabbedDockWindow()
3199 QDockWidgetGroupWindow* f =
new QDockWidgetGroupWindow(parentWidget(), Qt::Tool);
3200 new QDockWidgetGroupLayout(f);
3205void QMainWindowLayout::applyState(QMainWindowLayoutState &newState,
bool animate)
3212 isInApplyState =
true;
3213#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3214 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
3216 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
3217 for (QDockWidgetGroupWindow *dwgw : groups)
3218 used += dwgw->layoutInfo()->usedTabBars();
3220 const QSet<QTabBar*> retired = usedTabBars - used;
3222 for (QTabBar *tab_bar : retired) {
3223 unuseTabBar(tab_bar);
3227 const QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
3228 const QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
3229 usedSeparatorWidgets = usedSeps;
3230 for (QWidget *sepWidget : retiredSeps)
3234 for (
int i = 0; i < QInternal::DockCount; ++i)
3235 newState.dockAreaLayout.docks[i].reparentWidgets(parentWidget());
3238 newState.apply(dockOptions & QMainWindow::AnimatedDocks && animate);
3239 isInApplyState =
false;
3242void QMainWindowLayout::saveState(QDataStream &stream)
const
3244 layoutState.saveState(stream);
3247bool QMainWindowLayout::restoreState(QDataStream &stream)
3249 QScopedValueRollback<
bool> guard(isInRestoreState,
true);
3250 savedState = layoutState;
3251 layoutState.clear();
3252 layoutState.rect = savedState.rect;
3254 if (!layoutState.restoreState(stream, savedState)) {
3255 layoutState.deleteAllLayoutItems();
3256 layoutState = savedState;
3257 if (parentWidget()->isVisible())
3258 applyState(layoutState,
false);
3262 if (parentWidget()->isVisible()) {
3263 layoutState.fitLayout();
3264 applyState(layoutState,
false);
3267
3268
3269
3270
3271
3272
3273 if ((parentWidget()->windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized))
3274 && !layoutState.fits()) {
3275 restoredState.reset(
new QMainWindowLayoutState(layoutState));
3279 savedState.deleteAllLayoutItems();
3282#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
3283 if (parentWidget()->isVisible())
3290#if QT_CONFIG(draganddrop)
3291bool QMainWindowLayout::needsPlatformDrag()
3293 static const bool wayland =
3294 QGuiApplication::platformName().startsWith(
"wayland"_L1, Qt::CaseInsensitive);
3298Qt::DropAction QMainWindowLayout::performPlatformWidgetDrag(QLayoutItem *widgetItem,
3299 const QPoint &pressPosition)
3301 draggingWidget = widgetItem;
3302 QWidget *widget = widgetItem->widget();
3303 auto drag = QDrag(widget);
3304 auto mimeData =
new QMimeData();
3305 auto window = widgetItem->widget()->windowHandle();
3307 auto serialize = [](
const auto &object) {
3309 QDataStream dataStream(&data, QIODevice::WriteOnly);
3310 dataStream << object;
3313 mimeData->setData(
"application/x-qt-mainwindowdrag-window"_L1,
3314 serialize(
reinterpret_cast<qintptr>(window)));
3315 mimeData->setData(
"application/x-qt-mainwindowdrag-position"_L1, serialize(pressPosition));
3316 drag.setMimeData(mimeData);
3318 auto result = drag.exec();
3320 draggingWidget =
nullptr;
3327#include "qmainwindowlayout.moc"
3328#include "moc_qmainwindowlayout_p.cpp"
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *mainWindow)
static void fixToolBarOrientation(QLayoutItem *item, int dockPos)
static QList< T > findChildrenHelper(const QObject *o)
QList< QObject * > QObjectList