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"
19#if QT_CONFIG(rubberband)
20#include "qrubberband.h"
26#include <qapplication.h>
27#if QT_CONFIG(draganddrop)
31#if QT_CONFIG(statusbar)
32#include <qstatusbar.h>
36#include <qstylepainter.h>
37#include <qvarlengtharray.h>
42#ifndef QT_NO_DEBUG_STREAM
44# include <qtextstream.h>
47#include <private/qmenu_p.h>
48#include <private/qapplication_p.h>
49#include <private/qlayoutengine_p.h>
50#include <private/qwidgetresizehandler_p.h>
52#include <qpa/qplatformwindow_p.h>
54#include <QScopedValueRollback>
58Q_LOGGING_CATEGORY(lcMainWindowLayout,
"qt.mainwindow.layout");
60#if defined(Q_OS_MACOS)
61Q_STATIC_LOGGING_CATEGORY(lcUnifiedToolBar,
"qt.mainwindow.unifiedtoolbar");
65using StateMarkers = QMainWindowLayoutState::StateMarkers;
68using StateMarkers = QMainWindowLayoutState::StateMarkers;
72 return options.testFlag(QMainWindow::AnimatedDocks) ? QWidgetAnimator::AnimationRule::Run
73 : QWidgetAnimator::AnimationRule::Stop;
77
78
80#if QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG_STREAM)
82static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent);
84static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutItem &item, QString indent)
86 qout << indent <<
"QDockAreaLayoutItem: "
87 <<
"pos: " << item.pos <<
" size:" << item.size
88 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
89 <<
" keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) <<
'\n';
91 if (item.widgetItem !=
nullptr) {
92 qout << indent <<
"widget: "
93 << item.widgetItem->widget()->metaObject()->className()
94 <<
" \"" << item.widgetItem->widget()->windowTitle() <<
"\"\n";
95 }
else if (item.subinfo !=
nullptr) {
96 qout << indent <<
"subinfo:\n";
97 dumpLayout(qout, *item.subinfo, indent +
" "_L1);
98 }
else if (item.placeHolderItem !=
nullptr) {
99 QRect r = item.placeHolderItem->topLevelRect;
100 qout << indent <<
"placeHolder: "
101 <<
"pos: " << item.pos <<
" size:" << item.size
102 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
103 <<
" keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize)
104 <<
" objectName:" << item.placeHolderItem->objectName
105 <<
" hidden:" << item.placeHolderItem->hidden
106 <<
" window:" << item.placeHolderItem->window
107 <<
" rect:" << r.x() <<
',' << r.y() <<
' '
108 << r.width() <<
'x' << r.height() <<
'\n';
112static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent)
114 const QSize minSize = layout.minimumSize();
115 qout << indent <<
"QDockAreaLayoutInfo: "
116 << layout.rect.left() <<
','
117 << layout.rect.top() <<
' '
118 << layout.rect.width() <<
'x'
119 << layout.rect.height()
120 <<
" min size: " << minSize.width() <<
',' << minSize.height()
121 <<
" orient:" << layout.o
123 <<
" tabbed:" << layout.tabbed
124 <<
" tbshape:" << layout.tabBarShape
130 for (
int i = 0; i < layout.item_list.size(); ++i) {
131 qout << indent <<
"Item: " << i <<
'\n';
132 dumpLayout(qout, layout.item_list.at(i), indent +
" "_L1);
136static void dumpLayout(QTextStream &qout,
const QDockAreaLayout &layout)
138 qout <<
"QDockAreaLayout: "
139 << layout.rect.left() <<
','
140 << layout.rect.top() <<
' '
141 << layout.rect.width() <<
'x'
142 << layout.rect.height() <<
'\n';
144 qout <<
"TopDockArea:\n";
145 dumpLayout(qout, layout.docks[QInternal::TopDock],
" "_L1);
146 qout <<
"LeftDockArea:\n";
147 dumpLayout(qout, layout.docks[QInternal::LeftDock],
" "_L1);
148 qout <<
"RightDockArea:\n";
149 dumpLayout(qout, layout.docks[QInternal::RightDock],
" "_L1);
150 qout <<
"BottomDockArea:\n";
151 dumpLayout(qout, layout.docks[QInternal::BottomDock],
" "_L1);
154QDebug operator<<(QDebug debug,
const QDockAreaLayout &layout)
158 dumpLayout(str, layout);
163QDebug operator<<(QDebug debug,
const QMainWindowLayout *layout)
166 return std::move(debug) << layout->layoutState.dockAreaLayout;
167 return debug <<
"QMainWindowLayout(0x0)";
173static void dumpItemLists(
const QMainWindowLayout *layout,
const char *function,
const char *comment)
175 for (
int i = 0; i < QInternal::DockCount; ++i) {
176 const auto &list = layout->layoutState.dockAreaLayout.docks[i].item_list;
179 qDebug() << function << comment <<
"Dock" << i << list;
182#define DUMP(comment) dumpItemLists(this, __FUNCTION__, comment)
187#ifndef QT_NO_DEBUG_STREAM
188QDebug operator<<(QDebug debug, StateMarkers marker)
190#define CASE(val) case QMainWindowLayoutState::StateMarkers::val:
191 debug.noquote().nospace() << "StateMarkers::" << #val;
194 QDebugStateSaver saver(debug);
196 CASE(FloatingDockWidgetTab);
209 stream << uchar(marker);
210 qCDebug(lcMainWindowLayout) <<
"Writing state marker" << marker;
218 marker =
static_cast<StateMarkers>(m);
219 qCDebug(lcMainWindowLayout) <<
"Reading state marker" << marker;
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
257#if QT_CONFIG(dockwidget)
258class QDockWidgetGroupLayout :
public QLayout,
259 public QMainWindowLayoutSeparatorHelper<QDockWidgetGroupLayout>
261 QWidgetResizeHandler *resizer;
263 QDockWidgetGroupLayout(QDockWidgetGroupWindow* parent) : QLayout(parent) {
264 setSizeConstraint(QLayout::SetMinAndMaxSize);
265 resizer =
new QWidgetResizeHandler(parent);
267 ~QDockWidgetGroupLayout() {
268 layoutState.deleteAllLayoutItems();
271 void addItem(QLayoutItem*) override { Q_UNREACHABLE(); }
272 int count()
const override {
return 0; }
273 QLayoutItem* itemAt(
int index)
const override
276 return layoutState.itemAt(&x, index);
278 QLayoutItem* takeAt(
int index) override
281 QLayoutItem *ret = layoutState.takeAt(&x, index);
282 if (savedState.rect.isValid() && ret->widget()) {
284 QList<
int> path = savedState.indexOf(ret->widget());
286 savedState.remove(path);
288 path = layoutState.indexOf(ret->widget());
290 layoutState.remove(path);
294 QSize sizeHint()
const override
296 int fw = frameWidth();
297 return layoutState.sizeHint() + QSize(fw, fw);
299 QSize minimumSize()
const override
301 int fw = frameWidth();
302 return layoutState.minimumSize() + QSize(fw, fw);
304 QSize maximumSize()
const override
306 int fw = frameWidth();
307 return layoutState.maximumSize() + QSize(fw, fw);
309 void setGeometry(
const QRect&r) override
311 groupWindow()->destroyOrHideIfEmpty();
312 QDockAreaLayoutInfo *li = dockAreaLayoutInfo();
315 int fw = frameWidth();
317 li->reparentWidgets(parentWidget());
319 li->rect = r.adjusted(fw, fw, -fw, -fw);
321 li->apply(QWidgetAnimator::AnimationRule::Stop);
322 if (savedState.rect.isValid())
323 savedState.rect = li->rect;
324 resizer->setEnabled(!nativeWindowDeco());
327 QDockAreaLayoutInfo *dockAreaLayoutInfo() {
return &layoutState; }
329#if QT_CONFIG(toolbar)
330 QToolBarAreaLayout *toolBarAreaLayout()
336 bool nativeWindowDeco()
const
338 return groupWindow()->hasNativeDecos();
341 int frameWidth()
const
343 return nativeWindowDeco() ? 0 :
344 parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, parentWidget());
347 QDockWidgetGroupWindow *groupWindow()
const
349 return static_cast<QDockWidgetGroupWindow *>(parent());
352 QDockAreaLayoutInfo layoutState;
353 QDockAreaLayoutInfo savedState;
356bool QDockWidgetGroupWindow::event(QEvent *e)
358 auto lay =
static_cast<QDockWidgetGroupLayout *>(layout());
359 if (lay && lay->windowEvent(e))
366 if (QDockWidget *dw = activeTabbedDockWidget()) {
375 if (QDockWidget *dw = activeTabbedDockWidget())
376 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->moveEvent(
static_cast<QMoveEvent*>(e));
379 case QEvent::NonClientAreaMouseMove:
380 case QEvent::NonClientAreaMouseButtonPress:
381 case QEvent::NonClientAreaMouseButtonRelease:
382 case QEvent::NonClientAreaMouseButtonDblClick:
385 if (QDockWidget *dw = activeTabbedDockWidget())
386 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->nonClientAreaMouseEvent(
static_cast<QMouseEvent*>(e));
389 case QEvent::ChildAdded:
390 if (qobject_cast<QDockWidget *>(
static_cast<QChildEvent*>(e)->child()))
393 case QEvent::LayoutRequest:
395 destroyOrHideIfEmpty();
398 updateCurrentGapRect();
404 return QWidget::event(e);
407void QDockWidgetGroupWindow::paintEvent(QPaintEvent *)
409 QDockWidgetGroupLayout *lay =
static_cast<QDockWidgetGroupLayout *>(layout());
410 bool nativeDeco = lay->nativeWindowDeco();
413 QStyleOptionFrame framOpt;
414 framOpt.initFrom(
this);
415 QStylePainter p(
this);
416 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
420QDockAreaLayoutInfo *QDockWidgetGroupWindow::layoutInfo()
const
422 return static_cast<QDockWidgetGroupLayout *>(layout())->dockAreaLayoutInfo();
427
428
429
430
431const QDockAreaLayoutInfo *QDockWidgetGroupWindow::tabLayoutInfo()
const
433 const QDockAreaLayoutInfo *info = layoutInfo();
434 while (info && !info->tabbed) {
437 const QDockAreaLayoutInfo *next =
nullptr;
438 bool isSingle =
false;
439 for (
const auto &item : info->item_list) {
440 if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
442 if (next || isSingle)
446 else if (item.widgetItem)
457
458
459QDockWidget *QDockWidgetGroupWindow::activeTabbedDockWidget()
const
461 QDockWidget *dw =
nullptr;
462 const QDockAreaLayoutInfo *info = tabLayoutInfo();
465 if (info->tabBar && info->tabBar->currentIndex() >= 0) {
466 int i = info->tabIndexToListIndex(info->tabBar->currentIndex());
468 const QDockAreaLayoutItem &item = info->item_list.at(i);
470 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
474 for (
int i = 0; !dw && i < info->item_list.size(); ++i) {
475 const QDockAreaLayoutItem &item = info->item_list.at(i);
478 if (!item.widgetItem)
480 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
488
489
490
491void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
493 const QDockAreaLayoutInfo *info = layoutInfo();
494 if (!info->isEmpty()) {
499 if (!info->item_list.isEmpty()) {
505 const auto dockWidgetsList = dockWidgets();
506 for (QDockWidget *dw : dockWidgetsList) {
507 const bool wasFloating = dw->isFloating();
508 const bool wasHidden = dw->isHidden();
509 dw->setParent(parentWidget());
510 qCDebug(lcQpaDockWidgets) <<
"Reparented:" << dw <<
"to" << parentWidget() <<
"by" <<
this;
512 dw->setFloating(
true);
515 QMainWindowLayout *ml =
516 qt_mainwindow_layout(
static_cast<QMainWindow *>(parentWidget()));
517 Qt::DockWidgetArea area = ml->dockWidgetArea(
this);
518 if (area == Qt::NoDockWidgetArea)
519 area = Qt::LeftDockWidgetArea;
520 static_cast<QMainWindow *>(parentWidget())->addDockWidget(area, dw);
521 qCDebug(lcQpaDockWidgets) <<
"Redocked to Mainwindow:" << area << dw <<
"by" <<
this;
526 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
527 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
528 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
529 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
530 std::unique_ptr<QLayoutItem> cleanup = parentInfo.takeWidgetItem(
this);
531 parentInfo.remove(
this);
536
537
538
539
540bool QDockWidgetGroupWindow::hasVisibleDockWidgets()
const
542 const auto &children = findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
543 for (
auto child : children) {
548 if (!child->testAttribute(Qt::WA_WState_Hidden))
555
556
557void QDockWidgetGroupWindow::adjustFlags()
559 Qt::WindowFlags oldFlags = windowFlags();
560 Qt::WindowFlags flags = oldFlags;
563 QDockWidget *top = activeTabbedDockWidget();
565 QDockWidget *top =
nullptr;
569 ((oldFlags & ~Qt::FramelessWindowHint) | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
570 }
else if (
static_cast<QDockWidgetGroupLayout *>(layout())->nativeWindowDeco()) {
571 flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
572 flags.setFlag(Qt::WindowCloseButtonHint, top->features() & QDockWidget::DockWidgetClosable);
573 flags &= ~Qt::FramelessWindowHint;
575 flags &= ~(Qt::WindowCloseButtonHint | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
576 flags |= Qt::FramelessWindowHint;
579 if (oldFlags != flags) {
582 setWindowFlags(flags);
583 const bool gainedNativeDecos = (oldFlags & Qt::FramelessWindowHint) && !(flags & Qt::FramelessWindowHint);
584 const bool lostNativeDecos = !(oldFlags & Qt::FramelessWindowHint) && (flags & Qt::FramelessWindowHint);
588 if (lostNativeDecos) {
589 QRect newGeometry = geometry();
590 newGeometry.setTop(frameGeometry().top());
591 const int bottomFrame = geometry().top() - frameGeometry().top();
592 m_removedFrameSize = QSize((frameSize() - size()).width(), bottomFrame);
593 setGeometry(newGeometry);
594 }
else if (gainedNativeDecos && m_removedFrameSize.isValid()) {
595 QRect r = geometry();
596 r.adjust(-m_removedFrameSize.width() / 2, 0,
597 -m_removedFrameSize.width() / 2, -m_removedFrameSize.height());
599 m_removedFrameSize = QSize();
602 setVisible(hasVisibleDockWidgets());
605 QWidget *titleBarOf = top ? top : parentWidget();
606 setWindowTitle(titleBarOf->windowTitle());
607 setWindowIcon(titleBarOf->windowIcon());
610bool QDockWidgetGroupWindow::hasNativeDecos()
const
613 QDockWidget *dw = activeTabbedDockWidget();
617 if (!QDockWidgetLayout::wmSupportsNativeWindowDeco())
620 return dw->titleBarWidget() ==
nullptr;
627QT_WARNING_DISABLE_GCC(
"-Waggressive-loop-optimizations")
629
630
631
632
633
634
635bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem,
const QPoint &mousePos)
637 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
638 if (savedState.isEmpty())
639 savedState = *layoutInfo();
641 QMainWindow::DockOptions opts =
static_cast<QMainWindow *>(parentWidget())->dockOptions();
642 QDockAreaLayoutInfo newState = savedState;
643 bool nestingEnabled =
644 (opts & QMainWindow::AllowNestedDocks) && !(opts & QMainWindow::ForceTabbedDocks);
645 QDockAreaLayoutInfo::TabMode tabMode =
646#if !QT_CONFIG(tabbar)
647 QDockAreaLayoutInfo::NoTabs;
649 nestingEnabled ? QDockAreaLayoutInfo::AllowTabs : QDockAreaLayoutInfo::ForceTabs;
650 if (
auto group = qobject_cast<QDockWidgetGroupWindow *>(widgetItem->widget())) {
651 if (!group->tabLayoutInfo())
652 tabMode = QDockAreaLayoutInfo::NoTabs;
654 if (newState.tabbed) {
656 newState.item_list = { QDockAreaLayoutItem(
new QDockAreaLayoutInfo(newState)) };
657 newState.item_list.first().size = pick(savedState.o, savedState.rect.size());
658 newState.tabbed =
false;
659 newState.tabBar =
nullptr;
663 auto newGapPos = newState.gapIndex(mousePos, nestingEnabled, tabMode);
664 Q_ASSERT(!newGapPos.isEmpty());
668 if (newGapPos == currentGapPos || newState.hasGapItem(newGapPos))
671 currentGapPos = newGapPos;
672 newState.insertGap(currentGapPos, widgetItem);
674 *layoutInfo() = std::move(newState);
675 updateCurrentGapRect();
676 const auto rule = toAnimationRule(opts);
677 layoutInfo()->apply(rule);
682void QDockWidgetGroupWindow::updateCurrentGapRect()
684 if (!currentGapPos.isEmpty())
685 currentGapRect = layoutInfo()->info(currentGapPos)->itemRect(currentGapPos.last(),
true);
689
690
691void QDockWidgetGroupWindow::restore()
693 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
694 if (!savedState.isEmpty()) {
695 *layoutInfo() = savedState;
696 savedState = QDockAreaLayoutInfo();
698 currentGapRect = QRect();
699 currentGapPos.clear();
701 layoutInfo()->fitItems();
702 const auto *mw =
static_cast<QMainWindow *>(parentWidget());
703 const auto rule = toAnimationRule(mw->dockOptions());
704 layoutInfo()->apply(rule);
708
709
710void QDockWidgetGroupWindow::apply()
712 static_cast<QDockWidgetGroupLayout *>(layout())->savedState.clear();
713 currentGapRect = QRect();
714 layoutInfo()->plug(currentGapPos);
715 currentGapPos.clear();
717 layoutInfo()->apply(QWidgetAnimator::AnimationRule::Stop);
720void QDockWidgetGroupWindow::childEvent(QChildEvent *event)
722 switch (event->type()) {
723 case QEvent::ChildRemoved:
724 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
725 dockWidget->removeEventFilter(
this);
726 destroyIfSingleItemLeft();
728 case QEvent::ChildAdded:
729 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child())) {
730 dockWidget->installEventFilter(
this);
731 if (objectName().isEmpty())
732 setObjectName(dockWidget->objectName() + QLatin1String(
"_groupWindow"));
740bool QDockWidgetGroupWindow::eventFilter(QObject *obj, QEvent *event)
742 auto *dockWidget = qobject_cast<QDockWidget *>(obj);
744 return QWidget::eventFilter(obj, event);
746 switch (event->type()) {
750 reparentToMainWindow(dockWidget);
751 dockWidget->setFloating(
false);
757 if (dockWidget->isVisible())
764 return QWidget::eventFilter(obj, event);
767void QDockWidgetGroupWindow::destroyIfSingleItemLeft()
769 const auto &dockWidgets =
this->dockWidgets();
772 if (dockWidgets.count() != 1)
775 auto *lastDockWidget = dockWidgets.at(0);
780 if (layoutInfo()->indexOf(lastDockWidget).isEmpty())
783 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
784 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
785 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
788 mwLayout->unplug(lastDockWidget, QDockWidgetPrivate::DragScope::Widget);
789 const QPoint position = pos();
793 reparentToMainWindow(lastDockWidget);
797 if (lastDockWidget->isFloating())
798 lastDockWidget->move(position);
801 layoutInfo()->item_list.clear();
803 destroyOrHideIfEmpty();
806void QDockWidgetGroupWindow::reparentToMainWindow(QDockWidget *dockWidget)
812 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
813 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
814 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
816 mwLayout->widgetAnimator.abort(dockWidget);
823 mwLayout->savedState.clear();
824 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
825 dockWidget->removeEventFilter(
this);
826 parentInfo.add(dockWidget);
827 layoutInfo()->remove(dockWidget);
828 const bool wasFloating = dockWidget->isFloating();
829 const bool wasVisible = dockWidget->isVisible();
830 dockWidget->setParent(mainWindow);
831 dockWidget->setFloating(wasFloating);
832 dockWidget->setVisible(wasVisible);
837
838
842QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win)
844#if QT_CONFIG(toolbar)
845 toolBarAreaLayout(win),
847#if QT_CONFIG(dockwidget)
857QSize QMainWindowLayoutState::sizeHint()
const
862#if QT_CONFIG(dockwidget)
863 result = dockAreaLayout.sizeHint();
865 if (centralWidgetItem)
866 result = centralWidgetItem->sizeHint();
869#if QT_CONFIG(toolbar)
870 result = toolBarAreaLayout.sizeHint(result);
876QSize QMainWindowLayoutState::minimumSize()
const
880#if QT_CONFIG(dockwidget)
881 result = dockAreaLayout.minimumSize();
883 if (centralWidgetItem)
884 result = centralWidgetItem->minimumSize();
887#if QT_CONFIG(toolbar)
888 result = toolBarAreaLayout.minimumSize(result);
895
896
897
898
899bool QMainWindowLayoutState::fits()
const
901 Q_ASSERT(mainWindow);
905#if QT_CONFIG(dockwidget)
906 size = dockAreaLayout.minimumStableSize();
909#if QT_CONFIG(toolbar)
910 size.rwidth() += toolBarAreaLayout.docks[QInternal::LeftDock].rect.width();
911 size.rwidth() += toolBarAreaLayout.docks[QInternal::RightDock].rect.width();
912 size.rheight() += toolBarAreaLayout.docks[QInternal::TopDock].rect.height();
913 size.rheight() += toolBarAreaLayout.docks[QInternal::BottomDock].rect.height();
916 return size.width() <= mainWindow->width() && size.height() <= mainWindow->height();
919void QMainWindowLayoutState::apply(QWidgetAnimator::AnimationRule rule)
921#if QT_CONFIG(toolbar)
922 toolBarAreaLayout.apply(rule);
925#if QT_CONFIG(dockwidget)
927 dockAreaLayout.apply(rule);
929 if (centralWidgetItem) {
930 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
932 layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, rule);
937void QMainWindowLayoutState::fitLayout()
940#if !QT_CONFIG(toolbar)
943 toolBarAreaLayout.rect = rect;
944 r = toolBarAreaLayout.fitLayout();
947#if QT_CONFIG(dockwidget)
948 dockAreaLayout.rect = r;
949 dockAreaLayout.fitLayout();
951 centralWidgetRect = r;
955void QMainWindowLayoutState::deleteAllLayoutItems()
957#if QT_CONFIG(toolbar)
958 toolBarAreaLayout.deleteAllLayoutItems();
961#if QT_CONFIG(dockwidget)
962 dockAreaLayout.deleteAllLayoutItems();
966void QMainWindowLayoutState::deleteCentralWidgetItem()
968#if QT_CONFIG(dockwidget)
969 delete dockAreaLayout.centralWidgetItem;
970 dockAreaLayout.centralWidgetItem =
nullptr;
972 delete centralWidgetItem;
973 centralWidgetItem = 0;
977QLayoutItem *QMainWindowLayoutState::itemAt(
int index,
int *x)
const
979#if QT_CONFIG(toolbar)
980 if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
984#if QT_CONFIG(dockwidget)
985 if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
988 if (centralWidgetItem && (*x)++ == index)
989 return centralWidgetItem;
995QLayoutItem *QMainWindowLayoutState::takeAt(
int index,
int *x)
997#if QT_CONFIG(toolbar)
998 if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
1002#if QT_CONFIG(dockwidget)
1003 if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
1006 if (centralWidgetItem && (*x)++ == index) {
1007 QLayoutItem *ret = centralWidgetItem;
1008 centralWidgetItem =
nullptr;
1016QList<
int> QMainWindowLayoutState::indexOf(QWidget *widget)
const
1020#if QT_CONFIG(toolbar)
1022 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
1023 result = toolBarAreaLayout.indexOf(toolBar);
1024 if (!result.isEmpty())
1030#if QT_CONFIG(dockwidget)
1032 if (qobject_cast<QDockWidget *>(widget) || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1033 result = dockAreaLayout.indexOf(widget);
1034 if (!result.isEmpty())
1043bool QMainWindowLayoutState::contains(QWidget *widget)
const
1045#if QT_CONFIG(dockwidget)
1046 if (dockAreaLayout.centralWidgetItem !=
nullptr && dockAreaLayout.centralWidgetItem->widget() == widget)
1048 if (!dockAreaLayout.indexOf(widget).isEmpty())
1051 if (centralWidgetItem && centralWidgetItem->widget() == widget)
1055#if QT_CONFIG(toolbar)
1056 if (!toolBarAreaLayout.indexOf(widget).isEmpty())
1062void QMainWindowLayoutState::setCentralWidget(QWidget *widget)
1064 QLayoutItem *item =
nullptr;
1066 deleteCentralWidgetItem();
1068 if (widget !=
nullptr)
1069 item =
new QWidgetItemV2(widget);
1071#if QT_CONFIG(dockwidget)
1072 dockAreaLayout.centralWidgetItem = item;
1074 centralWidgetItem = item;
1078QWidget *QMainWindowLayoutState::centralWidget()
const
1080 QLayoutItem *item =
nullptr;
1082#if QT_CONFIG(dockwidget)
1083 item = dockAreaLayout.centralWidgetItem;
1085 item = centralWidgetItem;
1088 if (item !=
nullptr)
1089 return item->widget();
1093QList<
int> QMainWindowLayoutState::gapIndex(QWidget *widget,
1094 const QPoint &pos)
const
1098#if QT_CONFIG(toolbar)
1100 if (qobject_cast<QToolBar*>(widget) !=
nullptr) {
1101 result = toolBarAreaLayout.gapIndex(pos);
1102 if (!result.isEmpty())
1108#if QT_CONFIG(dockwidget)
1110 if (qobject_cast<QDockWidget *>(widget) !=
nullptr
1111 || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1112 bool disallowTabs =
false;
1113#if QT_CONFIG(tabbar)
1114 if (
auto *group = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1115 if (!group->tabLayoutInfo())
1116 disallowTabs =
true;
1119 result = dockAreaLayout.gapIndex(pos, disallowTabs);
1120 if (!result.isEmpty())
1129bool QMainWindowLayoutState::insertGap(
const QList<
int> &path, QLayoutItem *item)
1134 int i = path.first();
1136#if QT_CONFIG(toolbar)
1138 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) !=
nullptr);
1139 return toolBarAreaLayout.insertGap(path.mid(1), item);
1143#if QT_CONFIG(dockwidget)
1145 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) || qobject_cast<QDockWidgetGroupWindow*>(item->widget()));
1146 return dockAreaLayout.insertGap(path.mid(1), item);
1153void QMainWindowLayoutState::remove(
const QList<
int> &path)
1155 int i = path.first();
1157#if QT_CONFIG(toolbar)
1159 toolBarAreaLayout.remove(path.mid(1));
1162#if QT_CONFIG(dockwidget)
1164 dockAreaLayout.remove(path.mid(1));
1168void QMainWindowLayoutState::remove(QLayoutItem *item)
1170#if QT_CONFIG(toolbar)
1171 toolBarAreaLayout.remove(item);
1174#if QT_CONFIG(dockwidget)
1176 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
1177 QList<
int> path = dockAreaLayout.indexOf(dockWidget);
1178 if (!path.isEmpty())
1179 dockAreaLayout.remove(path);
1184void QMainWindowLayoutState::clear()
1186#if QT_CONFIG(toolbar)
1187 toolBarAreaLayout.clear();
1190#if QT_CONFIG(dockwidget)
1191 dockAreaLayout.clear();
1193 centralWidgetRect = QRect();
1199bool QMainWindowLayoutState::isValid()
const
1201 return rect.isValid();
1204QLayoutItem *QMainWindowLayoutState::item(
const QList<
int> &path)
1206 int i = path.first();
1208#if QT_CONFIG(toolbar)
1210 const QToolBarAreaLayoutItem *tbItem = toolBarAreaLayout.item(path.mid(1));
1212 return tbItem->widgetItem;
1216#if QT_CONFIG(dockwidget)
1218 return dockAreaLayout.item(path.mid(1)).widgetItem;
1224QRect QMainWindowLayoutState::itemRect(
const QList<
int> &path)
const
1226 int i = path.first();
1228#if QT_CONFIG(toolbar)
1230 return toolBarAreaLayout.itemRect(path.mid(1));
1233#if QT_CONFIG(dockwidget)
1235 return dockAreaLayout.itemRect(path.mid(1));
1241QRect QMainWindowLayoutState::gapRect(
const QList<
int> &path)
const
1243 int i = path.first();
1245#if QT_CONFIG(toolbar)
1247 return toolBarAreaLayout.itemRect(path.mid(1));
1250#if QT_CONFIG(dockwidget)
1252 return dockAreaLayout.gapRect(path.mid(1));
1258QLayoutItem *QMainWindowLayoutState::plug(
const QList<
int> &path)
1260 int i = path.first();
1262#if QT_CONFIG(toolbar)
1264 return toolBarAreaLayout.plug(path.mid(1));
1267#if QT_CONFIG(dockwidget)
1269 return dockAreaLayout.plug(path.mid(1));
1275QLayoutItem *QMainWindowLayoutState::unplug(
const QList<
int> &path, QMainWindowLayoutState *other)
1277 int i = path.first();
1279#if !QT_CONFIG(toolbar)
1283 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout :
nullptr);
1286#if QT_CONFIG(dockwidget)
1288 return dockAreaLayout.unplug(path.mid(1));
1294void QMainWindowLayoutState::saveState(QDataStream &stream)
const
1296#if QT_CONFIG(dockwidget)
1297 dockAreaLayout.saveState(stream);
1298#if QT_CONFIG(tabbar)
1299 const QList<QDockWidgetGroupWindow *> floatingTabs =
1300 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
1302 for (QDockWidgetGroupWindow *floating : floatingTabs) {
1303 if (floating->layoutInfo()->isEmpty())
1305 stream << StateMarkers::FloatingDockWidgetTab;
1306 stream << floating->geometry();
1307 floating->layoutInfo()->saveState(stream);
1311#if QT_CONFIG(toolbar)
1312 toolBarAreaLayout.saveState(stream);
1317bool QMainWindowLayoutState::checkFormat(QDataStream &stream)
1319 while (!stream.atEnd()) {
1320 StateMarkers marker;
1324#if QT_CONFIG(toolbar)
1325 case StateMarkers::ToolBar:
1326 case StateMarkers::ToolBarEx:
1328 const auto toolBars = mainWindow->findChildren<QToolBar*>();
1329 if (!toolBarAreaLayout.restoreState(stream, toolBars,
static_cast<uchar>(marker), QInternal::Testing))
1335#if QT_CONFIG(dockwidget)
1336 case StateMarkers::DockWidget:
1338 const auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1339 if (!dockAreaLayout.restoreState(stream, dockWidgets, QInternal::Testing))
1343#if QT_CONFIG(tabbar)
1344 case StateMarkers::FloatingDockWidgetTab:
1348 QDockAreaLayoutInfo info;
1349 auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1350 if (!info.restoreState(stream, dockWidgets, QInternal::Testing))
1366bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
1367 const QMainWindowLayoutState &oldState)
1371 while(!_stream.atEnd()) {
1373 QByteArray ba(length,
'\0');
1374 length = _stream.readRawData(ba.data(), ba.size());
1379 QDataStream ds(copy);
1380 ds.setVersion(_stream.version());
1381 if (!checkFormat(ds))
1384 QDataStream stream(copy);
1385 stream.setVersion(_stream.version());
1387 while (!stream.atEnd()) {
1388 StateMarkers marker;
1392#if QT_CONFIG(dockwidget)
1393 case StateMarkers::DockWidget:
1395 const auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1396 if (!dockAreaLayout.restoreState(stream, dockWidgets, QInternal::Live))
1399 for (
auto *w : dockWidgets) {
1400 const QList<
int> path = dockAreaLayout.indexOf(w);
1401 if (path.isEmpty()) {
1402 QList<
int> oldPath = oldState.dockAreaLayout.indexOf(w);
1403 if (oldPath.isEmpty())
1405 QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
1406 if (info ==
nullptr) {
1414#if QT_CONFIG(tabwidget)
1415 case StateMarkers::FloatingDockWidgetTab:
1417 auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1419 for (
auto *dockWidget : std::as_const(dockWidgets)) {
1420 QPointer<QDockWidgetGroupWindow> gw = qobject_cast<QDockWidgetGroupWindow *>(dockWidget->parent());
1423 const bool visible = gw->isVisible();
1424 gw->reparentToMainWindow(dockWidget);
1425 dockWidget->setFloating(
true);
1426 dockWidget->setVisible(visible);
1429 const auto groupWindows = mainWindow->findChildren<QDockWidgetGroupWindow *>();
1430 for (
auto *gw : groupWindows)
1431 Q_ASSERT(gw->dockWidgets().isEmpty());
1434 QDockWidgetGroupWindow* floatingTab = qt_mainwindow_layout(mainWindow)->createTabbedDockWindow();
1435 *floatingTab->layoutInfo() = QDockAreaLayoutInfo(
1436 &dockAreaLayout.sep, QInternal::LeftDock,
1437 Qt::Horizontal, QTabBar::RoundedSouth, mainWindow);
1440 QDockAreaLayoutInfo *info = floatingTab->layoutInfo();
1441 if (!info->restoreState(stream, dockWidgets, QInternal::Live))
1443 geometry = QDockAreaLayout::constrainedRect(geometry, floatingTab);
1444 floatingTab->move(geometry.topLeft());
1445 floatingTab->resize(geometry.size());
1449 if (info->onlyHasPlaceholders())
1450 info->reparentWidgets(floatingTab);
1452 floatingTab->show();
1458#if QT_CONFIG(toolbar)
1459 case StateMarkers::ToolBar:
1460 case StateMarkers::ToolBarEx:
1462 const auto toolBars = mainWindow->findChildren<QToolBar*>();
1463 if (!toolBarAreaLayout.restoreState(stream, toolBars,
static_cast<uchar>(marker), QInternal::Live))
1466 for (
auto *bar : toolBars) {
1467 const QList<
int> path = toolBarAreaLayout.indexOf(bar);
1468 if (path.isEmpty()) {
1469 const QList<
int> oldPath = oldState.toolBarAreaLayout.indexOf(bar);
1470 if (oldPath.isEmpty())
1472 toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(
nullptr, bar);
1488
1489
1491#if QT_CONFIG(toolbar)
1493static constexpr Qt::ToolBarArea validateToolBarArea(Qt::ToolBarArea area)
1496 case Qt::LeftToolBarArea:
1497 case Qt::RightToolBarArea:
1498 case Qt::TopToolBarArea:
1499 case Qt::BottomToolBarArea:
1504 return Qt::TopToolBarArea;
1507static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
1510 case Qt::LeftToolBarArea:
return QInternal::LeftDock;
1511 case Qt::RightToolBarArea:
return QInternal::RightDock;
1512 case Qt::TopToolBarArea:
return QInternal::TopDock;
1513 case Qt::BottomToolBarArea:
return QInternal::BottomDock;
1518 return QInternal::DockCount;
1521static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
1524 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1525 case QInternal::RightDock:
return Qt::RightToolBarArea;
1526 case QInternal::TopDock:
return Qt::TopToolBarArea;
1527 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1530 return Qt::NoToolBarArea;
1533static inline Qt::ToolBarArea toToolBarArea(
int pos)
1535 return toToolBarArea(
static_cast<QInternal::DockPosition>(pos));
1538void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
1540 area = validateToolBarArea(area);
1542 layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1543 if (savedState.isValid())
1544 savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1549void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
1551 layoutState.toolBarAreaLayout.insertToolBarBreak(before);
1552 if (savedState.isValid())
1553 savedState.toolBarAreaLayout.insertToolBarBreak(before);
1557void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
1559 layoutState.toolBarAreaLayout.removeToolBarBreak(before);
1560 if (savedState.isValid())
1561 savedState.toolBarAreaLayout.removeToolBarBreak(before);
1565void QMainWindowLayout::moveToolBar(QToolBar *toolbar,
int pos)
1567 layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1568 if (savedState.isValid())
1569 savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1574
1575void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
1578 QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
1579 toolbar, SLOT(_q_updateIconSize(QSize)));
1580 QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
1581 toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
1583 removeWidget(toolbar);
1588
1589
1590
1591
1594
1595
1596void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
1600 area = validateToolBarArea(area);
1602 addChildWidget(toolbar);
1603 QLayoutItem *item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
1604 if (savedState.isValid() && item) {
1606 savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
1611 toolbar->d_func()->updateWindowFlags(
false );
1615
1616
1617void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
1619 addChildWidget(toolbar);
1620 QLayoutItem *item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
1621 if (savedState.isValid() && item) {
1623 savedState.toolBarAreaLayout.insertItem(before, item);
1625 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
1626 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1627 if (!currentGapPos.isEmpty()) {
1628 currentGapPos.prepend(0);
1629 currentGapRect = layoutState.itemRect(currentGapPos);
1635Qt::ToolBarArea QMainWindowLayout::toolBarArea(
const QToolBar *toolbar)
const
1637 QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar);
1639 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1640 case QInternal::RightDock:
return Qt::RightToolBarArea;
1641 case QInternal::TopDock:
return Qt::TopToolBarArea;
1642 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1645 return Qt::NoToolBarArea;
1648bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar)
const
1650 return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
1653void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar)
const
1655 option->toolBarArea = toolBarArea(toolBar);
1656 layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
1659void QMainWindowLayout::toggleToolBarsVisible()
1661 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
1662 if (!layoutState.mainWindow->isMaximized()) {
1663 QPoint topLeft = parentWidget()->geometry().topLeft();
1664 QRect r = parentWidget()->geometry();
1665 r = layoutState.toolBarAreaLayout.rectHint(r);
1667 parentWidget()->setGeometry(r);
1676
1677
1679#if QT_CONFIG(dockwidget)
1681static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area)
1684 case Qt::LeftDockWidgetArea:
return QInternal::LeftDock;
1685 case Qt::RightDockWidgetArea:
return QInternal::RightDock;
1686 case Qt::TopDockWidgetArea:
return QInternal::TopDock;
1687 case Qt::BottomDockWidgetArea:
return QInternal::BottomDock;
1688 case Qt::DockWidgetArea::NoDockWidgetArea:
1689 case Qt::DockWidgetArea::AllDockWidgetAreas:
1693 return QInternal::DockCount;
1696inline static Qt::DockWidgetArea toDockWidgetArea(
int pos)
1698 return QDockWidgetPrivate::toDockWidgetArea(
static_cast<QInternal::DockPosition>(pos));
1703static bool isAreaAllowed(QWidget *widget,
const QList<
int> &path)
1705 Q_ASSERT_X((path.size() > 1),
"isAreaAllowed",
"invalid path size");
1706 const Qt::DockWidgetArea area = toDockWidgetArea(path[1]);
1709 if (QDockWidget *dw = qobject_cast<QDockWidget *>(widget)) {
1710 const bool allowed = dw->isAreaAllowed(area);
1712 qCDebug(lcQpaDockWidgets) <<
"No permission for single DockWidget" << widget <<
"to dock on" << area;
1717 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1718 const QList<QDockWidget *> children = dwgw->findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly);
1720 if (children.size() == 1) {
1722 const bool allowed = children.at(0)->isAreaAllowed(area);
1724 qCDebug(lcQpaDockWidgets) <<
"No permission for DockWidgetGroupWindow" << widget <<
"to dock on" << area;
1728 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"has" << children.size() <<
"children:";
1729 qCDebug(lcQpaDockWidgets) << children;
1730 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"can dock at" << area <<
"and anywhere else.";
1734 qCDebug(lcQpaDockWidgets) <<
"Docking requested for invalid widget type (coding error)." << widget << area;
1738void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1740 if (layoutState.dockAreaLayout.corners[corner] == area)
1742 layoutState.dockAreaLayout.corners[corner] = area;
1743 if (savedState.isValid())
1744 savedState.dockAreaLayout.corners[corner] = area;
1748Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner)
const
1750 return layoutState.dockAreaLayout.corners[corner];
1756QRect QMainWindowLayout::dockWidgetAreaRect(
const Qt::DockWidgetArea area, DockWidgetAreaSize size)
const
1758 const QInternal::DockPosition dockPosition = toDockPos(area);
1761 if (dockPosition == QInternal::DockCount) {
1762 qCDebug(lcQpaDockWidgets) <<
"QMainWindowLayout::dockWidgetAreaRect called with" << area;
1766 const QDockAreaLayout dl = layoutState.dockAreaLayout;
1769 return (size == Maximum) ? dl.gapRect(dockPosition) : dl.docks[dockPosition].rect;
1773
1774
1775
1776void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1777 QDockWidget *dockwidget,
1778 Qt::Orientation orientation)
1780 addChildWidget(dockwidget);
1784 if (!movingSeparator.isEmpty())
1785 endSeparatorMove(movingSeparatorPos);
1787 layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
1791bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1793 addChildWidget(dockwidget);
1794 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1796 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1801#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
1802static QTabBar::Shape tabwidgetPositionToTabBarShape(QDockWidget *w)
1804 switch (
static_cast<QDockWidgetPrivate *>(qt_widget_private(w))->tabPosition) {
1805 case QTabWidget::North:
1806 return QTabBar::RoundedNorth;
1807 case QTabWidget::South:
1808 return QTabBar::RoundedSouth;
1809 case QTabWidget::West:
1810 return QTabBar::RoundedWest;
1811 case QTabWidget::East:
1812 return QTabBar::RoundedEast;
1814 Q_UNREACHABLE_RETURN(QTabBar::RoundedSouth);
1818#if QT_CONFIG(tabbar)
1819void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1825 if (layoutState.dockAreaLayout.indexOf(first).isEmpty()) {
1826 qCritical() <<
"Coding error: QDockWidget" << first
1827 <<
"tabbed before QMainWindow::addDockWidget()."
1828 <<
"Ignoring" <<
__FUNCTION__;
1833 if (layoutState.dockAreaLayout.indexOf(second).isEmpty()) {
1834 layoutState.mainWindow->addDockWidget(first->dockLocation(), second);
1835 qCDebug(lcQpaDockWidgets) <<
"QDockWidget" << second <<
"has been added to"
1836 << parent() <<
"at" << first->dockLocation();
1840 if (isDockWidgetTabbed(second)) {
1841 qCDebug(lcQpaDockWidgets) <<
"QDockWidget" << second
1842 <<
"is already tabbed. Ignoring" <<
__FUNCTION__;
1846 const auto oldLocationFirst = dockWidgetArea(first);
1847 if (first->isFloating()) {
1848 tabifyWhileFloating(first, second);
1850 applyRestoredState();
1851 addChildWidget(second);
1852 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1854 const auto newLocationFirst = dockWidgetArea(first);
1855 if (newLocationFirst != oldLocationFirst)
1856 emit second->dockLocationChanged(newLocationFirst);
1860void QMainWindowLayout::tabifyWhileFloating(QDockWidget *first, QDockWidget *second)
1862 Q_ASSERT(first->isFloating());
1863 Q_ASSERT(!isDockWidgetTabbed(first));
1864 Q_ASSERT(!isDockWidgetTabbed(second));
1867 second->setFloating(
true);
1869 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
1870 floatingTabs->setGeometry(first->geometry());
1871 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
1872 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(first);
1874 const QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(first));
1875 Q_ASSERT(dockPosition != QInternal::DockPosition::DockCount);
1876 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPosition,
1877 Qt::Horizontal, shape,
1878 static_cast<QMainWindow *>(parentWidget()));
1879 info->tabBar = getTabBar();
1880 info->tabbed =
true;
1883 second->d_func()->plug(first->geometry());
1884 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[dockPosition];
1885 parentInfo.add(floatingTabs);
1886 first->setParent(floatingTabs);
1887 second->setParent(floatingTabs);
1888 floatingTabs->show();
1889 floatingTabs->raise();
1892bool QMainWindowLayout::documentMode()
const
1894 return _documentMode;
1897void QMainWindowLayout::setDocumentMode(
bool enabled)
1899 if (_documentMode == enabled)
1902 _documentMode = enabled;
1905 for (QTabBar *bar : std::as_const(usedTabBars))
1906 bar->setDocumentMode(_documentMode);
1909void QMainWindowLayout::setVerticalTabsEnabled(
bool enabled)
1911 if (verticalTabsEnabled == enabled)
1914 verticalTabsEnabled = enabled;
1916 updateTabBarShapes();
1919#if QT_CONFIG(tabwidget)
1920QTabWidget::TabShape QMainWindowLayout::tabShape()
const
1925void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1927 if (_tabShape == tabShape)
1930 _tabShape = tabShape;
1932 updateTabBarShapes();
1935QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area)
const
1937 const QInternal::DockPosition dockPos = toDockPos(area);
1938 if (dockPos < QInternal::DockCount)
1939 return tabPositions[dockPos];
1940 qWarning(
"QMainWindowLayout::tabPosition called with out-of-bounds value '%d'",
int(area));
1941 return QTabWidget::North;
1944void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1946 static constexpr Qt::DockWidgetArea dockWidgetAreas[] = {
1947 Qt::TopDockWidgetArea,
1948 Qt::LeftDockWidgetArea,
1949 Qt::BottomDockWidgetArea,
1950 Qt::RightDockWidgetArea
1952 static constexpr QInternal::DockPosition dockPositions[] = {
1954 QInternal::LeftDock,
1955 QInternal::BottomDock,
1956 QInternal::RightDock
1959 for (
int i = 0; i < QInternal::DockCount; ++i)
1960 if (areas & dockWidgetAreas[i])
1961 tabPositions[dockPositions[i]] = tabPosition;
1963 updateTabBarShapes();
1966QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
1969void QMainWindowLayout::showTabBars()
1971 const auto usedTabBarsCopy = usedTabBars;
1972 for (QTabBar *tab_bar : usedTabBarsCopy) {
1973 if (usedTabBars.contains(tab_bar))
1978void QMainWindowLayout::updateTabBarShapes()
1980#if QT_CONFIG(tabwidget)
1981 static constexpr QTabWidget::TabPosition vertical[] = {
1988 static constexpr QTabBar::Shape vertical[] = {
1989 QTabBar::RoundedWest,
1990 QTabBar::RoundedEast,
1991 QTabBar::RoundedNorth,
1992 QTabBar::RoundedSouth
1996 QDockAreaLayout &layout = layoutState.dockAreaLayout;
1998 for (
int i = 0; i < QInternal::DockCount; ++i) {
1999#if QT_CONFIG(tabwidget)
2000 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
2001 QTabBar::Shape shape = _q_tb_tabBarShapeFrom(_tabShape, pos);
2003 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
2005 layout.docks[i].setTabBarShape(shape);
2010void QMainWindowLayout::splitDockWidget(QDockWidget *after,
2011 QDockWidget *dockwidget,
2012 Qt::Orientation orientation)
2014 applyRestoredState();
2015 addChildWidget(dockwidget);
2016 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
2017 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
2021Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(
const QWidget *widget)
const
2023 const QList<
int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
2024 if (pathToWidget.isEmpty())
2025 return Qt::NoDockWidgetArea;
2026 return toDockWidgetArea(pathToWidget.first());
2029void QMainWindowLayout::keepSize(QDockWidget *w)
2031 layoutState.dockAreaLayout.keepSize(w);
2034#if QT_CONFIG(tabbar)
2037class QMainWindowTabBar :
public QTabBar
2040 QPointer<QMainWindow> mainWindow;
2041 QPointer<QDockWidget> draggingDock;
2043 QMainWindowTabBar(QMainWindow *parent);
2044 ~QMainWindowTabBar();
2045 QDockWidget *dockAt(
int index)
const;
2046 QList<QDockWidget *> dockWidgets()
const;
2047 bool contains(
const QDockWidget *dockWidget)
const;
2049 bool event(QEvent *e) override;
2050 void mouseReleaseEvent(QMouseEvent*) override;
2051 void mouseMoveEvent(QMouseEvent*) override;
2055QDebug operator<<(QDebug debug,
const QMainWindowTabBar *bar)
2058 return debug <<
"QMainWindowTabBar(0x0)";
2059 QDebugStateSaver saver(debug);
2060 debug.nospace().noquote() <<
"QMainWindowTabBar(" <<
static_cast<
const void *>(bar) <<
", ";
2061 debug.nospace().noquote() <<
"ParentWidget=(" << bar->parentWidget() <<
"), ";
2062 const auto dockWidgets = bar->dockWidgets();
2063 if (dockWidgets.isEmpty())
2064 debug.nospace().noquote() <<
"No QDockWidgets";
2066 debug.nospace().noquote() <<
"DockWidgets(" << dockWidgets <<
")";
2067 debug.nospace().noquote() <<
")";
2071QMainWindowTabBar *QMainWindowLayout::findTabBar(
const QDockWidget *dockWidget)
const
2073 for (
auto *bar : usedTabBars) {
2074 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
2075 auto *tabBar =
static_cast<QMainWindowTabBar *>(bar);
2076 if (tabBar->contains(dockWidget))
2082QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
2083 : QTabBar(parent), mainWindow(parent)
2085 setExpanding(
false);
2088QList<QDockWidget *> QMainWindowTabBar::dockWidgets()
const
2090 QList<QDockWidget *> docks;
2091 for (
int i = 0; i < count(); ++i) {
2092 if (QDockWidget *dock = dockAt(i))
2098bool QMainWindowTabBar::contains(
const QDockWidget *dockWidget)
const
2100 for (
int i = 0; i < count(); ++i) {
2101 if (dockAt(i) == dockWidget)
2112QDockWidget *QMainWindowTabBar::dockAt(
int index)
const
2114 QMainWindowTabBar *that =
const_cast<QMainWindowTabBar *>(
this);
2115 QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
2116 QDockAreaLayoutInfo *info = mlayout ? mlayout->dockInfo(that) :
nullptr;
2120 const int itemIndex = info->tabIndexToListIndex(index);
2121 if (itemIndex >= 0) {
2122 Q_ASSERT(itemIndex < info->item_list.count());
2123 const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
2124 return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) :
nullptr;
2131
2132
2133
2134
2135
2136
2137
2138
2139static void moveToUnplugPosition(QPoint mouse, QDockWidget *dockWidget)
2141 Q_ASSERT(dockWidget);
2143 if (
auto *tbWidget = dockWidget->titleBarWidget()) {
2144 dockWidget->move(mouse - tbWidget->rect().center());
2148 const bool vertical = dockWidget->features().testFlag(QDockWidget::DockWidgetVerticalTitleBar);
2149 const int deltaX = vertical ? QApplication::startDragDistance() : dockWidget->width() / 2;
2150 const int deltaY = vertical ? dockWidget->height() / 2 : QApplication::startDragDistance();
2151 dockWidget->move(mouse - QPoint(deltaX, deltaY));
2154void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
2161 QTabBarPrivate *d =
static_cast<QTabBarPrivate*>(d_ptr.data());
2162 if (!draggingDock && (mainWindow->dockOptions() & QMainWindow::GroupedDragging)) {
2163 int offset = QApplication::startDragDistance() + 1;
2165 QRect r = rect().adjusted(-offset, -offset, offset, offset);
2166 if (d->dragInProgress && !r.contains(e->position().toPoint()) && d->validIndex(d->pressedIndex)) {
2167 draggingDock = dockAt(d->pressedIndex);
2171 d->moveTabFinished(d->pressedIndex);
2172 d->pressedIndex = -1;
2174 d->movingTab->setVisible(
false);
2175 d->dragStartPosition = QPoint();
2178 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2179 QDockWidgetLayout *dwlayout =
static_cast<QDockWidgetLayout *>(draggingDock->layout());
2180 dockPriv->initDrag(dwlayout->titleArea().center(),
true);
2181 dockPriv->startDrag(QDockWidgetPrivate::DragScope::Widget);
2182 if (dockPriv->state)
2183 dockPriv->state->ctrlDrag = e->modifiers() & Qt::ControlModifier;
2189 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2190 if (dockPriv->state && dockPriv->state->dragging) {
2192 moveToUnplugPosition(e->globalPosition().toPoint(), draggingDock);
2195 QTabBar::mouseMoveEvent(e);
2198QMainWindowTabBar::~QMainWindowTabBar()
2202 if (!qobject_cast<QMainWindow *>(mainWindow) || mainWindow == parentWidget())
2207 auto *mwLayout = qt_mainwindow_layout(mainWindow);
2210 mwLayout->usedTabBars.remove(
this);
2213void QMainWindowTabBar::mouseReleaseEvent(QMouseEvent *e)
2215 if (draggingDock && e->button() == Qt::LeftButton) {
2216 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2217 if (dockPriv->state && dockPriv->state->dragging)
2218 dockPriv->endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
2220 draggingDock =
nullptr;
2222 QTabBar::mouseReleaseEvent(e);
2225bool QMainWindowTabBar::event(QEvent *e)
2229 if (e->type() != QEvent::ToolTip)
2230 return QTabBar::event(e);
2231 QSize size =
this->size();
2232 QSize hint = sizeHint();
2233 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
2234 size = size.transposed();
2235 hint = hint.transposed();
2237 if (size.width() < hint.width())
2238 return QTabBar::event(e);
2243QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(
const QDockWidget *dockWidget)
const
2245 const auto *bar = findTabBar(dockWidget);
2249 QList<QDockWidget *> buddies = bar->dockWidgets();
2252 buddies.removeOne(dockWidget);
2256bool QMainWindowLayout::isDockWidgetTabbed(
const QDockWidget *dockWidget)
const
2261 const auto *bar = findTabBar(dockWidget);
2262 return bar && bar->count() > 1;
2265void QMainWindowLayout::unuseTabBar(QTabBar *bar)
2267 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
2271QTabBar *QMainWindowLayout::getTabBar()
2273 if (!usedTabBars.isEmpty() && !isInRestoreState) {
2275
2276
2277
2278
2282 QTabBar *bar =
new QMainWindowTabBar(
static_cast<QMainWindow *>(parentWidget()));
2283 bar->setDrawBase(
true);
2284 bar->setElideMode(Qt::ElideRight);
2285 bar->setDocumentMode(_documentMode);
2286 bar->setMovable(
true);
2287 connect(bar, SIGNAL(currentChanged(
int)),
this, SLOT(tabChanged()));
2288 connect(bar, &QTabBar::tabMoved,
this, &QMainWindowLayout::tabMoved);
2290 usedTabBars.insert(bar);
2294QWidget *QMainWindowLayout::getSeparatorWidget()
2296 auto *separator =
new QWidget(parentWidget());
2297 separator->setAttribute(Qt::WA_MouseNoMask,
true);
2298 separator->setAutoFillBackground(
false);
2299 separator->setObjectName(
"qt_qmainwindow_extended_splitter"_L1);
2300 usedSeparatorWidgets.insert(separator);
2305
2306
2307
2308QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget)
2310 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
2314 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2315 for (QDockWidgetGroupWindow *dwgw : groups) {
2316 info = dwgw->layoutInfo()->info(widget);
2323void QMainWindowLayout::tabChanged()
2325 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2328 QDockAreaLayoutInfo *info = dockInfo(tb);
2329 if (info ==
nullptr)
2332 QDockWidget *activated = info->apply(QWidgetAnimator::AnimationRule::Stop);
2335 emit
static_cast<QMainWindow *>(parentWidget())->tabifiedDockWidgetActivated(activated);
2337 if (
auto dwgw = qobject_cast<QDockWidgetGroupWindow*>(tb->parentWidget()))
2338 dwgw->adjustFlags();
2340 if (QWidget *w = centralWidget())
2344void QMainWindowLayout::tabMoved(
int from,
int to)
2346 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2348 QDockAreaLayoutInfo *info = dockInfo(tb);
2351 info->moveTab(from, to);
2354void QMainWindowLayout::raise(QDockWidget *widget)
2356 QDockAreaLayoutInfo *info = dockInfo(widget);
2357 if (info ==
nullptr)
2361 info->setCurrentTab(widget);
2369
2370
2372int QMainWindowLayout::count()
const
2375 while (itemAt(result))
2380QLayoutItem *QMainWindowLayout::itemAt(
int index)
const
2384 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
2387 if (statusbar && x++ == index)
2393QLayoutItem *QMainWindowLayout::takeAt(
int index)
2397 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
2399 if (QWidget *w = ret->widget()) {
2400 widgetAnimator.abort(w);
2401 if (w == pluggingWidget)
2402 pluggingWidget =
nullptr;
2405 if (savedState.isValid() ) {
2407 savedState.remove(ret);
2409 layoutState.remove(ret);
2412#if QT_CONFIG(toolbar)
2413 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
2414 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
2415 if (!currentGapPos.isEmpty()) {
2416 currentGapPos.prepend(0);
2417 currentGapRect = layoutState.itemRect(currentGapPos);
2425 if (statusbar && x++ == index) {
2426 QLayoutItem *ret = statusbar;
2427 statusbar =
nullptr;
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451void QMainWindowLayout::applyRestoredState()
2453 if (restoredState) {
2454 layoutState = *restoredState;
2455 restoredState.reset();
2456 discardRestoredStateTimer.stop();
2460void QMainWindowLayout::setGeometry(
const QRect &_r)
2464 if (savedState.isValid() || (restoredState && isInApplyState))
2469 QLayout::setGeometry(r);
2472 QRect sbr(QPoint(r.left(), 0),
2473 QSize(r.width(), statusbar->heightForWidth(r.width()))
2474 .expandedTo(statusbar->minimumSize()));
2475 sbr.moveBottom(r.bottom());
2476 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
2477 statusbar->setGeometry(vr);
2478 r.setBottom(sbr.top() - 1);
2481 if (restoredState) {
2483
2484
2485
2486
2487
2488
2489 layoutState = *restoredState;
2490 if (restoredState->fits()) {
2491 restoredState.reset();
2492 discardRestoredStateTimer.stop();
2495
2496
2497
2498
2499
2500
2501
2502
2503 discardRestoredStateTimer.start(150,
this);
2507 layoutState.rect = r;
2509 layoutState.fitLayout();
2510 applyState(layoutState,
false);
2512#if defined(Q_OS_MACOS)
2513 updateUnifiedToolBarArea();
2517void QMainWindowLayout::timerEvent(QTimerEvent *e)
2519 if (e->timerId() == discardRestoredStateTimer.timerId()) {
2520 discardRestoredStateTimer.stop();
2521 restoredState.reset();
2523 QLayout::timerEvent(e);
2526void QMainWindowLayout::addItem(QLayoutItem *)
2527{ qWarning(
"QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
2529QSize QMainWindowLayout::sizeHint()
const
2531 if (!szHint.isValid()) {
2532 szHint = layoutState.sizeHint();
2533 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
2534 szHint = QSize(qMax(sbHint.width(), szHint.width()),
2535 sbHint.height() + szHint.height());
2540QSize QMainWindowLayout::minimumSize()
const
2542 if (!minSize.isValid()) {
2543 minSize = layoutState.minimumSize();
2544 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
2545 minSize = QSize(qMax(sbMin.width(), minSize.width()),
2546 sbMin.height() + minSize.height());
2551void QMainWindowLayout::invalidate()
2553 QLayout::invalidate();
2554 minSize = szHint = QSize();
2557#if QT_CONFIG(dockwidget)
2558void QMainWindowLayout::setCurrentHoveredFloat(QDockWidgetGroupWindow *w)
2560 if (currentHoveredFloat != w) {
2561 if (currentHoveredFloat) {
2562 disconnect(currentHoveredFloat.data(), &QObject::destroyed,
2563 this, &QMainWindowLayout::updateGapIndicator);
2564 disconnect(currentHoveredFloat.data(), &QDockWidgetGroupWindow::resized,
2565 this, &QMainWindowLayout::updateGapIndicator);
2566 if (currentHoveredFloat)
2567 currentHoveredFloat->restore();
2569 restore(QInternal::KeepSavedState);
2572 currentHoveredFloat = w;
2575 connect(w, &QObject::destroyed,
2576 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2577 connect(w, &QDockWidgetGroupWindow::resized,
2578 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2581 updateGapIndicator();
2587
2588
2592#if QT_CONFIG(toolbar)
2593 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
2594 if (toolBar ==
nullptr)
2597 QRect oldGeo = toolBar->geometry();
2599 QInternal::DockPosition pos
2600 =
static_cast<QInternal::DockPosition>(dockPos);
2601 Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
2602 ? Qt::Horizontal : Qt::Vertical;
2603 if (o != toolBar->orientation())
2604 toolBar->setOrientation(o);
2606 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
2607 .expandedTo(toolBar->minimumSize());
2609 if (toolBar->size() != hint) {
2610 QRect newGeo(oldGeo.topLeft(), hint);
2611 if (toolBar->layoutDirection() == Qt::RightToLeft)
2612 newGeo.moveRight(oldGeo.right());
2613 toolBar->setGeometry(newGeo);
2622void QMainWindowLayout::revert(QLayoutItem *widgetItem)
2624 if (!savedState.isValid())
2627 QWidget *widget = widgetItem->widget();
2628 layoutState = savedState;
2629 currentGapPos = layoutState.indexOf(widget);
2630 if (currentGapPos.isEmpty())
2632 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2633 layoutState.unplug(currentGapPos);
2634 layoutState.fitLayout();
2635 currentGapRect = layoutState.itemRect(currentGapPos);
2640bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
2642#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) && QT_CONFIG(tabbar)
2643 if (currentHoveredFloat) {
2644 QWidget *widget = widgetItem->widget();
2645 QList<
int> previousPath = layoutState.indexOf(widget);
2646 if (!previousPath.isEmpty())
2647 layoutState.remove(previousPath);
2648 previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2651 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2652 for (QDockWidgetGroupWindow *dwgw : groups) {
2653 if (dwgw == currentHoveredFloat)
2655 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2656 if (!path.isEmpty())
2657 dwgw->layoutInfo()->remove(path);
2659 currentGapRect = QRect();
2660 currentHoveredFloat->apply();
2661 if (!previousPath.isEmpty())
2662 currentHoveredFloat->layoutInfo()->remove(previousPath);
2663 QRect globalRect = currentHoveredFloat->currentGapRect;
2664 globalRect.moveTopLeft(currentHoveredFloat->mapToGlobal(globalRect.topLeft()));
2665 pluggingWidget = widget;
2666 const auto rule = toAnimationRule(dockOptions);
2667 widgetAnimator.animate(widget, globalRect, rule);
2672 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
2675 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2677 QWidget *widget = widgetItem->widget();
2679#if QT_CONFIG(dockwidget)
2682 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2683 for (QDockWidgetGroupWindow *dwgw : groups) {
2684 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2685 if (!path.isEmpty())
2686 dwgw->layoutInfo()->remove(path);
2690 QList<
int> previousPath = layoutState.indexOf(widget);
2692 const QLayoutItem *it = layoutState.plug(currentGapPos);
2695 Q_ASSERT(it == widgetItem);
2696 if (!previousPath.isEmpty())
2697 layoutState.remove(previousPath);
2699 pluggingWidget = widget;
2700 QRect globalRect = currentGapRect;
2701 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
2702#if QT_CONFIG(dockwidget)
2703 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2704 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
2705 if (layout->nativeWindowDeco()) {
2706 globalRect.adjust(0, layout->titleHeight(), 0, 0);
2708 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, widget);
2709 globalRect.adjust(-fw, -fw, fw, fw);
2713 const auto rule = toAnimationRule(dockOptions);
2714 widgetAnimator.animate(widget, globalRect, rule);
2719void QMainWindowLayout::animationFinished(QWidget *widget)
2723#if QT_CONFIG(toolbar)
2724 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2725 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
2726 if (tbl->animating) {
2727 tbl->animating =
false;
2729 tbl->layoutActions(tb->size());
2735 if (widget == pluggingWidget) {
2737#if QT_CONFIG(dockwidget)
2738#if QT_CONFIG(tabbar)
2739 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
2743 QDockAreaLayoutInfo *srcInfo = dwgw->layoutInfo();
2744 const QDockAreaLayoutInfo *srcTabInfo = dwgw->tabLayoutInfo();
2745 QDockAreaLayoutInfo *dstParentInfo;
2748 if (currentHoveredFloat) {
2749 dstPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2750 Q_ASSERT(dstPath.size() >= 1);
2751 dstParentInfo = currentHoveredFloat->layoutInfo()->info(dstPath);
2753 dstPath = layoutState.dockAreaLayout.indexOf(widget);
2754 Q_ASSERT(dstPath.size() >= 2);
2755 dstParentInfo = layoutState.dockAreaLayout.info(dstPath);
2757 Q_ASSERT(dstParentInfo);
2758 int idx = dstPath.constLast();
2759 Q_ASSERT(dstParentInfo->item_list[idx].widgetItem->widget() == dwgw);
2760 if (dstParentInfo->tabbed && srcTabInfo) {
2762 delete dstParentInfo->item_list[idx].widgetItem;
2763 dstParentInfo->item_list.removeAt(idx);
2764 std::copy(srcTabInfo->item_list.cbegin(), srcTabInfo->item_list.cend(),
2765 std::inserter(dstParentInfo->item_list,
2766 dstParentInfo->item_list.begin() + idx));
2767 quintptr currentId = srcTabInfo->currentTabId();
2768 *srcInfo = QDockAreaLayoutInfo();
2769 dstParentInfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2771 dstParentInfo->updateTabBar();
2772 dstParentInfo->setCurrentTabId(currentId);
2774 QDockAreaLayoutItem &item = dstParentInfo->item_list[idx];
2775 Q_ASSERT(item.widgetItem->widget() == dwgw);
2776 delete item.widgetItem;
2777 item.widgetItem =
nullptr;
2778 item.subinfo =
new QDockAreaLayoutInfo(std::move(*srcInfo));
2779 *srcInfo = QDockAreaLayoutInfo();
2780 item.subinfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2782 item.subinfo->setTabBarShape(dstParentInfo->tabBarShape);
2784 dwgw->destroyOrHideIfEmpty();
2788 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2789 dw->setParent(currentHoveredFloat ? currentHoveredFloat.data() : parentWidget());
2791 dw->d_func()->plug(currentGapRect);
2794#if QT_CONFIG(toolbar)
2795 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
2796 tb->d_func()->plug(currentGapRect);
2800 currentGapPos.clear();
2801 pluggingWidget =
nullptr;
2802#if QT_CONFIG(dockwidget)
2803 setCurrentHoveredFloat(
nullptr);
2807 layoutState.apply(QWidgetAnimator::AnimationRule::Stop);
2809#if QT_CONFIG(dockwidget)
2810#if QT_CONFIG(tabbar)
2811 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2814 if (QDockAreaLayoutInfo *info = dockInfo(widget))
2815 info->setCurrentTab(widget);
2821 if (!widgetAnimator.animating()) {
2823#if QT_CONFIG(dockwidget)
2824 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
2825#if QT_CONFIG(tabbar)
2831 updateGapIndicator();
2834void QMainWindowLayout::restore(QInternal::SaveStateRule rule)
2836 if (!savedState.isValid())
2839 layoutState = savedState;
2840 applyState(layoutState);
2841 if (rule == QInternal::ClearSavedState)
2843 currentGapPos.clear();
2844 pluggingWidget =
nullptr;
2845 updateGapIndicator();
2848QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout)
2849 : QLayout(parentLayout ?
static_cast<QWidget *>(
nullptr) : mainwindow)
2850 , layoutState(mainwindow)
2851 , savedState(mainwindow)
2852 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
2853 , statusbar(
nullptr)
2854#if QT_CONFIG(dockwidget)
2855#if QT_CONFIG(tabbar)
2856 , _documentMode(
false)
2857 , verticalTabsEnabled(
false)
2858#if QT_CONFIG(tabwidget)
2859 , _tabShape(QTabWidget::Rounded)
2863 , widgetAnimator(
this)
2864 , pluggingWidget(
nullptr)
2867 setParent(parentLayout);
2869#if QT_CONFIG(dockwidget)
2870#if QT_CONFIG(tabbar)
2871 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent,
nullptr, mainwindow);
2874#if QT_CONFIG(tabwidget)
2875 for (
int i = 0; i < QInternal::DockCount; ++i)
2876 tabPositions[i] = QTabWidget::South;
2879 pluggingWidget =
nullptr;
2881 setObjectName(mainwindow->objectName() +
"_layout"_L1);
2884QMainWindowLayout::~QMainWindowLayout()
2886 layoutState.deleteAllLayoutItems();
2887 layoutState.deleteCentralWidgetItem();
2892void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
2894 if (opts == dockOptions)
2899#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
2900 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
2906#if QT_CONFIG(statusbar)
2907QStatusBar *QMainWindowLayout::statusBar()
const
2908{
return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
2910void QMainWindowLayout::setStatusBar(QStatusBar *sb)
2915 statusbar = sb ?
new QWidgetItemV2(sb) :
nullptr;
2920QWidget *QMainWindowLayout::centralWidget()
const
2922 return layoutState.centralWidget();
2925void QMainWindowLayout::setCentralWidget(QWidget *widget)
2927 if (widget !=
nullptr)
2928 addChildWidget(widget);
2929 layoutState.setCentralWidget(widget);
2930 if (savedState.isValid()) {
2931#if QT_CONFIG(dockwidget)
2932 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
2933 savedState.dockAreaLayout.fallbackToSizeHints =
true;
2935 savedState.centralWidgetItem = layoutState.centralWidgetItem;
2941#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2943
2944
2945
2946
2947
2948
2949static bool unplugGroup(QMainWindowLayout *layout, QLayoutItem **item,
2950 QDockAreaLayoutItem &parentItem)
2952 if (!parentItem.subinfo || !parentItem.subinfo->tabbed)
2956 QDockWidgetGroupWindow *floatingTabs = layout->createTabbedDockWindow();
2957 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
2958 *info = std::move(*parentItem.subinfo);
2959 delete parentItem.subinfo;
2960 parentItem.subinfo =
nullptr;
2961 floatingTabs->setGeometry(info->rect.translated(layout->parentWidget()->pos()));
2962 floatingTabs->show();
2963 floatingTabs->raise();
2964 *item =
new QDockWidgetGroupWindowItem(floatingTabs);
2965 parentItem.widgetItem = *item;
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope)
2982#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2983 auto *groupWindow = qobject_cast<
const QDockWidgetGroupWindow *>(widget->parentWidget());
2984 if (!widget->isWindow() && groupWindow) {
2985 if (scope == QDockWidgetPrivate::DragScope::Group && groupWindow->tabLayoutInfo()) {
2988 if (QDockAreaLayoutInfo *info = dockInfo(widget->parentWidget())) {
2989 QList<
int> groupWindowPath = info->indexOf(widget->parentWidget());
2990 return groupWindowPath.isEmpty() ?
nullptr : info->item(groupWindowPath).widgetItem;
2992 qCDebug(lcQpaDockWidgets) <<
"Drag only:" << widget <<
"Group:" << (scope == QDockWidgetPrivate::DragScope::Group);
2995 const QList<
int> path = groupWindow->layoutInfo()->indexOf(widget);
2996 QDockAreaLayoutItem parentItem = groupWindow->layoutInfo()->item(path);
2997 QLayoutItem *item = parentItem.widgetItem;
2998 if (scope == QDockWidgetPrivate::DragScope::Group && path.size() > 1
2999 && unplugGroup(
this, &item, parentItem)) {
3000 qCDebug(lcQpaDockWidgets) <<
"Unplugging:" << widget <<
"from" << item;
3004 QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget);
3005 Q_ASSERT(dockWidget);
3006 dockWidget->d_func()->unplug(widget->geometry());
3008 qCDebug(lcQpaDockWidgets) <<
"Unplugged from floating dock:" << widget <<
"from" << groupWindow;
3013 QList<
int> path = layoutState.indexOf(widget);
3017 QLayoutItem *item = layoutState.item(path);
3018 if (widget->isWindow())
3021 QRect r = layoutState.itemRect(path);
3022 savedState = layoutState;
3024#if QT_CONFIG(dockwidget)
3025 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
3026 Q_ASSERT(path.constFirst() == 1);
3027#if QT_CONFIG(tabwidget)
3028 if (scope == QDockWidgetPrivate::DragScope::Group && (dockOptions & QMainWindow::GroupedDragging) && path.size() > 3
3029 && unplugGroup(
this, &item,
3030 layoutState.dockAreaLayout.item(path.mid(1, path.size() - 2)))) {
3032 savedState = layoutState;
3038 switch (dockWidgetArea(dw)) {
3039 case Qt::LeftDockWidgetArea:
3040 case Qt::RightDockWidgetArea:
3041 r.setHeight(r.height() - sep);
3043 case Qt::TopDockWidgetArea:
3044 case Qt::BottomDockWidgetArea:
3045 r.setWidth(r.width() - sep);
3047 case Qt::NoDockWidgetArea:
3048 case Qt::DockWidgetArea_Mask:
3056 const auto *layout = qobject_cast<QDockWidgetLayout *>(dw->layout());
3057 const bool verticalTitleBar = layout ? layout->verticalTitleBar :
false;
3058 const int tbHeight = QApplication::style()
3059 ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight,
nullptr, dw)
3061 const int minHeight = verticalTitleBar ? 2 * tbHeight : tbHeight;
3062 const int minWidth = verticalTitleBar ? tbHeight : 2 * tbHeight;
3063 r.setSize(r.size().expandedTo(QSize(minWidth, minHeight)));
3064 qCDebug(lcQpaDockWidgets) << dw <<
"will be unplugged with size" << r.size();
3066 dw->d_func()->unplug(r);
3070#if QT_CONFIG(toolbar)
3071 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
3072 tb->d_func()->unplug(r);
3076#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
3080 layoutState.unplug(path ,&savedState);
3081 savedState.fitLayout();
3082 currentGapPos = path;
3084 updateGapIndicator();
3086 fixToolBarOrientation(item, currentGapPos.at(1));
3091void QMainWindowLayout::updateGapIndicator()
3093#if QT_CONFIG(rubberband)
3094 if (!widgetAnimator.animating() && (!currentGapPos.isEmpty()
3095#if QT_CONFIG(dockwidget)
3096 || currentHoveredFloat
3099 QWidget *expectedParent =
3100#if QT_CONFIG(dockwidget)
3101 currentHoveredFloat ? currentHoveredFloat.data() :
3104 if (!gapIndicator) {
3105 gapIndicator =
new QRubberBand(QRubberBand::Rectangle, expectedParent);
3107 gapIndicator->setObjectName(
"qt_rubberband"_L1);
3108 }
else if (gapIndicator->parent() != expectedParent) {
3109 gapIndicator->setParent(expectedParent);
3113 const bool sigBlockState = gapIndicator->signalsBlocked();
3114 auto resetSignals = qScopeGuard([
this, sigBlockState](){ gapIndicator->blockSignals(sigBlockState); });
3115 gapIndicator->blockSignals(
true);
3117#if QT_CONFIG(dockwidget)
3118 if (currentHoveredFloat)
3119 gapIndicator->setGeometry(currentHoveredFloat->currentGapRect);
3122 gapIndicator->setGeometry(currentGapRect);
3124 gapIndicator->show();
3125 gapIndicator->raise();
3129 }
else if (gapIndicator) {
3130 gapIndicator->hide();
3136void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
3137 const QPoint &mousePos) {
3138 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() ||
3139 pluggingWidget !=
nullptr || hoverTarget ==
nullptr)
3142 QWidget *widget = hoverTarget->widget();
3144#if QT_CONFIG(dockwidget)
3146 if ((dockOptions & QMainWindow::GroupedDragging) && (qobject_cast<QDockWidget*>(widget)
3147 || qobject_cast<QDockWidgetGroupWindow *>(widget))) {
3150 QVarLengthArray<QWidget *, 10> candidates;
3151 const auto siblings = parentWidget()->children();
3152 for (QObject *c : siblings) {
3153 QWidget *w = qobject_cast<QWidget*>(c);
3158 if (!qobject_cast<QDockWidget*>(w) && !qobject_cast<QDockWidgetGroupWindow *>(w))
3164 if (w != widget && w->isWindow() && w->isVisible() && !w->isMinimized())
3167 if (QDockWidgetGroupWindow *group = qobject_cast<QDockWidgetGroupWindow *>(w)) {
3170 const auto groupChildren = group->children();
3171 for (QObject *c : groupChildren) {
3172 if (QDockWidget *dw = qobject_cast<QDockWidget*>(c)) {
3173 if (dw != widget && dw->isFloating() && dw->isVisible() && !dw->isMinimized())
3180 for (QWidget *w : candidates) {
3181 const QScreen *screen1 = qt_widget_private(widget)->associatedScreen();
3182 const QScreen *screen2 = qt_widget_private(w)->associatedScreen();
3183 if (screen1 && screen2 && screen1 != screen2)
3185 if (!w->geometry().contains(mousePos))
3188#if QT_CONFIG(tabwidget)
3189 if (
auto dropTo = qobject_cast<QDockWidget *>(w)) {
3192 w = dropTo->widget();
3195 if (!qobject_cast<QDockWidgetGroupWindow *>(w)) {
3196 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
3197 floatingTabs->setGeometry(dropTo->geometry());
3198 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
3199 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dropTo);
3206 QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(dropTo));
3207 if (dockPosition == QInternal::DockPosition::DockCount)
3208 dockPosition = toDockPos(dockWidgetArea(widget));
3209 if (dockPosition == QInternal::DockPosition::DockCount)
3210 dockPosition = QInternal::DockPosition::RightDock;
3212 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPosition,
3213 Qt::Horizontal, shape,
3214 static_cast<QMainWindow *>(parentWidget()));
3215 info->tabBar = getTabBar();
3216 info->tabbed =
true;
3218 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[dockPosition];
3219 parentInfo.add(floatingTabs);
3220 dropTo->setParent(floatingTabs);
3221 qCDebug(lcQpaDockWidgets) <<
"Wrapping" << widget <<
"into floating tabs" << floatingTabs;
3227 qCDebug(lcQpaDockWidgets) <<
"Showing" << dropTo;
3229 qCDebug(lcQpaDockWidgets) <<
"Raising" << widget;
3232 auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(w);
3233 Q_ASSERT(groupWindow);
3234 if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) {
3236 setCurrentHoveredFloat(groupWindow);
3237 applyState(layoutState);
3245 if (currentHoveredFloat)
3246 currentHoveredFloat->destroyIfSingleItemLeft();
3248 setCurrentHoveredFloat(
nullptr);
3249 layoutState.dockAreaLayout.fallbackToSizeHints =
false;
3252 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
3254 if (!savedState.isValid())
3255 savedState = layoutState;
3257 QList<
int> path = savedState.gapIndex(widget, pos);
3259 if (!path.isEmpty()) {
3260 bool allowed =
false;
3262#if QT_CONFIG(dockwidget)
3263 allowed = isAreaAllowed(widget, path);
3265#if QT_CONFIG(toolbar)
3266 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
3267 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
3274 if (path == currentGapPos)
3277 currentGapPos = path;
3278 if (path.isEmpty()) {
3279 fixToolBarOrientation(hoverTarget, 2);
3280 restore(QInternal::KeepSavedState);
3284 fixToolBarOrientation(hoverTarget, currentGapPos.at(1));
3286 QMainWindowLayoutState newState = savedState;
3288 if (!newState.insertGap(path, hoverTarget)) {
3289 restore(QInternal::KeepSavedState);
3293 QSize min = newState.minimumSize();
3294 QSize size = newState.rect.size();
3296 if (min.width() > size.width() || min.height() > size.height()) {
3297 restore(QInternal::KeepSavedState);
3301 newState.fitLayout();
3303 currentGapRect = newState.gapRect(currentGapPos);
3305#if QT_CONFIG(dockwidget)
3306 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
3308 layoutState = std::move(newState);
3309 applyState(layoutState);
3311 updateGapIndicator();
3314#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3315QDockWidgetGroupWindow *QMainWindowLayout::createTabbedDockWindow()
3317 QDockWidgetGroupWindow* f =
new QDockWidgetGroupWindow(parentWidget(), Qt::Tool);
3318 new QDockWidgetGroupLayout(f);
3323void QMainWindowLayout::applyState(QMainWindowLayoutState &newState,
bool animate)
3330 isInApplyState =
true;
3331#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3332 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
3334 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
3335 for (QDockWidgetGroupWindow *dwgw : groups)
3336 used += dwgw->layoutInfo()->usedTabBars();
3338 const QSet<QTabBar*> retired = usedTabBars - used;
3340 for (QTabBar *tab_bar : retired) {
3341 unuseTabBar(tab_bar);
3345 const QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
3346 const QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
3347 usedSeparatorWidgets = usedSeps;
3348 for (QWidget *sepWidget : retiredSeps)
3352 for (
int i = 0; i < QInternal::DockCount; ++i)
3353 newState.dockAreaLayout.docks[i].reparentWidgets(parentWidget());
3356 const auto rule = animate ? toAnimationRule(dockOptions) : QWidgetAnimator::AnimationRule::Stop;
3357 newState.apply(rule);
3358 isInApplyState =
false;
3361void QMainWindowLayout::saveState(QDataStream &stream)
const
3363 layoutState.saveState(stream);
3366bool QMainWindowLayout::restoreState(QDataStream &stream)
3368 QScopedValueRollback<
bool> guard(isInRestoreState,
true);
3369 savedState = layoutState;
3370 layoutState.clear();
3371 layoutState.rect = savedState.rect;
3373 if (!layoutState.restoreState(stream, savedState)) {
3374 layoutState.deleteAllLayoutItems();
3375 layoutState = savedState;
3376 if (parentWidget()->isVisible())
3377 applyState(layoutState,
false);
3381 if (parentWidget()->isVisible()) {
3382 layoutState.fitLayout();
3383 applyState(layoutState,
false);
3386
3387
3388
3389
3390
3391
3392 if ((parentWidget()->windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized))
3393 && !layoutState.fits()) {
3394 restoredState.reset(
new QMainWindowLayoutState(layoutState));
3398 savedState.deleteAllLayoutItems();
3401#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
3402 if (parentWidget()->isVisible())
3409#if QT_CONFIG(draganddrop)
3410bool QMainWindowLayout::needsPlatformDrag()
3412 static const bool wayland =
3413 QGuiApplication::platformName().startsWith(
"wayland"_L1, Qt::CaseInsensitive);
3417Qt::DropAction QMainWindowLayout::performPlatformWidgetDrag(QLayoutItem *widgetItem,
3418 const QPoint &pressPosition)
3420 draggingWidget = widgetItem;
3421 QWidget *widget = widgetItem->widget();
3422 auto drag = QDrag(widget);
3423 auto mimeData =
new QMimeData();
3424 auto window = widgetItem->widget()->windowHandle();
3426 auto serialize = [](
const auto &object) {
3428 QDataStream dataStream(&data, QIODevice::WriteOnly);
3429 dataStream << object;
3432 mimeData->setData(
"application/x-qt-mainwindowdrag-window"_L1,
3433 serialize(
reinterpret_cast<qintptr>(window)));
3434 mimeData->setData(
"application/x-qt-mainwindowdrag-position"_L1, serialize(pressPosition));
3435 drag.setMimeData(mimeData);
3437 auto result = drag.exec();
3439 draggingWidget =
nullptr;
3444#if defined(Q_OS_MACOS)
3445void QMainWindowLayout::registerUnifiedToolBarArea(QWidget *widget,
int upper,
int lower)
3447 qCDebug(lcUnifiedToolBar) <<
"Registering unified toolbar area" << upper << lower <<
"for" << widget;
3448 m_unifiedToolBarAreas.insert(widget, UnifiedToolBarRange(widget, upper, lower));
3449 updateUnifiedToolBarArea();
3452void QMainWindowLayout::setUnifiedToolBarAreaEnabled(QWidget *widget,
bool enable)
3454 qCDebug(lcUnifiedToolBar) << (enable ?
"Enabling" :
"Disabling") <<
"unified toolbar area for" << widget;
3455 m_enabledUnifiedToolBarAreas.insert(widget, enable);
3456 updateUnifiedToolBarArea();
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470void QMainWindowLayout::updateUnifiedToolBarArea()
3472 qCDebug(lcUnifiedToolBar) <<
"Updating unified toolbar area";
3474 QWindow *window = parentWidget()->windowHandle();
3476 qCDebug(lcUnifiedToolBar) <<
"No window yet, skipping";
3481 std::vector<UnifiedToolBarRange> ranges(m_unifiedToolBarAreas.cbegin(), m_unifiedToolBarAreas.cend());
3482 std::sort(ranges.begin(), ranges.end());
3486 const auto safeAreaMargins = QWidgetPrivate::get(parentWidget())->safeAreaMargins();
3487 int height = safeAreaMargins.top();
3489 for (UnifiedToolBarRange range : ranges) {
3490 bool enabled = m_enabledUnifiedToolBarAreas.value(range.widget,
false);
3491 qCDebug(lcUnifiedToolBar) <<
"Considering" << (enabled ?
"enabled" :
"disabled")
3492 <<
"toolbar area" << range.upper << range.lower <<
"for" << range.widget;
3503 if (range.upper <= (height + 1))
3504 height = qMax(height, range.lower);
3509 QSize unifiedToolBarAreaSize(window->width(), height);
3510 if (unifiedToolBarAreaSize == m_unifiedToolBarAreaSize)
3513 qCDebug(lcUnifiedToolBar) <<
"New unified toolbar area size is" << unifiedToolBarAreaSize;
3514 m_unifiedToolBarAreaSize = unifiedToolBarAreaSize;
3518 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSTahoe) {
3519 if (
auto *cocoaWindow = window->nativeInterface<QNativeInterface::Private::QCocoaWindow>()) {
3520 cocoaWindow->manageVisualEffectArea(quintptr(
this), QRect(QPoint(), m_unifiedToolBarAreaSize),
3521 NSVisualEffectMaterial(3) ,
3522 NSVisualEffectBlendingMode(1) ,
3523 NSVisualEffectState(0) );
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538bool QMainWindowLayout::testUnifiedToolBarAreaPosition(
int position)
const
3540 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
3541 if (!mainWindow->unifiedTitleAndToolBarOnMac())
3544 qCDebug(lcUnifiedToolBar) <<
"Testing whether" << position <<
"is part of"
3545 <<
"unified toolbar area" << m_unifiedToolBarAreaSize;
3547 return 0 <= position && position < m_unifiedToolBarAreaSize.height();
3554#include "qmainwindowlayout.moc"
3555#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 constexpr QWidgetAnimator::AnimationRule toAnimationRule(QMainWindow::DockOptions options)
QTextStream & operator<<(QTextStream &s, QTextStreamFunction f)
QDataStream & operator>>(QDataStream &stream, QImage &image)