1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtWidgets module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "QtWidgets/qapplication.h"
42#include "QtWidgets/qwidget.h"
43#if QT_CONFIG(tabbar)
44#include "QtWidgets/qtabbar.h"
45#endif
46#include "QtWidgets/qstyle.h"
47#include "QtWidgets/qdesktopwidget.h"
48#include <private/qdesktopwidget_p.h>
49#include "QtWidgets/qapplication.h"
50#include "QtCore/qvariant.h"
51#include "qdockarealayout_p.h"
52#include "qdockwidget.h"
53#include "qmainwindow.h"
54#include "qwidgetanimator_p.h"
55#include "qmainwindowlayout_p.h"
56#include "qmenu_p.h"
57#include "qdockwidget_p.h"
58#include <private/qlayoutengine_p.h>
59
60#include <qpainter.h>
61#include <qstyleoption.h>
62
63QT_BEGIN_NAMESPACE
64
65// qmainwindow.cpp
66extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
67
68enum { StateFlagVisible = 1, StateFlagFloating = 2 };
69
70/******************************************************************************
71** QPlaceHolderItem
72*/
73
74QPlaceHolderItem::QPlaceHolderItem(QWidget *w)
75{
76 objectName = w->objectName();
77 hidden = w->isHidden();
78 window = w->isWindow();
79 if (window)
80 topLevelRect = w->geometry();
81}
82
83/******************************************************************************
84** QDockAreaLayoutItem
85*/
86
87QDockAreaLayoutItem::QDockAreaLayoutItem(QLayoutItem *_widgetItem)
88 : widgetItem(_widgetItem), subinfo(nullptr), placeHolderItem(nullptr), pos(0), size(-1), flags(NoFlags)
89{
90}
91
92QDockAreaLayoutItem::QDockAreaLayoutItem(QDockAreaLayoutInfo *_subinfo)
93 : widgetItem(nullptr), subinfo(_subinfo), placeHolderItem(nullptr), pos(0), size(-1), flags(NoFlags)
94{
95}
96
97QDockAreaLayoutItem::QDockAreaLayoutItem(QPlaceHolderItem *_placeHolderItem)
98 : widgetItem(nullptr), subinfo(nullptr), placeHolderItem(_placeHolderItem), pos(0), size(-1), flags(NoFlags)
99{
100}
101
102QDockAreaLayoutItem::QDockAreaLayoutItem(const QDockAreaLayoutItem &other)
103 : widgetItem(other.widgetItem), subinfo(nullptr), placeHolderItem(nullptr), pos(other.pos),
104 size(other.size), flags(other.flags)
105{
106 if (other.subinfo != nullptr)
107 subinfo = new QDockAreaLayoutInfo(*other.subinfo);
108 else if (other.placeHolderItem != nullptr)
109 placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
110}
111
112QDockAreaLayoutItem::~QDockAreaLayoutItem()
113{
114 delete subinfo;
115 delete placeHolderItem;
116}
117
118bool QDockAreaLayoutItem::skip() const
119{
120 if (placeHolderItem != nullptr)
121 return true;
122
123 if (flags & GapItem)
124 return false;
125
126 if (widgetItem != nullptr)
127 return widgetItem->isEmpty();
128
129 if (subinfo != nullptr) {
130 for (int i = 0; i < subinfo->item_list.count(); ++i) {
131 if (!subinfo->item_list.at(i).skip())
132 return false;
133 }
134 }
135
136 return true;
137}
138
139QSize QDockAreaLayoutItem::minimumSize() const
140{
141 if (widgetItem)
142 return widgetItem->minimumSize().grownBy(m: widgetItem->widget()->contentsMargins());
143 if (subinfo != nullptr)
144 return subinfo->minimumSize();
145 return QSize(0, 0);
146}
147
148QSize QDockAreaLayoutItem::maximumSize() const
149{
150 if (widgetItem)
151 return widgetItem->maximumSize().grownBy(m: widgetItem->widget()->contentsMargins());
152 if (subinfo != nullptr)
153 return subinfo->maximumSize();
154 return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
155}
156
157bool QDockAreaLayoutItem::hasFixedSize(Qt::Orientation o) const
158{
159 return perp(o, size: minimumSize()) == perp(o, size: maximumSize());
160}
161
162bool QDockAreaLayoutItem::expansive(Qt::Orientation o) const
163{
164 if ((flags & GapItem) || placeHolderItem != nullptr)
165 return false;
166 if (widgetItem != nullptr)
167 return ((widgetItem->expandingDirections() & o) == o);
168 if (subinfo != nullptr)
169 return subinfo->expansive(o);
170 return false;
171}
172
173QSize QDockAreaLayoutItem::sizeHint() const
174{
175 if (placeHolderItem != nullptr)
176 return QSize(0, 0);
177 if (widgetItem)
178 return widgetItem->sizeHint().grownBy(m: widgetItem->widget()->contentsMargins());
179 if (subinfo != nullptr)
180 return subinfo->sizeHint();
181 return QSize(-1, -1);
182}
183
184QDockAreaLayoutItem
185 &QDockAreaLayoutItem::operator = (const QDockAreaLayoutItem &other)
186{
187 widgetItem = other.widgetItem;
188 if (other.subinfo == nullptr)
189 subinfo = nullptr;
190 else
191 subinfo = new QDockAreaLayoutInfo(*other.subinfo);
192
193 delete placeHolderItem;
194 if (other.placeHolderItem == nullptr)
195 placeHolderItem = nullptr;
196 else
197 placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
198
199 pos = other.pos;
200 size = other.size;
201 flags = other.flags;
202
203 return *this;
204}
205
206/******************************************************************************
207** QDockAreaLayoutInfo
208*/
209
210#if QT_CONFIG(tabbar)
211static quintptr tabId(const QDockAreaLayoutItem &item)
212{
213 if (item.widgetItem == nullptr)
214 return 0;
215 return reinterpret_cast<quintptr>(item.widgetItem->widget());
216}
217#endif
218
219static const int zero = 0;
220
221QDockAreaLayoutInfo::QDockAreaLayoutInfo()
222 : sep(&zero), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(nullptr)
223#if QT_CONFIG(tabbar)
224 , tabbed(false), tabBar(nullptr), tabBarShape(QTabBar::RoundedSouth)
225#endif
226{
227}
228
229QDockAreaLayoutInfo::QDockAreaLayoutInfo(const int *_sep, QInternal::DockPosition _dockPos,
230 Qt::Orientation _o, int tbshape,
231 QMainWindow *window)
232 : sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window)
233#if QT_CONFIG(tabbar)
234 , tabbed(false), tabBar(nullptr), tabBarShape(static_cast<QTabBar::Shape>(tbshape))
235#endif
236{
237#if !QT_CONFIG(tabbar)
238 Q_UNUSED(tbshape);
239#endif
240}
241
242QSize QDockAreaLayoutInfo::size() const
243{
244 return isEmpty() ? QSize(0, 0) : rect.size();
245}
246
247void QDockAreaLayoutInfo::clear()
248{
249 item_list.clear();
250 rect = QRect();
251#if QT_CONFIG(tabbar)
252 tabbed = false;
253 tabBar = nullptr;
254#endif
255}
256
257bool QDockAreaLayoutInfo::isEmpty() const
258{
259 return next(idx: -1) == -1;
260}
261
262bool QDockAreaLayoutInfo::onlyHasPlaceholders() const
263{
264 for (const QDockAreaLayoutItem &item : item_list) {
265 if (!item.placeHolderItem)
266 return false;
267 }
268
269 return true;
270}
271
272QSize QDockAreaLayoutInfo::minimumSize() const
273{
274 if (isEmpty())
275 return QSize(0, 0);
276
277 int a = 0, b = 0;
278 bool first = true;
279 for (int i = 0; i < item_list.size(); ++i) {
280 const QDockAreaLayoutItem &item = item_list.at(i);
281 if (item.skip())
282 continue;
283
284 QSize min_size = item.minimumSize();
285#if QT_CONFIG(tabbar)
286 if (tabbed) {
287 a = qMax(a, b: pick(o, size: min_size));
288 } else
289#endif
290 {
291 if (!first)
292 a += *sep;
293 a += pick(o, size: min_size);
294 }
295 b = qMax(a: b, b: perp(o, size: min_size));
296
297 first = false;
298 }
299
300 QSize result;
301 rpick(o, size&: result) = a;
302 rperp(o, size&: result) = b;
303
304#if QT_CONFIG(tabbar)
305 QSize tbm = tabBarMinimumSize();
306 if (!tbm.isNull()) {
307 switch (tabBarShape) {
308 case QTabBar::RoundedNorth:
309 case QTabBar::RoundedSouth:
310 case QTabBar::TriangularNorth:
311 case QTabBar::TriangularSouth:
312 result.rheight() += tbm.height();
313 result.rwidth() = qMax(a: tbm.width(), b: result.width());
314 break;
315 case QTabBar::RoundedEast:
316 case QTabBar::RoundedWest:
317 case QTabBar::TriangularEast:
318 case QTabBar::TriangularWest:
319 result.rheight() = qMax(a: tbm.height(), b: result.height());
320 result.rwidth() += tbm.width();
321 break;
322 default:
323 break;
324 }
325 }
326#endif // QT_CONFIG(tabbar)
327
328 return result;
329}
330
331QSize QDockAreaLayoutInfo::maximumSize() const
332{
333 if (isEmpty())
334 return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
335
336 int a = 0, b = QWIDGETSIZE_MAX;
337#if QT_CONFIG(tabbar)
338 if (tabbed)
339 a = QWIDGETSIZE_MAX;
340#endif
341
342 int min_perp = 0;
343
344 bool first = true;
345 for (int i = 0; i < item_list.size(); ++i) {
346 const QDockAreaLayoutItem &item = item_list.at(i);
347 if (item.skip())
348 continue;
349
350 QSize max_size = item.maximumSize();
351 min_perp = qMax(a: min_perp, b: perp(o, size: item.minimumSize()));
352
353#if QT_CONFIG(tabbar)
354 if (tabbed) {
355 a = qMin(a, b: pick(o, size: max_size));
356 } else
357#endif
358 {
359 if (!first)
360 a += *sep;
361 a += pick(o, size: max_size);
362 }
363 b = qMin(a: b, b: perp(o, size: max_size));
364
365 a = qMin(a, b: int(QWIDGETSIZE_MAX));
366 b = qMin(a: b, b: int(QWIDGETSIZE_MAX));
367
368 first = false;
369 }
370
371 b = qMax(a: b, b: min_perp);
372
373 QSize result;
374 rpick(o, size&: result) = a;
375 rperp(o, size&: result) = b;
376
377#if QT_CONFIG(tabbar)
378 QSize tbh = tabBarSizeHint();
379 if (!tbh.isNull()) {
380 switch (tabBarShape) {
381 case QTabBar::RoundedNorth:
382 case QTabBar::RoundedSouth:
383 result.rheight() += tbh.height();
384 break;
385 case QTabBar::RoundedEast:
386 case QTabBar::RoundedWest:
387 result.rwidth() += tbh.width();
388 break;
389 default:
390 break;
391 }
392 }
393#endif // QT_CONFIG(tabbar)
394
395 return result;
396}
397
398QSize QDockAreaLayoutInfo::sizeHint() const
399{
400 if (isEmpty())
401 return QSize(0, 0);
402
403 int a = 0, b = 0;
404 int min_perp = 0;
405 int max_perp = QWIDGETSIZE_MAX;
406 const QDockAreaLayoutItem *previous = nullptr;
407 for (int i = 0; i < item_list.size(); ++i) {
408 const QDockAreaLayoutItem &item = item_list.at(i);
409 if (item.skip())
410 continue;
411
412 bool gap = item.flags & QDockAreaLayoutItem::GapItem;
413
414 QSize size_hint = item.sizeHint();
415 min_perp = qMax(a: min_perp, b: perp(o, size: item.minimumSize()));
416 max_perp = qMin(a: max_perp, b: perp(o, size: item.maximumSize()));
417
418#if QT_CONFIG(tabbar)
419 if (tabbed) {
420 a = qMax(a, b: gap ? item.size : pick(o, size: size_hint));
421 } else
422#endif
423 {
424 if (previous && !gap && !(previous->flags & QDockAreaLayoutItem::GapItem)
425 && !previous->hasFixedSize(o)) {
426 a += *sep;
427 }
428 a += gap ? item.size : pick(o, size: size_hint);
429 }
430 b = qMax(a: b, b: perp(o, size: size_hint));
431
432 previous = &item;
433 }
434
435 max_perp = qMax(a: max_perp, b: min_perp);
436 b = qMax(a: b, b: min_perp);
437 b = qMin(a: b, b: max_perp);
438
439 QSize result;
440 rpick(o, size&: result) = a;
441 rperp(o, size&: result) = b;
442
443#if QT_CONFIG(tabbar)
444 if (tabbed) {
445 QSize tbh = tabBarSizeHint();
446 switch (tabBarShape) {
447 case QTabBar::RoundedNorth:
448 case QTabBar::RoundedSouth:
449 case QTabBar::TriangularNorth:
450 case QTabBar::TriangularSouth:
451 result.rheight() += tbh.height();
452 result.rwidth() = qMax(a: tbh.width(), b: result.width());
453 break;
454 case QTabBar::RoundedEast:
455 case QTabBar::RoundedWest:
456 case QTabBar::TriangularEast:
457 case QTabBar::TriangularWest:
458 result.rheight() = qMax(a: tbh.height(), b: result.height());
459 result.rwidth() += tbh.width();
460 break;
461 default:
462 break;
463 }
464 }
465#endif // QT_CONFIG(tabbar)
466
467 return result;
468}
469
470bool QDockAreaLayoutInfo::expansive(Qt::Orientation o) const
471{
472 for (int i = 0; i < item_list.size(); ++i) {
473 if (item_list.at(i).expansive(o))
474 return true;
475 }
476 return false;
477}
478
479/* QDockAreaLayoutInfo::maximumSize() doesn't return the real max size. For example,
480 if the layout is empty, it returns QWIDGETSIZE_MAX. This is so that empty dock areas
481 don't constrain the size of the QMainWindow, but sometimes we really need to know the
482 maximum size. Also, these functions take into account widgets that want to keep their
483 size (f.ex. when they are hidden and then shown, they should not change size).
484*/
485
486static int realMinSize(const QDockAreaLayoutInfo &info)
487{
488 int result = 0;
489 bool first = true;
490 for (int i = 0; i < info.item_list.size(); ++i) {
491 const QDockAreaLayoutItem &item = info.item_list.at(i);
492 if (item.skip())
493 continue;
494
495 int min = 0;
496 if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
497 min = item.size;
498 else
499 min = pick(o: info.o, size: item.minimumSize());
500
501 if (!first)
502 result += *info.sep;
503 result += min;
504
505 first = false;
506 }
507
508 return result;
509}
510
511static int realMaxSize(const QDockAreaLayoutInfo &info)
512{
513 int result = 0;
514 bool first = true;
515 for (int i = 0; i < info.item_list.size(); ++i) {
516 const QDockAreaLayoutItem &item = info.item_list.at(i);
517 if (item.skip())
518 continue;
519
520 int max = 0;
521 if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
522 max = item.size;
523 else
524 max = pick(o: info.o, size: item.maximumSize());
525
526 if (!first)
527 result += *info.sep;
528 result += max;
529
530 if (result >= QWIDGETSIZE_MAX)
531 return QWIDGETSIZE_MAX;
532
533 first = false;
534 }
535
536 return result;
537}
538
539void QDockAreaLayoutInfo::fitItems()
540{
541#if QT_CONFIG(tabbar)
542 if (tabbed) {
543 return;
544 }
545#endif
546
547 QVector<QLayoutStruct> layout_struct_list(item_list.size()*2);
548 int j = 0;
549
550 int size = pick(o, size: rect.size());
551 int min_size = realMinSize(info: *this);
552 int max_size = realMaxSize(info: *this);
553 int last_index = -1;
554
555 const QDockAreaLayoutItem *previous = nullptr;
556 for (int i = 0; i < item_list.size(); ++i) {
557 QDockAreaLayoutItem &item = item_list[i];
558 if (item.skip())
559 continue;
560
561 bool gap = item.flags & QDockAreaLayoutItem::GapItem;
562 if (previous && !gap) {
563 if (!(previous->flags & QDockAreaLayoutItem::GapItem)) {
564 QLayoutStruct &ls = layout_struct_list[j++];
565 ls.init();
566 ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : *sep;
567 ls.empty = false;
568 }
569 }
570
571 if (item.flags & QDockAreaLayoutItem::KeepSize) {
572 // Check if the item can keep its size, without violating size constraints
573 // of other items.
574
575 if (size < min_size) {
576 // There is too little space to keep this widget's size
577 item.flags &= ~QDockAreaLayoutItem::KeepSize;
578 min_size -= item.size;
579 min_size += pick(o, size: item.minimumSize());
580 min_size = qMax(a: 0, b: min_size);
581 } else if (size > max_size) {
582 // There is too much space to keep this widget's size
583 item.flags &= ~QDockAreaLayoutItem::KeepSize;
584 max_size -= item.size;
585 max_size += pick(o, size: item.maximumSize());
586 max_size = qMin<int>(QWIDGETSIZE_MAX, b: max_size);
587 }
588 }
589
590 last_index = j;
591 QLayoutStruct &ls = layout_struct_list[j++];
592 ls.init();
593 ls.empty = false;
594 if (item.flags & QDockAreaLayoutItem::KeepSize) {
595 ls.minimumSize = ls.maximumSize = ls.sizeHint = item.size;
596 ls.expansive = false;
597 ls.stretch = 0;
598 } else {
599 ls.maximumSize = pick(o, size: item.maximumSize());
600 ls.expansive = item.expansive(o);
601 ls.minimumSize = pick(o, size: item.minimumSize());
602 ls.sizeHint = item.size == -1 ? pick(o, size: item.sizeHint()) : item.size;
603 ls.stretch = ls.expansive ? ls.sizeHint : 0;
604 }
605
606 item.flags &= ~QDockAreaLayoutItem::KeepSize;
607 previous = &item;
608 }
609 layout_struct_list.resize(asize: j);
610
611 // If there is more space than the widgets can take (due to maximum size constraints),
612 // we detect it here and stretch the last widget to take up the rest of the space.
613 if (size > max_size && last_index != -1) {
614 layout_struct_list[last_index].maximumSize = QWIDGETSIZE_MAX;
615 layout_struct_list[last_index].expansive = true;
616 }
617
618 qGeomCalc(chain&: layout_struct_list, start: 0, count: j, pos: pick(o, pos: rect.topLeft()), space: size, spacer: 0);
619
620 j = 0;
621 bool prev_gap = false;
622 bool first = true;
623 for (int i = 0; i < item_list.size(); ++i) {
624 QDockAreaLayoutItem &item = item_list[i];
625 if (item.skip())
626 continue;
627
628 bool gap = item.flags & QDockAreaLayoutItem::GapItem;
629 if (!first && !gap && !prev_gap)
630 ++j;
631
632 const QLayoutStruct &ls = layout_struct_list.at(i: j++);
633 item.size = ls.size;
634 item.pos = ls.pos;
635
636 if (item.subinfo != nullptr) {
637 item.subinfo->rect = itemRect(index: i);
638 item.subinfo->fitItems();
639 }
640
641 prev_gap = gap;
642 first = false;
643 }
644}
645
646static QInternal::DockPosition dockPosHelper(const QRect &rect, const QPoint &_pos,
647 Qt::Orientation o,
648 bool nestingEnabled,
649 QDockAreaLayoutInfo::TabMode tabMode)
650{
651 if (tabMode == QDockAreaLayoutInfo::ForceTabs)
652 return QInternal::DockCount;
653
654 QPoint pos = _pos - rect.topLeft();
655
656 int x = pos.x();
657 int y = pos.y();
658 int w = rect.width();
659 int h = rect.height();
660
661 if (tabMode != QDockAreaLayoutInfo::NoTabs) {
662 // is it in the center?
663 if (nestingEnabled) {
664 /* 2/3
665 +--------------+
666 | |
667 | CCCCCCCC |
668 2/3 | CCCCCCCC |
669 | CCCCCCCC |
670 | |
671 +--------------+ */
672
673 QRect center(w/6, h/6, 2*w/3, 2*h/3);
674 if (center.contains(p: pos))
675 return QInternal::DockCount;
676 } else if (o == Qt::Horizontal) {
677 /* 2/3
678 +--------------+
679 | CCCCCCCC |
680 | CCCCCCCC |
681 | CCCCCCCC |
682 | CCCCCCCC |
683 | CCCCCCCC |
684 +--------------+ */
685
686 if (x > w/6 && x < w*5/6)
687 return QInternal::DockCount;
688 } else {
689 /*
690 +--------------+
691 | |
692 2/3 |CCCCCCCCCCCCCC|
693 |CCCCCCCCCCCCCC|
694 | |
695 +--------------+ */
696 if (y > h/6 && y < 5*h/6)
697 return QInternal::DockCount;
698 }
699 }
700
701 // not in the center. which edge?
702 if (nestingEnabled) {
703 if (o == Qt::Horizontal) {
704 /* 1/3 1/3 1/3
705 +------------+ (we've already ruled out the center)
706 |LLLLTTTTRRRR|
707 |LLLLTTTTRRRR|
708 |LLLLBBBBRRRR|
709 |LLLLBBBBRRRR|
710 +------------+ */
711
712 if (x < w/3)
713 return QInternal::LeftDock;
714 if (x > 2*w/3)
715 return QInternal::RightDock;
716 if (y < h/2)
717 return QInternal::TopDock;
718 return QInternal::BottomDock;
719 } else {
720 /* +------------+ (we've already ruled out the center)
721 1/3 |TTTTTTTTTTTT|
722 |LLLLLLRRRRRR|
723 1/3 |LLLLLLRRRRRR|
724 1/3 |BBBBBBBBBBBB|
725 +------------+ */
726
727 if (y < h/3)
728 return QInternal::TopDock;
729 if (y > 2*h/3)
730 return QInternal::BottomDock;
731 if (x < w/2)
732 return QInternal::LeftDock;
733 return QInternal::RightDock;
734 }
735 } else {
736 if (o == Qt::Horizontal) {
737 return x < w/2
738 ? QInternal::LeftDock
739 : QInternal::RightDock;
740 } else {
741 return y < h/2
742 ? QInternal::TopDock
743 : QInternal::BottomDock;
744 }
745 }
746}
747
748QList<int> QDockAreaLayoutInfo::gapIndex(const QPoint& _pos,
749 bool nestingEnabled, TabMode tabMode) const
750{
751 QList<int> result;
752 QRect item_rect;
753 int item_index = 0;
754
755#if QT_CONFIG(tabbar)
756 if (tabbed) {
757 item_rect = tabContentRect();
758 } else
759#endif
760 {
761 int pos = pick(o, pos: _pos);
762
763 int last = -1;
764 for (int i = 0; i < item_list.size(); ++i) {
765 const QDockAreaLayoutItem &item = item_list.at(i);
766 if (item.skip())
767 continue;
768
769 last = i;
770
771 if (item.pos + item.size < pos)
772 continue;
773
774 if (item.subinfo != nullptr
775#if QT_CONFIG(tabbar)
776 && !item.subinfo->tabbed
777#endif
778 ) {
779 result = item.subinfo->gapIndex(_pos, nestingEnabled,
780 tabMode);
781 result.prepend(t: i);
782 return result;
783 }
784
785 item_rect = itemRect(index: i);
786 item_index = i;
787 break;
788 }
789
790 if (item_rect.isNull()) {
791 result.append(t: last + 1);
792 return result;
793 }
794 }
795
796 Q_ASSERT(!item_rect.isNull());
797
798 QInternal::DockPosition dock_pos
799 = dockPosHelper(rect: item_rect, _pos, o, nestingEnabled, tabMode);
800
801 switch (dock_pos) {
802 case QInternal::LeftDock:
803 if (o == Qt::Horizontal)
804 result << item_index;
805 else
806 result << item_index << 0; // this subinfo doesn't exist yet, but insertGap()
807 // handles this by inserting it
808 break;
809 case QInternal::RightDock:
810 if (o == Qt::Horizontal)
811 result << item_index + 1;
812 else
813 result << item_index << 1;
814 break;
815 case QInternal::TopDock:
816 if (o == Qt::Horizontal)
817 result << item_index << 0;
818 else
819 result << item_index;
820 break;
821 case QInternal::BottomDock:
822 if (o == Qt::Horizontal)
823 result << item_index << 1;
824 else
825 result << item_index + 1;
826 break;
827 case QInternal::DockCount:
828 result << (-item_index - 1) << 0; // negative item_index means "on top of"
829 // -item_index - 1, insertGap()
830 // will insert a tabbed subinfo
831 break;
832 default:
833 break;
834 }
835
836 return result;
837}
838
839static inline int shrink(QLayoutStruct &ls, int delta)
840{
841 if (ls.empty)
842 return 0;
843 int old_size = ls.size;
844 ls.size = qMax(a: ls.size - delta, b: ls.minimumSize);
845 return old_size - ls.size;
846}
847
848static inline int grow(QLayoutStruct &ls, int delta)
849{
850 if (ls.empty)
851 return 0;
852 int old_size = ls.size;
853 ls.size = qMin(a: ls.size + delta, b: ls.maximumSize);
854 return ls.size - old_size;
855}
856
857static int separatorMoveHelper(QVector<QLayoutStruct> &list, int index, int delta, int sep)
858{
859 // adjust sizes
860 int pos = -1;
861 for (int i = 0; i < list.size(); ++i) {
862 const QLayoutStruct &ls = list.at(i);
863 if (!ls.empty) {
864 pos = ls.pos;
865 break;
866 }
867 }
868 if (pos == -1)
869 return 0;
870
871 if (delta > 0) {
872 int growlimit = 0;
873 for (int i = 0; i<=index; ++i) {
874 const QLayoutStruct &ls = list.at(i);
875 if (ls.empty)
876 continue;
877 if (ls.maximumSize == QLAYOUTSIZE_MAX) {
878 growlimit = QLAYOUTSIZE_MAX;
879 break;
880 }
881 growlimit += ls.maximumSize - ls.size;
882 }
883 if (delta > growlimit)
884 delta = growlimit;
885
886 int d = 0;
887 for (int i = index + 1; d < delta && i < list.count(); ++i)
888 d += shrink(ls&: list[i], delta: delta - d);
889 delta = d;
890 d = 0;
891 for (int i = index; d < delta && i >= 0; --i)
892 d += grow(ls&: list[i], delta: delta - d);
893 } else if (delta < 0) {
894 int growlimit = 0;
895 for (int i = index + 1; i < list.count(); ++i) {
896 const QLayoutStruct &ls = list.at(i);
897 if (ls.empty)
898 continue;
899 if (ls.maximumSize == QLAYOUTSIZE_MAX) {
900 growlimit = QLAYOUTSIZE_MAX;
901 break;
902 }
903 growlimit += ls.maximumSize - ls.size;
904 }
905 if (-delta > growlimit)
906 delta = -growlimit;
907
908 int d = 0;
909 for (int i = index; d < -delta && i >= 0; --i)
910 d += shrink(ls&: list[i], delta: -delta - d);
911 delta = -d;
912 d = 0;
913 for (int i = index + 1; d < -delta && i < list.count(); ++i)
914 d += grow(ls&: list[i], delta: -delta - d);
915 }
916
917 // adjust positions
918 bool first = true;
919 for (int i = 0; i < list.size(); ++i) {
920 QLayoutStruct &ls = list[i];
921 if (ls.empty) {
922 ls.pos = pos + (first ? 0 : sep);
923 continue;
924 }
925 if (!first)
926 pos += sep;
927 ls.pos = pos;
928 pos += ls.size;
929 first = false;
930 }
931
932 return delta;
933}
934
935int QDockAreaLayoutInfo::separatorMove(int index, int delta)
936{
937#if QT_CONFIG(tabbar)
938 Q_ASSERT(!tabbed);
939#endif
940
941 QVector<QLayoutStruct> list(item_list.size());
942 for (int i = 0; i < list.size(); ++i) {
943 const QDockAreaLayoutItem &item = item_list.at(i);
944 QLayoutStruct &ls = list[i];
945 Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
946 if (item.skip()) {
947 ls.empty = true;
948 } else {
949 const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep;
950 ls.empty = false;
951 ls.pos = item.pos;
952 ls.size = item.size + separatorSpace;
953 ls.minimumSize = pick(o, size: item.minimumSize()) + separatorSpace;
954 ls.maximumSize = pick(o, size: item.maximumSize()) + separatorSpace;
955
956 }
957 }
958
959 //the separator space has been added to the size, so we pass 0 as a parameter
960 delta = separatorMoveHelper(list, index, delta, sep: 0 /*separator*/);
961
962 for (int i = 0; i < list.size(); ++i) {
963 QDockAreaLayoutItem &item = item_list[i];
964 if (item.skip())
965 continue;
966 QLayoutStruct &ls = list[i];
967 const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep;
968 item.size = ls.size - separatorSpace;
969 item.pos = ls.pos;
970 if (item.subinfo != nullptr) {
971 item.subinfo->rect = itemRect(index: i);
972 item.subinfo->fitItems();
973 }
974 }
975
976 return delta;
977}
978
979void QDockAreaLayoutInfo::unnest(int index)
980{
981 QDockAreaLayoutItem &item = item_list[index];
982 if (item.subinfo == nullptr)
983 return;
984 if (item.subinfo->item_list.count() > 1)
985 return;
986
987 if (item.subinfo->item_list.count() == 0) {
988 item_list.removeAt(i: index);
989 } else if (item.subinfo->item_list.count() == 1) {
990 QDockAreaLayoutItem &child = item.subinfo->item_list.first();
991 if (child.widgetItem != nullptr) {
992 item.widgetItem = child.widgetItem;
993 delete item.subinfo;
994 item.subinfo = nullptr;
995 } else if (child.subinfo != nullptr) {
996 QDockAreaLayoutInfo *tmp = item.subinfo;
997 item.subinfo = child.subinfo;
998 child.subinfo = nullptr;
999 tmp->item_list.clear();
1000 delete tmp;
1001 }
1002 }
1003}
1004
1005void QDockAreaLayoutInfo::remove(const QList<int> &path)
1006{
1007 Q_ASSERT(!path.isEmpty());
1008
1009 if (path.count() > 1) {
1010 const int index = path.first();
1011 QDockAreaLayoutItem &item = item_list[index];
1012 Q_ASSERT(item.subinfo != nullptr);
1013 item.subinfo->remove(path: path.mid(pos: 1));
1014 unnest(index);
1015 } else {
1016 int index = path.first();
1017 item_list.removeAt(i: index);
1018 }
1019}
1020
1021QLayoutItem *QDockAreaLayoutInfo::plug(const QList<int> &path)
1022{
1023 Q_ASSERT(!path.isEmpty());
1024
1025 int index = path.first();
1026 if (index < 0)
1027 index = -index - 1;
1028
1029 if (path.count() > 1) {
1030 QDockAreaLayoutItem &item = item_list[index];
1031 Q_ASSERT(item.subinfo != nullptr);
1032 return item.subinfo->plug(path: path.mid(pos: 1));
1033 }
1034
1035 QDockAreaLayoutItem &item = item_list[index];
1036
1037 Q_ASSERT(item.widgetItem != nullptr);
1038 Q_ASSERT(item.flags & QDockAreaLayoutItem::GapItem);
1039 item.flags &= ~QDockAreaLayoutItem::GapItem;
1040 return item.widgetItem;
1041}
1042
1043QLayoutItem *QDockAreaLayoutInfo::unplug(const QList<int> &path)
1044{
1045 Q_ASSERT(!path.isEmpty());
1046
1047 const int index = path.first();
1048 if (path.count() > 1) {
1049 QDockAreaLayoutItem &item = item_list[index];
1050 Q_ASSERT(item.subinfo != nullptr);
1051 return item.subinfo->unplug(path: path.mid(pos: 1));
1052 }
1053
1054 QDockAreaLayoutItem &item = item_list[index];
1055 int prev = this->prev(idx: index);
1056 int next = this->next(idx: index);
1057
1058 Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
1059 item.flags |= QDockAreaLayoutItem::GapItem;
1060
1061#if QT_CONFIG(tabbar)
1062 if (tabbed) {
1063 } else
1064#endif
1065 {
1066 if (prev != -1 && !(item_list.at(i: prev).flags & QDockAreaLayoutItem::GapItem)) {
1067 item.pos -= *sep;
1068 item.size += *sep;
1069 }
1070 if (next != -1 && !(item_list.at(i: next).flags & QDockAreaLayoutItem::GapItem))
1071 item.size += *sep;
1072 }
1073
1074 return item.widgetItem;
1075}
1076
1077#if QT_CONFIG(tabbar)
1078
1079quintptr QDockAreaLayoutInfo::currentTabId() const
1080{
1081 if (!tabbed || tabBar == nullptr)
1082 return 0;
1083
1084 int index = tabBar->currentIndex();
1085 if (index == -1)
1086 return 0;
1087
1088 return qvariant_cast<quintptr>(v: tabBar->tabData(index));
1089}
1090
1091void QDockAreaLayoutInfo::setCurrentTab(QWidget *widget)
1092{
1093 setCurrentTabId(reinterpret_cast<quintptr>(widget));
1094}
1095
1096void QDockAreaLayoutInfo::setCurrentTabId(quintptr id)
1097{
1098 if (!tabbed || tabBar == nullptr)
1099 return;
1100
1101 for (int i = 0; i < tabBar->count(); ++i) {
1102 if (qvariant_cast<quintptr>(v: tabBar->tabData(index: i)) == id) {
1103 tabBar->setCurrentIndex(i);
1104 return;
1105 }
1106 }
1107}
1108
1109#endif // QT_CONFIG(tabbar)
1110
1111static QRect dockedGeometry(QWidget *widget)
1112{
1113 int titleHeight = 0;
1114
1115 QDockWidgetLayout *layout
1116 = qobject_cast<QDockWidgetLayout*>(object: widget->layout());
1117 if (layout && layout->nativeWindowDeco())
1118 titleHeight = layout->titleHeight();
1119
1120 QRect result = widget->geometry();
1121 result.adjust(dx1: 0, dy1: -titleHeight, dx2: 0, dy2: 0);
1122 return result;
1123}
1124
1125bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
1126{
1127 Q_ASSERT(!path.isEmpty());
1128
1129 bool insert_tabbed = false;
1130 int index = path.first();
1131 if (index < 0) {
1132 insert_tabbed = true;
1133 index = -index - 1;
1134 }
1135
1136// dump(qDebug() << "insertGap() before:" << index << tabIndex, *this, QString());
1137
1138 if (path.count() > 1) {
1139 QDockAreaLayoutItem &item = item_list[index];
1140
1141 if (item.subinfo == nullptr
1142#if QT_CONFIG(tabbar)
1143 || (item.subinfo->tabbed && !insert_tabbed)
1144#endif
1145 ) {
1146
1147 // this is not yet a nested layout - make it
1148
1149 QDockAreaLayoutInfo *subinfo = item.subinfo;
1150 QLayoutItem *widgetItem = item.widgetItem;
1151 QPlaceHolderItem *placeHolderItem = item.placeHolderItem;
1152 QRect r = subinfo == nullptr ? widgetItem ? dockedGeometry(widget: widgetItem->widget()) : placeHolderItem->topLevelRect : subinfo->rect;
1153
1154 Qt::Orientation opposite = o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal;
1155#if !QT_CONFIG(tabbar)
1156 const int tabBarShape = 0;
1157#endif
1158 QDockAreaLayoutInfo *new_info
1159 = new QDockAreaLayoutInfo(sep, dockPos, opposite, tabBarShape, mainWindow);
1160
1161 //item become a new top-level
1162 item.subinfo = new_info;
1163 item.widgetItem = nullptr;
1164 item.placeHolderItem = nullptr;
1165
1166 QDockAreaLayoutItem new_item
1167 = widgetItem == nullptr
1168 ? QDockAreaLayoutItem(subinfo)
1169 : widgetItem ? QDockAreaLayoutItem(widgetItem) : QDockAreaLayoutItem(placeHolderItem);
1170 new_item.size = pick(o: opposite, size: r.size());
1171 new_item.pos = pick(o: opposite, pos: r.topLeft());
1172 new_info->item_list.append(t: new_item);
1173#if QT_CONFIG(tabbar)
1174 if (insert_tabbed) {
1175 new_info->tabbed = true;
1176 }
1177#endif
1178 }
1179
1180 return item.subinfo->insertGap(path: path.mid(pos: 1), dockWidgetItem);
1181 }
1182
1183 // create the gap item
1184 QDockAreaLayoutItem gap_item;
1185 gap_item.flags |= QDockAreaLayoutItem::GapItem;
1186 gap_item.widgetItem = dockWidgetItem; // so minimumSize(), maximumSize() and
1187 // sizeHint() will work
1188#if QT_CONFIG(tabbar)
1189 if (!tabbed)
1190#endif
1191 {
1192 int prev = this->prev(idx: index);
1193 int next = this->next(idx: index - 1);
1194 // find out how much space we have in the layout
1195 int space = 0;
1196 if (isEmpty()) {
1197 // I am an empty dock area, therefore I am a top-level dock area.
1198 switch (dockPos) {
1199 case QInternal::LeftDock:
1200 case QInternal::RightDock:
1201 if (o == Qt::Vertical) {
1202 // the "size" is the height of the dock area (remember we are empty)
1203 space = pick(o: Qt::Vertical, size: rect.size());
1204 } else {
1205 space = pick(o: Qt::Horizontal, size: dockWidgetItem->widget()->size());
1206 }
1207 break;
1208 case QInternal::TopDock:
1209 case QInternal::BottomDock:
1210 default:
1211 if (o == Qt::Horizontal) {
1212 // the "size" is width of the dock area
1213 space = pick(o: Qt::Horizontal, size: rect.size());
1214 } else {
1215 space = pick(o: Qt::Vertical, size: dockWidgetItem->widget()->size());
1216 }
1217 break;
1218 }
1219 } else {
1220 for (int i = 0; i < item_list.count(); ++i) {
1221 const QDockAreaLayoutItem &item = item_list.at(i);
1222 if (item.skip())
1223 continue;
1224 Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
1225 space += item.size - pick(o, size: item.minimumSize());
1226 }
1227 }
1228
1229 // find the actual size of the gap
1230 int gap_size = 0;
1231 int sep_size = 0;
1232 if (isEmpty()) {
1233 gap_size = space;
1234 sep_size = 0;
1235 } else {
1236 QRect r = dockedGeometry(widget: dockWidgetItem->widget());
1237 gap_size = pick(o, size: r.size());
1238 if (prev != -1 && !(item_list.at(i: prev).flags & QDockAreaLayoutItem::GapItem))
1239 sep_size += *sep;
1240 if (next != -1 && !(item_list.at(i: next).flags & QDockAreaLayoutItem::GapItem))
1241 sep_size += *sep;
1242 }
1243 if (gap_size + sep_size > space)
1244 gap_size = pick(o, size: gap_item.minimumSize());
1245 gap_item.size = gap_size + sep_size;
1246 }
1247
1248 // finally, insert the gap
1249 item_list.insert(i: index, t: gap_item);
1250
1251// dump(qDebug() << "insertGap() after:" << index << tabIndex, *this, QString());
1252
1253 return true;
1254}
1255
1256QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(QWidget *widget)
1257{
1258 for (int i = 0; i < item_list.count(); ++i) {
1259 const QDockAreaLayoutItem &item = item_list.at(i);
1260 if (item.skip())
1261 continue;
1262
1263#if QT_CONFIG(tabbar)
1264 if (tabbed && widget == tabBar)
1265 return this;
1266#endif
1267
1268 if (item.widgetItem != nullptr && item.widgetItem->widget() == widget)
1269 return this;
1270
1271 if (item.subinfo != nullptr) {
1272 if (QDockAreaLayoutInfo *result = item.subinfo->info(widget))
1273 return result;
1274 }
1275 }
1276
1277 return nullptr;
1278}
1279
1280QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(const QList<int> &path)
1281{
1282 int index = path.first();
1283 if (index < 0)
1284 index = -index - 1;
1285 if (index >= item_list.count())
1286 return this;
1287 if (path.count() == 1 || item_list[index].subinfo == nullptr)
1288 return this;
1289 return item_list[index].subinfo->info(path: path.mid(pos: 1));
1290}
1291
1292QRect QDockAreaLayoutInfo::itemRect(int index, bool isGap) const
1293{
1294 const QDockAreaLayoutItem &item = item_list.at(i: index);
1295
1296 if (item.skip())
1297 return QRect();
1298
1299 if (isGap && !(item.flags & QDockAreaLayoutItem::GapItem))
1300 return QRect();
1301
1302 QRect result;
1303
1304#if QT_CONFIG(tabbar)
1305 if (tabbed) {
1306 if (isGap || tabId(item) == currentTabId())
1307 result = tabContentRect();
1308 } else
1309#endif
1310 {
1311 int pos = item.pos;
1312 int size = item.size;
1313
1314 if (isGap) {
1315 int prev = this->prev(idx: index);
1316 int next = this->next(idx: index);
1317 if (prev != -1 && !(item_list.at(i: prev).flags & QDockAreaLayoutItem::GapItem)) {
1318 pos += *sep;
1319 size -= *sep;
1320 }
1321 if (next != -1 && !(item_list.at(i: next).flags & QDockAreaLayoutItem::GapItem))
1322 size -= *sep;
1323 }
1324
1325 QPoint p;
1326 rpick(o, pos&: p) = pos;
1327 rperp(o, pos&: p) = perp(o, pos: rect.topLeft());
1328 QSize s;
1329 rpick(o, size&: s) = size;
1330 rperp(o, size&: s) = perp(o, size: rect.size());
1331 result = QRect(p, s);
1332 }
1333
1334 return result;
1335}
1336
1337QRect QDockAreaLayoutInfo::itemRect(const QList<int> &path) const
1338{
1339 Q_ASSERT(!path.isEmpty());
1340
1341 const int index = path.first();
1342 if (path.count() > 1) {
1343 const QDockAreaLayoutItem &item = item_list.at(i: index);
1344 Q_ASSERT(item.subinfo != nullptr);
1345 return item.subinfo->itemRect(path: path.mid(pos: 1));
1346 }
1347
1348 return itemRect(index);
1349}
1350
1351QRect QDockAreaLayoutInfo::separatorRect(int index) const
1352{
1353#if QT_CONFIG(tabbar)
1354 if (tabbed)
1355 return QRect();
1356#endif
1357
1358 const QDockAreaLayoutItem &item = item_list.at(i: index);
1359 if (item.skip())
1360 return QRect();
1361
1362 QPoint pos = rect.topLeft();
1363 rpick(o, pos) = item.pos + item.size;
1364 QSize s = rect.size();
1365 rpick(o, size&: s) = *sep;
1366
1367 return QRect(pos, s);
1368}
1369
1370QRect QDockAreaLayoutInfo::separatorRect(const QList<int> &path) const
1371{
1372 Q_ASSERT(!path.isEmpty());
1373
1374 const int index = path.first();
1375 if (path.count() > 1) {
1376 const QDockAreaLayoutItem &item = item_list.at(i: index);
1377 Q_ASSERT(item.subinfo != nullptr);
1378 return item.subinfo->separatorRect(path: path.mid(pos: 1));
1379 }
1380 return separatorRect(index);
1381}
1382
1383QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const
1384{
1385#if QT_CONFIG(tabbar)
1386 if (tabbed)
1387 return QList<int>();
1388#endif
1389
1390 int pos = pick(o, pos: _pos);
1391
1392 for (int i = 0; i < item_list.size(); ++i) {
1393 const QDockAreaLayoutItem &item = item_list.at(i);
1394 if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
1395 continue;
1396
1397 if (item.pos + item.size > pos) {
1398 if (item.subinfo != nullptr) {
1399 QList<int> result = item.subinfo->findSeparator(_pos);
1400 if (!result.isEmpty()) {
1401 result.prepend(t: i);
1402 return result;
1403 } else {
1404 return QList<int>();
1405 }
1406 }
1407 }
1408
1409 int next = this->next(idx: i);
1410 if (next == -1 || (item_list.at(i: next).flags & QDockAreaLayoutItem::GapItem))
1411 continue;
1412
1413 QRect sepRect = separatorRect(index: i);
1414 if (!sepRect.isNull() && *sep == 1)
1415 sepRect.adjust(dx1: -2, dy1: -2, dx2: 2, dy2: 2);
1416 //we also make sure we don't find a separator that's not there
1417 if (sepRect.contains(p: _pos) && !item.hasFixedSize(o)) {
1418 return QList<int>() << i;
1419 }
1420
1421 }
1422
1423 return QList<int>();
1424}
1425
1426QList<int> QDockAreaLayoutInfo::indexOfPlaceHolder(const QString &objectName) const
1427{
1428 for (int i = 0; i < item_list.size(); ++i) {
1429 const QDockAreaLayoutItem &item = item_list.at(i);
1430
1431 if (item.subinfo != nullptr) {
1432 QList<int> result = item.subinfo->indexOfPlaceHolder(objectName);
1433 if (!result.isEmpty()) {
1434 result.prepend(t: i);
1435 return result;
1436 }
1437 continue;
1438 }
1439
1440 if (item.placeHolderItem != nullptr && item.placeHolderItem->objectName == objectName) {
1441 QList<int> result;
1442 result << i;
1443 return result;
1444 }
1445 }
1446
1447 return QList<int>();
1448}
1449
1450QList<int> QDockAreaLayoutInfo::indexOf(QWidget *widget) const
1451{
1452 for (int i = 0; i < item_list.size(); ++i) {
1453 const QDockAreaLayoutItem &item = item_list.at(i);
1454
1455 if (item.placeHolderItem != nullptr)
1456 continue;
1457
1458 if (item.subinfo != nullptr) {
1459 QList<int> result = item.subinfo->indexOf(widget);
1460 if (!result.isEmpty()) {
1461 result.prepend(t: i);
1462 return result;
1463 }
1464 continue;
1465 }
1466
1467 if (!(item.flags & QDockAreaLayoutItem::GapItem) && item.widgetItem && item.widgetItem->widget() == widget) {
1468 QList<int> result;
1469 result << i;
1470 return result;
1471 }
1472 }
1473
1474 return QList<int>();
1475}
1476
1477QMainWindowLayout *QDockAreaLayoutInfo::mainWindowLayout() const
1478{
1479 QMainWindowLayout *result = qt_mainwindow_layout(window: mainWindow);
1480 Q_ASSERT(result != nullptr);
1481 return result;
1482}
1483
1484bool QDockAreaLayoutInfo::hasFixedSize() const
1485{
1486 return perp(o, size: minimumSize()) == perp(o, size: maximumSize());
1487}
1488
1489/*! \internal
1490 Applies the layout and returns the activated QDockWidget or nullptr.
1491 */
1492QDockWidget *QDockAreaLayoutInfo::apply(bool animate)
1493{
1494 QWidgetAnimator &widgetAnimator = mainWindowLayout()->widgetAnimator;
1495
1496#if QT_CONFIG(tabbar)
1497 if (tabbed) {
1498 QRect tab_rect;
1499 QSize tbh = tabBarSizeHint();
1500
1501 if (!tbh.isNull()) {
1502 switch (tabBarShape) {
1503 case QTabBar::RoundedNorth:
1504 case QTabBar::TriangularNorth:
1505 tab_rect = QRect(rect.left(), rect.top(), rect.width(), tbh.height());
1506 break;
1507 case QTabBar::RoundedSouth:
1508 case QTabBar::TriangularSouth:
1509 tab_rect = QRect(rect.left(), rect.bottom() - tbh.height() + 1,
1510 rect.width(), tbh.height());
1511 break;
1512 case QTabBar::RoundedEast:
1513 case QTabBar::TriangularEast:
1514 tab_rect = QRect(rect.right() - tbh.width() + 1, rect.top(),
1515 tbh.width(), rect.height());
1516 break;
1517 case QTabBar::RoundedWest:
1518 case QTabBar::TriangularWest:
1519 tab_rect = QRect(rect.left(), rect.top(),
1520 tbh.width(), rect.height());
1521 break;
1522 default:
1523 break;
1524 }
1525 }
1526
1527 widgetAnimator.animate(widget: tabBar, final_geometry: tab_rect, animate);
1528 }
1529#endif // QT_CONFIG(tabbar)
1530
1531 QDockWidget *activated = nullptr;
1532
1533 for (int i = 0; i < item_list.size(); ++i) {
1534 QDockAreaLayoutItem &item = item_list[i];
1535
1536 if (item.flags & QDockAreaLayoutItem::GapItem)
1537 continue;
1538
1539 if (item.subinfo != nullptr) {
1540 item.subinfo->apply(animate);
1541 continue;
1542 }
1543
1544 if (item.skip())
1545 continue;
1546
1547 Q_ASSERT(item.widgetItem);
1548 QRect r = itemRect(index: i);
1549 QWidget *w = item.widgetItem->widget();
1550
1551 QRect geo = w->geometry();
1552 widgetAnimator.animate(widget: w, final_geometry: r, animate);
1553 if (!w->isHidden() && w->window()->isVisible()) {
1554 QDockWidget *dw = qobject_cast<QDockWidget*>(object: w);
1555 if (!r.isValid() && geo.right() >= 0 && geo.bottom() >= 0) {
1556 dw->lower();
1557 emit dw->visibilityChanged(visible: false);
1558 } else if (r.isValid()
1559 && (geo.right() < 0 || geo.bottom() < 0)) {
1560 emit dw->visibilityChanged(visible: true);
1561 activated = dw;
1562 }
1563 }
1564 }
1565#if QT_CONFIG(tabbar)
1566 if (*sep == 1)
1567 updateSeparatorWidgets();
1568#endif // QT_CONFIG(tabbar)
1569
1570 return activated;
1571}
1572
1573static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over)
1574{
1575 QStyleOption opt(0);
1576 opt.state = QStyle::State_None;
1577 if (w->isEnabled())
1578 opt.state |= QStyle::State_Enabled;
1579 if (o != Qt::Horizontal)
1580 opt.state |= QStyle::State_Horizontal;
1581 if (mouse_over)
1582 opt.state |= QStyle::State_MouseOver;
1583 opt.rect = r;
1584 opt.palette = w->palette();
1585
1586 w->style()->drawPrimitive(pe: QStyle::PE_IndicatorDockWidgetResizeHandle, opt: &opt, p, w);
1587}
1588
1589QRegion QDockAreaLayoutInfo::separatorRegion() const
1590{
1591 QRegion result;
1592
1593 if (isEmpty())
1594 return result;
1595#if QT_CONFIG(tabbar)
1596 if (tabbed)
1597 return result;
1598#endif
1599
1600 for (int i = 0; i < item_list.count(); ++i) {
1601 const QDockAreaLayoutItem &item = item_list.at(i);
1602
1603 if (item.skip())
1604 continue;
1605
1606 int next = this->next(idx: i);
1607
1608 if (item.subinfo)
1609 result |= item.subinfo->separatorRegion();
1610
1611 if (next == -1)
1612 break;
1613 result |= separatorRect(index: i);
1614 }
1615
1616 return result;
1617}
1618
1619void QDockAreaLayoutInfo::paintSeparators(QPainter *p, QWidget *widget,
1620 const QRegion &clip,
1621 const QPoint &mouse) const
1622{
1623 if (isEmpty())
1624 return;
1625#if QT_CONFIG(tabbar)
1626 if (tabbed)
1627 return;
1628#endif
1629
1630 for (int i = 0; i < item_list.count(); ++i) {
1631 const QDockAreaLayoutItem &item = item_list.at(i);
1632
1633 if (item.skip())
1634 continue;
1635
1636 int next = this->next(idx: i);
1637 if ((item.flags & QDockAreaLayoutItem::GapItem)
1638 || (next != -1 && (item_list.at(i: next).flags & QDockAreaLayoutItem::GapItem)))
1639 continue;
1640
1641 if (item.subinfo) {
1642 if (clip.contains(r: item.subinfo->rect))
1643 item.subinfo->paintSeparators(p, widget, clip, mouse);
1644 }
1645
1646 if (next == -1)
1647 break;
1648 QRect r = separatorRect(index: i);
1649 if (clip.contains(r) && !item.hasFixedSize(o))
1650 paintSep(p, w: widget, r, o, mouse_over: r.contains(p: mouse));
1651 }
1652}
1653
1654int QDockAreaLayoutInfo::next(int index) const
1655{
1656 for (int i = index + 1; i < item_list.size(); ++i) {
1657 if (!item_list.at(i).skip())
1658 return i;
1659 }
1660 return -1;
1661}
1662
1663int QDockAreaLayoutInfo::prev(int index) const
1664{
1665 for (int i = index - 1; i >= 0; --i) {
1666 if (!item_list.at(i).skip())
1667 return i;
1668 }
1669 return -1;
1670}
1671
1672#if QT_CONFIG(tabbar)
1673void QDockAreaLayoutInfo::tab(int index, QLayoutItem *dockWidgetItem)
1674{
1675 if (tabbed) {
1676 item_list.append(t: QDockAreaLayoutItem(dockWidgetItem));
1677 updateTabBar();
1678 setCurrentTab(dockWidgetItem->widget());
1679 } else {
1680 QDockAreaLayoutInfo *new_info
1681 = new QDockAreaLayoutInfo(sep, dockPos, o, tabBarShape, mainWindow);
1682 item_list[index].subinfo = new_info;
1683 new_info->item_list.append(t: QDockAreaLayoutItem(item_list.at(i: index).widgetItem));
1684 item_list[index].widgetItem = nullptr;
1685 new_info->item_list.append(t: QDockAreaLayoutItem(dockWidgetItem));
1686 new_info->tabbed = true;
1687 new_info->updateTabBar();
1688 new_info->setCurrentTab(dockWidgetItem->widget());
1689 }
1690}
1691#endif // QT_CONFIG(tabbar)
1692
1693void QDockAreaLayoutInfo::split(int index, Qt::Orientation orientation,
1694 QLayoutItem *dockWidgetItem)
1695{
1696 if (orientation == o) {
1697 item_list.insert(i: index + 1, t: QDockAreaLayoutItem(dockWidgetItem));
1698 } else {
1699#if !QT_CONFIG(tabbar)
1700 const int tabBarShape = 0;
1701#endif
1702 QDockAreaLayoutInfo *new_info
1703 = new QDockAreaLayoutInfo(sep, dockPos, orientation, tabBarShape, mainWindow);
1704 item_list[index].subinfo = new_info;
1705 new_info->item_list.append(t: QDockAreaLayoutItem(item_list.at(i: index).widgetItem));
1706 item_list[index].widgetItem = nullptr;
1707 new_info->item_list.append(t: QDockAreaLayoutItem(dockWidgetItem));
1708 }
1709}
1710
1711QDockAreaLayoutItem &QDockAreaLayoutInfo::item(const QList<int> &path)
1712{
1713 Q_ASSERT(!path.isEmpty());
1714 const int index = path.first();
1715 if (path.count() > 1) {
1716 const QDockAreaLayoutItem &item = item_list[index];
1717 Q_ASSERT(item.subinfo != nullptr);
1718 return item.subinfo->item(path: path.mid(pos: 1));
1719 }
1720 return item_list[index];
1721}
1722
1723QLayoutItem *QDockAreaLayoutInfo::itemAt(int *x, int index) const
1724{
1725 for (int i = 0; i < item_list.count(); ++i) {
1726 const QDockAreaLayoutItem &item = item_list.at(i);
1727 if (item.placeHolderItem != nullptr)
1728 continue;
1729 if (item.subinfo) {
1730 if (QLayoutItem *ret = item.subinfo->itemAt(x, index))
1731 return ret;
1732 } else if (item.widgetItem) {
1733 if ((*x)++ == index)
1734 return item.widgetItem;
1735 }
1736 }
1737 return nullptr;
1738}
1739
1740QLayoutItem *QDockAreaLayoutInfo::takeAt(int *x, int index)
1741{
1742 for (int i = 0; i < item_list.count(); ++i) {
1743 QDockAreaLayoutItem &item = item_list[i];
1744 if (item.placeHolderItem != nullptr)
1745 continue;
1746 else if (item.subinfo) {
1747 if (QLayoutItem *ret = item.subinfo->takeAt(x, index)) {
1748 unnest(index: i);
1749 return ret;
1750 }
1751 } else if (item.widgetItem) {
1752 if ((*x)++ == index) {
1753 item.placeHolderItem = new QPlaceHolderItem(item.widgetItem->widget());
1754 QLayoutItem *ret = item.widgetItem;
1755 item.widgetItem = nullptr;
1756 if (item.size != -1)
1757 item.flags |= QDockAreaLayoutItem::KeepSize;
1758 return ret;
1759 }
1760 }
1761 }
1762 return nullptr;
1763}
1764
1765void QDockAreaLayoutInfo::deleteAllLayoutItems()
1766{
1767 for (int i = 0; i < item_list.count(); ++i) {
1768 QDockAreaLayoutItem &item= item_list[i];
1769 if (item.subinfo) {
1770 item.subinfo->deleteAllLayoutItems();
1771 } else {
1772 delete item.widgetItem;
1773 item.widgetItem = nullptr;
1774 }
1775 }
1776}
1777
1778void QDockAreaLayoutInfo::saveState(QDataStream &stream) const
1779{
1780#if QT_CONFIG(tabbar)
1781 if (tabbed) {
1782 stream << (uchar) TabMarker;
1783
1784 // write the index in item_list of the widget that's currently on top.
1785 quintptr id = currentTabId();
1786 int index = -1;
1787 for (int i = 0; i < item_list.count(); ++i) {
1788 if (tabId(item: item_list.at(i)) == id) {
1789 index = i;
1790 break;
1791 }
1792 }
1793 stream << index;
1794 } else
1795#endif // QT_CONFIG(tabbar)
1796 {
1797 stream << (uchar) SequenceMarker;
1798 }
1799
1800 stream << (uchar) o << item_list.count();
1801
1802 for (int i = 0; i < item_list.count(); ++i) {
1803 const QDockAreaLayoutItem &item = item_list.at(i);
1804 if (item.widgetItem != nullptr) {
1805 stream << (uchar) WidgetMarker;
1806 QWidget *w = item.widgetItem->widget();
1807 QString name = w->objectName();
1808 if (Q_UNLIKELY(name.isEmpty())) {
1809 qWarning(msg: "QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%ls;",
1810 w, qUtf16Printable(w->windowTitle()));
1811 }
1812 stream << name;
1813
1814 uchar flags = 0;
1815 if (!w->isHidden())
1816 flags |= StateFlagVisible;
1817 if (w->isWindow())
1818 flags |= StateFlagFloating;
1819 stream << flags;
1820
1821 if (w->isWindow()) {
1822 const QRect geometry = w->geometry();
1823 stream << geometry.x() << geometry.y() << geometry.width() << geometry.height();
1824 } else {
1825 stream << item.pos << item.size << pick(o, size: item.minimumSize())
1826 << pick(o, size: item.maximumSize());
1827 }
1828 } else if (item.placeHolderItem != nullptr) {
1829 stream << (uchar) WidgetMarker;
1830 stream << item.placeHolderItem->objectName;
1831 uchar flags = 0;
1832 if (!item.placeHolderItem->hidden)
1833 flags |= StateFlagVisible;
1834 if (item.placeHolderItem->window)
1835 flags |= StateFlagFloating;
1836 stream << flags;
1837 if (item.placeHolderItem->window) {
1838 QRect r = item.placeHolderItem->topLevelRect;
1839 stream << r.x() << r.y() << r.width() << r.height();
1840 } else {
1841 stream << item.pos << item.size << (int)0 << (int)0;
1842 }
1843 } else if (item.subinfo != nullptr) {
1844 stream << (uchar) SequenceMarker << item.pos << item.size << pick(o, size: item.minimumSize()) << pick(o, size: item.maximumSize());
1845 item.subinfo->saveState(stream);
1846 }
1847 }
1848}
1849
1850static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
1851{
1852 switch (pos) {
1853 case QInternal::LeftDock: return Qt::LeftDockWidgetArea;
1854 case QInternal::RightDock: return Qt::RightDockWidgetArea;
1855 case QInternal::TopDock: return Qt::TopDockWidgetArea;
1856 case QInternal::BottomDock: return Qt::BottomDockWidgetArea;
1857 default: break;
1858 }
1859 return Qt::NoDockWidgetArea;
1860}
1861
1862bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*> &widgets, bool testing)
1863{
1864 uchar marker;
1865 stream >> marker;
1866 if (marker != TabMarker && marker != SequenceMarker)
1867 return false;
1868
1869#if QT_CONFIG(tabbar)
1870 tabbed = marker == TabMarker;
1871
1872 int index = -1;
1873 if (tabbed)
1874 stream >> index;
1875#endif
1876
1877 uchar orientation;
1878 stream >> orientation;
1879 o = static_cast<Qt::Orientation>(orientation);
1880
1881 int cnt;
1882 stream >> cnt;
1883
1884 for (int i = 0; i < cnt; ++i) {
1885 uchar nextMarker;
1886 stream >> nextMarker;
1887 if (nextMarker == WidgetMarker) {
1888 QString name;
1889 uchar flags;
1890 stream >> name >> flags;
1891 if (name.isEmpty()) {
1892 int dummy;
1893 stream >> dummy >> dummy >> dummy >> dummy;
1894 continue;
1895 }
1896
1897 QDockWidget *widget = nullptr;
1898 for (int j = 0; j < widgets.count(); ++j) {
1899 if (widgets.at(i: j)->objectName() == name) {
1900 widget = widgets.takeAt(i: j);
1901 break;
1902 }
1903 }
1904
1905 if (widget == nullptr) {
1906 QPlaceHolderItem *placeHolder = new QPlaceHolderItem;
1907 QDockAreaLayoutItem item(placeHolder);
1908
1909 placeHolder->objectName = name;
1910 placeHolder->window = flags & StateFlagFloating;
1911 placeHolder->hidden = !(flags & StateFlagVisible);
1912 if (placeHolder->window) {
1913 int x, y, w, h;
1914 stream >> x >> y >> w >> h;
1915 placeHolder->topLevelRect = QRect(x, y, w, h);
1916 } else {
1917 int dummy;
1918 stream >> item.pos >> item.size >> dummy >> dummy;
1919 }
1920 if (item.size != -1)
1921 item.flags |= QDockAreaLayoutItem::KeepSize;
1922 if (!testing)
1923 item_list.append(t: item);
1924 } else {
1925 QDockAreaLayoutItem item(new QDockWidgetItem(widget));
1926 if (flags & StateFlagFloating) {
1927 bool drawer = false;
1928
1929 if (!testing) {
1930 widget->hide();
1931 if (!drawer)
1932 widget->setFloating(true);
1933 }
1934
1935 int x, y, w, h;
1936 stream >> x >> y >> w >> h;
1937
1938 if (!testing)
1939 widget->setGeometry(QDockAreaLayout::constrainedRect(rect: QRect(x, y, w, h), widget));
1940
1941 if (!testing) {
1942 widget->setVisible(flags & StateFlagVisible);
1943 item_list.append(t: item);
1944 }
1945 } else {
1946 int dummy;
1947 stream >> item.pos >> item.size >> dummy >> dummy;
1948 if (!testing) {
1949 item_list.append(t: item);
1950 widget->setFloating(false);
1951 widget->setVisible(flags & StateFlagVisible);
1952 emit widget->dockLocationChanged(area: toDockWidgetArea(pos: dockPos));
1953 }
1954 }
1955 if (testing) {
1956 //was it is not really added to the layout, we need to delete the object here
1957 delete item.widgetItem;
1958 }
1959 }
1960 } else if (nextMarker == SequenceMarker) {
1961 int dummy;
1962#if !QT_CONFIG(tabbar)
1963 const int tabBarShape = 0;
1964#endif
1965 QDockAreaLayoutItem item(new QDockAreaLayoutInfo(sep, dockPos, o,
1966 tabBarShape, mainWindow));
1967 stream >> item.pos >> item.size >> dummy >> dummy;
1968 //we need to make sure the element is in the list so the dock widget can eventually be docked correctly
1969 if (!testing)
1970 item_list.append(t: item);
1971
1972 //here we need to make sure we change the item in the item_list
1973 QDockAreaLayoutItem &lastItem = testing ? item : item_list.last();
1974
1975 if (!lastItem.subinfo->restoreState(stream, widgets, testing))
1976 return false;
1977
1978 } else {
1979 return false;
1980 }
1981 }
1982
1983#if QT_CONFIG(tabbar)
1984 if (!testing && tabbed && index >= 0 && index < item_list.count()) {
1985 updateTabBar();
1986 setCurrentTabId(tabId(item: item_list.at(i: index)));
1987 }
1988 if (!testing && *sep == 1)
1989 updateSeparatorWidgets();
1990#endif
1991
1992 return true;
1993}
1994
1995#if QT_CONFIG(tabbar)
1996void QDockAreaLayoutInfo::updateSeparatorWidgets() const
1997{
1998 if (tabbed) {
1999 separatorWidgets.clear();
2000 return;
2001 }
2002
2003 int j = 0;
2004 for (int i = 0; i < item_list.count(); ++i) {
2005 const QDockAreaLayoutItem &item = item_list.at(i);
2006
2007 if (item.skip())
2008 continue;
2009
2010 int next = this->next(index: i);
2011 if ((item.flags & QDockAreaLayoutItem::GapItem)
2012 || (next != -1 && (item_list.at(i: next).flags & QDockAreaLayoutItem::GapItem)))
2013 continue;
2014
2015 if (item.subinfo) {
2016 item.subinfo->updateSeparatorWidgets();
2017 }
2018
2019 if (next == -1)
2020 break;
2021
2022 QWidget *sepWidget;
2023 if (j < separatorWidgets.size() && separatorWidgets.at(i: j)) {
2024 sepWidget = separatorWidgets.at(i: j);
2025 } else {
2026 sepWidget = mainWindowLayout()->getSeparatorWidget();
2027 separatorWidgets.append(t: sepWidget);
2028 }
2029 j++;
2030
2031 sepWidget->raise();
2032
2033 QRect sepRect = separatorRect(index: i).adjusted(xp1: -2, yp1: -2, xp2: 2, yp2: 2);
2034 sepWidget->setGeometry(sepRect);
2035 sepWidget->setMask( QRegion(separatorRect(index: i).translated( p: - sepRect.topLeft())));
2036 sepWidget->show();
2037 }
2038
2039 for (int k = j; k < separatorWidgets.size(); ++k) {
2040 separatorWidgets[k]->hide();
2041 }
2042 separatorWidgets.resize(asize: j);
2043 Q_ASSERT(separatorWidgets.size() == j);
2044}
2045
2046/*! \internal
2047 reparent all the widgets contained in this layout portion to the
2048 specified parent. This is used to reparent dock widgets and tabbars
2049 to the floating window or the main window
2050 */
2051void QDockAreaLayoutInfo::reparentWidgets(QWidget *parent)
2052{
2053 if (tabBar)
2054 tabBar->setParent(parent);
2055
2056 for (int i = 0; i < item_list.count(); ++i) {
2057 const QDockAreaLayoutItem &item = item_list.at(i);
2058 if (item.flags & QDockAreaLayoutItem::GapItem)
2059 continue;
2060 if (item.subinfo)
2061 item.subinfo->reparentWidgets(parent);
2062 if (item.widgetItem) {
2063 QWidget *w = item.widgetItem->widget();
2064 if (qobject_cast<QDockWidgetGroupWindow *>(object: w))
2065 continue;
2066 if (w->parent() != parent) {
2067 bool hidden = w->isHidden();
2068 w->setParent(parent, f: w->windowFlags());
2069 if (!hidden)
2070 w->show();
2071 }
2072 }
2073 }
2074}
2075
2076//returns whether the tabbar is visible or not
2077bool QDockAreaLayoutInfo::updateTabBar() const
2078{
2079 if (!tabbed)
2080 return false;
2081
2082 QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this);
2083
2084 if (that->tabBar == nullptr) {
2085 that->tabBar = mainWindowLayout()->getTabBar();
2086 that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape));
2087 that->tabBar->setDrawBase(true);
2088 }
2089
2090 const QSignalBlocker blocker(tabBar);
2091 bool gap = false;
2092
2093 const quintptr oldCurrentId = currentTabId();
2094
2095 int tab_idx = 0;
2096 for (int i = 0; i < item_list.count(); ++i) {
2097 const QDockAreaLayoutItem &item = item_list.at(i);
2098 if (item.skip())
2099 continue;
2100 if (item.flags & QDockAreaLayoutItem::GapItem) {
2101 gap = true;
2102 continue;
2103 }
2104 if (item.widgetItem == nullptr)
2105 continue;
2106
2107 QDockWidget *dw = qobject_cast<QDockWidget*>(object: item.widgetItem->widget());
2108 QString title = dw->d_func()->fixedWindowTitle;
2109 quintptr id = tabId(item);
2110 if (tab_idx == tabBar->count()) {
2111 tabBar->insertTab(index: tab_idx, text: title);
2112#ifndef QT_NO_TOOLTIP
2113 tabBar->setTabToolTip(index: tab_idx, tip: title);
2114#endif
2115 tabBar->setTabData(index: tab_idx, data: id);
2116 } else if (qvariant_cast<quintptr>(v: tabBar->tabData(index: tab_idx)) != id) {
2117 if (tab_idx + 1 < tabBar->count()
2118 && qvariant_cast<quintptr>(v: tabBar->tabData(index: tab_idx + 1)) == id)
2119 tabBar->removeTab(index: tab_idx);
2120 else {
2121 tabBar->insertTab(index: tab_idx, text: title);
2122#ifndef QT_NO_TOOLTIP
2123 tabBar->setTabToolTip(index: tab_idx, tip: title);
2124#endif
2125 tabBar->setTabData(index: tab_idx, data: id);
2126 }
2127 }
2128
2129 if (title != tabBar->tabText(index: tab_idx)) {
2130 tabBar->setTabText(index: tab_idx, text: title);
2131#ifndef QT_NO_TOOLTIP
2132 tabBar->setTabToolTip(index: tab_idx, tip: title);
2133#endif
2134 }
2135
2136 ++tab_idx;
2137 }
2138
2139 while (tab_idx < tabBar->count()) {
2140 tabBar->removeTab(index: tab_idx);
2141 }
2142
2143 if (oldCurrentId > 0 && currentTabId() != oldCurrentId)
2144 that->setCurrentTabId(oldCurrentId);
2145
2146 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(object: tabBar->parent()))
2147 dwgw->adjustFlags();
2148
2149 //returns if the tabbar is visible or not
2150 return ( (gap ? 1 : 0) + tabBar->count()) > 1;
2151}
2152
2153void QDockAreaLayoutInfo::setTabBarShape(int shape)
2154{
2155 if (shape == tabBarShape)
2156 return;
2157 tabBarShape = shape;
2158 if (tabBar != nullptr)
2159 tabBar->setShape(static_cast<QTabBar::Shape>(shape));
2160
2161 for (int i = 0; i < item_list.count(); ++i) {
2162 QDockAreaLayoutItem &item = item_list[i];
2163 if (item.subinfo != nullptr)
2164 item.subinfo->setTabBarShape(shape);
2165 }
2166}
2167
2168QSize QDockAreaLayoutInfo::tabBarMinimumSize() const
2169{
2170 if (!updateTabBar())
2171 return QSize(0, 0);
2172
2173 return tabBar->minimumSizeHint();
2174}
2175
2176QSize QDockAreaLayoutInfo::tabBarSizeHint() const
2177{
2178 if (!updateTabBar())
2179 return QSize(0, 0);
2180
2181 return tabBar->sizeHint();
2182}
2183
2184QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const
2185{
2186 QSet<QTabBar*> result;
2187
2188 if (tabbed) {
2189 updateTabBar();
2190 result.insert(value: tabBar);
2191 }
2192
2193 for (int i = 0; i < item_list.count(); ++i) {
2194 const QDockAreaLayoutItem &item = item_list.at(i);
2195 if (item.subinfo != nullptr)
2196 result += item.subinfo->usedTabBars();
2197 }
2198
2199 return result;
2200}
2201
2202// returns a set of all used separator widgets for this dockarelayout info
2203// and all subinfos
2204QSet<QWidget*> QDockAreaLayoutInfo::usedSeparatorWidgets() const
2205{
2206 QSet<QWidget*> result;
2207 const int numSeparatorWidgets = separatorWidgets.count();
2208 result.reserve(asize: numSeparatorWidgets);
2209
2210 for (int i = 0; i < numSeparatorWidgets; ++i)
2211 result << separatorWidgets.at(i);
2212
2213 for (int i = 0; i < item_list.count(); ++i) {
2214 const QDockAreaLayoutItem &item = item_list.at(i);
2215 if (item.subinfo != nullptr)
2216 result += item.subinfo->usedSeparatorWidgets();
2217 }
2218
2219 return result;
2220}
2221
2222QRect QDockAreaLayoutInfo::tabContentRect() const
2223{
2224 if (!tabbed)
2225 return QRect();
2226
2227 QRect result = rect;
2228 QSize tbh = tabBarSizeHint();
2229
2230 if (!tbh.isNull()) {
2231 switch (tabBarShape) {
2232 case QTabBar::RoundedNorth:
2233 case QTabBar::TriangularNorth:
2234 result.adjust(dx1: 0, dy1: tbh.height(), dx2: 0, dy2: 0);
2235 break;
2236 case QTabBar::RoundedSouth:
2237 case QTabBar::TriangularSouth:
2238 result.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -tbh.height());
2239 break;
2240 case QTabBar::RoundedEast:
2241 case QTabBar::TriangularEast:
2242 result.adjust(dx1: 0, dy1: 0, dx2: -tbh.width(), dy2: 0);
2243 break;
2244 case QTabBar::RoundedWest:
2245 case QTabBar::TriangularWest:
2246 result.adjust(dx1: tbh.width(), dy1: 0, dx2: 0, dy2: 0);
2247 break;
2248 default:
2249 break;
2250 }
2251 }
2252
2253 return result;
2254}
2255
2256int QDockAreaLayoutInfo::tabIndexToListIndex(int tabIndex) const
2257{
2258 Q_ASSERT(tabbed && tabBar);
2259 quintptr data = qvariant_cast<quintptr>(v: tabBar->tabData(index: tabIndex));
2260 for (int i = 0; i < item_list.count(); ++i) {
2261 if (tabId(item: item_list.at(i)) == data)
2262 return i;
2263 }
2264 return -1;
2265}
2266
2267void QDockAreaLayoutInfo::moveTab(int from, int to)
2268{
2269 item_list.move(from: tabIndexToListIndex(tabIndex: from), to: tabIndexToListIndex(tabIndex: to));
2270}
2271#endif // QT_CONFIG(tabbar)
2272
2273/******************************************************************************
2274** QDockAreaLayout
2275*/
2276
2277QDockAreaLayout::QDockAreaLayout(QMainWindow *win) : fallbackToSizeHints(true)
2278{
2279 mainWindow = win;
2280 sep = win->style()->pixelMetric(metric: QStyle::PM_DockWidgetSeparatorExtent, option: nullptr, widget: win);
2281#if QT_CONFIG(tabbar)
2282 const int tabShape = QTabBar::RoundedSouth;
2283#else
2284 const int tabShape = 0;
2285#endif
2286 docks[QInternal::LeftDock]
2287 = QDockAreaLayoutInfo(&sep, QInternal::LeftDock, Qt::Vertical, tabShape, win);
2288 docks[QInternal::RightDock]
2289 = QDockAreaLayoutInfo(&sep, QInternal::RightDock, Qt::Vertical, tabShape, win);
2290 docks[QInternal::TopDock]
2291 = QDockAreaLayoutInfo(&sep, QInternal::TopDock, Qt::Horizontal, tabShape, win);
2292 docks[QInternal::BottomDock]
2293 = QDockAreaLayoutInfo(&sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win);
2294 centralWidgetItem = nullptr;
2295
2296
2297 corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea;
2298 corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea;
2299 corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea;
2300 corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
2301}
2302
2303bool QDockAreaLayout::isValid() const
2304{
2305 return rect.isValid();
2306}
2307
2308void QDockAreaLayout::saveState(QDataStream &stream) const
2309{
2310 stream << (uchar) DockWidgetStateMarker;
2311 int cnt = 0;
2312 for (int i = 0; i < QInternal::DockCount; ++i) {
2313 if (!docks[i].item_list.isEmpty())
2314 ++cnt;
2315 }
2316 stream << cnt;
2317 for (int i = 0; i < QInternal::DockCount; ++i) {
2318 if (docks[i].item_list.isEmpty())
2319 continue;
2320 stream << i << docks[i].rect.size();
2321 docks[i].saveState(stream);
2322 }
2323
2324 stream << centralWidgetRect.size();
2325
2326 for (int i = 0; i < 4; ++i)
2327 stream << static_cast<int>(corners[i]);
2328}
2329
2330bool QDockAreaLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &_dockwidgets, bool testing)
2331{
2332 QList<QDockWidget*> dockwidgets = _dockwidgets;
2333
2334 int cnt;
2335 stream >> cnt;
2336 for (int i = 0; i < cnt; ++i) {
2337 int pos;
2338 stream >> pos;
2339 QSize size;
2340 stream >> size;
2341 if (!testing) {
2342 docks[pos].rect = QRect(QPoint(0, 0), size);
2343 }
2344 if (!docks[pos].restoreState(stream, widgets&: dockwidgets, testing)) {
2345 stream.setStatus(QDataStream::ReadCorruptData);
2346 return false;
2347 }
2348 }
2349
2350 QSize size;
2351 stream >> size;
2352 centralWidgetRect = QRect(QPoint(0, 0), size);
2353
2354 bool ok = stream.status() == QDataStream::Ok;
2355
2356 if (ok) {
2357 int cornerData[4];
2358 for (int i = 0; i < 4; ++i)
2359 stream >> cornerData[i];
2360 if (stream.status() == QDataStream::Ok) {
2361 for (int i = 0; i < 4; ++i)
2362 corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]);
2363 }
2364
2365 if (!testing)
2366 fallbackToSizeHints = false;
2367 }
2368
2369 return ok;
2370}
2371
2372QList<int> QDockAreaLayout::indexOfPlaceHolder(const QString &objectName) const
2373{
2374 for (int i = 0; i < QInternal::DockCount; ++i) {
2375 QList<int> result = docks[i].indexOfPlaceHolder(objectName);
2376 if (!result.isEmpty()) {
2377 result.prepend(t: i);
2378 return result;
2379 }
2380 }
2381 return QList<int>();
2382}
2383
2384QList<int> QDockAreaLayout::indexOf(QWidget *dockWidget) const
2385{
2386 for (int i = 0; i < QInternal::DockCount; ++i) {
2387 QList<int> result = docks[i].indexOf(widget: dockWidget);
2388 if (!result.isEmpty()) {
2389 result.prepend(t: i);
2390 return result;
2391 }
2392 }
2393 return QList<int>();
2394}
2395
2396QList<int> QDockAreaLayout::gapIndex(const QPoint &pos, bool disallowTabs) const
2397{
2398 QMainWindow::DockOptions opts = mainWindow->dockOptions();
2399 bool nestingEnabled = opts & QMainWindow::AllowNestedDocks;
2400 QDockAreaLayoutInfo::TabMode tabMode = QDockAreaLayoutInfo::NoTabs;
2401#if QT_CONFIG(tabbar)
2402 if (!disallowTabs) {
2403 if (opts & QMainWindow::AllowTabbedDocks || opts & QMainWindow::VerticalTabs)
2404 tabMode = QDockAreaLayoutInfo::AllowTabs;
2405 if (opts & QMainWindow::ForceTabbedDocks)
2406 tabMode = QDockAreaLayoutInfo::ForceTabs;
2407
2408 if (tabMode == QDockAreaLayoutInfo::ForceTabs)
2409 nestingEnabled = false;
2410 }
2411#endif
2412
2413
2414 for (int i = 0; i < QInternal::DockCount; ++i) {
2415 const QDockAreaLayoutInfo &info = docks[i];
2416
2417 if (!info.isEmpty() && info.rect.contains(p: pos)) {
2418 QList<int> result
2419 = docks[i].gapIndex(pos: pos, nestingEnabled, tabMode);
2420 if (!result.isEmpty())
2421 result.prepend(t: i);
2422 return result;
2423 }
2424 }
2425
2426 for (int i = 0; i < QInternal::DockCount; ++i) {
2427 const QDockAreaLayoutInfo &info = docks[i];
2428
2429 if (info.isEmpty()) {
2430 QRect r;
2431 switch (i) {
2432 case QInternal::LeftDock:
2433 r = QRect(rect.left(), rect.top(), EmptyDropAreaSize, rect.height());
2434 break;
2435 case QInternal::RightDock:
2436 r = QRect(rect.right() - EmptyDropAreaSize, rect.top(),
2437 EmptyDropAreaSize, rect.height());
2438 break;
2439 case QInternal::TopDock:
2440 r = QRect(rect.left(), rect.top(), rect.width(), EmptyDropAreaSize);
2441 break;
2442 case QInternal::BottomDock:
2443 r = QRect(rect.left(), rect.bottom() - EmptyDropAreaSize,
2444 rect.width(), EmptyDropAreaSize);
2445 break;
2446 }
2447 if (r.contains(p: pos)) {
2448 if (opts & QMainWindow::ForceTabbedDocks && !info.item_list.isEmpty()) {
2449 //in case of ForceTabbedDocks, we pass -1 in order to force the gap to be tabbed
2450 //it mustn't be completely empty otherwise it won't work
2451 return QList<int>() << i << -1 << 0;
2452 } else {
2453 return QList<int>() << i << 0;
2454 }
2455 }
2456 }
2457 }
2458
2459 return QList<int>();
2460}
2461
2462QList<int> QDockAreaLayout::findSeparator(const QPoint &pos) const
2463{
2464 QList<int> result;
2465 for (int i = 0; i < QInternal::DockCount; ++i) {
2466 const QDockAreaLayoutInfo &info = docks[i];
2467 if (info.isEmpty())
2468 continue;
2469 QRect rect = separatorRect(index: i);
2470 if (!rect.isNull() && sep == 1)
2471 rect.adjust(dx1: -2, dy1: -2, dx2: 2, dy2: 2);
2472 if (rect.contains(p: pos) && !info.hasFixedSize()) {
2473 result << i;
2474 break;
2475 } else if (info.rect.contains(p: pos)) {
2476 result = docks[i].findSeparator(pos: pos);
2477 if (!result.isEmpty()) {
2478 result.prepend(t: i);
2479 break;
2480 }
2481 }
2482 }
2483
2484 return result;
2485}
2486
2487QDockAreaLayoutInfo *QDockAreaLayout::info(QWidget *widget)
2488{
2489 for (int i = 0; i < QInternal::DockCount; ++i) {
2490 if (QDockAreaLayoutInfo *result = docks[i].info(widget))
2491 return result;
2492 }
2493
2494 return nullptr;
2495}
2496
2497QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path)
2498{
2499 Q_ASSERT(!path.isEmpty());
2500 const int index = path.first();
2501 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2502
2503 if (path.count() == 1)
2504 return &docks[index];
2505
2506 return docks[index].info(path: path.mid(pos: 1));
2507}
2508
2509const QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) const
2510{
2511 return const_cast<QDockAreaLayout*>(this)->info(path);
2512}
2513
2514QDockAreaLayoutItem &QDockAreaLayout::item(const QList<int> &path)
2515{
2516 Q_ASSERT(!path.isEmpty());
2517 const int index = path.first();
2518 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2519 return docks[index].item(path: path.mid(pos: 1));
2520}
2521
2522QRect QDockAreaLayout::itemRect(const QList<int> &path) const
2523{
2524 Q_ASSERT(!path.isEmpty());
2525 const int index = path.first();
2526 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2527 return docks[index].itemRect(path: path.mid(pos: 1));
2528}
2529
2530QRect QDockAreaLayout::separatorRect(int index) const
2531{
2532 const QDockAreaLayoutInfo &dock = docks[index];
2533 if (dock.isEmpty())
2534 return QRect();
2535 QRect r = dock.rect;
2536 switch (index) {
2537 case QInternal::LeftDock:
2538 return QRect(r.right() + 1, r.top(), sep, r.height());
2539 case QInternal::RightDock:
2540 return QRect(r.left() - sep, r.top(), sep, r.height());
2541 case QInternal::TopDock:
2542 return QRect(r.left(), r.bottom() + 1, r.width(), sep);
2543 case QInternal::BottomDock:
2544 return QRect(r.left(), r.top() - sep, r.width(), sep);
2545 default:
2546 break;
2547 }
2548 return QRect();
2549}
2550
2551QRect QDockAreaLayout::separatorRect(const QList<int> &path) const
2552{
2553 Q_ASSERT(!path.isEmpty());
2554
2555 const int index = path.first();
2556 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2557
2558 if (path.count() == 1)
2559 return separatorRect(index);
2560 else
2561 return docks[index].separatorRect(path: path.mid(pos: 1));
2562}
2563
2564bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
2565{
2566 Q_ASSERT(!path.isEmpty());
2567 const int index = path.first();
2568 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2569 return docks[index].insertGap(path: path.mid(pos: 1), dockWidgetItem);
2570}
2571
2572QLayoutItem *QDockAreaLayout::plug(const QList<int> &path)
2573{
2574#if QT_CONFIG(tabbar)
2575 Q_ASSERT(!path.isEmpty());
2576 const int index = path.first();
2577 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2578 QLayoutItem *item = docks[index].plug(path: path.mid(pos: 1));
2579 docks[index].reparentWidgets(parent: mainWindow);
2580 return item;
2581#else
2582 return nullptr;
2583#endif
2584}
2585
2586QLayoutItem *QDockAreaLayout::unplug(const QList<int> &path)
2587{
2588 Q_ASSERT(!path.isEmpty());
2589 const int index = path.first();
2590 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2591 return docks[index].unplug(path: path.mid(pos: 1));
2592}
2593
2594void QDockAreaLayout::remove(const QList<int> &path)
2595{
2596 Q_ASSERT(!path.isEmpty());
2597 const int index = path.first();
2598 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2599 docks[index].remove(path: path.mid(pos: 1));
2600}
2601
2602void QDockAreaLayout::removePlaceHolder(const QString &name)
2603{
2604 QList<int> index = indexOfPlaceHolder(objectName: name);
2605 if (!index.isEmpty())
2606 remove(path: index);
2607 const auto groups =
2608 mainWindow->findChildren<QDockWidgetGroupWindow *>(aName: QString(), options: Qt::FindDirectChildrenOnly);
2609 for (QDockWidgetGroupWindow *dwgw : groups) {
2610 index = dwgw->layoutInfo()->indexOfPlaceHolder(objectName: name);
2611 if (!index.isEmpty()) {
2612 dwgw->layoutInfo()->remove(path: index);
2613 dwgw->destroyOrHideIfEmpty();
2614 }
2615 }
2616}
2617
2618static inline int qMax(int i1, int i2, int i3) { return qMax(a: i1, b: qMax(a: i2, b: i3)); }
2619
2620void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list,
2621 QVector<QLayoutStruct> *_hor_struct_list)
2622{
2623 QSize center_hint(0, 0);
2624 QSize center_min(0, 0);
2625 QSize center_max(0, 0);
2626 const bool have_central = centralWidgetItem != nullptr && !centralWidgetItem->isEmpty();
2627 if (have_central) {
2628 center_hint = centralWidgetRect.size();
2629 if (!center_hint.isValid())
2630 center_hint = centralWidgetItem->sizeHint();
2631 center_min = centralWidgetItem->minimumSize();
2632 center_max = centralWidgetItem->maximumSize();
2633 }
2634
2635 QRect center_rect = rect;
2636 if (!docks[QInternal::LeftDock].isEmpty())
2637 center_rect.setLeft(rect.left() + docks[QInternal::LeftDock].rect.width() + sep);
2638 if (!docks[QInternal::TopDock].isEmpty())
2639 center_rect.setTop(rect.top() + docks[QInternal::TopDock].rect.height() + sep);
2640 if (!docks[QInternal::RightDock].isEmpty())
2641 center_rect.setRight(rect.right() - docks[QInternal::RightDock].rect.width() - sep);
2642 if (!docks[QInternal::BottomDock].isEmpty())
2643 center_rect.setBottom(rect.bottom() - docks[QInternal::BottomDock].rect.height() - sep);
2644
2645 QSize left_hint = docks[QInternal::LeftDock].size();
2646 if (left_hint.isNull() || fallbackToSizeHints)
2647 left_hint = docks[QInternal::LeftDock].sizeHint();
2648 QSize left_min = docks[QInternal::LeftDock].minimumSize();
2649 QSize left_max = docks[QInternal::LeftDock].maximumSize();
2650 left_hint = left_hint.boundedTo(otherSize: left_max).expandedTo(otherSize: left_min);
2651
2652 QSize right_hint = docks[QInternal::RightDock].size();
2653 if (right_hint.isNull() || fallbackToSizeHints)
2654 right_hint = docks[QInternal::RightDock].sizeHint();
2655 QSize right_min = docks[QInternal::RightDock].minimumSize();
2656 QSize right_max = docks[QInternal::RightDock].maximumSize();
2657 right_hint = right_hint.boundedTo(otherSize: right_max).expandedTo(otherSize: right_min);
2658
2659 QSize top_hint = docks[QInternal::TopDock].size();
2660 if (top_hint.isNull() || fallbackToSizeHints)
2661 top_hint = docks[QInternal::TopDock].sizeHint();
2662 QSize top_min = docks[QInternal::TopDock].minimumSize();
2663 QSize top_max = docks[QInternal::TopDock].maximumSize();
2664 top_hint = top_hint.boundedTo(otherSize: top_max).expandedTo(otherSize: top_min);
2665
2666 QSize bottom_hint = docks[QInternal::BottomDock].size();
2667 if (bottom_hint.isNull() || fallbackToSizeHints)
2668 bottom_hint = docks[QInternal::BottomDock].sizeHint();
2669 QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
2670 QSize bottom_max = docks[QInternal::BottomDock].maximumSize();
2671 bottom_hint = bottom_hint.boundedTo(otherSize: bottom_max).expandedTo(otherSize: bottom_min);
2672
2673 if (_ver_struct_list != nullptr) {
2674 QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list;
2675 ver_struct_list.resize(asize: 3);
2676
2677 // top --------------------------------------------------
2678 ver_struct_list[0].init();
2679 ver_struct_list[0].stretch = 0;
2680 ver_struct_list[0].sizeHint = top_hint.height();
2681 ver_struct_list[0].minimumSize = top_min.height();
2682 ver_struct_list[0].maximumSize = top_max.height();
2683 ver_struct_list[0].expansive = false;
2684 ver_struct_list[0].empty = docks[QInternal::TopDock].isEmpty();
2685 ver_struct_list[0].pos = docks[QInternal::TopDock].rect.top();
2686 ver_struct_list[0].size = docks[QInternal::TopDock].rect.height();
2687
2688 // center --------------------------------------------------
2689 ver_struct_list[1].init();
2690 ver_struct_list[1].stretch = center_hint.height();
2691
2692 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
2693 || docks[QInternal::TopDock].isEmpty();
2694 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
2695 || docks[QInternal::BottomDock].isEmpty();
2696 bool tr_significant = corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
2697 || docks[QInternal::TopDock].isEmpty();
2698 bool br_significant = corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
2699 || docks[QInternal::BottomDock].isEmpty();
2700
2701 int left = (tl_significant && bl_significant) ? left_hint.height() : 0;
2702 int right = (tr_significant && br_significant) ? right_hint.height() : 0;
2703 ver_struct_list[1].sizeHint = qMax(i1: left, i2: center_hint.height(), i3: right);
2704
2705 left = (tl_significant && bl_significant) ? left_min.height() : 0;
2706 right = (tr_significant && br_significant) ? right_min.height() : 0;
2707 ver_struct_list[1].minimumSize = qMax(i1: left, i2: center_min.height(), i3: right);
2708 ver_struct_list[1].maximumSize = center_max.height();
2709 ver_struct_list[1].expansive = have_central;
2710 ver_struct_list[1].empty = docks[QInternal::LeftDock].isEmpty()
2711 && !have_central
2712 && docks[QInternal::RightDock].isEmpty();
2713 ver_struct_list[1].pos = center_rect.top();
2714 ver_struct_list[1].size = center_rect.height();
2715
2716 // bottom --------------------------------------------------
2717 ver_struct_list[2].init();
2718 ver_struct_list[2].stretch = 0;
2719 ver_struct_list[2].sizeHint = bottom_hint.height();
2720 ver_struct_list[2].minimumSize = bottom_min.height();
2721 ver_struct_list[2].maximumSize = bottom_max.height();
2722 ver_struct_list[2].expansive = false;
2723 ver_struct_list[2].empty = docks[QInternal::BottomDock].isEmpty();
2724 ver_struct_list[2].pos = docks[QInternal::BottomDock].rect.top();
2725 ver_struct_list[2].size = docks[QInternal::BottomDock].rect.height();
2726
2727 for (int i = 0; i < 3; ++i) {
2728 ver_struct_list[i].sizeHint
2729 = qMax(a: ver_struct_list[i].sizeHint, b: ver_struct_list[i].minimumSize);
2730 }
2731 if (have_central && ver_struct_list[0].empty && ver_struct_list[2].empty)
2732 ver_struct_list[1].maximumSize = QWIDGETSIZE_MAX;
2733 }
2734
2735 if (_hor_struct_list != nullptr) {
2736 QVector<QLayoutStruct> &hor_struct_list = *_hor_struct_list;
2737 hor_struct_list.resize(asize: 3);
2738
2739 // left --------------------------------------------------
2740 hor_struct_list[0].init();
2741 hor_struct_list[0].stretch = 0;
2742 hor_struct_list[0].sizeHint = left_hint.width();
2743 hor_struct_list[0].minimumSize = left_min.width();
2744 hor_struct_list[0].maximumSize = left_max.width();
2745 hor_struct_list[0].expansive = false;
2746 hor_struct_list[0].empty = docks[QInternal::LeftDock].isEmpty();
2747 hor_struct_list[0].pos = docks[QInternal::LeftDock].rect.left();
2748 hor_struct_list[0].size = docks[QInternal::LeftDock].rect.width();
2749
2750 // center --------------------------------------------------
2751 hor_struct_list[1].init();
2752 hor_struct_list[1].stretch = center_hint.width();
2753
2754 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
2755 || docks[QInternal::LeftDock].isEmpty();
2756 bool tr_significant = corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
2757 || docks[QInternal::RightDock].isEmpty();
2758 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
2759 || docks[QInternal::LeftDock].isEmpty();
2760 bool br_significant = corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
2761 || docks[QInternal::RightDock].isEmpty();
2762
2763 int top = (tl_significant && tr_significant) ? top_hint.width() : 0;
2764 int bottom = (bl_significant && br_significant) ? bottom_hint.width() : 0;
2765 hor_struct_list[1].sizeHint = qMax(i1: top, i2: center_hint.width(), i3: bottom);
2766
2767 top = (tl_significant && tr_significant) ? top_min.width() : 0;
2768 bottom = (bl_significant && br_significant) ? bottom_min.width() : 0;
2769 hor_struct_list[1].minimumSize = qMax(i1: top, i2: center_min.width(), i3: bottom);
2770
2771 hor_struct_list[1].maximumSize = center_max.width();
2772 hor_struct_list[1].expansive = have_central;
2773 hor_struct_list[1].empty = !have_central;
2774 hor_struct_list[1].pos = center_rect.left();
2775 hor_struct_list[1].size = center_rect.width();
2776
2777 // right --------------------------------------------------
2778 hor_struct_list[2].init();
2779 hor_struct_list[2].stretch = 0;
2780 hor_struct_list[2].sizeHint = right_hint.width();
2781 hor_struct_list[2].minimumSize = right_min.width();
2782 hor_struct_list[2].maximumSize = right_max.width();
2783 hor_struct_list[2].expansive = false;
2784 hor_struct_list[2].empty = docks[QInternal::RightDock].isEmpty();
2785 hor_struct_list[2].pos = docks[QInternal::RightDock].rect.left();
2786 hor_struct_list[2].size = docks[QInternal::RightDock].rect.width();
2787
2788 for (int i = 0; i < 3; ++i) {
2789 hor_struct_list[i].sizeHint
2790 = qMax(a: hor_struct_list[i].sizeHint, b: hor_struct_list[i].minimumSize);
2791 }
2792 if (have_central && hor_struct_list[0].empty && hor_struct_list[2].empty)
2793 hor_struct_list[1].maximumSize = QWIDGETSIZE_MAX;
2794
2795 }
2796}
2797
2798void QDockAreaLayout::setGrid(QVector<QLayoutStruct> *ver_struct_list,
2799 QVector<QLayoutStruct> *hor_struct_list)
2800{
2801
2802 // top ---------------------------------------------------
2803
2804 if (!docks[QInternal::TopDock].isEmpty()) {
2805 QRect r = docks[QInternal::TopDock].rect;
2806 if (hor_struct_list != nullptr) {
2807 r.setLeft(corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
2808 || docks[QInternal::LeftDock].isEmpty()
2809 ? rect.left() : hor_struct_list->at(i: 1).pos);
2810 r.setRight(corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
2811 || docks[QInternal::RightDock].isEmpty()
2812 ? rect.right() : hor_struct_list->at(i: 2).pos - sep - 1);
2813 }
2814 if (ver_struct_list != nullptr) {
2815 r.setTop(rect.top());
2816 r.setBottom(ver_struct_list->at(i: 1).pos - sep - 1);
2817 }
2818 docks[QInternal::TopDock].rect = r;
2819 docks[QInternal::TopDock].fitItems();
2820 }
2821
2822 // bottom ---------------------------------------------------
2823
2824 if (!docks[QInternal::BottomDock].isEmpty()) {
2825 QRect r = docks[QInternal::BottomDock].rect;
2826 if (hor_struct_list != nullptr) {
2827 r.setLeft(corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
2828 || docks[QInternal::LeftDock].isEmpty()
2829 ? rect.left() : hor_struct_list->at(i: 1).pos);
2830 r.setRight(corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
2831 || docks[QInternal::RightDock].isEmpty()
2832 ? rect.right() : hor_struct_list->at(i: 2).pos - sep - 1);
2833 }
2834 if (ver_struct_list != nullptr) {
2835 r.setTop(ver_struct_list->at(i: 2).pos);
2836 r.setBottom(rect.bottom());
2837 }
2838 docks[QInternal::BottomDock].rect = r;
2839 docks[QInternal::BottomDock].fitItems();
2840 }
2841
2842 // left ---------------------------------------------------
2843
2844 if (!docks[QInternal::LeftDock].isEmpty()) {
2845 QRect r = docks[QInternal::LeftDock].rect;
2846 if (hor_struct_list != nullptr) {
2847 r.setLeft(rect.left());
2848 r.setRight(hor_struct_list->at(i: 1).pos - sep - 1);
2849 }
2850 if (ver_struct_list != nullptr) {
2851 r.setTop(corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
2852 || docks[QInternal::TopDock].isEmpty()
2853 ? rect.top() : ver_struct_list->at(i: 1).pos);
2854 r.setBottom(corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
2855 || docks[QInternal::BottomDock].isEmpty()
2856 ? rect.bottom() : ver_struct_list->at(i: 2).pos - sep - 1);
2857 }
2858 docks[QInternal::LeftDock].rect = r;
2859 docks[QInternal::LeftDock].fitItems();
2860 }
2861
2862 // right ---------------------------------------------------
2863
2864 if (!docks[QInternal::RightDock].isEmpty()) {
2865 QRect r = docks[QInternal::RightDock].rect;
2866 if (hor_struct_list != nullptr) {
2867 r.setLeft(hor_struct_list->at(i: 2).pos);
2868 r.setRight(rect.right());
2869 }
2870 if (ver_struct_list != nullptr) {
2871 r.setTop(corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
2872 || docks[QInternal::TopDock].isEmpty()
2873 ? rect.top() : ver_struct_list->at(i: 1).pos);
2874 r.setBottom(corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
2875 || docks[QInternal::BottomDock].isEmpty()
2876 ? rect.bottom() : ver_struct_list->at(i: 2).pos - sep - 1);
2877 }
2878 docks[QInternal::RightDock].rect = r;
2879 docks[QInternal::RightDock].fitItems();
2880 }
2881
2882 // center ---------------------------------------------------
2883
2884 if (hor_struct_list != nullptr) {
2885 centralWidgetRect.setLeft(hor_struct_list->at(i: 1).pos);
2886 centralWidgetRect.setWidth(hor_struct_list->at(i: 1).size);
2887 }
2888 if (ver_struct_list != nullptr) {
2889 centralWidgetRect.setTop(ver_struct_list->at(i: 1).pos);
2890 centralWidgetRect.setHeight(ver_struct_list->at(i: 1).size);
2891 }
2892}
2893
2894void QDockAreaLayout::fitLayout()
2895{
2896 QVector<QLayoutStruct> ver_struct_list(3);
2897 QVector<QLayoutStruct> hor_struct_list(3);
2898 getGrid(ver_struct_list: &ver_struct_list, hor_struct_list: &hor_struct_list);
2899
2900 qGeomCalc(chain&: ver_struct_list, start: 0, count: 3, pos: rect.top(), space: rect.height(), spacer: sep);
2901 qGeomCalc(chain&: hor_struct_list, start: 0, count: 3, pos: rect.left(), space: rect.width(), spacer: sep);
2902
2903 setGrid(ver_struct_list: &ver_struct_list, hor_struct_list: &hor_struct_list);
2904}
2905
2906void QDockAreaLayout::clear()
2907{
2908 for (int i = 0; i < QInternal::DockCount; ++i)
2909 docks[i].clear();
2910
2911 rect = QRect();
2912 centralWidgetRect = QRect();
2913}
2914
2915QSize QDockAreaLayout::sizeHint() const
2916{
2917 int left_sep = 0;
2918 int right_sep = 0;
2919 int top_sep = 0;
2920 int bottom_sep = 0;
2921
2922 if (centralWidgetItem != nullptr) {
2923 left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
2924 right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
2925 top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
2926 bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
2927 }
2928
2929 QSize left = docks[QInternal::LeftDock].sizeHint() + QSize(left_sep, 0);
2930 QSize right = docks[QInternal::RightDock].sizeHint() + QSize(right_sep, 0);
2931 QSize top = docks[QInternal::TopDock].sizeHint() + QSize(0, top_sep);
2932 QSize bottom = docks[QInternal::BottomDock].sizeHint() + QSize(0, bottom_sep);
2933 QSize center = centralWidgetItem == nullptr ? QSize(0, 0) : centralWidgetItem->sizeHint();
2934
2935 int row1 = top.width();
2936 int row2 = left.width() + center.width() + right.width();
2937 int row3 = bottom.width();
2938 int col1 = left.height();
2939 int col2 = top.height() + center.height() + bottom.height();
2940 int col3 = right.height();
2941
2942 if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
2943 row1 += left.width();
2944 else
2945 col1 += top.height();
2946
2947 if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
2948 row1 += right.width();
2949 else
2950 col3 += top.height();
2951
2952 if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
2953 row3 += left.width();
2954 else
2955 col1 += bottom.height();
2956
2957 if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
2958 row3 += right.width();
2959 else
2960 col3 += bottom.height();
2961
2962 return QSize(qMax(i1: row1, i2: row2, i3: row3), qMax(i1: col1, i2: col2, i3: col3));
2963}
2964
2965QSize QDockAreaLayout::minimumSize() const
2966{
2967 int left_sep = 0;
2968 int right_sep = 0;
2969 int top_sep = 0;
2970 int bottom_sep = 0;
2971
2972 if (centralWidgetItem != nullptr) {
2973 left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
2974 right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
2975 top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
2976 bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
2977 }
2978
2979 QSize left = docks[QInternal::LeftDock].minimumSize() + QSize(left_sep, 0);
2980 QSize right = docks[QInternal::RightDock].minimumSize() + QSize(right_sep, 0);
2981 QSize top = docks[QInternal::TopDock].minimumSize() + QSize(0, top_sep);
2982 QSize bottom = docks[QInternal::BottomDock].minimumSize() + QSize(0, bottom_sep);
2983 QSize center = centralWidgetItem == nullptr ? QSize(0, 0) : centralWidgetItem->minimumSize();
2984
2985 int row1 = top.width();
2986 int row2 = left.width() + center.width() + right.width();
2987 int row3 = bottom.width();
2988 int col1 = left.height();
2989 int col2 = top.height() + center.height() + bottom.height();
2990 int col3 = right.height();
2991
2992 if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
2993 row1 += left.width();
2994 else
2995 col1 += top.height();
2996
2997 if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
2998 row1 += right.width();
2999 else
3000 col3 += top.height();
3001
3002 if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
3003 row3 += left.width();
3004 else
3005 col1 += bottom.height();
3006
3007 if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
3008 row3 += right.width();
3009 else
3010 col3 += bottom.height();
3011
3012 return QSize(qMax(i1: row1, i2: row2, i3: row3), qMax(i1: col1, i2: col2, i3: col3));
3013}
3014
3015/*! \internal
3016 Try to fit the given rectangle \a rect on the screen which contains
3017 the window \a widget.
3018 Used to compute the geometry of a dragged a dock widget that should
3019 be shown with \a rect, but needs to be visible on the screen
3020 */
3021QRect QDockAreaLayout::constrainedRect(QRect rect, QWidget* widget)
3022{
3023 QRect desktop;
3024 if (QDesktopWidgetPrivate::isVirtualDesktop())
3025 desktop = QDesktopWidgetPrivate::screenGeometry(point: rect.topLeft());
3026 else
3027 desktop = QDesktopWidgetPrivate::screenGeometry(widget);
3028
3029 if (desktop.isValid()) {
3030 rect.setWidth(qMin(a: rect.width(), b: desktop.width()));
3031 rect.setHeight(qMin(a: rect.height(), b: desktop.height()));
3032 rect.moveLeft(pos: qMax(a: rect.left(), b: desktop.left()));
3033 rect.moveTop(pos: qMax(a: rect.top(), b: desktop.top()));
3034 rect.moveRight(pos: qMin(a: rect.right(), b: desktop.right()));
3035 rect.moveBottom(pos: qMin(a: rect.bottom(), b: desktop.bottom()));
3036 }
3037
3038 return rect;
3039}
3040
3041bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget)
3042{
3043 QDockAreaLayoutItem *item = nullptr;
3044 const auto groups =
3045 mainWindow->findChildren<QDockWidgetGroupWindow *>(aName: QString(), options: Qt::FindDirectChildrenOnly);
3046 for (QDockWidgetGroupWindow *dwgw : groups) {
3047 QList<int> index = dwgw->layoutInfo()->indexOfPlaceHolder(objectName: dockWidget->objectName());
3048 if (!index.isEmpty()) {
3049 dockWidget->setParent(dwgw);
3050 item = const_cast<QDockAreaLayoutItem *>(&dwgw->layoutInfo()->item(path: index));
3051 break;
3052 }
3053 }
3054 if (!item) {
3055 QList<int> index = indexOfPlaceHolder(objectName: dockWidget->objectName());
3056 if (index.isEmpty())
3057 return false;
3058 item = const_cast<QDockAreaLayoutItem *>(&this->item(path: index));
3059 }
3060
3061 QPlaceHolderItem *placeHolder = item->placeHolderItem;
3062 Q_ASSERT(placeHolder != nullptr);
3063
3064 item->widgetItem = new QDockWidgetItem(dockWidget);
3065
3066 if (placeHolder->window) {
3067 const QRect r = constrainedRect(rect: placeHolder->topLevelRect, widget: dockWidget);
3068 dockWidget->d_func()->setWindowState(floating: true, unplug: true, rect: r);
3069 }
3070 dockWidget->setVisible(!placeHolder->hidden);
3071
3072 item->placeHolderItem = nullptr;
3073 delete placeHolder;
3074
3075 return true;
3076}
3077
3078void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget,
3079 Qt::Orientation orientation)
3080{
3081 QLayoutItem *dockWidgetItem = new QDockWidgetItem(dockWidget);
3082 QDockAreaLayoutInfo &info = docks[pos];
3083 if (orientation == info.o || info.item_list.count() <= 1) {
3084 // empty dock areas, or dock areas containing exactly one widget can have their orientation
3085 // switched.
3086 info.o = orientation;
3087
3088 QDockAreaLayoutItem new_item(dockWidgetItem);
3089 info.item_list.append(t: new_item);
3090#if QT_CONFIG(tabbar)
3091 if (info.tabbed && !new_item.skip()) {
3092 info.updateTabBar();
3093 info.setCurrentTabId(tabId(item: new_item));
3094 }
3095#endif
3096 } else {
3097#if QT_CONFIG(tabbar)
3098 int tbshape = info.tabBarShape;
3099#else
3100 int tbshape = 0;
3101#endif
3102 QDockAreaLayoutInfo new_info(&sep, pos, orientation, tbshape, mainWindow);
3103 new_info.item_list.append(t: QDockAreaLayoutItem(new QDockAreaLayoutInfo(info)));
3104 new_info.item_list.append(t: QDockAreaLayoutItem(dockWidgetItem));
3105 info = new_info;
3106 }
3107
3108 removePlaceHolder(name: dockWidget->objectName());
3109}
3110
3111#if QT_CONFIG(tabbar)
3112void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
3113{
3114 const QList<int> path = indexOf(dockWidget: first);
3115 if (path.isEmpty())
3116 return;
3117
3118 QDockAreaLayoutInfo *info = this->info(path);
3119 Q_ASSERT(info != nullptr);
3120 info->tab(index: path.last(), dockWidgetItem: new QDockWidgetItem(second));
3121
3122 removePlaceHolder(name: second->objectName());
3123}
3124#endif // QT_CONFIG(tabbar)
3125
3126void QDockAreaLayout::resizeDocks(const QList<QDockWidget *> &docks,
3127 const QList<int> &sizes, Qt::Orientation o)
3128{
3129 if (Q_UNLIKELY(docks.count() != sizes.count())) {
3130 qWarning(msg: "QMainWidget::resizeDocks: size of the lists are not the same");
3131 return;
3132 }
3133 int count = docks.count();
3134 fallbackToSizeHints = false;
3135 for (int i = 0; i < count; ++i) {
3136 QList<int> path = indexOf(dockWidget: docks[i]);
3137 if (Q_UNLIKELY(path.isEmpty())) {
3138 qWarning(msg: "QMainWidget::resizeDocks: one QDockWidget is not part of the layout");
3139 continue;
3140 }
3141 int size = sizes[i];
3142 if (Q_UNLIKELY(size <= 0)) {
3143 qWarning(msg: "QMainWidget::resizeDocks: all sizes need to be larger than 0");
3144 size = 1;
3145 }
3146
3147 while (path.size() > 1) {
3148 QDockAreaLayoutInfo *info = this->info(path);
3149#if QT_CONFIG(tabbar)
3150 if (!info->tabbed && info->o == o) {
3151 info->item_list[path.constLast()].size = size;
3152 int totalSize = 0;
3153 for (const QDockAreaLayoutItem &item : qAsConst(t&: info->item_list)) {
3154 if (!item.skip()) {
3155 if (totalSize != 0)
3156 totalSize += sep;
3157 totalSize += item.size == -1 ? pick(o, size: item.sizeHint()) : item.size;
3158 }
3159 }
3160 size = totalSize;
3161 }
3162#endif // QT_CONFIG(tabbar)
3163 path.removeLast();
3164 }
3165
3166 const int dockNum = path.constFirst();
3167 Q_ASSERT(dockNum < QInternal::DockCount);
3168 QRect &r = this->docks[dockNum].rect;
3169 QSize s = r.size();
3170 rpick(o, size&: s) = size;
3171 r.setSize(s);
3172 }
3173}
3174
3175void QDockAreaLayout::splitDockWidget(QDockWidget *after,
3176 QDockWidget *dockWidget,
3177 Qt::Orientation orientation)
3178{
3179 const QList<int> path = indexOf(dockWidget: after);
3180 if (path.isEmpty())
3181 return;
3182
3183 QDockAreaLayoutInfo *info = this->info(path);
3184 Q_ASSERT(info != nullptr);
3185 info->split(index: path.last(), orientation, dockWidgetItem: new QDockWidgetItem(dockWidget));
3186
3187 removePlaceHolder(name: dockWidget->objectName());
3188}
3189
3190void QDockAreaLayout::apply(bool animate)
3191{
3192 QWidgetAnimator &widgetAnimator = qt_mainwindow_layout(window: mainWindow)->widgetAnimator;
3193
3194 for (int i = 0; i < QInternal::DockCount; ++i)
3195 docks[i].apply(animate);
3196 if (centralWidgetItem != nullptr && !centralWidgetItem->isEmpty()) {
3197 widgetAnimator.animate(widget: centralWidgetItem->widget(), final_geometry: centralWidgetRect,
3198 animate);
3199 }
3200#if QT_CONFIG(tabbar)
3201 if (sep == 1)
3202 updateSeparatorWidgets();
3203#endif // QT_CONFIG(tabbar)
3204}
3205
3206void QDockAreaLayout::paintSeparators(QPainter *p, QWidget *widget,
3207 const QRegion &clip,
3208 const QPoint &mouse) const
3209{
3210 for (int i = 0; i < QInternal::DockCount; ++i) {
3211 const QDockAreaLayoutInfo &dock = docks[i];
3212 if (dock.isEmpty())
3213 continue;
3214 QRect r = separatorRect(index: i);
3215 if (clip.contains(r) && !dock.hasFixedSize()) {
3216 Qt::Orientation opposite = dock.o == Qt::Horizontal
3217 ? Qt::Vertical : Qt::Horizontal;
3218 paintSep(p, w: widget, r, o: opposite, mouse_over: r.contains(p: mouse));
3219 }
3220 if (clip.contains(r: dock.rect))
3221 dock.paintSeparators(p, widget, clip, mouse);
3222 }
3223}
3224
3225QRegion QDockAreaLayout::separatorRegion() const
3226{
3227 QRegion result;
3228
3229 for (int i = 0; i < QInternal::DockCount; ++i) {
3230 const QDockAreaLayoutInfo &dock = docks[i];
3231 if (dock.isEmpty())
3232 continue;
3233 result |= separatorRect(index: i);
3234 result |= dock.separatorRegion();
3235 }
3236
3237 return result;
3238}
3239
3240int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &origin,
3241 const QPoint &dest)
3242{
3243 int delta = 0;
3244 int index = separator.last();
3245
3246 if (separator.count() > 1) {
3247 QDockAreaLayoutInfo *info = this->info(path: separator);
3248 delta = pick(o: info->o, pos: dest - origin);
3249 if (delta != 0)
3250 delta = info->separatorMove(index, delta);
3251 info->apply(animate: false);
3252 return delta;
3253 }
3254
3255 QVector<QLayoutStruct> list;
3256
3257 if (index == QInternal::LeftDock || index == QInternal::RightDock)
3258 getGrid(ver_struct_list: nullptr, hor_struct_list: &list);
3259 else
3260 getGrid(ver_struct_list: &list, hor_struct_list: nullptr);
3261
3262 int sep_index = index == QInternal::LeftDock || index == QInternal::TopDock
3263 ? 0 : 1;
3264 Qt::Orientation o = index == QInternal::LeftDock || index == QInternal::RightDock
3265 ? Qt::Horizontal
3266 : Qt::Vertical;
3267
3268 delta = pick(o, pos: dest - origin);
3269 delta = separatorMoveHelper(list, index: sep_index, delta, sep);
3270
3271 fallbackToSizeHints = false;
3272
3273 if (index == QInternal::LeftDock || index == QInternal::RightDock)
3274 setGrid(ver_struct_list: nullptr, hor_struct_list: &list);
3275 else
3276 setGrid(ver_struct_list: &list, hor_struct_list: nullptr);
3277
3278 apply(animate: false);
3279
3280 return delta;
3281}
3282
3283int QDockAreaLayoutInfo::separatorMove(const QList<int> &separator, const QPoint &origin,
3284 const QPoint &dest)
3285{
3286 int delta = 0;
3287 int index = separator.last();
3288 QDockAreaLayoutInfo *info = this->info(path: separator);
3289 delta = pick(o: info->o, pos: dest - origin);
3290 if (delta != 0)
3291 delta = info->separatorMove(index, delta);
3292 info->apply(animate: false);
3293 return delta;
3294}
3295
3296#if QT_CONFIG(tabbar)
3297// Sets the correct positions for the separator widgets
3298// Allocates new sepearator widgets with getSeparatorWidget
3299void QDockAreaLayout::updateSeparatorWidgets() const
3300{
3301 int j = 0;
3302
3303 for (int i = 0; i < QInternal::DockCount; ++i) {
3304 const QDockAreaLayoutInfo &dock = docks[i];
3305 if (dock.isEmpty())
3306 continue;
3307
3308 QWidget *sepWidget;
3309 if (j < separatorWidgets.size()) {
3310 sepWidget = separatorWidgets.at(i: j);
3311 } else {
3312 sepWidget = qt_mainwindow_layout(window: mainWindow)->getSeparatorWidget();
3313 separatorWidgets.append(t: sepWidget);
3314 }
3315 j++;
3316
3317 sepWidget->raise();
3318
3319 QRect sepRect = separatorRect(index: i).adjusted(xp1: -2, yp1: -2, xp2: 2, yp2: 2);
3320 sepWidget->setGeometry(sepRect);
3321 sepWidget->setMask( QRegion(separatorRect(index: i).translated( p: - sepRect.topLeft())));
3322 sepWidget->show();
3323 }
3324 for (int i = j; i < separatorWidgets.size(); ++i)
3325 separatorWidgets.at(i)->hide();
3326
3327 separatorWidgets.resize(asize: j);
3328}
3329#endif // QT_CONFIG(tabbar)
3330
3331QLayoutItem *QDockAreaLayout::itemAt(int *x, int index) const
3332{
3333 Q_ASSERT(x != nullptr);
3334
3335 for (int i = 0; i < QInternal::DockCount; ++i) {
3336 const QDockAreaLayoutInfo &dock = docks[i];
3337 if (QLayoutItem *ret = dock.itemAt(x, index))
3338 return ret;
3339 }
3340
3341 if (centralWidgetItem && (*x)++ == index)
3342 return centralWidgetItem;
3343
3344 return nullptr;
3345}
3346
3347QLayoutItem *QDockAreaLayout::takeAt(int *x, int index)
3348{
3349 Q_ASSERT(x != nullptr);
3350
3351 for (int i = 0; i < QInternal::DockCount; ++i) {
3352 QDockAreaLayoutInfo &dock = docks[i];
3353 if (QLayoutItem *ret = dock.takeAt(x, index))
3354 return ret;
3355 }
3356
3357 if (centralWidgetItem && (*x)++ == index) {
3358 QLayoutItem *ret = centralWidgetItem;
3359 centralWidgetItem = nullptr;
3360 return ret;
3361 }
3362
3363 return nullptr;
3364}
3365
3366void QDockAreaLayout::deleteAllLayoutItems()
3367{
3368 for (int i = 0; i < QInternal::DockCount; ++i)
3369 docks[i].deleteAllLayoutItems();
3370}
3371
3372#if QT_CONFIG(tabbar)
3373QSet<QTabBar*> QDockAreaLayout::usedTabBars() const
3374{
3375 QSet<QTabBar*> result;
3376 for (int i = 0; i < QInternal::DockCount; ++i) {
3377 const QDockAreaLayoutInfo &dock = docks[i];
3378 result += dock.usedTabBars();
3379 }
3380 return result;
3381}
3382
3383// Returns the set of all used separator widgets
3384QSet<QWidget*> QDockAreaLayout::usedSeparatorWidgets() const
3385{
3386 QSet<QWidget*> result;
3387 const int numSeparators = separatorWidgets.count();
3388 result.reserve(asize: numSeparators);
3389 for (int i = 0; i < numSeparators; ++i)
3390 result << separatorWidgets.at(i);
3391 for (int i = 0; i < QInternal::DockCount; ++i) {
3392 const QDockAreaLayoutInfo &dock = docks[i];
3393 result += dock.usedSeparatorWidgets();
3394 }
3395 return result;
3396}
3397#endif
3398
3399QRect QDockAreaLayout::gapRect(const QList<int> &path) const
3400{
3401 const QDockAreaLayoutInfo *info = this->info(path);
3402 if (info == nullptr)
3403 return QRect();
3404 int index = path.last();
3405 if (index < 0 || index >= info->item_list.count())
3406 return QRect();
3407 return info->itemRect(index, isGap: true);
3408}
3409
3410void QDockAreaLayout::keepSize(QDockWidget *w)
3411{
3412 QList<int> path = indexOf(dockWidget: w);
3413 if (path.isEmpty())
3414 return;
3415 QDockAreaLayoutItem &item = this->item(path);
3416 if (item.size != -1)
3417 item.flags |= QDockAreaLayoutItem::KeepSize;
3418}
3419
3420void QDockAreaLayout::styleChangedEvent()
3421{
3422 sep = mainWindow->style()->pixelMetric(metric: QStyle::PM_DockWidgetSeparatorExtent, option: nullptr, widget: mainWindow);
3423 if (isValid())
3424 fitLayout();
3425}
3426
3427QT_END_NAMESPACE
3428

source code of qtbase/src/widgets/widgets/qdockarealayout.cpp