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>
55#include <QtCore/private/qoffsetstringarray_p.h>
61Q_LOGGING_CATEGORY(lcMainWindowLayout,
"qt.mainwindow.layout");
63#if defined(Q_OS_MACOS)
64Q_STATIC_LOGGING_CATEGORY(lcUnifiedToolBar,
"qt.mainwindow.unifiedtoolbar");
68using StateMarkers = QMainWindowLayoutState::StateMarkers;
71using StateMarkers = QMainWindowLayoutState::StateMarkers;
75 return options.testFlag(QMainWindow::AnimatedDocks) ? QWidgetAnimator::AnimationRule::Run
76 : QWidgetAnimator::AnimationRule::Stop;
80
81
83#if QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG_STREAM)
85static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent);
87static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutItem &item, QString indent)
89 qout << indent <<
"QDockAreaLayoutItem: "
90 <<
"pos: " << item.pos <<
" size:" << item.size
91 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
92 <<
" keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) <<
'\n';
94 if (item.widgetItem !=
nullptr) {
95 qout << indent <<
"widget: "
96 << item.widgetItem->widget()->metaObject()->className()
97 <<
" \"" << item.widgetItem->widget()->windowTitle() <<
"\"\n";
98 }
else if (item.subinfo !=
nullptr) {
99 qout << indent <<
"subinfo:\n";
100 dumpLayout(qout, *item.subinfo, indent +
" "_L1);
101 }
else if (item.placeHolderItem !=
nullptr) {
102 QRect r = item.placeHolderItem->topLevelRect;
103 qout << indent <<
"placeHolder: "
104 <<
"pos: " << item.pos <<
" size:" << item.size
105 <<
" gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
106 <<
" keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize)
107 <<
" objectName:" << item.placeHolderItem->objectName
108 <<
" hidden:" << item.placeHolderItem->hidden
109 <<
" window:" << item.placeHolderItem->window
110 <<
" rect:" << r.x() <<
',' << r.y() <<
' '
111 << r.width() <<
'x' << r.height() <<
'\n';
115static void dumpLayout(QTextStream &qout,
const QDockAreaLayoutInfo &layout, QString indent)
117 const QSize minSize = layout.minimumSize();
118 qout << indent <<
"QDockAreaLayoutInfo: "
119 << layout.rect.left() <<
','
120 << layout.rect.top() <<
' '
121 << layout.rect.width() <<
'x'
122 << layout.rect.height()
123 <<
" min size: " << minSize.width() <<
',' << minSize.height()
124 <<
" orient:" << layout.o
126 <<
" tabbed:" << layout.tabbed
127 <<
" tbshape:" << layout.tabBarShape
133 for (
int i = 0; i < layout.item_list.size(); ++i) {
134 qout << indent <<
"Item: " << i <<
'\n';
135 dumpLayout(qout, layout.item_list.at(i), indent +
" "_L1);
139static void dumpLayout(QTextStream &qout,
const QDockAreaLayout &layout)
141 qout <<
"QDockAreaLayout: "
142 << layout.rect.left() <<
','
143 << layout.rect.top() <<
' '
144 << layout.rect.width() <<
'x'
145 << layout.rect.height() <<
'\n';
147 qout <<
"TopDockArea:\n";
148 dumpLayout(qout, layout.docks[QInternal::TopDock],
" "_L1);
149 qout <<
"LeftDockArea:\n";
150 dumpLayout(qout, layout.docks[QInternal::LeftDock],
" "_L1);
151 qout <<
"RightDockArea:\n";
152 dumpLayout(qout, layout.docks[QInternal::RightDock],
" "_L1);
153 qout <<
"BottomDockArea:\n";
154 dumpLayout(qout, layout.docks[QInternal::BottomDock],
" "_L1);
157QDebug operator<<(QDebug debug,
const QDockAreaLayout &layout)
161 dumpLayout(str, layout);
166QDebug operator<<(QDebug debug,
const QMainWindowLayout *layout)
169 return std::move(debug) << layout->layoutState.dockAreaLayout;
170 return debug <<
"QMainWindowLayout(0x0)";
176static void dumpItemLists(
const QMainWindowLayout *layout,
const char *function,
const char *comment)
178 for (
int i = 0; i < QInternal::DockCount; ++i) {
179 const auto &list = layout->layoutState.dockAreaLayout.docks[i].item_list;
182 qDebug() << function << comment <<
"Dock" << i << list;
185#define DUMP(comment) dumpItemLists(this, __FUNCTION__, comment)
190#ifndef QT_NO_DEBUG_STREAM
191QDebug operator<<(QDebug debug, StateMarkers marker)
193#define CASE(val) case QMainWindowLayoutState::StateMarkers::val:
194 debug.noquote().nospace() << "StateMarkers::" << #val;
197 QDebugStateSaver saver(debug);
199 CASE(FloatingDockWidgetTab);
212 stream << uchar(marker);
213 qCDebug(lcMainWindowLayout) <<
"Writing state marker" << marker;
221 marker =
static_cast<StateMarkers>(m);
222 qCDebug(lcMainWindowLayout) <<
"Reading state marker" << marker;
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
255
256
257
260#if QT_CONFIG(dockwidget)
261class QDockWidgetGroupLayout :
public QLayout,
262 public QMainWindowLayoutSeparatorHelper<QDockWidgetGroupLayout>
264 QWidgetResizeHandler *resizer;
266 QDockWidgetGroupLayout(QDockWidgetGroupWindow* parent) : QLayout(parent) {
267 setSizeConstraint(QLayout::SetMinAndMaxSize);
268 resizer =
new QWidgetResizeHandler(parent);
270 ~QDockWidgetGroupLayout() {
271 layoutState.deleteAllLayoutItems();
274 void addItem(QLayoutItem*) override { Q_UNREACHABLE(); }
275 int count()
const override {
return 0; }
276 QLayoutItem* itemAt(
int index)
const override
279 return layoutState.itemAt(&x, index);
281 QLayoutItem* takeAt(
int index) override
284 QLayoutItem *ret = layoutState.takeAt(&x, index);
285 if (savedState.rect.isValid() && ret->widget()) {
287 QList<
int> path = savedState.indexOf(ret->widget());
289 savedState.remove(path);
291 path = layoutState.indexOf(ret->widget());
293 layoutState.remove(path);
297 QSize sizeHint()
const override
299 int fw = frameWidth();
300 return layoutState.sizeHint() + QSize(fw, fw);
302 QSize minimumSize()
const override
304 int fw = frameWidth();
305 return layoutState.minimumSize() + QSize(fw, fw);
307 QSize maximumSize()
const override
309 int fw = frameWidth();
310 return layoutState.maximumSize() + QSize(fw, fw);
312 void setGeometry(
const QRect&r) override
314 groupWindow()->destroyOrHideIfEmpty();
315 QDockAreaLayoutInfo *li = dockAreaLayoutInfo();
318 int fw = frameWidth();
320 li->reparentWidgets(parentWidget());
322 li->rect = r.adjusted(fw, fw, -fw, -fw);
324 li->apply(QWidgetAnimator::AnimationRule::Stop);
325 if (savedState.rect.isValid())
326 savedState.rect = li->rect;
327 resizer->setEnabled(!nativeWindowDeco());
330 QDockAreaLayoutInfo *dockAreaLayoutInfo() {
return &layoutState; }
332#if QT_CONFIG(toolbar)
333 QToolBarAreaLayout *toolBarAreaLayout()
339 bool nativeWindowDeco()
const
341 return groupWindow()->hasNativeDecos();
344 int frameWidth()
const
346 return nativeWindowDeco() ? 0 :
347 parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, parentWidget());
350 QDockWidgetGroupWindow *groupWindow()
const
352 return static_cast<QDockWidgetGroupWindow *>(parent());
355 QDockAreaLayoutInfo layoutState;
356 QDockAreaLayoutInfo savedState;
359bool QDockWidgetGroupWindow::event(QEvent *e)
361 auto lay =
static_cast<QDockWidgetGroupLayout *>(layout());
362 if (lay && lay->windowEvent(e))
369 if (QDockWidget *dw = activeTabbedDockWidget()) {
378 if (QDockWidget *dw = activeTabbedDockWidget())
379 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->moveEvent(
static_cast<QMoveEvent*>(e));
382 case QEvent::NonClientAreaMouseMove:
383 case QEvent::NonClientAreaMouseButtonPress:
384 case QEvent::NonClientAreaMouseButtonRelease:
385 case QEvent::NonClientAreaMouseButtonDblClick:
388 if (QDockWidget *dw = activeTabbedDockWidget())
389 static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(dw))->nonClientAreaMouseEvent(
static_cast<QMouseEvent*>(e));
392 case QEvent::ChildAdded:
393 if (qobject_cast<QDockWidget *>(
static_cast<QChildEvent*>(e)->child()))
396 case QEvent::LayoutRequest:
398 destroyOrHideIfEmpty();
401 updateCurrentGapRect();
407 return QWidget::event(e);
410void QDockWidgetGroupWindow::paintEvent(QPaintEvent *)
412 QDockWidgetGroupLayout *lay =
static_cast<QDockWidgetGroupLayout *>(layout());
413 bool nativeDeco = lay->nativeWindowDeco();
416 QStyleOptionFrame framOpt;
417 framOpt.initFrom(
this);
418 QStylePainter p(
this);
419 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
423QDockAreaLayoutInfo *QDockWidgetGroupWindow::layoutInfo()
const
425 return static_cast<QDockWidgetGroupLayout *>(layout())->dockAreaLayoutInfo();
430
431
432
433
434const QDockAreaLayoutInfo *QDockWidgetGroupWindow::tabLayoutInfo()
const
436 const QDockAreaLayoutInfo *info = layoutInfo();
437 while (info && !info->tabbed) {
440 const QDockAreaLayoutInfo *next =
nullptr;
441 bool isSingle =
false;
442 for (
const auto &item : info->item_list) {
443 if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
445 if (next || isSingle)
449 else if (item.widgetItem)
460
461
462QDockWidget *QDockWidgetGroupWindow::activeTabbedDockWidget()
const
464 QDockWidget *dw =
nullptr;
465 const QDockAreaLayoutInfo *info = tabLayoutInfo();
468 if (info->tabBar && info->tabBar->currentIndex() >= 0) {
469 int i = info->tabIndexToListIndex(info->tabBar->currentIndex());
471 const QDockAreaLayoutItem &item = info->item_list.at(i);
473 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
477 for (
int i = 0; !dw && i < info->item_list.size(); ++i) {
478 const QDockAreaLayoutItem &item = info->item_list.at(i);
481 if (!item.widgetItem)
483 dw = qobject_cast<QDockWidget *>(item.widgetItem->widget());
491
492
493
494void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
496 const QDockAreaLayoutInfo *info = layoutInfo();
497 if (!info->isEmpty()) {
502 if (!info->item_list.isEmpty()) {
508 const auto dockWidgetsList = dockWidgets();
509 for (QDockWidget *dw : dockWidgetsList) {
510 const bool wasFloating = dw->isFloating();
511 const bool wasHidden = dw->isHidden();
512 dw->setParent(parentWidget());
513 qCDebug(lcQpaDockWidgets) <<
"Reparented:" << dw <<
"to" << parentWidget() <<
"by" <<
this;
515 dw->setFloating(
true);
518 QMainWindowLayout *ml =
519 qt_mainwindow_layout(
static_cast<QMainWindow *>(parentWidget()));
520 Qt::DockWidgetArea area = ml->dockWidgetArea(
this);
521 if (area == Qt::NoDockWidgetArea)
522 area = Qt::LeftDockWidgetArea;
523 static_cast<QMainWindow *>(parentWidget())->addDockWidget(area, dw);
524 qCDebug(lcQpaDockWidgets) <<
"Redocked to Mainwindow:" << area << dw <<
"by" <<
this;
529 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
530 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
531 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
532 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
533 std::unique_ptr<QLayoutItem> cleanup = parentInfo.takeWidgetItem(
this);
534 parentInfo.remove(
this);
539
540
541
542
543bool QDockWidgetGroupWindow::hasVisibleDockWidgets()
const
545 const auto &children = findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
546 for (
auto child : children) {
551 if (!child->testAttribute(Qt::WA_WState_Hidden))
558
559
560void QDockWidgetGroupWindow::adjustFlags()
562 Qt::WindowFlags oldFlags = windowFlags();
563 Qt::WindowFlags flags = oldFlags;
566 QDockWidget *top = activeTabbedDockWidget();
568 QDockWidget *top =
nullptr;
572 ((oldFlags & ~Qt::FramelessWindowHint) | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
573 }
else if (
static_cast<QDockWidgetGroupLayout *>(layout())->nativeWindowDeco()) {
574 flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
575 flags.setFlag(Qt::WindowCloseButtonHint, top->features() & QDockWidget::DockWidgetClosable);
576 flags &= ~Qt::FramelessWindowHint;
578 flags &= ~(Qt::WindowCloseButtonHint | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
579 flags |= Qt::FramelessWindowHint;
582 if (oldFlags != flags) {
585 setWindowFlags(flags);
586 const bool gainedNativeDecos = (oldFlags & Qt::FramelessWindowHint) && !(flags & Qt::FramelessWindowHint);
587 const bool lostNativeDecos = !(oldFlags & Qt::FramelessWindowHint) && (flags & Qt::FramelessWindowHint);
591 if (lostNativeDecos) {
592 QRect newGeometry = geometry();
593 newGeometry.setTop(frameGeometry().top());
594 const int bottomFrame = geometry().top() - frameGeometry().top();
595 m_removedFrameSize = QSize((frameSize() - size()).width(), bottomFrame);
596 setGeometry(newGeometry);
597 }
else if (gainedNativeDecos && m_removedFrameSize.isValid()) {
598 QRect r = geometry();
599 r.adjust(-m_removedFrameSize.width() / 2, 0,
600 -m_removedFrameSize.width() / 2, -m_removedFrameSize.height());
602 m_removedFrameSize = QSize();
605 setVisible(hasVisibleDockWidgets());
608 QWidget *titleBarOf = top ? top : parentWidget();
609 setWindowTitle(titleBarOf->windowTitle());
610 setWindowIcon(titleBarOf->windowIcon());
613bool QDockWidgetGroupWindow::hasNativeDecos()
const
616 QDockWidget *dw = activeTabbedDockWidget();
620 if (!QDockWidgetLayout::wmSupportsNativeWindowDeco())
623 return dw->titleBarWidget() ==
nullptr;
630QT_WARNING_DISABLE_GCC(
"-Waggressive-loop-optimizations")
632
633
634
635
636
637
638bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem,
const QPoint &mousePos)
640 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
641 if (savedState.isEmpty())
642 savedState = *layoutInfo();
644 QMainWindow::DockOptions opts =
static_cast<QMainWindow *>(parentWidget())->dockOptions();
645 QDockAreaLayoutInfo newState = savedState;
646 bool nestingEnabled =
647 (opts & QMainWindow::AllowNestedDocks) && !(opts & QMainWindow::ForceTabbedDocks);
648 QDockAreaLayoutInfo::TabMode tabMode =
649#if !QT_CONFIG(tabbar)
650 QDockAreaLayoutInfo::NoTabs;
652 nestingEnabled ? QDockAreaLayoutInfo::AllowTabs : QDockAreaLayoutInfo::ForceTabs;
653 if (
auto group = qobject_cast<QDockWidgetGroupWindow *>(widgetItem->widget())) {
654 if (!group->tabLayoutInfo())
655 tabMode = QDockAreaLayoutInfo::NoTabs;
657 if (newState.tabbed) {
659 newState.item_list = { QDockAreaLayoutItem(
new QDockAreaLayoutInfo(newState)) };
660 newState.item_list.first().size = pick(savedState.o, savedState.rect.size());
661 newState.tabbed =
false;
662 newState.tabBar =
nullptr;
666 auto newGapPos = newState.gapIndex(mousePos, nestingEnabled, tabMode);
667 Q_ASSERT(!newGapPos.isEmpty());
671 if (newGapPos == currentGapPos || newState.hasGapItem(newGapPos))
674 currentGapPos = newGapPos;
675 newState.insertGap(currentGapPos, widgetItem);
677 *layoutInfo() = std::move(newState);
678 updateCurrentGapRect();
679 const auto rule = toAnimationRule(opts);
680 layoutInfo()->apply(rule);
685void QDockWidgetGroupWindow::updateCurrentGapRect()
687 if (!currentGapPos.isEmpty())
688 currentGapRect = layoutInfo()->info(currentGapPos)->itemRect(currentGapPos.last(),
true);
692
693
694void QDockWidgetGroupWindow::restore()
696 QDockAreaLayoutInfo &savedState =
static_cast<QDockWidgetGroupLayout *>(layout())->savedState;
697 if (!savedState.isEmpty()) {
698 *layoutInfo() = savedState;
699 savedState = QDockAreaLayoutInfo();
701 currentGapRect = QRect();
702 currentGapPos.clear();
704 layoutInfo()->fitItems();
705 const auto *mw =
static_cast<QMainWindow *>(parentWidget());
706 const auto rule = toAnimationRule(mw->dockOptions());
707 layoutInfo()->apply(rule);
711
712
713void QDockWidgetGroupWindow::apply()
715 static_cast<QDockWidgetGroupLayout *>(layout())->savedState.clear();
716 currentGapRect = QRect();
717 layoutInfo()->plug(currentGapPos);
718 currentGapPos.clear();
720 layoutInfo()->apply(QWidgetAnimator::AnimationRule::Stop);
723void QDockWidgetGroupWindow::childEvent(QChildEvent *event)
725 switch (event->type()) {
726 case QEvent::ChildRemoved:
727 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
728 dockWidget->removeEventFilter(
this);
729 destroyIfSingleItemLeft();
731 case QEvent::ChildAdded:
732 if (
auto *dockWidget = qobject_cast<QDockWidget *>(event->child())) {
733 dockWidget->installEventFilter(
this);
734 if (objectName().isEmpty())
735 setObjectName(dockWidget->objectName() + QLatin1String(
"_groupWindow"));
743bool QDockWidgetGroupWindow::eventFilter(QObject *obj, QEvent *event)
745 auto *dockWidget = qobject_cast<QDockWidget *>(obj);
747 return QWidget::eventFilter(obj, event);
749 switch (event->type()) {
753 reparentToMainWindow(dockWidget);
754 dockWidget->setFloating(
false);
760 if (dockWidget->isVisible())
767 return QWidget::eventFilter(obj, event);
770void QDockWidgetGroupWindow::destroyIfSingleItemLeft()
772 const auto &dockWidgets =
this->dockWidgets();
775 if (dockWidgets.count() != 1)
778 auto *lastDockWidget = dockWidgets.at(0);
783 if (layoutInfo()->indexOf(lastDockWidget).isEmpty())
786 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
787 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
788 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
791 mwLayout->unplug(lastDockWidget, QDockWidgetPrivate::DragScope::Widget);
792 const QPoint position = pos();
796 reparentToMainWindow(lastDockWidget);
800 if (lastDockWidget->isFloating())
801 lastDockWidget->move(position);
804 layoutInfo()->item_list.clear();
806 destroyOrHideIfEmpty();
809void QDockWidgetGroupWindow::reparentToMainWindow(QDockWidget *dockWidget)
815 Q_ASSERT(qobject_cast<QMainWindow *>(parentWidget()));
816 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
817 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
819 mwLayout->widgetAnimator.abort(dockWidget);
826 mwLayout->savedState.clear();
827 QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
828 dockWidget->removeEventFilter(
this);
829 parentInfo.add(dockWidget);
830 layoutInfo()->remove(dockWidget);
831 const bool wasFloating = dockWidget->isFloating();
832 const bool wasVisible = dockWidget->isVisible();
833 dockWidget->setParent(mainWindow);
834 dockWidget->setFloating(wasFloating);
835 dockWidget->setVisible(wasVisible);
840
841
845QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win)
847#if QT_CONFIG(toolbar)
848 toolBarAreaLayout(win),
850#if QT_CONFIG(dockwidget)
860QSize QMainWindowLayoutState::sizeHint()
const
865#if QT_CONFIG(dockwidget)
866 result = dockAreaLayout.sizeHint();
868 if (centralWidgetItem)
869 result = centralWidgetItem->sizeHint();
872#if QT_CONFIG(toolbar)
873 result = toolBarAreaLayout.sizeHint(result);
879QSize QMainWindowLayoutState::minimumSize()
const
883#if QT_CONFIG(dockwidget)
884 result = dockAreaLayout.minimumSize();
886 if (centralWidgetItem)
887 result = centralWidgetItem->minimumSize();
890#if QT_CONFIG(toolbar)
891 result = toolBarAreaLayout.minimumSize(result);
898
899
900
901
902bool QMainWindowLayoutState::fits()
const
904 Q_ASSERT(mainWindow);
908#if QT_CONFIG(dockwidget)
909 size = dockAreaLayout.minimumStableSize();
912#if QT_CONFIG(toolbar)
913 size.rwidth() += toolBarAreaLayout.docks[QInternal::LeftDock].rect.width();
914 size.rwidth() += toolBarAreaLayout.docks[QInternal::RightDock].rect.width();
915 size.rheight() += toolBarAreaLayout.docks[QInternal::TopDock].rect.height();
916 size.rheight() += toolBarAreaLayout.docks[QInternal::BottomDock].rect.height();
919 return size.width() <= mainWindow->width() && size.height() <= mainWindow->height();
922void QMainWindowLayoutState::apply(QWidgetAnimator::AnimationRule rule)
924#if QT_CONFIG(toolbar)
925 toolBarAreaLayout.apply(rule);
928#if QT_CONFIG(dockwidget)
930 dockAreaLayout.apply(rule);
932 if (centralWidgetItem) {
933 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
935 layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, rule);
940void QMainWindowLayoutState::fitLayout()
943#if !QT_CONFIG(toolbar)
946 toolBarAreaLayout.rect = rect;
947 r = toolBarAreaLayout.fitLayout();
950#if QT_CONFIG(dockwidget)
951 dockAreaLayout.rect = r;
952 dockAreaLayout.fitLayout();
954 centralWidgetRect = r;
958void QMainWindowLayoutState::deleteAllLayoutItems()
960#if QT_CONFIG(toolbar)
961 toolBarAreaLayout.deleteAllLayoutItems();
964#if QT_CONFIG(dockwidget)
965 dockAreaLayout.deleteAllLayoutItems();
969void QMainWindowLayoutState::deleteCentralWidgetItem()
971#if QT_CONFIG(dockwidget)
972 delete dockAreaLayout.centralWidgetItem;
973 dockAreaLayout.centralWidgetItem =
nullptr;
975 delete centralWidgetItem;
976 centralWidgetItem = 0;
980QLayoutItem *QMainWindowLayoutState::itemAt(
int index,
int *x)
const
982#if QT_CONFIG(toolbar)
983 if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
987#if QT_CONFIG(dockwidget)
988 if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
991 if (centralWidgetItem && (*x)++ == index)
992 return centralWidgetItem;
998QLayoutItem *QMainWindowLayoutState::takeAt(
int index,
int *x)
1000#if QT_CONFIG(toolbar)
1001 if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
1005#if QT_CONFIG(dockwidget)
1006 if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
1009 if (centralWidgetItem && (*x)++ == index) {
1010 QLayoutItem *ret = centralWidgetItem;
1011 centralWidgetItem =
nullptr;
1019QList<
int> QMainWindowLayoutState::indexOf(QWidget *widget)
const
1023#if QT_CONFIG(toolbar)
1025 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
1026 result = toolBarAreaLayout.indexOf(toolBar);
1027 if (!result.isEmpty())
1033#if QT_CONFIG(dockwidget)
1035 if (qobject_cast<QDockWidget *>(widget) || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1036 result = dockAreaLayout.indexOf(widget);
1037 if (!result.isEmpty())
1046bool QMainWindowLayoutState::contains(QWidget *widget)
const
1048#if QT_CONFIG(dockwidget)
1049 if (dockAreaLayout.centralWidgetItem !=
nullptr && dockAreaLayout.centralWidgetItem->widget() == widget)
1051 if (!dockAreaLayout.indexOf(widget).isEmpty())
1054 if (centralWidgetItem && centralWidgetItem->widget() == widget)
1058#if QT_CONFIG(toolbar)
1059 if (!toolBarAreaLayout.indexOf(widget).isEmpty())
1065void QMainWindowLayoutState::setCentralWidget(QWidget *widget)
1067 QLayoutItem *item =
nullptr;
1069 deleteCentralWidgetItem();
1071 if (widget !=
nullptr)
1072 item =
new QWidgetItemV2(widget);
1074#if QT_CONFIG(dockwidget)
1075 dockAreaLayout.centralWidgetItem = item;
1077 centralWidgetItem = item;
1081QWidget *QMainWindowLayoutState::centralWidget()
const
1083 QLayoutItem *item =
nullptr;
1085#if QT_CONFIG(dockwidget)
1086 item = dockAreaLayout.centralWidgetItem;
1088 item = centralWidgetItem;
1091 if (item !=
nullptr)
1092 return item->widget();
1096QList<
int> QMainWindowLayoutState::gapIndex(QWidget *widget,
1097 const QPoint &pos)
const
1101#if QT_CONFIG(toolbar)
1103 if (qobject_cast<QToolBar*>(widget) !=
nullptr) {
1104 result = toolBarAreaLayout.gapIndex(pos);
1105 if (!result.isEmpty())
1111#if QT_CONFIG(dockwidget)
1113 if (qobject_cast<QDockWidget *>(widget) !=
nullptr
1114 || qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1115 bool disallowTabs =
false;
1116#if QT_CONFIG(tabbar)
1117 if (
auto *group = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1118 if (!group->tabLayoutInfo())
1119 disallowTabs =
true;
1122 result = dockAreaLayout.gapIndex(pos, disallowTabs);
1123 if (!result.isEmpty())
1132bool QMainWindowLayoutState::insertGap(
const QList<
int> &path, QLayoutItem *item)
1137 int i = path.first();
1139#if QT_CONFIG(toolbar)
1141 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) !=
nullptr);
1142 return toolBarAreaLayout.insertGap(path.mid(1), item);
1146#if QT_CONFIG(dockwidget)
1148 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) || qobject_cast<QDockWidgetGroupWindow*>(item->widget()));
1149 return dockAreaLayout.insertGap(path.mid(1), item);
1156void QMainWindowLayoutState::remove(
const QList<
int> &path)
1158 int i = path.first();
1160#if QT_CONFIG(toolbar)
1162 toolBarAreaLayout.remove(path.mid(1));
1165#if QT_CONFIG(dockwidget)
1167 dockAreaLayout.remove(path.mid(1));
1171void QMainWindowLayoutState::remove(QLayoutItem *item)
1173#if QT_CONFIG(toolbar)
1174 toolBarAreaLayout.remove(item);
1177#if QT_CONFIG(dockwidget)
1179 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
1180 QList<
int> path = dockAreaLayout.indexOf(dockWidget);
1181 if (!path.isEmpty())
1182 dockAreaLayout.remove(path);
1187void QMainWindowLayoutState::clear()
1189#if QT_CONFIG(toolbar)
1190 toolBarAreaLayout.clear();
1193#if QT_CONFIG(dockwidget)
1194 dockAreaLayout.clear();
1196 centralWidgetRect = QRect();
1202bool QMainWindowLayoutState::isValid()
const
1204 return rect.isValid();
1207QLayoutItem *QMainWindowLayoutState::item(
const QList<
int> &path)
1209 int i = path.first();
1211#if QT_CONFIG(toolbar)
1213 const QToolBarAreaLayoutItem *tbItem = toolBarAreaLayout.item(path.mid(1));
1215 return tbItem->widgetItem;
1219#if QT_CONFIG(dockwidget)
1221 return dockAreaLayout.item(path.mid(1)).widgetItem;
1227QRect QMainWindowLayoutState::itemRect(
const QList<
int> &path)
const
1229 int i = path.first();
1231#if QT_CONFIG(toolbar)
1233 return toolBarAreaLayout.itemRect(path.mid(1));
1236#if QT_CONFIG(dockwidget)
1238 return dockAreaLayout.itemRect(path.mid(1));
1244QRect QMainWindowLayoutState::gapRect(
const QList<
int> &path)
const
1246 int i = path.first();
1248#if QT_CONFIG(toolbar)
1250 return toolBarAreaLayout.itemRect(path.mid(1));
1253#if QT_CONFIG(dockwidget)
1255 return dockAreaLayout.gapRect(path.mid(1));
1261QLayoutItem *QMainWindowLayoutState::plug(
const QList<
int> &path)
1263 int i = path.first();
1265#if QT_CONFIG(toolbar)
1267 return toolBarAreaLayout.plug(path.mid(1));
1270#if QT_CONFIG(dockwidget)
1272 return dockAreaLayout.plug(path.mid(1));
1278QLayoutItem *QMainWindowLayoutState::unplug(
const QList<
int> &path, QMainWindowLayoutState *other)
1280 int i = path.first();
1282#if !QT_CONFIG(toolbar)
1286 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout :
nullptr);
1289#if QT_CONFIG(dockwidget)
1291 return dockAreaLayout.unplug(path.mid(1));
1297void QMainWindowLayoutState::saveState(QDataStream &stream)
const
1299#if QT_CONFIG(dockwidget)
1300 dockAreaLayout.saveState(stream);
1301#if QT_CONFIG(tabbar)
1302 const QList<QDockWidgetGroupWindow *> floatingTabs =
1303 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
1305 for (QDockWidgetGroupWindow *floating : floatingTabs) {
1306 if (floating->layoutInfo()->isEmpty())
1308 stream << StateMarkers::FloatingDockWidgetTab;
1309 stream << floating->geometry();
1310 floating->layoutInfo()->saveState(stream);
1314#if QT_CONFIG(toolbar)
1315 toolBarAreaLayout.saveState(stream);
1320bool QMainWindowLayoutState::checkFormat(QDataStream &stream)
1322 while (!stream.atEnd()) {
1323 StateMarkers marker;
1327#if QT_CONFIG(toolbar)
1328 case StateMarkers::ToolBar:
1329 case StateMarkers::ToolBarEx:
1331 const auto toolBars = mainWindow->findChildren<QToolBar*>();
1332 if (!toolBarAreaLayout.restoreState(stream, toolBars,
static_cast<uchar>(marker), QInternal::Testing))
1338#if QT_CONFIG(dockwidget)
1339 case StateMarkers::DockWidget:
1341 const auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1342 if (!dockAreaLayout.restoreState(stream, dockWidgets, QInternal::Testing))
1346#if QT_CONFIG(tabbar)
1347 case StateMarkers::FloatingDockWidgetTab:
1351 QDockAreaLayoutInfo info;
1352 auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1353 if (!info.restoreState(stream, dockWidgets, QInternal::Testing))
1369bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
1370 const QMainWindowLayoutState &oldState)
1374 while(!_stream.atEnd()) {
1376 QByteArray ba(length,
'\0');
1377 length = _stream.readRawData(ba.data(), ba.size());
1382 QDataStream ds(copy);
1383 ds.setVersion(_stream.version());
1384 if (!checkFormat(ds))
1387 QDataStream stream(copy);
1388 stream.setVersion(_stream.version());
1390 while (!stream.atEnd()) {
1391 StateMarkers marker;
1395#if QT_CONFIG(dockwidget)
1396 case StateMarkers::DockWidget:
1398 const auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1399 if (!dockAreaLayout.restoreState(stream, dockWidgets, QInternal::Live))
1402 for (
auto *w : dockWidgets) {
1403 const QList<
int> path = dockAreaLayout.indexOf(w);
1404 if (path.isEmpty()) {
1405 QList<
int> oldPath = oldState.dockAreaLayout.indexOf(w);
1406 if (oldPath.isEmpty())
1408 QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
1409 if (info ==
nullptr) {
1417#if QT_CONFIG(tabwidget)
1418 case StateMarkers::FloatingDockWidgetTab:
1420 auto dockWidgets = mainWindow->findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
1422 for (
auto *dockWidget : std::as_const(dockWidgets)) {
1423 QPointer<QDockWidgetGroupWindow> gw = qobject_cast<QDockWidgetGroupWindow *>(dockWidget->parent());
1426 const bool visible = gw->isVisible();
1427 gw->reparentToMainWindow(dockWidget);
1428 dockWidget->setFloating(
true);
1429 dockWidget->setVisible(visible);
1432 const auto groupWindows = mainWindow->findChildren<QDockWidgetGroupWindow *>();
1433 for (
auto *gw : groupWindows)
1434 Q_ASSERT(gw->dockWidgets().isEmpty());
1437 QDockWidgetGroupWindow* floatingTab = qt_mainwindow_layout(mainWindow)->createTabbedDockWindow();
1438 *floatingTab->layoutInfo() = QDockAreaLayoutInfo(
1439 &dockAreaLayout.sep, QInternal::LeftDock,
1440 Qt::Horizontal, QTabBar::RoundedSouth, mainWindow);
1443 QDockAreaLayoutInfo *info = floatingTab->layoutInfo();
1444 if (!info->restoreState(stream, dockWidgets, QInternal::Live))
1446 geometry = QDockAreaLayout::constrainedRect(geometry, floatingTab);
1447 floatingTab->move(geometry.topLeft());
1448 floatingTab->resize(geometry.size());
1452 if (info->onlyHasPlaceholders())
1453 info->reparentWidgets(floatingTab);
1455 floatingTab->show();
1461#if QT_CONFIG(toolbar)
1462 case StateMarkers::ToolBar:
1463 case StateMarkers::ToolBarEx:
1465 const auto toolBars = mainWindow->findChildren<QToolBar*>();
1466 if (!toolBarAreaLayout.restoreState(stream, toolBars,
static_cast<uchar>(marker), QInternal::Live))
1469 for (
auto *bar : toolBars) {
1470 const QList<
int> path = toolBarAreaLayout.indexOf(bar);
1471 if (path.isEmpty()) {
1472 const QList<
int> oldPath = oldState.toolBarAreaLayout.indexOf(bar);
1473 if (oldPath.isEmpty())
1475 toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(
nullptr, bar);
1491
1492
1494#if QT_CONFIG(toolbar)
1496static constexpr Qt::ToolBarArea validateToolBarArea(Qt::ToolBarArea area)
1499 case Qt::LeftToolBarArea:
1500 case Qt::RightToolBarArea:
1501 case Qt::TopToolBarArea:
1502 case Qt::BottomToolBarArea:
1507 return Qt::TopToolBarArea;
1510static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
1513 case Qt::LeftToolBarArea:
return QInternal::LeftDock;
1514 case Qt::RightToolBarArea:
return QInternal::RightDock;
1515 case Qt::TopToolBarArea:
return QInternal::TopDock;
1516 case Qt::BottomToolBarArea:
return QInternal::BottomDock;
1521 return QInternal::DockCount;
1524static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
1527 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1528 case QInternal::RightDock:
return Qt::RightToolBarArea;
1529 case QInternal::TopDock:
return Qt::TopToolBarArea;
1530 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1533 return Qt::NoToolBarArea;
1536static inline Qt::ToolBarArea toToolBarArea(
int pos)
1538 return toToolBarArea(
static_cast<QInternal::DockPosition>(pos));
1541void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
1543 area = validateToolBarArea(area);
1545 layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1546 if (savedState.isValid())
1547 savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
1552void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
1554 layoutState.toolBarAreaLayout.insertToolBarBreak(before);
1555 if (savedState.isValid())
1556 savedState.toolBarAreaLayout.insertToolBarBreak(before);
1560void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
1562 layoutState.toolBarAreaLayout.removeToolBarBreak(before);
1563 if (savedState.isValid())
1564 savedState.toolBarAreaLayout.removeToolBarBreak(before);
1568void QMainWindowLayout::moveToolBar(QToolBar *toolbar,
int pos)
1570 layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1571 if (savedState.isValid())
1572 savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
1577
1578void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
1581 QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
1582 toolbar, SLOT(_q_updateIconSize(QSize)));
1583 QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
1584 toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
1586 removeWidget(toolbar);
1591
1592
1593
1594
1597
1598
1599void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
1603 area = validateToolBarArea(area);
1605 addChildWidget(toolbar);
1606 QLayoutItem *item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
1607 if (savedState.isValid() && item) {
1609 savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
1614 toolbar->d_func()->updateWindowFlags(
false );
1618
1619
1620void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
1622 addChildWidget(toolbar);
1623 QLayoutItem *item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
1624 if (savedState.isValid() && item) {
1626 savedState.toolBarAreaLayout.insertItem(before, item);
1628 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
1629 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1630 if (!currentGapPos.isEmpty()) {
1631 currentGapPos.prepend(0);
1632 currentGapRect = layoutState.itemRect(currentGapPos);
1638Qt::ToolBarArea QMainWindowLayout::toolBarArea(
const QToolBar *toolbar)
const
1640 std::optional<QInternal::DockPosition> pos
1641 = layoutState.toolBarAreaLayout.findToolBar(toolbar);
1643 return Qt::NoToolBarArea;
1645 case QInternal::LeftDock:
return Qt::LeftToolBarArea;
1646 case QInternal::RightDock:
return Qt::RightToolBarArea;
1647 case QInternal::TopDock:
return Qt::TopToolBarArea;
1648 case QInternal::BottomDock:
return Qt::BottomToolBarArea;
1651 return Qt::NoToolBarArea;
1654bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar)
const
1656 return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
1659void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar)
const
1661 option->toolBarArea = toolBarArea(toolBar);
1662 layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
1665void QMainWindowLayout::toggleToolBarsVisible()
1667 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
1668 if (!layoutState.mainWindow->isMaximized()) {
1669 QPoint topLeft = parentWidget()->geometry().topLeft();
1670 QRect r = parentWidget()->geometry();
1671 r = layoutState.toolBarAreaLayout.rectHint(r);
1673 parentWidget()->setGeometry(r);
1682
1683
1685#if QT_CONFIG(dockwidget)
1687static std::optional<QInternal::DockPosition> toDockPos(Qt::DockWidgetArea area)
1690 case Qt::LeftDockWidgetArea:
return QInternal::LeftDock;
1691 case Qt::RightDockWidgetArea:
return QInternal::RightDock;
1692 case Qt::TopDockWidgetArea:
return QInternal::TopDock;
1693 case Qt::BottomDockWidgetArea:
return QInternal::BottomDock;
1694 case Qt::DockWidgetArea::NoDockWidgetArea:
1695 case Qt::DockWidgetArea::AllDockWidgetAreas:
1699 return std::nullopt;
1702enum class WarnInvalidDockAreaLocation {
1709static void warn_invalid_dock_area(Qt::DockWidgetArea area, WarnInvalidDockAreaLocation loc)
1711 constexpr auto strings = qOffsetStringArray(
1712 "dockWidgetAreaRect",
1717 qCWarning(lcQpaDockWidgets,
1718 "QMainWindowLayout::%s: called with out-of-bounds area value '%d'",
1719 strings[qToUnderlying(loc)],
1723inline static Qt::DockWidgetArea toDockWidgetArea(
int pos)
1725 return QDockWidgetPrivate::toDockWidgetArea(
static_cast<QInternal::DockPosition>(pos));
1730static bool isAreaAllowed(QWidget *widget,
const QList<
int> &path)
1732 Q_ASSERT_X((path.size() > 1),
"isAreaAllowed",
"invalid path size");
1733 const Qt::DockWidgetArea area = toDockWidgetArea(path[1]);
1736 if (QDockWidget *dw = qobject_cast<QDockWidget *>(widget)) {
1737 const bool allowed = dw->isAreaAllowed(area);
1739 qCDebug(lcQpaDockWidgets) <<
"No permission for single DockWidget" << widget <<
"to dock on" << area;
1744 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1745 const QList<QDockWidget *> children = dwgw->findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly);
1747 if (children.size() == 1) {
1749 const bool allowed = children.at(0)->isAreaAllowed(area);
1751 qCDebug(lcQpaDockWidgets) <<
"No permission for DockWidgetGroupWindow" << widget <<
"to dock on" << area;
1755 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"has" << children.size() <<
"children:";
1756 qCDebug(lcQpaDockWidgets) << children;
1757 qCDebug(lcQpaDockWidgets) <<
"DockWidgetGroupWindow" << widget <<
"can dock at" << area <<
"and anywhere else.";
1761 qCDebug(lcQpaDockWidgets) <<
"Docking requested for invalid widget type (coding error)." << widget << area;
1765void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1767 if (layoutState.dockAreaLayout.corners[corner] == area)
1769 layoutState.dockAreaLayout.corners[corner] = area;
1770 if (savedState.isValid())
1771 savedState.dockAreaLayout.corners[corner] = area;
1775Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner)
const
1777 return layoutState.dockAreaLayout.corners[corner];
1783QRect QMainWindowLayout::dockWidgetAreaRect(
const Qt::DockWidgetArea area, DockWidgetAreaSize size)
const
1785 const std::optional dockPosition = toDockPos(area);
1788 if (!dockPosition) {
1789 warn_invalid_dock_area(area, WarnInvalidDockAreaLocation::DockWidgetAreaRect);
1793 const QDockAreaLayout dl = layoutState.dockAreaLayout;
1796 return size == Maximum ? dl.gapRect(*dockPosition) : dl.docks[*dockPosition].rect;
1800
1801
1802
1803void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1804 QDockWidget *dockwidget,
1805 Qt::Orientation orientation)
1807 addChildWidget(dockwidget);
1811 if (!movingSeparator.isEmpty())
1812 endSeparatorMove(movingSeparatorPos);
1814 const std::optional dockPos = toDockPos(area);
1816 return warn_invalid_dock_area(area, WarnInvalidDockAreaLocation::AddDockWidget);
1818 layoutState.dockAreaLayout.addDockWidget(*dockPos, dockwidget, orientation);
1822bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1824 addChildWidget(dockwidget);
1825 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1827 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1832#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
1833static QTabBar::Shape tabwidgetPositionToTabBarShape(QDockWidget *w)
1835 switch (
static_cast<QDockWidgetPrivate *>(qt_widget_private(w))->tabPosition) {
1836 case QTabWidget::North:
1837 return QTabBar::RoundedNorth;
1838 case QTabWidget::South:
1839 return QTabBar::RoundedSouth;
1840 case QTabWidget::West:
1841 return QTabBar::RoundedWest;
1842 case QTabWidget::East:
1843 return QTabBar::RoundedEast;
1845 Q_UNREACHABLE_RETURN(QTabBar::RoundedSouth);
1849#if QT_CONFIG(tabbar)
1850void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1856 if (layoutState.dockAreaLayout.indexOf(first).isEmpty()) {
1857 qCritical() <<
"Coding error: QDockWidget" << first
1858 <<
"tabbed before QMainWindow::addDockWidget()."
1859 <<
"Ignoring" <<
__FUNCTION__;
1864 if (layoutState.dockAreaLayout.indexOf(second).isEmpty()) {
1865 layoutState.mainWindow->addDockWidget(first->dockLocation(), second);
1866 qCDebug(lcQpaDockWidgets) <<
"QDockWidget" << second <<
"has been added to"
1867 << parent() <<
"at" << first->dockLocation();
1871 if (isDockWidgetTabbed(second)) {
1872 qCDebug(lcQpaDockWidgets) <<
"QDockWidget" << second
1873 <<
"is already tabbed. Ignoring" <<
__FUNCTION__;
1877 const auto oldLocationFirst = dockWidgetArea(first);
1878 if (first->isFloating()) {
1879 tabifyWhileFloating(first, second);
1881 applyRestoredState();
1882 addChildWidget(second);
1883 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1885 const auto newLocationFirst = dockWidgetArea(first);
1886 if (newLocationFirst != oldLocationFirst)
1887 emit second->dockLocationChanged(newLocationFirst);
1891void QMainWindowLayout::tabifyWhileFloating(QDockWidget *first, QDockWidget *second)
1893 Q_ASSERT(first->isFloating());
1894 Q_ASSERT(!isDockWidgetTabbed(first));
1895 Q_ASSERT(!isDockWidgetTabbed(second));
1898 second->setFloating(
true);
1900 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
1901 floatingTabs->setGeometry(first->geometry());
1902 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
1903 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(first);
1905 const std::optional dockPosition = toDockPos(dockWidgetArea(first));
1906 Q_ASSERT(dockPosition);
1907 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, *dockPosition,
1908 Qt::Horizontal, shape,
1909 static_cast<QMainWindow *>(parentWidget()));
1910 info->tabBar = getTabBar();
1911 info->tabbed =
true;
1914 second->d_func()->plug(first->geometry());
1915 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[*dockPosition];
1916 parentInfo.add(floatingTabs);
1917 first->setParent(floatingTabs);
1918 second->setParent(floatingTabs);
1919 floatingTabs->show();
1920 floatingTabs->raise();
1923bool QMainWindowLayout::documentMode()
const
1925 return _documentMode;
1928void QMainWindowLayout::setDocumentMode(
bool enabled)
1930 if (_documentMode == enabled)
1933 _documentMode = enabled;
1936 for (QTabBar *bar : std::as_const(usedTabBars))
1937 bar->setDocumentMode(_documentMode);
1940void QMainWindowLayout::setVerticalTabsEnabled(
bool enabled)
1942 if (verticalTabsEnabled == enabled)
1945 verticalTabsEnabled = enabled;
1947 updateTabBarShapes();
1950#if QT_CONFIG(tabwidget)
1951QTabWidget::TabShape QMainWindowLayout::tabShape()
const
1956void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1958 if (_tabShape == tabShape)
1961 _tabShape = tabShape;
1963 updateTabBarShapes();
1966QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area)
const
1968 if (
const std::optional dockPos = toDockPos(area))
1969 return tabPositions[*dockPos];
1970 warn_invalid_dock_area(area, WarnInvalidDockAreaLocation::TabPosition);
1971 return QTabWidget::North;
1974void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1976 static constexpr Qt::DockWidgetArea dockWidgetAreas[] = {
1977 Qt::TopDockWidgetArea,
1978 Qt::LeftDockWidgetArea,
1979 Qt::BottomDockWidgetArea,
1980 Qt::RightDockWidgetArea
1982 static constexpr QInternal::DockPosition dockPositions[] = {
1984 QInternal::LeftDock,
1985 QInternal::BottomDock,
1986 QInternal::RightDock
1989 for (
int i = 0; i < QInternal::DockCount; ++i)
1990 if (areas & dockWidgetAreas[i])
1991 tabPositions[dockPositions[i]] = tabPosition;
1993 updateTabBarShapes();
1996QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
1999void QMainWindowLayout::showTabBars()
2001 const auto usedTabBarsCopy = usedTabBars;
2002 for (QTabBar *tab_bar : usedTabBarsCopy) {
2003 if (usedTabBars.contains(tab_bar))
2008void QMainWindowLayout::updateTabBarShapes()
2010#if QT_CONFIG(tabwidget)
2011 static constexpr QTabWidget::TabPosition vertical[] = {
2018 static constexpr QTabBar::Shape vertical[] = {
2019 QTabBar::RoundedWest,
2020 QTabBar::RoundedEast,
2021 QTabBar::RoundedNorth,
2022 QTabBar::RoundedSouth
2026 QDockAreaLayout &layout = layoutState.dockAreaLayout;
2028 for (
int i = 0; i < QInternal::DockCount; ++i) {
2029#if QT_CONFIG(tabwidget)
2030 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
2031 QTabBar::Shape shape = _q_tb_tabBarShapeFrom(_tabShape, pos);
2033 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
2035 layout.docks[i].setTabBarShape(shape);
2040void QMainWindowLayout::splitDockWidget(QDockWidget *after,
2041 QDockWidget *dockwidget,
2042 Qt::Orientation orientation)
2044 applyRestoredState();
2045 addChildWidget(dockwidget);
2046 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
2047 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
2051Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(
const QWidget *widget)
const
2053 const QList<
int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
2054 if (pathToWidget.isEmpty())
2055 return Qt::NoDockWidgetArea;
2056 return toDockWidgetArea(pathToWidget.first());
2059void QMainWindowLayout::keepSize(QDockWidget *w)
2061 layoutState.dockAreaLayout.keepSize(w);
2064#if QT_CONFIG(tabbar)
2067class QMainWindowTabBar :
public QTabBar
2070 QPointer<QMainWindow> mainWindow;
2071 QPointer<QDockWidget> draggingDock;
2073 QMainWindowTabBar(QMainWindow *parent);
2074 ~QMainWindowTabBar();
2075 QDockWidget *dockAt(
int index)
const;
2076 QList<QDockWidget *> dockWidgets()
const;
2077 bool contains(
const QDockWidget *dockWidget)
const;
2079 bool event(QEvent *e) override;
2080 void mouseReleaseEvent(QMouseEvent*) override;
2081 void mouseMoveEvent(QMouseEvent*) override;
2085QDebug operator<<(QDebug debug,
const QMainWindowTabBar *bar)
2088 return debug <<
"QMainWindowTabBar(0x0)";
2089 QDebugStateSaver saver(debug);
2090 debug.nospace().noquote() <<
"QMainWindowTabBar(" <<
static_cast<
const void *>(bar) <<
", ";
2091 debug.nospace().noquote() <<
"ParentWidget=(" << bar->parentWidget() <<
"), ";
2092 const auto dockWidgets = bar->dockWidgets();
2093 if (dockWidgets.isEmpty())
2094 debug.nospace().noquote() <<
"No QDockWidgets";
2096 debug.nospace().noquote() <<
"DockWidgets(" << dockWidgets <<
")";
2097 debug.nospace().noquote() <<
")";
2101QMainWindowTabBar *QMainWindowLayout::findTabBar(
const QDockWidget *dockWidget)
const
2103 for (
auto *bar : usedTabBars) {
2104 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
2105 auto *tabBar =
static_cast<QMainWindowTabBar *>(bar);
2106 if (tabBar->contains(dockWidget))
2112QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
2113 : QTabBar(parent), mainWindow(parent)
2115 setExpanding(
false);
2118QList<QDockWidget *> QMainWindowTabBar::dockWidgets()
const
2120 QList<QDockWidget *> docks;
2121 for (
int i = 0; i < count(); ++i) {
2122 if (QDockWidget *dock = dockAt(i))
2128bool QMainWindowTabBar::contains(
const QDockWidget *dockWidget)
const
2130 for (
int i = 0; i < count(); ++i) {
2131 if (dockAt(i) == dockWidget)
2142QDockWidget *QMainWindowTabBar::dockAt(
int index)
const
2144 QMainWindowTabBar *that =
const_cast<QMainWindowTabBar *>(
this);
2145 QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
2146 QDockAreaLayoutInfo *info = mlayout ? mlayout->dockInfo(that) :
nullptr;
2150 const int itemIndex = info->tabIndexToListIndex(index);
2151 if (itemIndex >= 0) {
2152 Q_ASSERT(itemIndex < info->item_list.count());
2153 const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
2154 return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) :
nullptr;
2161
2162
2163
2164
2165
2166
2167
2168
2169static void moveToUnplugPosition(QPoint mouse, QDockWidget *dockWidget)
2171 Q_ASSERT(dockWidget);
2173 if (
auto *tbWidget = dockWidget->titleBarWidget()) {
2174 dockWidget->move(mouse - tbWidget->rect().center());
2178 const bool vertical = dockWidget->features().testFlag(QDockWidget::DockWidgetVerticalTitleBar);
2179 const int deltaX = vertical ? QApplication::startDragDistance() : dockWidget->width() / 2;
2180 const int deltaY = vertical ? dockWidget->height() / 2 : QApplication::startDragDistance();
2181 dockWidget->move(mouse - QPoint(deltaX, deltaY));
2184void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
2191 QTabBarPrivate *d =
static_cast<QTabBarPrivate*>(d_ptr.data());
2192 if (!draggingDock && (mainWindow->dockOptions() & QMainWindow::GroupedDragging)) {
2193 int offset = QApplication::startDragDistance() + 1;
2195 QRect r = rect().adjusted(-offset, -offset, offset, offset);
2196 if (d->dragInProgress && !r.contains(e->position().toPoint()) && d->validIndex(d->pressedIndex)) {
2197 draggingDock = dockAt(d->pressedIndex);
2201 d->moveTabFinished(d->pressedIndex);
2202 d->pressedIndex = -1;
2204 d->movingTab->setVisible(
false);
2205 d->dragStartPosition = QPoint();
2208 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2209 QDockWidgetLayout *dwlayout =
static_cast<QDockWidgetLayout *>(draggingDock->layout());
2210 dockPriv->initDrag(dwlayout->titleArea().center(),
true);
2211 dockPriv->startDrag(QDockWidgetPrivate::DragScope::Widget);
2212 if (dockPriv->state)
2213 dockPriv->state->ctrlDrag = e->modifiers() & Qt::ControlModifier;
2219 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2220 if (dockPriv->state && dockPriv->state->dragging) {
2222 moveToUnplugPosition(e->globalPosition().toPoint(), draggingDock);
2225 QTabBar::mouseMoveEvent(e);
2228QMainWindowTabBar::~QMainWindowTabBar()
2232 if (!qobject_cast<QMainWindow *>(mainWindow) || mainWindow == parentWidget())
2237 auto *mwLayout = qt_mainwindow_layout(mainWindow);
2240 mwLayout->usedTabBars.remove(
this);
2243void QMainWindowTabBar::mouseReleaseEvent(QMouseEvent *e)
2245 if (draggingDock && e->button() == Qt::LeftButton) {
2246 QDockWidgetPrivate *dockPriv =
static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
2247 if (dockPriv->state && dockPriv->state->dragging)
2248 dockPriv->endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
2250 draggingDock =
nullptr;
2252 QTabBar::mouseReleaseEvent(e);
2255bool QMainWindowTabBar::event(QEvent *e)
2259 if (e->type() != QEvent::ToolTip)
2260 return QTabBar::event(e);
2261 QSize size =
this->size();
2262 QSize hint = sizeHint();
2263 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
2264 size = size.transposed();
2265 hint = hint.transposed();
2267 if (size.width() < hint.width())
2268 return QTabBar::event(e);
2273QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(
const QDockWidget *dockWidget)
const
2275 const auto *bar = findTabBar(dockWidget);
2279 QList<QDockWidget *> buddies = bar->dockWidgets();
2282 buddies.removeOne(dockWidget);
2286bool QMainWindowLayout::isDockWidgetTabbed(
const QDockWidget *dockWidget)
const
2291 const auto *bar = findTabBar(dockWidget);
2292 return bar && bar->count() > 1;
2295void QMainWindowLayout::unuseTabBar(QTabBar *bar)
2297 Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
2301QTabBar *QMainWindowLayout::getTabBar()
2303 if (!usedTabBars.isEmpty() && !isInRestoreState) {
2305
2306
2307
2308
2312 QTabBar *bar =
new QMainWindowTabBar(
static_cast<QMainWindow *>(parentWidget()));
2313 bar->setDrawBase(
true);
2314 bar->setElideMode(Qt::ElideRight);
2315 bar->setDocumentMode(_documentMode);
2316 bar->setMovable(
true);
2317 connect(bar, SIGNAL(currentChanged(
int)),
this, SLOT(tabChanged()));
2318 connect(bar, &QTabBar::tabMoved,
this, &QMainWindowLayout::tabMoved);
2320 usedTabBars.insert(bar);
2324QWidget *QMainWindowLayout::getSeparatorWidget()
2326 auto *separator =
new QWidget(parentWidget());
2327 separator->setAttribute(Qt::WA_MouseNoMask,
true);
2328 separator->setAutoFillBackground(
false);
2329 separator->setObjectName(
"qt_qmainwindow_extended_splitter"_L1);
2330 usedSeparatorWidgets.insert(separator);
2335
2336
2337
2338QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget)
2340 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
2344 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2345 for (QDockWidgetGroupWindow *dwgw : groups) {
2346 info = dwgw->layoutInfo()->info(widget);
2353void QMainWindowLayout::tabChanged()
2355 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2358 QDockAreaLayoutInfo *info = dockInfo(tb);
2359 if (info ==
nullptr)
2362 QDockWidget *activated = info->apply(QWidgetAnimator::AnimationRule::Stop);
2365 emit
static_cast<QMainWindow *>(parentWidget())->tabifiedDockWidgetActivated(activated);
2367 if (
auto dwgw = qobject_cast<QDockWidgetGroupWindow*>(tb->parentWidget()))
2368 dwgw->adjustFlags();
2370 if (QWidget *w = centralWidget())
2374void QMainWindowLayout::tabMoved(
int from,
int to)
2376 QTabBar *tb = qobject_cast<QTabBar*>(sender());
2378 QDockAreaLayoutInfo *info = dockInfo(tb);
2381 info->moveTab(from, to);
2384void QMainWindowLayout::raise(QDockWidget *widget)
2386 QDockAreaLayoutInfo *info = dockInfo(widget);
2387 if (info ==
nullptr)
2391 info->setCurrentTab(widget);
2399
2400
2402int QMainWindowLayout::count()
const
2405 while (itemAt(result))
2410QLayoutItem *QMainWindowLayout::itemAt(
int index)
const
2414 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
2417 if (statusbar && x++ == index)
2423QLayoutItem *QMainWindowLayout::takeAt(
int index)
2427 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
2429 if (QWidget *w = ret->widget()) {
2430 widgetAnimator.abort(w);
2431 if (w == pluggingWidget)
2432 pluggingWidget =
nullptr;
2435 if (savedState.isValid() ) {
2437 savedState.remove(ret);
2439 layoutState.remove(ret);
2442#if QT_CONFIG(toolbar)
2443 if (!currentGapPos.isEmpty() && currentGapPos.constFirst() == 0) {
2444 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
2445 if (!currentGapPos.isEmpty()) {
2446 currentGapPos.prepend(0);
2447 currentGapRect = layoutState.itemRect(currentGapPos);
2455 if (statusbar && x++ == index) {
2456 QLayoutItem *ret = statusbar;
2457 statusbar =
nullptr;
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481void QMainWindowLayout::applyRestoredState()
2483 if (restoredState) {
2484 layoutState = *restoredState;
2485 restoredState.reset();
2486 discardRestoredStateTimer.stop();
2490void QMainWindowLayout::setGeometry(
const QRect &_r)
2494 if (savedState.isValid() || (restoredState && isInApplyState))
2499 QLayout::setGeometry(r);
2502 QRect sbr(QPoint(r.left(), 0),
2503 QSize(r.width(), statusbar->heightForWidth(r.width()))
2504 .expandedTo(statusbar->minimumSize()));
2505 sbr.moveBottom(r.bottom());
2506 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
2507 statusbar->setGeometry(vr);
2508 r.setBottom(sbr.top() - 1);
2511 if (restoredState) {
2513
2514
2515
2516
2517
2518
2519 layoutState = *restoredState;
2520 if (restoredState->fits()) {
2521 restoredState.reset();
2522 discardRestoredStateTimer.stop();
2525
2526
2527
2528
2529
2530
2531
2532
2533 discardRestoredStateTimer.start(150,
this);
2537 layoutState.rect = r;
2539 layoutState.fitLayout();
2540 applyState(layoutState,
false);
2542#if defined(Q_OS_MACOS)
2543 updateUnifiedToolBarArea();
2547void QMainWindowLayout::timerEvent(QTimerEvent *e)
2549 if (e->timerId() == discardRestoredStateTimer.timerId()) {
2550 discardRestoredStateTimer.stop();
2551 restoredState.reset();
2553 QLayout::timerEvent(e);
2556void QMainWindowLayout::addItem(QLayoutItem *)
2557{ qWarning(
"QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
2559QSize QMainWindowLayout::sizeHint()
const
2561 if (!szHint.isValid()) {
2562 szHint = layoutState.sizeHint();
2563 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
2564 szHint = QSize(qMax(sbHint.width(), szHint.width()),
2565 sbHint.height() + szHint.height());
2570QSize QMainWindowLayout::minimumSize()
const
2572 if (!minSize.isValid()) {
2573 minSize = layoutState.minimumSize();
2574 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
2575 minSize = QSize(qMax(sbMin.width(), minSize.width()),
2576 sbMin.height() + minSize.height());
2581void QMainWindowLayout::invalidate()
2583 QLayout::invalidate();
2584 minSize = szHint = QSize();
2587#if QT_CONFIG(dockwidget)
2588void QMainWindowLayout::setCurrentHoveredFloat(QDockWidgetGroupWindow *w)
2590 if (currentHoveredFloat != w) {
2591 if (currentHoveredFloat) {
2592 disconnect(currentHoveredFloat.data(), &QObject::destroyed,
2593 this, &QMainWindowLayout::updateGapIndicator);
2594 disconnect(currentHoveredFloat.data(), &QDockWidgetGroupWindow::resized,
2595 this, &QMainWindowLayout::updateGapIndicator);
2596 if (currentHoveredFloat)
2597 currentHoveredFloat->restore();
2599 restore(QInternal::KeepSavedState);
2602 currentHoveredFloat = w;
2605 connect(w, &QObject::destroyed,
2606 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2607 connect(w, &QDockWidgetGroupWindow::resized,
2608 this, &QMainWindowLayout::updateGapIndicator, Qt::UniqueConnection);
2611 updateGapIndicator();
2617
2618
2622#if QT_CONFIG(toolbar)
2623 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
2624 if (toolBar ==
nullptr)
2627 QRect oldGeo = toolBar->geometry();
2629 QInternal::DockPosition pos
2630 =
static_cast<QInternal::DockPosition>(dockPos);
2631 Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
2632 ? Qt::Horizontal : Qt::Vertical;
2633 if (o != toolBar->orientation())
2634 toolBar->setOrientation(o);
2636 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
2637 .expandedTo(toolBar->minimumSize());
2639 if (toolBar->size() != hint) {
2640 QRect newGeo(oldGeo.topLeft(), hint);
2641 if (toolBar->layoutDirection() == Qt::RightToLeft)
2642 newGeo.moveRight(oldGeo.right());
2643 toolBar->setGeometry(newGeo);
2652void QMainWindowLayout::revert(QLayoutItem *widgetItem)
2654 if (!savedState.isValid())
2657 QWidget *widget = widgetItem->widget();
2658 layoutState = savedState;
2659 currentGapPos = layoutState.indexOf(widget);
2660 if (currentGapPos.isEmpty())
2662 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2663 layoutState.unplug(currentGapPos);
2664 layoutState.fitLayout();
2665 currentGapRect = layoutState.itemRect(currentGapPos);
2670bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
2672#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) && QT_CONFIG(tabbar)
2673 if (currentHoveredFloat) {
2674 QWidget *widget = widgetItem->widget();
2675 QList<
int> previousPath = layoutState.indexOf(widget);
2676 if (!previousPath.isEmpty())
2677 layoutState.remove(previousPath);
2678 previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2681 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2682 for (QDockWidgetGroupWindow *dwgw : groups) {
2683 if (dwgw == currentHoveredFloat)
2685 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2686 if (!path.isEmpty())
2687 dwgw->layoutInfo()->remove(path);
2689 currentGapRect = QRect();
2690 currentHoveredFloat->apply();
2691 if (!previousPath.isEmpty())
2692 currentHoveredFloat->layoutInfo()->remove(previousPath);
2693 QRect globalRect = currentHoveredFloat->currentGapRect;
2694 globalRect.moveTopLeft(currentHoveredFloat->mapToGlobal(globalRect.topLeft()));
2695 pluggingWidget = widget;
2696 const auto rule = toAnimationRule(dockOptions);
2697 widgetAnimator.animate(widget, globalRect, rule);
2702 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
2705 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
2707 QWidget *widget = widgetItem->widget();
2709#if QT_CONFIG(dockwidget)
2712 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
2713 for (QDockWidgetGroupWindow *dwgw : groups) {
2714 QList<
int> path = dwgw->layoutInfo()->indexOf(widget);
2715 if (!path.isEmpty())
2716 dwgw->layoutInfo()->remove(path);
2720 QList<
int> previousPath = layoutState.indexOf(widget);
2722 const QLayoutItem *it = layoutState.plug(currentGapPos);
2725 Q_ASSERT(it == widgetItem);
2726 if (!previousPath.isEmpty())
2727 layoutState.remove(previousPath);
2729 pluggingWidget = widget;
2730 QRect globalRect = currentGapRect;
2731 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
2732#if QT_CONFIG(dockwidget)
2733 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2734 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
2735 if (layout->nativeWindowDeco()) {
2736 globalRect.adjust(0, layout->titleHeight(), 0, 0);
2738 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, widget);
2739 globalRect.adjust(-fw, -fw, fw, fw);
2743 const auto rule = toAnimationRule(dockOptions);
2744 widgetAnimator.animate(widget, globalRect, rule);
2749void QMainWindowLayout::animationFinished(QWidget *widget)
2753#if QT_CONFIG(toolbar)
2754 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
2755 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
2756 if (tbl->animating) {
2757 tbl->animating =
false;
2759 tbl->layoutActions(tb->size());
2765 if (widget == pluggingWidget) {
2767#if QT_CONFIG(dockwidget)
2768#if QT_CONFIG(tabbar)
2769 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
2773 QDockAreaLayoutInfo *srcInfo = dwgw->layoutInfo();
2774 const QDockAreaLayoutInfo *srcTabInfo = dwgw->tabLayoutInfo();
2775 QDockAreaLayoutInfo *dstParentInfo;
2778 if (currentHoveredFloat) {
2779 dstPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
2780 Q_ASSERT(dstPath.size() >= 1);
2781 dstParentInfo = currentHoveredFloat->layoutInfo()->info(dstPath);
2783 dstPath = layoutState.dockAreaLayout.indexOf(widget);
2784 Q_ASSERT(dstPath.size() >= 2);
2785 dstParentInfo = layoutState.dockAreaLayout.info(dstPath);
2787 Q_ASSERT(dstParentInfo);
2788 int idx = dstPath.constLast();
2789 Q_ASSERT(dstParentInfo->item_list[idx].widgetItem->widget() == dwgw);
2790 if (dstParentInfo->tabbed && srcTabInfo) {
2792 delete dstParentInfo->item_list[idx].widgetItem;
2793 dstParentInfo->item_list.removeAt(idx);
2794 std::copy(srcTabInfo->item_list.cbegin(), srcTabInfo->item_list.cend(),
2795 std::inserter(dstParentInfo->item_list,
2796 dstParentInfo->item_list.begin() + idx));
2797 quintptr currentId = srcTabInfo->currentTabId();
2798 *srcInfo = QDockAreaLayoutInfo();
2799 dstParentInfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2801 dstParentInfo->updateTabBar();
2802 dstParentInfo->setCurrentTabId(currentId);
2804 QDockAreaLayoutItem &item = dstParentInfo->item_list[idx];
2805 Q_ASSERT(item.widgetItem->widget() == dwgw);
2806 delete item.widgetItem;
2807 item.widgetItem =
nullptr;
2808 item.subinfo =
new QDockAreaLayoutInfo(std::move(*srcInfo));
2809 *srcInfo = QDockAreaLayoutInfo();
2810 item.subinfo->reparentWidgets(currentHoveredFloat ? currentHoveredFloat.data()
2812 item.subinfo->setTabBarShape(dstParentInfo->tabBarShape);
2814 dwgw->destroyOrHideIfEmpty();
2818 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
2819 dw->setParent(currentHoveredFloat ? currentHoveredFloat.data() : parentWidget());
2821 dw->d_func()->plug(currentGapRect);
2824#if QT_CONFIG(toolbar)
2825 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
2826 tb->d_func()->plug(currentGapRect);
2830 currentGapPos.clear();
2831 pluggingWidget =
nullptr;
2832#if QT_CONFIG(dockwidget)
2833 setCurrentHoveredFloat(
nullptr);
2837 layoutState.apply(QWidgetAnimator::AnimationRule::Stop);
2839#if QT_CONFIG(dockwidget)
2840#if QT_CONFIG(tabbar)
2841 if (qobject_cast<QDockWidget*>(widget) !=
nullptr) {
2844 if (QDockAreaLayoutInfo *info = dockInfo(widget))
2845 info->setCurrentTab(widget);
2851 if (!widgetAnimator.animating()) {
2853#if QT_CONFIG(dockwidget)
2854 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
2855#if QT_CONFIG(tabbar)
2861 updateGapIndicator();
2864void QMainWindowLayout::restore(QInternal::SaveStateRule rule)
2866 if (!savedState.isValid())
2869 layoutState = savedState;
2870 applyState(layoutState);
2871 if (rule == QInternal::ClearSavedState)
2873 currentGapPos.clear();
2874 pluggingWidget =
nullptr;
2875 updateGapIndicator();
2878QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout)
2879 : QLayout(parentLayout ?
static_cast<QWidget *>(
nullptr) : mainwindow)
2880 , layoutState(mainwindow)
2881 , savedState(mainwindow)
2882 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
2883 , statusbar(
nullptr)
2884#if QT_CONFIG(dockwidget)
2885#if QT_CONFIG(tabbar)
2886 , _documentMode(
false)
2887 , verticalTabsEnabled(
false)
2888#if QT_CONFIG(tabwidget)
2889 , _tabShape(QTabWidget::Rounded)
2893 , widgetAnimator(
this)
2894 , pluggingWidget(
nullptr)
2897 setParent(parentLayout);
2899#if QT_CONFIG(dockwidget)
2900#if QT_CONFIG(tabbar)
2901 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent,
nullptr, mainwindow);
2904#if QT_CONFIG(tabwidget)
2905 for (
int i = 0; i < QInternal::DockCount; ++i)
2906 tabPositions[i] = QTabWidget::South;
2909 pluggingWidget =
nullptr;
2911 setObjectName(mainwindow->objectName() +
"_layout"_L1);
2914QMainWindowLayout::~QMainWindowLayout()
2916 layoutState.deleteAllLayoutItems();
2917 layoutState.deleteCentralWidgetItem();
2922void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
2924 if (opts == dockOptions)
2929#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
2930 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
2936#if QT_CONFIG(statusbar)
2937QStatusBar *QMainWindowLayout::statusBar()
const
2938{
return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
2940void QMainWindowLayout::setStatusBar(QStatusBar *sb)
2945 statusbar = sb ?
new QWidgetItemV2(sb) :
nullptr;
2950QWidget *QMainWindowLayout::centralWidget()
const
2952 return layoutState.centralWidget();
2955void QMainWindowLayout::setCentralWidget(QWidget *widget)
2957 if (widget !=
nullptr)
2958 addChildWidget(widget);
2959 layoutState.setCentralWidget(widget);
2960 if (savedState.isValid()) {
2961#if QT_CONFIG(dockwidget)
2962 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
2963 savedState.dockAreaLayout.fallbackToSizeHints =
true;
2965 savedState.centralWidgetItem = layoutState.centralWidgetItem;
2971#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
2973
2974
2975
2976
2977
2978
2979static bool unplugGroup(QMainWindowLayout *layout, QLayoutItem **item,
2980 QDockAreaLayoutItem &parentItem)
2982 if (!parentItem.subinfo || !parentItem.subinfo->tabbed)
2986 QDockWidgetGroupWindow *floatingTabs = layout->createTabbedDockWindow();
2987 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
2988 *info = std::move(*parentItem.subinfo);
2989 delete parentItem.subinfo;
2990 parentItem.subinfo =
nullptr;
2991 floatingTabs->setGeometry(info->rect.translated(layout->parentWidget()->pos()));
2992 floatingTabs->show();
2993 floatingTabs->raise();
2994 *item =
new QDockWidgetGroupWindowItem(floatingTabs);
2995 parentItem.widgetItem = *item;
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope)
3012#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3013 auto *groupWindow = qobject_cast<
const QDockWidgetGroupWindow *>(widget->parentWidget());
3014 if (!widget->isWindow() && groupWindow) {
3015 if (scope == QDockWidgetPrivate::DragScope::Group && groupWindow->tabLayoutInfo()) {
3018 if (QDockAreaLayoutInfo *info = dockInfo(widget->parentWidget())) {
3019 QList<
int> groupWindowPath = info->indexOf(widget->parentWidget());
3020 return groupWindowPath.isEmpty() ?
nullptr : info->item(groupWindowPath).widgetItem;
3022 qCDebug(lcQpaDockWidgets) <<
"Drag only:" << widget <<
"Group:" << (scope == QDockWidgetPrivate::DragScope::Group);
3025 const QList<
int> path = groupWindow->layoutInfo()->indexOf(widget);
3026 QDockAreaLayoutItem parentItem = groupWindow->layoutInfo()->item(path);
3027 QLayoutItem *item = parentItem.widgetItem;
3028 if (scope == QDockWidgetPrivate::DragScope::Group && path.size() > 1
3029 && unplugGroup(
this, &item, parentItem)) {
3030 qCDebug(lcQpaDockWidgets) <<
"Unplugging:" << widget <<
"from" << item;
3034 QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget);
3035 Q_ASSERT(dockWidget);
3036 dockWidget->d_func()->unplug(widget->geometry());
3038 qCDebug(lcQpaDockWidgets) <<
"Unplugged from floating dock:" << widget <<
"from" << groupWindow;
3043 QList<
int> path = layoutState.indexOf(widget);
3047 QLayoutItem *item = layoutState.item(path);
3048 if (widget->isWindow())
3051 QRect r = layoutState.itemRect(path);
3052 savedState = layoutState;
3054#if QT_CONFIG(dockwidget)
3055 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
3056 Q_ASSERT(path.constFirst() == 1);
3057#if QT_CONFIG(tabwidget)
3058 if (scope == QDockWidgetPrivate::DragScope::Group && (dockOptions & QMainWindow::GroupedDragging) && path.size() > 3
3059 && unplugGroup(
this, &item,
3060 layoutState.dockAreaLayout.item(path.mid(1, path.size() - 2)))) {
3062 savedState = layoutState;
3068 switch (dockWidgetArea(dw)) {
3069 case Qt::LeftDockWidgetArea:
3070 case Qt::RightDockWidgetArea:
3071 r.setHeight(r.height() - sep);
3073 case Qt::TopDockWidgetArea:
3074 case Qt::BottomDockWidgetArea:
3075 r.setWidth(r.width() - sep);
3077 case Qt::NoDockWidgetArea:
3078 case Qt::DockWidgetArea_Mask:
3086 const auto *layout = qobject_cast<QDockWidgetLayout *>(dw->layout());
3087 const bool verticalTitleBar = layout ? layout->verticalTitleBar :
false;
3088 const int tbHeight = QApplication::style()
3089 ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight,
nullptr, dw)
3091 const int minHeight = verticalTitleBar ? 2 * tbHeight : tbHeight;
3092 const int minWidth = verticalTitleBar ? tbHeight : 2 * tbHeight;
3093 r.setSize(r.size().expandedTo(QSize(minWidth, minHeight)));
3094 qCDebug(lcQpaDockWidgets) << dw <<
"will be unplugged with size" << r.size();
3096 dw->d_func()->unplug(r);
3100#if QT_CONFIG(toolbar)
3101 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
3102 tb->d_func()->unplug(r);
3106#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
3110 layoutState.unplug(path ,&savedState);
3111 savedState.fitLayout();
3112 currentGapPos = path;
3114 updateGapIndicator();
3116 fixToolBarOrientation(item, currentGapPos.at(1));
3121void QMainWindowLayout::updateGapIndicator()
3123#if QT_CONFIG(rubberband)
3124 if (!widgetAnimator.animating() && (!currentGapPos.isEmpty()
3125#if QT_CONFIG(dockwidget)
3126 || currentHoveredFloat
3129 QWidget *expectedParent =
3130#if QT_CONFIG(dockwidget)
3131 currentHoveredFloat ? currentHoveredFloat.data() :
3134 if (!gapIndicator) {
3135 gapIndicator =
new QRubberBand(QRubberBand::Rectangle, expectedParent);
3137 gapIndicator->setObjectName(
"qt_rubberband"_L1);
3138 }
else if (gapIndicator->parent() != expectedParent) {
3139 gapIndicator->setParent(expectedParent);
3143 const bool sigBlockState = gapIndicator->signalsBlocked();
3144 auto resetSignals = qScopeGuard([
this, sigBlockState](){ gapIndicator->blockSignals(sigBlockState); });
3145 gapIndicator->blockSignals(
true);
3147#if QT_CONFIG(dockwidget)
3148 if (currentHoveredFloat)
3149 gapIndicator->setGeometry(currentHoveredFloat->currentGapRect);
3152 gapIndicator->setGeometry(currentGapRect);
3154 gapIndicator->show();
3155 gapIndicator->raise();
3159 }
else if (gapIndicator) {
3160 gapIndicator->hide();
3166void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
3167 const QPoint &mousePos) {
3168 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() ||
3169 pluggingWidget !=
nullptr || hoverTarget ==
nullptr)
3172 QWidget *widget = hoverTarget->widget();
3174#if QT_CONFIG(dockwidget)
3176 if ((dockOptions & QMainWindow::GroupedDragging) && (qobject_cast<QDockWidget*>(widget)
3177 || qobject_cast<QDockWidgetGroupWindow *>(widget))) {
3180 QVarLengthArray<QWidget *, 10> candidates;
3181 const auto siblings = parentWidget()->children();
3182 for (QObject *c : siblings) {
3183 QWidget *w = qobject_cast<QWidget*>(c);
3188 if (!qobject_cast<QDockWidget*>(w) && !qobject_cast<QDockWidgetGroupWindow *>(w))
3194 if (w != widget && w->isWindow() && w->isVisible() && !w->isMinimized())
3197 if (QDockWidgetGroupWindow *group = qobject_cast<QDockWidgetGroupWindow *>(w)) {
3200 const auto groupChildren = group->children();
3201 for (QObject *c : groupChildren) {
3202 if (QDockWidget *dw = qobject_cast<QDockWidget*>(c)) {
3203 if (dw != widget && dw->isFloating() && dw->isVisible() && !dw->isMinimized())
3210 for (QWidget *w : candidates) {
3211 const QScreen *screen1 = qt_widget_private(widget)->associatedScreen();
3212 const QScreen *screen2 = qt_widget_private(w)->associatedScreen();
3213 if (screen1 && screen2 && screen1 != screen2)
3215 if (!w->geometry().contains(mousePos))
3218#if QT_CONFIG(tabwidget)
3219 if (
auto dropTo = qobject_cast<QDockWidget *>(w)) {
3222 w = dropTo->widget();
3225 if (!qobject_cast<QDockWidgetGroupWindow *>(w)) {
3226 QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
3227 floatingTabs->setGeometry(dropTo->geometry());
3228 QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
3229 const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dropTo);
3236 std::optional dockPosition = toDockPos(dockWidgetArea(dropTo));
3238 dockPosition = toDockPos(dockWidgetArea(widget));
3240 dockPosition = QInternal::DockPosition::RightDock;
3242 *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, *dockPosition,
3243 Qt::Horizontal, shape,
3244 static_cast<QMainWindow *>(parentWidget()));
3245 info->tabBar = getTabBar();
3246 info->tabbed =
true;
3248 QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[*dockPosition];
3249 parentInfo.add(floatingTabs);
3250 dropTo->setParent(floatingTabs);
3251 qCDebug(lcQpaDockWidgets) <<
"Wrapping" << widget <<
"into floating tabs" << floatingTabs;
3257 qCDebug(lcQpaDockWidgets) <<
"Showing" << dropTo;
3259 qCDebug(lcQpaDockWidgets) <<
"Raising" << widget;
3262 auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(w);
3263 Q_ASSERT(groupWindow);
3264 if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) {
3266 setCurrentHoveredFloat(groupWindow);
3267 applyState(layoutState);
3275 if (currentHoveredFloat)
3276 currentHoveredFloat->destroyIfSingleItemLeft();
3278 setCurrentHoveredFloat(
nullptr);
3279 layoutState.dockAreaLayout.fallbackToSizeHints =
false;
3282 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
3284 if (!savedState.isValid())
3285 savedState = layoutState;
3287 QList<
int> path = savedState.gapIndex(widget, pos);
3289 if (!path.isEmpty()) {
3290 bool allowed =
false;
3292#if QT_CONFIG(dockwidget)
3293 allowed = isAreaAllowed(widget, path);
3295#if QT_CONFIG(toolbar)
3296 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
3297 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
3304 if (path == currentGapPos)
3307 currentGapPos = path;
3308 if (path.isEmpty()) {
3309 fixToolBarOrientation(hoverTarget, 2);
3310 restore(QInternal::KeepSavedState);
3314 fixToolBarOrientation(hoverTarget, currentGapPos.at(1));
3316 QMainWindowLayoutState newState = savedState;
3318 if (!newState.insertGap(path, hoverTarget)) {
3319 restore(QInternal::KeepSavedState);
3323 QSize min = newState.minimumSize();
3324 QSize size = newState.rect.size();
3326 if (min.width() > size.width() || min.height() > size.height()) {
3327 restore(QInternal::KeepSavedState);
3331 newState.fitLayout();
3333 currentGapRect = newState.gapRect(currentGapPos);
3335#if QT_CONFIG(dockwidget)
3336 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
3338 layoutState = std::move(newState);
3339 applyState(layoutState);
3341 updateGapIndicator();
3344#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3345QDockWidgetGroupWindow *QMainWindowLayout::createTabbedDockWindow()
3347 QDockWidgetGroupWindow* f =
new QDockWidgetGroupWindow(parentWidget(), Qt::Tool);
3348 new QDockWidgetGroupLayout(f);
3353void QMainWindowLayout::applyState(QMainWindowLayoutState &newState,
bool animate)
3360 isInApplyState =
true;
3361#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
3362 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
3364 parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
3365 for (QDockWidgetGroupWindow *dwgw : groups)
3366 used += dwgw->layoutInfo()->usedTabBars();
3368 const QSet<QTabBar*> retired = usedTabBars - used;
3370 for (QTabBar *tab_bar : retired) {
3371 unuseTabBar(tab_bar);
3375 const QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
3376 const QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
3377 usedSeparatorWidgets = usedSeps;
3378 for (QWidget *sepWidget : retiredSeps)
3382 for (
int i = 0; i < QInternal::DockCount; ++i)
3383 newState.dockAreaLayout.docks[i].reparentWidgets(parentWidget());
3386 const auto rule = animate ? toAnimationRule(dockOptions) : QWidgetAnimator::AnimationRule::Stop;
3387 newState.apply(rule);
3388 isInApplyState =
false;
3391void QMainWindowLayout::saveState(QDataStream &stream)
const
3393 layoutState.saveState(stream);
3396bool QMainWindowLayout::restoreState(QDataStream &stream)
3398 QScopedValueRollback<
bool> guard(isInRestoreState,
true);
3399 savedState = layoutState;
3400 layoutState.clear();
3401 layoutState.rect = savedState.rect;
3403 if (!layoutState.restoreState(stream, savedState)) {
3404 layoutState.deleteAllLayoutItems();
3405 layoutState = savedState;
3406 if (parentWidget()->isVisible())
3407 applyState(layoutState,
false);
3411 if (parentWidget()->isVisible()) {
3412 layoutState.fitLayout();
3413 applyState(layoutState,
false);
3416
3417
3418
3419
3420
3421
3422 if ((parentWidget()->windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized))
3423 && !layoutState.fits()) {
3424 restoredState.reset(
new QMainWindowLayoutState(layoutState));
3428 savedState.deleteAllLayoutItems();
3431#if QT_CONFIG(dockwidget) && QT_CONFIG(tabbar)
3432 if (parentWidget()->isVisible())
3439#if QT_CONFIG(draganddrop)
3440bool QMainWindowLayout::needsPlatformDrag()
3442 static const bool wayland =
3443 QGuiApplication::platformName().startsWith(
"wayland"_L1, Qt::CaseInsensitive);
3447Qt::DropAction QMainWindowLayout::performPlatformWidgetDrag(QLayoutItem *widgetItem,
3448 const QPoint &pressPosition)
3450 draggingWidget = widgetItem;
3451 QWidget *widget = widgetItem->widget();
3452 auto drag = QDrag(widget);
3453 auto mimeData =
new QMimeData();
3454 auto window = widgetItem->widget()->windowHandle();
3456 auto serialize = [](
const auto &object) {
3458 QDataStream dataStream(&data, QIODevice::WriteOnly);
3459 dataStream << object;
3462 mimeData->setData(
"application/x-qt-mainwindowdrag-window"_L1,
3463 serialize(
reinterpret_cast<qintptr>(window)));
3464 mimeData->setData(
"application/x-qt-mainwindowdrag-position"_L1, serialize(pressPosition));
3465 drag.setMimeData(mimeData);
3467 auto result = drag.exec();
3469 draggingWidget =
nullptr;
3474#if defined(Q_OS_MACOS)
3475void QMainWindowLayout::registerUnifiedToolBarArea(QWidget *widget,
int upper,
int lower)
3477 qCDebug(lcUnifiedToolBar) <<
"Registering unified toolbar area" << upper << lower <<
"for" << widget;
3478 m_unifiedToolBarAreas.insert(widget, UnifiedToolBarRange(widget, upper, lower));
3479 updateUnifiedToolBarArea();
3482void QMainWindowLayout::setUnifiedToolBarAreaEnabled(QWidget *widget,
bool enable)
3484 qCDebug(lcUnifiedToolBar) << (enable ?
"Enabling" :
"Disabling") <<
"unified toolbar area for" << widget;
3485 m_enabledUnifiedToolBarAreas.insert(widget, enable);
3486 updateUnifiedToolBarArea();
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500void QMainWindowLayout::updateUnifiedToolBarArea()
3502 qCDebug(lcUnifiedToolBar) <<
"Updating unified toolbar area";
3504 QWindow *window = parentWidget()->windowHandle();
3506 qCDebug(lcUnifiedToolBar) <<
"No window yet, skipping";
3511 std::vector<UnifiedToolBarRange> ranges(m_unifiedToolBarAreas.cbegin(), m_unifiedToolBarAreas.cend());
3512 std::sort(ranges.begin(), ranges.end());
3516 const auto safeAreaMargins = QWidgetPrivate::get(parentWidget())->safeAreaMargins();
3517 int height = safeAreaMargins.top();
3519 for (UnifiedToolBarRange range : ranges) {
3520 bool enabled = m_enabledUnifiedToolBarAreas.value(range.widget,
false);
3521 qCDebug(lcUnifiedToolBar) <<
"Considering" << (enabled ?
"enabled" :
"disabled")
3522 <<
"toolbar area" << range.upper << range.lower <<
"for" << range.widget;
3533 if (range.upper <= (height + 1))
3534 height = qMax(height, range.lower);
3539 QSize unifiedToolBarAreaSize(window->width(), height);
3540 if (unifiedToolBarAreaSize == m_unifiedToolBarAreaSize)
3543 qCDebug(lcUnifiedToolBar) <<
"New unified toolbar area size is" << unifiedToolBarAreaSize;
3544 m_unifiedToolBarAreaSize = unifiedToolBarAreaSize;
3548 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSTahoe) {
3549 if (
auto *cocoaWindow = window->nativeInterface<QNativeInterface::Private::QCocoaWindow>()) {
3550 cocoaWindow->manageVisualEffectArea(quintptr(
this), QRect(QPoint(), m_unifiedToolBarAreaSize),
3551 NSVisualEffectMaterial(3) ,
3552 NSVisualEffectBlendingMode(1) ,
3553 NSVisualEffectState(0) );
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568bool QMainWindowLayout::testUnifiedToolBarAreaPosition(
int position)
const
3570 auto *mainWindow =
static_cast<QMainWindow *>(parentWidget());
3571 if (!mainWindow->unifiedTitleAndToolBarOnMac())
3574 qCDebug(lcUnifiedToolBar) <<
"Testing whether" << position <<
"is part of"
3575 <<
"unified toolbar area" << m_unifiedToolBarAreaSize;
3577 return 0 <= position && position < m_unifiedToolBarAreaSize.height();
3584#include "qmainwindowlayout.moc"
3585#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)