Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qdockarealayout.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "QtWidgets/qapplication.h"
6#include "QtWidgets/qwidget.h"
7#if QT_CONFIG(tabbar)
8#include "QtWidgets/qtabbar.h"
9#endif
10#include "QtWidgets/qstyle.h"
11#include "QtWidgets/qapplication.h"
12#include "QtCore/qvariant.h"
13#include "qdockarealayout_p.h"
14#include "qdockwidget.h"
15#include "qmainwindow.h"
16#include "qwidgetanimator_p.h"
17#include "qmainwindowlayout_p.h"
18#include "qmenu_p.h"
19#include "qdockwidget_p.h"
20#include <private/qlayoutengine_p.h>
21
22#include <qpainter.h>
23#include <qstyleoption.h>
24
26
27Q_LOGGING_CATEGORY(lcQpaDockWidgets, "qt.widgets.dockwidgets");
28
29// qmainwindow.cpp
31
33
34/******************************************************************************
35** QPlaceHolderItem
36*/
37
39{
40 objectName = w->objectName();
41 hidden = w->isHidden();
42 window = w->isWindow();
43 if (window)
44 topLevelRect = w->geometry();
45}
46
47/******************************************************************************
48** QDockAreaLayoutItem
49*/
50
52 : widgetItem(_widgetItem), subinfo(nullptr), placeHolderItem(nullptr), pos(0), size(-1), flags(NoFlags)
53{
54}
55
57 : widgetItem(nullptr), subinfo(_subinfo), placeHolderItem(nullptr), pos(0), size(-1), flags(NoFlags)
58{
59}
60
62 : widgetItem(nullptr), subinfo(nullptr), placeHolderItem(_placeHolderItem), pos(0), size(-1), flags(NoFlags)
63{
64}
65
67 : widgetItem(other.widgetItem), subinfo(nullptr), placeHolderItem(nullptr), pos(other.pos),
69{
70 if (other.subinfo != nullptr)
71 subinfo = new QDockAreaLayoutInfo(*other.subinfo);
72 else if (other.placeHolderItem != nullptr)
73 placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
74}
75
81
83{
84 if (placeHolderItem != nullptr)
85 return true;
86
87 if (flags & GapItem)
88 return false;
89
90 if (widgetItem != nullptr)
91 return widgetItem->isEmpty();
92
93 if (subinfo != nullptr) {
94 for (int i = 0; i < subinfo->item_list.size(); ++i) {
95 if (!subinfo->item_list.at(i).skip())
96 return false;
97 }
98 }
99
100 return true;
101}
102
104{
105 if (widgetItem)
106 return widgetItem->minimumSize().grownBy(widgetItem->widget()->contentsMargins());
107 if (subinfo != nullptr)
108 return subinfo->minimumSize();
109 return QSize(0, 0);
110}
111
113{
114 if (widgetItem)
115 return widgetItem->maximumSize().grownBy(widgetItem->widget()->contentsMargins());
116 if (subinfo != nullptr)
117 return subinfo->maximumSize();
119}
120
125
127{
128 if ((flags & GapItem) || placeHolderItem != nullptr)
129 return false;
130 if (widgetItem != nullptr)
131 return ((widgetItem->expandingDirections() & o) == o);
132 if (subinfo != nullptr)
133 return subinfo->expansive(o);
134 return false;
135}
136
138{
139 if (placeHolderItem != nullptr)
140 return QSize(0, 0);
141 if (widgetItem)
142 return widgetItem->sizeHint().grownBy(widgetItem->widget()->contentsMargins());
143 if (subinfo != nullptr)
144 return subinfo->sizeHint();
145 return QSize(-1, -1);
146}
147
150{
151 if (this == &other)
152 return *this;
153
154 widgetItem = other.widgetItem;
155 delete subinfo;
156 if (other.subinfo == nullptr)
157 subinfo = nullptr;
158 else
159 subinfo = new QDockAreaLayoutInfo(*other.subinfo);
160
161 delete placeHolderItem;
162 if (other.placeHolderItem == nullptr)
163 placeHolderItem = nullptr;
164 else
165 placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
166
167 pos = other.pos;
168 size = other.size;
169 flags = other.flags;
170
171 return *this;
172}
173
174#ifndef QT_NO_DEBUG_STREAM
176{
177 QDebugStateSaver saver(dbg);
178 dbg.nospace();
179 return item ? dbg << *item : dbg << "QDockAreaLayoutItem(0x0)";
180}
181
183{
184 QDebugStateSaver saver(dbg);
185 dbg.nospace();
186 dbg << "QDockAreaLayoutItem(" << static_cast<const void *>(&item) << "->";
187 if (item.widgetItem) {
188 QWidget *widget = item.widgetItem->widget();
189 if (auto *dockWidget = qobject_cast<QDockWidget *>(widget)) {
190 dbg << "widgetItem(" << dockWidget << ")";
191 } else if (auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
192 dbg << "widgetItem(" << groupWindow << "->(" << groupWindow->dockWidgets() << "))";
193 } else {
194 dbg << "widgetItem(" << widget << ")";
195 }
196 } else if (item.subinfo) {
197 dbg << "subInfo(" << item.subinfo << "->(" << item.subinfo->item_list << ")";
198 } else if (item.placeHolderItem) {
199 dbg << "placeHolderItem(" << item.placeHolderItem << ")";
200 }
201 dbg << ")";
202 return dbg;
203}
204#endif // QT_NO_DEBUG_STREAM
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
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
230 Qt::Orientation _o, int tbshape,
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
243{
244 return isEmpty() ? QSize(0, 0) : rect.size();
245}
246
248{
250 rect = QRect();
251#if QT_CONFIG(tabbar)
252 tabbed = false;
253 tabBar = nullptr;
254#endif
255}
256
258{
259 return next(-1) == -1;
260}
261
263{
264 for (const QDockAreaLayoutItem &item : item_list) {
265 if (!item.placeHolderItem)
266 return false;
267 }
268
269 return true;
270}
271
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) {
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, pick(o, min_size));
288 } else
289#endif
290 {
291 if (!first)
292 a += *sep;
293 a += pick(o, min_size);
294 }
295 b = qMax(b, perp(o, min_size));
296
297 first = false;
298 }
299
301 rpick(o, result) = a;
302 rperp(o, result) = b;
303
304#if QT_CONFIG(tabbar)
305 QSize tbm = tabBarMinimumSize();
306 if (!tbm.isNull()) {
307 switch (tabBarShape) {
312 result.rheight() += tbm.height();
313 result.rwidth() = qMax(tbm.width(), result.width());
314 break;
319 result.rheight() = qMax(tbm.height(), 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
332{
333 if (isEmpty())
335
336 int a = 0, b = QWIDGETSIZE_MAX;
337#if QT_CONFIG(tabbar)
338 if (tabbed)
340#endif
341
342 int min_perp = 0;
343
344 bool first = true;
345 for (int i = 0; i < item_list.size(); ++i) {
347 if (item.skip())
348 continue;
349
350 QSize max_size = item.maximumSize();
351 min_perp = qMax(min_perp, perp(o, item.minimumSize()));
352
353#if QT_CONFIG(tabbar)
354 if (tabbed) {
355 a = qMin(a, pick(o, max_size));
356 } else
357#endif
358 {
359 if (!first)
360 a += *sep;
361 a += pick(o, max_size);
362 }
363 b = qMin(b, perp(o, max_size));
364
365 a = qMin(a, int(QWIDGETSIZE_MAX));
366 b = qMin(b, int(QWIDGETSIZE_MAX));
367
368 first = false;
369 }
370
371 b = qMax(b, min_perp);
372
374 rpick(o, result) = a;
375 rperp(o, result) = b;
376
377#if QT_CONFIG(tabbar)
378 QSize tbh = tabBarSizeHint();
379 if (!tbh.isNull()) {
380 switch (tabBarShape) {
383 result.rheight() += tbh.height();
384 break;
387 result.rwidth() += tbh.width();
388 break;
389 default:
390 break;
391 }
392 }
393#endif // QT_CONFIG(tabbar)
394
395 return result;
396}
397
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) {
409 if (item.skip())
410 continue;
411
413
414 QSize size_hint = item.sizeHint();
415 min_perp = qMax(min_perp, perp(o, item.minimumSize()));
416 max_perp = qMin(max_perp, perp(o, item.maximumSize()));
417
418#if QT_CONFIG(tabbar)
419 if (tabbed) {
420 a = qMax(a, gap ? item.size : pick(o, 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_hint);
429 }
430 b = qMax(b, perp(o, size_hint));
431
432 previous = &item;
433 }
434
435 max_perp = qMax(max_perp, min_perp);
436 b = qMax(b, min_perp);
437 b = qMin(b, max_perp);
438
440 rpick(o, result) = a;
441 rperp(o, result) = b;
442
443#if QT_CONFIG(tabbar)
444 if (tabbed) {
445 QSize tbh = tabBarSizeHint();
446 switch (tabBarShape) {
451 result.rheight() += tbh.height();
452 result.rwidth() = qMax(tbh.width(), result.width());
453 break;
458 result.rheight() = qMax(tbh.height(), 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
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
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(info.o, item.minimumSize());
500
501 if (!first)
502 result += *info.sep;
503 result += min;
504
505 first = false;
506 }
507
508 return result;
509}
510
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(info.o, 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
540{
541#if QT_CONFIG(tabbar)
542 if (tabbed) {
543 return;
544 }
545#endif
546
547 QList<QLayoutStruct> layout_struct_list(item_list.size() * 2);
548 int j = 0;
549
550 int size = pick(o, rect.size());
551 int min_size = realMinSize(*this);
552 int max_size = realMaxSize(*this);
553 int last_index = -1;
554
555 const QDockAreaLayoutItem *previous = nullptr;
556 for (int i = 0; i < item_list.size(); ++i) {
558 if (item.skip())
559 continue;
560
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
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, item.minimumSize());
580 min_size = qMax(0, 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, item.maximumSize());
586 max_size = qMin<int>(QWIDGETSIZE_MAX, max_size);
587 }
588 }
589
590 last_index = j;
591 QLayoutStruct &ls = layout_struct_list[j++];
592 ls.init();
593 ls.empty = false;
595 ls.minimumSize = ls.maximumSize = ls.sizeHint = item.size;
596 ls.expansive = false;
597 ls.stretch = 0;
598 } else {
599 ls.maximumSize = pick(o, item.maximumSize());
600 ls.expansive = item.expansive(o);
601 ls.minimumSize = pick(o, item.minimumSize());
602 ls.sizeHint = item.size == -1 ? pick(o, 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(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(layout_struct_list, 0, j, pick(o, rect.topLeft()), size, 0);
619
620 j = 0;
621 bool prev_gap = false;
622 bool first = true;
623 for (int i = 0; i < item_list.size(); ++i) {
625 if (item.skip())
626 continue;
627
629 if (!first && !gap && !prev_gap)
630 ++j;
631
632 const QLayoutStruct &ls = layout_struct_list.at(j++);
633 item.size = ls.size;
634 item.pos = ls.pos;
635
636 if (item.subinfo != nullptr) {
637 item.subinfo->rect = itemRect(i);
638 item.subinfo->fitItems();
639 }
640
641 prev_gap = gap;
642 first = false;
643 }
644}
645
648 bool nestingEnabled,
650{
651 if (tabMode == QDockAreaLayoutInfo::ForceTabs)
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(pos))
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)
688 } else {
689 /*
690 +--------------+
691 | |
692 2/3 |CCCCCCCCCCCCCC|
693 |CCCCCCCCCCCCCC|
694 | |
695 +--------------+ */
696 if (y > h/6 && y < 5*h/6)
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)
716 if (y < h/2)
717 return QInternal::TopDock;
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)
731 if (x < w/2)
732 return QInternal::LeftDock;
734 }
735 } else {
736 if (o == Qt::Horizontal) {
737 return x < w/2
740 } else {
741 return y < h/2
744 }
745 }
746}
747
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);
762
763 int last = -1;
764 for (int i = 0; i < item_list.size(); ++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(i);
782 return result;
783 }
784
785 item_rect = itemRect(i);
786 item_index = i;
787 break;
788 }
789
790 if (item_rect.isNull()) {
791 result.append(last + 1);
792 return result;
793 }
794 }
795
796 Q_ASSERT(!item_rect.isNull());
797
799 = dockPosHelper(item_rect, _pos, o, nestingEnabled, tabMode);
800
801 switch (dock_pos) {
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;
810 if (o == Qt::Horizontal)
811 result << item_index + 1;
812 else
813 result << item_index << 1;
814 break;
816 if (o == Qt::Horizontal)
817 result << item_index << 0;
818 else
819 result << item_index;
820 break;
822 if (o == Qt::Horizontal)
823 result << item_index << 1;
824 else
825 result << item_index + 1;
826 break;
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(ls.size - delta, 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(ls.size + delta, ls.maximumSize);
854 return ls.size - old_size;
855}
856
857static int separatorMoveHelper(QList<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.size(); ++i)
888 d += shrink(list[i], delta - d);
889 delta = d;
890 d = 0;
891 for (int i = index; d < delta && i >= 0; --i)
892 d += grow(list[i], delta - d);
893 } else if (delta < 0) {
894 int growlimit = 0;
895 for (int i = index + 1; i < list.size(); ++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(list[i], -delta - d);
911 delta = -d;
912 d = 0;
913 for (int i = index + 1; d < -delta && i < list.size(); ++i)
914 d += grow(list[i], -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
936{
937#if QT_CONFIG(tabbar)
938 Q_ASSERT(!tabbed);
939#endif
940
941 QList<QLayoutStruct> list(item_list.size());
942 for (int i = 0; i < list.size(); ++i) {
944 QLayoutStruct &ls = list[i];
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, item.minimumSize()) + separatorSpace;
954 ls.maximumSize = pick(o, 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, 0 /*separator*/);
961
962 for (int i = 0; i < list.size(); ++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(i);
972 item.subinfo->fitItems();
973 }
974 }
975
976 return delta;
977}
978
980{
982 if (item.subinfo == nullptr)
983 return;
984 if (item.subinfo->item_list.size() > 1)
985 return;
986
987 if (item.subinfo->item_list.size() == 0) {
989 } else if (item.subinfo->item_list.size() == 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.size() > 1) {
1010 const int index = path.first();
1012 Q_ASSERT(item.subinfo != nullptr);
1013 item.subinfo->remove(path.mid(1));
1014 unnest(index);
1015 } else {
1016 int index = path.first();
1018 }
1019}
1020
1022{
1023 const QList<int> path = indexOf(widget);
1024 if (path.isEmpty())
1025 return;
1026 remove(path);
1027}
1028
1030{
1031 Q_ASSERT(!path.isEmpty());
1032
1033 int index = path.first();
1034 if (index < 0)
1035 index = -index - 1;
1036
1037 if (path.size() > 1) {
1039 Q_ASSERT(item.subinfo != nullptr);
1040 return item.subinfo->plug(path.mid(1));
1041 }
1042
1044
1045 Q_ASSERT(item.widgetItem != nullptr);
1047 item.flags &= ~QDockAreaLayoutItem::GapItem;
1048 return item.widgetItem;
1049}
1050
1052{
1053 Q_ASSERT(!path.isEmpty());
1054
1055 const int index = path.first();
1056 if (path.size() > 1) {
1058 Q_ASSERT(item.subinfo != nullptr);
1059 return item.subinfo->unplug(path.mid(1));
1060 }
1061
1063 int prev = this->prev(index);
1064 int next = this->next(index);
1065
1068
1069#if QT_CONFIG(tabbar)
1070 if (tabbed) {
1071 } else
1072#endif
1073 {
1075 item.pos -= *sep;
1076 item.size += *sep;
1077 }
1079 item.size += *sep;
1080 }
1081
1082 return item.widgetItem;
1083}
1084
1085#if QT_CONFIG(tabbar)
1086
1087quintptr QDockAreaLayoutInfo::currentTabId() const
1088{
1089 if (!tabbed || tabBar == nullptr)
1090 return 0;
1091
1092 int index = tabBar->currentIndex();
1093 if (index == -1)
1094 return 0;
1095
1096 return qvariant_cast<quintptr>(tabBar->tabData(index));
1097}
1098
1099void QDockAreaLayoutInfo::setCurrentTab(QWidget *widget)
1100{
1101 setCurrentTabId(reinterpret_cast<quintptr>(widget));
1102}
1103
1104void QDockAreaLayoutInfo::setCurrentTabId(quintptr id)
1105{
1106 if (!tabbed || tabBar == nullptr)
1107 return;
1108
1109 for (int i = 0; i < tabBar->count(); ++i) {
1110 if (qvariant_cast<quintptr>(tabBar->tabData(i)) == id) {
1111 tabBar->setCurrentIndex(i);
1112 return;
1113 }
1114 }
1115}
1116
1117#endif // QT_CONFIG(tabbar)
1118
1120{
1121 int titleHeight = 0;
1122
1124 = qobject_cast<QDockWidgetLayout*>(widget->layout());
1125 if (layout && layout->nativeWindowDeco())
1126 titleHeight = layout->titleHeight();
1127
1129 result.adjust(0, -titleHeight, 0, 0);
1130 return result;
1131}
1132
1133bool QDockAreaLayoutInfo::hasGapItem(const QList<int> &path) const
1134{
1135 // empty path has no gap item
1136 if (path.isEmpty())
1137 return false;
1138
1139 // Index -1 isn't a gap
1140 // Index out of range points at a position to be created. That isn't a gap either.
1141 const int index = path.constFirst();
1142 if (index < 0 || index >= item_list.count())
1143 return false;
1144
1146}
1147
1148bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
1149{
1150 Q_ASSERT(!path.isEmpty());
1151
1152 bool insert_tabbed = false;
1153 int index = path.first();
1154 if (index < 0) {
1155 insert_tabbed = true;
1156 index = -index - 1;
1157 }
1158
1159 if (path.size() > 1) {
1161
1162 if (item.subinfo == nullptr
1163#if QT_CONFIG(tabbar)
1164 || (item.subinfo->tabbed && !insert_tabbed)
1165#endif
1166 ) {
1167
1168 // this is not yet a nested layout - make it
1169
1170 QDockAreaLayoutInfo *subinfo = item.subinfo;
1171 QLayoutItem *widgetItem = item.widgetItem;
1172 QPlaceHolderItem *placeHolderItem = item.placeHolderItem;
1173 QRect r = subinfo == nullptr ? widgetItem ? dockedGeometry(widgetItem->widget()) : placeHolderItem->topLevelRect : subinfo->rect;
1174
1176#if !QT_CONFIG(tabbar)
1177 const int tabBarShape = 0;
1178#endif
1179 QDockAreaLayoutInfo *new_info
1180 = new QDockAreaLayoutInfo(sep, dockPos, opposite, tabBarShape, mainWindow);
1181
1182 //item become a new top-level
1183 item.subinfo = new_info;
1184 item.widgetItem = nullptr;
1185 item.placeHolderItem = nullptr;
1186
1187 QDockAreaLayoutItem new_item
1188 = widgetItem == nullptr
1189 ? QDockAreaLayoutItem(subinfo)
1190 : widgetItem ? QDockAreaLayoutItem(widgetItem) : QDockAreaLayoutItem(placeHolderItem);
1191 new_item.size = pick(opposite, r.size());
1192 new_item.pos = pick(opposite, r.topLeft());
1193 new_info->item_list.append(new_item);
1194#if QT_CONFIG(tabbar)
1195 if (insert_tabbed) {
1196 new_info->tabbed = true;
1197 }
1198#endif
1199 }
1200
1201 return item.subinfo->insertGap(path.mid(1), dockWidgetItem);
1202 }
1203
1204 // create the gap item
1205 QDockAreaLayoutItem gap_item;
1207 gap_item.widgetItem = dockWidgetItem; // so minimumSize(), maximumSize() and
1208 // sizeHint() will work
1209#if QT_CONFIG(tabbar)
1210 if (!tabbed)
1211#endif
1212 {
1213 int prev = this->prev(index);
1214 int next = this->next(index - 1);
1215 // find out how much space we have in the layout
1216 int space = 0;
1217 if (isEmpty()) {
1218 // I am an empty dock area, therefore I am a top-level dock area.
1219 switch (dockPos) {
1222 if (o == Qt::Vertical) {
1223 // the "size" is the height of the dock area (remember we are empty)
1224 space = pick(Qt::Vertical, rect.size());
1225 } else {
1226 space = pick(Qt::Horizontal, dockWidgetItem->widget()->size());
1227 }
1228 break;
1229 case QInternal::TopDock:
1231 default:
1232 if (o == Qt::Horizontal) {
1233 // the "size" is width of the dock area
1234 space = pick(Qt::Horizontal, rect.size());
1235 } else {
1236 space = pick(Qt::Vertical, dockWidgetItem->widget()->size());
1237 }
1238 break;
1239 }
1240 } else {
1241 for (int i = 0; i < item_list.size(); ++i) {
1243 if (item.skip())
1244 continue;
1246 "QDockAreaLayoutInfo::insertGap", "inserting two gaps after each other");
1247 space += item.size - pick(o, item.minimumSize());
1248 qCDebug(lcQpaDockWidgets) << "Item space:" << item.flags << this;
1249 }
1250 }
1251
1252 // find the actual size of the gap
1253 int gap_size = 0;
1254 int sep_size = 0;
1255 if (isEmpty()) {
1256 gap_size = space;
1257 sep_size = 0;
1258 } else {
1259 QRect r = dockedGeometry(dockWidgetItem->widget());
1260 gap_size = pick(o, r.size());
1262 sep_size += *sep;
1264 sep_size += *sep;
1265 }
1266 if (gap_size + sep_size > space)
1267 gap_size = pick(o, gap_item.minimumSize());
1268 gap_item.size = gap_size + sep_size;
1269 }
1270
1271 // finally, insert the gap
1272 item_list.insert(index, gap_item);
1273 qCDebug(lcQpaDockWidgets) << "Insert gap after:" << index << this;
1274
1275 return true;
1276}
1277
1279{
1280 for (int i = 0; i < item_list.size(); ++i) {
1282 if (item.skip())
1283 continue;
1284
1285#if QT_CONFIG(tabbar)
1286 if (tabbed && widget == tabBar)
1287 return this;
1288#endif
1289
1290 if (item.widgetItem != nullptr && item.widgetItem->widget() == widget)
1291 return this;
1292
1293 if (item.subinfo != nullptr) {
1294 if (QDockAreaLayoutInfo *result = item.subinfo->info(widget))
1295 return result;
1296 }
1297 }
1298
1299 return nullptr;
1300}
1301
1303{
1304 int index = path.first();
1305 if (index < 0)
1306 index = -index - 1;
1307 if (index >= item_list.size())
1308 return this;
1309 if (path.size() == 1 || item_list[index].subinfo == nullptr)
1310 return this;
1311 return item_list[index].subinfo->info(path.mid(1));
1312}
1313
1315{
1317
1318 if (item.skip())
1319 return QRect();
1320
1321 if (isGap && !(item.flags & QDockAreaLayoutItem::GapItem))
1322 return QRect();
1323
1324 QRect result;
1325
1326#if QT_CONFIG(tabbar)
1327 if (tabbed) {
1328 if (isGap || tabId(item) == currentTabId())
1329 result = tabContentRect();
1330 } else
1331#endif
1332 {
1333 int pos = item.pos;
1334 int size = item.size;
1335
1336 if (isGap) {
1337 int prev = this->prev(index);
1338 int next = this->next(index);
1340 pos += *sep;
1341 size -= *sep;
1342 }
1344 size -= *sep;
1345 }
1346
1347 QPoint p;
1348 rpick(o, p) = pos;
1349 rperp(o, p) = perp(o, rect.topLeft());
1350 QSize s;
1351 rpick(o, s) = size;
1352 rperp(o, s) = perp(o, rect.size());
1353 result = QRect(p, s);
1354 }
1355
1356 return result;
1357}
1358
1360{
1361 Q_ASSERT(!path.isEmpty());
1362
1363 const int index = path.first();
1364 if (path.size() > 1) {
1366 Q_ASSERT(item.subinfo != nullptr);
1367 return item.subinfo->itemRect(path.mid(1));
1368 }
1369
1370 return itemRect(index);
1371}
1372
1374{
1375#if QT_CONFIG(tabbar)
1376 if (tabbed)
1377 return QRect();
1378#endif
1379
1381 if (item.skip())
1382 return QRect();
1383
1384 QPoint pos = rect.topLeft();
1385 rpick(o, pos) = item.pos + item.size;
1386 QSize s = rect.size();
1387 rpick(o, s) = *sep;
1388
1389 return QRect(pos, s);
1390}
1391
1393{
1394 Q_ASSERT(!path.isEmpty());
1395
1396 const int index = path.first();
1397 if (path.size() > 1) {
1399 Q_ASSERT(item.subinfo != nullptr);
1400 return item.subinfo->separatorRect(path.mid(1));
1401 }
1402 return separatorRect(index);
1403}
1404
1405QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const
1406{
1407#if QT_CONFIG(tabbar)
1408 if (tabbed)
1409 return QList<int>();
1410#endif
1411
1412 int pos = pick(o, _pos);
1413
1414 for (int i = 0; i < item_list.size(); ++i) {
1416 if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
1417 continue;
1418
1419 if (item.pos + item.size > pos) {
1420 if (item.subinfo != nullptr) {
1421 QList<int> result = item.subinfo->findSeparator(_pos);
1422 if (!result.isEmpty()) {
1423 result.prepend(i);
1424 return result;
1425 } else {
1426 return QList<int>();
1427 }
1428 }
1429 }
1430
1431 int next = this->next(i);
1432 if (next == -1 || (item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
1433 continue;
1434
1435 QRect sepRect = separatorRect(i);
1436 if (!sepRect.isNull() && *sep == 1)
1437 sepRect.adjust(-2, -2, 2, 2);
1438 //we also make sure we don't find a separator that's not there
1439 if (sepRect.contains(_pos) && !item.hasFixedSize(o)) {
1440 return QList<int>() << i;
1441 }
1442
1443 }
1444
1445 return QList<int>();
1446}
1447
1448QList<int> QDockAreaLayoutInfo::indexOfPlaceHolder(const QString &objectName) const
1449{
1450 for (int i = 0; i < item_list.size(); ++i) {
1452
1453 if (item.subinfo != nullptr) {
1454 QList<int> result = item.subinfo->indexOfPlaceHolder(objectName);
1455 if (!result.isEmpty()) {
1456 result.prepend(i);
1457 return result;
1458 }
1459 continue;
1460 }
1461
1462 if (item.placeHolderItem != nullptr && item.placeHolderItem->objectName == objectName) {
1463 QList<int> result;
1464 result << i;
1465 return result;
1466 }
1467 }
1468
1469 return QList<int>();
1470}
1471
1473{
1474 for (int i = 0; i < item_list.size(); ++i) {
1476
1477 if (item.placeHolderItem != nullptr)
1478 continue;
1479
1480 if (item.subinfo != nullptr) {
1481 QList<int> result = item.subinfo->indexOf(widget);
1482 if (!result.isEmpty()) {
1483 result.prepend(i);
1484 return result;
1485 }
1486 continue;
1487 }
1488
1489 if (!(item.flags & QDockAreaLayoutItem::GapItem) && item.widgetItem && item.widgetItem->widget() == widget) {
1490 QList<int> result;
1491 result << i;
1492 return result;
1493 }
1494 }
1495
1496 return QList<int>();
1497}
1498
1505
1507{
1508 return perp(o, minimumSize()) == perp(o, maximumSize());
1509}
1510
1515{
1516 QWidgetAnimator &widgetAnimator = mainWindowLayout()->widgetAnimator;
1517
1518#if QT_CONFIG(tabbar)
1519 if (tabbed) {
1520 QRect tab_rect;
1521 QSize tbh = tabBarSizeHint();
1522
1523 if (!tbh.isNull()) {
1524 switch (tabBarShape) {
1527 tab_rect = QRect(rect.left(), rect.top(), rect.width(), tbh.height());
1528 break;
1531 tab_rect = QRect(rect.left(), rect.bottom() - tbh.height() + 1,
1532 rect.width(), tbh.height());
1533 break;
1536 tab_rect = QRect(rect.right() - tbh.width() + 1, rect.top(),
1537 tbh.width(), rect.height());
1538 break;
1541 tab_rect = QRect(rect.left(), rect.top(),
1542 tbh.width(), rect.height());
1543 break;
1544 default:
1545 break;
1546 }
1547 }
1548
1549 widgetAnimator.animate(tabBar, tab_rect, animate);
1550 }
1551#endif // QT_CONFIG(tabbar)
1552
1553 QDockWidget *activated = nullptr;
1554
1555 for (int i = 0; i < item_list.size(); ++i) {
1557
1559 continue;
1560
1561 if (item.subinfo != nullptr) {
1562 item.subinfo->apply(animate);
1563 continue;
1564 }
1565
1566 if (item.skip())
1567 continue;
1568
1569 Q_ASSERT(item.widgetItem);
1570 QRect r = itemRect(i);
1571 QWidget *w = item.widgetItem->widget();
1572
1573 QRect geo = w->geometry();
1574 widgetAnimator.animate(w, r, animate);
1575 if (!w->isHidden() && w->window()->isVisible()) {
1576 QDockWidget *dw = qobject_cast<QDockWidget*>(w);
1577 if (!r.isValid() && geo.right() >= 0 && geo.bottom() >= 0) {
1578 dw->lower();
1579 emit dw->visibilityChanged(false);
1580 } else if (r.isValid()
1581 && (geo.right() < 0 || geo.bottom() < 0)) {
1582 emit dw->visibilityChanged(true);
1583 activated = dw;
1584 }
1585 }
1586 }
1587#if QT_CONFIG(tabbar)
1588 if (*sep == 1)
1589 updateSeparatorWidgets();
1590#endif // QT_CONFIG(tabbar)
1591
1592 return activated;
1593}
1594
1595static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over)
1596{
1597 QStyleOption opt(0);
1599 if (w->isEnabled())
1601 if (o != Qt::Horizontal)
1603 if (mouse_over)
1605 opt.rect = r;
1606 opt.palette = w->palette();
1607
1608 w->style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, p, w);
1609}
1610
1612{
1614
1615 if (isEmpty())
1616 return result;
1617#if QT_CONFIG(tabbar)
1618 if (tabbed)
1619 return result;
1620#endif
1621
1622 for (int i = 0; i < item_list.size(); ++i) {
1624
1625 if (item.skip())
1626 continue;
1627
1628 int next = this->next(i);
1629
1630 if (item.subinfo)
1631 result |= item.subinfo->separatorRegion();
1632
1633 if (next == -1)
1634 break;
1636 }
1637
1638 return result;
1639}
1640
1642 const QRegion &clip,
1643 const QPoint &mouse) const
1644{
1645 if (isEmpty())
1646 return;
1647#if QT_CONFIG(tabbar)
1648 if (tabbed)
1649 return;
1650#endif
1651
1652 for (int i = 0; i < item_list.size(); ++i) {
1654
1655 if (item.skip())
1656 continue;
1657
1658 int next = this->next(i);
1661 continue;
1662
1663 if (item.subinfo) {
1664 if (clip.contains(item.subinfo->rect))
1665 item.subinfo->paintSeparators(p, widget, clip, mouse);
1666 }
1667
1668 if (next == -1)
1669 break;
1671 if (clip.contains(r) && !item.hasFixedSize(o))
1672 paintSep(p, widget, r, o, r.contains(mouse));
1673 }
1674}
1675
1677{
1678 for (int i = index + 1; i < item_list.size(); ++i) {
1679 if (!item_list.at(i).skip())
1680 return i;
1681 }
1682 return -1;
1683}
1684
1686{
1687 for (int i = index - 1; i >= 0; --i) {
1688 if (!item_list.at(i).skip())
1689 return i;
1690 }
1691 return -1;
1692}
1693
1694#if QT_CONFIG(tabbar)
1695void QDockAreaLayoutInfo::tab(int index, QLayoutItem *dockWidgetItem)
1696{
1697 if (tabbed) {
1698 item_list.append(QDockAreaLayoutItem(dockWidgetItem));
1699 updateTabBar();
1700 setCurrentTab(dockWidgetItem->widget());
1701 } else {
1702 QDockAreaLayoutInfo *new_info
1703 = new QDockAreaLayoutInfo(sep, dockPos, o, tabBarShape, mainWindow);
1704 item_list[index].subinfo = new_info;
1705 new_info->item_list.append(QDockAreaLayoutItem(item_list.at(index).widgetItem));
1706 item_list[index].widgetItem = nullptr;
1707 new_info->item_list.append(QDockAreaLayoutItem(dockWidgetItem));
1708 new_info->tabbed = true;
1709 new_info->updateTabBar();
1710 new_info->setCurrentTab(dockWidgetItem->widget());
1711 }
1712}
1713#endif // QT_CONFIG(tabbar)
1714
1716 QLayoutItem *dockWidgetItem)
1717{
1718 if (orientation == o) {
1719 item_list.insert(index + 1, QDockAreaLayoutItem(dockWidgetItem));
1720 } else {
1721#if !QT_CONFIG(tabbar)
1722 const int tabBarShape = 0;
1723#endif
1724 QDockAreaLayoutInfo *new_info
1725 = new QDockAreaLayoutInfo(sep, dockPos, orientation, tabBarShape, mainWindow);
1726 item_list[index].subinfo = new_info;
1727 new_info->item_list.append(QDockAreaLayoutItem(item_list.at(index).widgetItem));
1728 item_list[index].widgetItem = nullptr;
1729 new_info->item_list.append(QDockAreaLayoutItem(dockWidgetItem));
1730 }
1731}
1732
1734{
1735 Q_ASSERT(!path.isEmpty());
1736 const int index = path.first();
1737 if (path.size() > 1) {
1739 Q_ASSERT(item.subinfo != nullptr);
1740 return item.subinfo->item(path.mid(1));
1741 }
1742 return item_list[index];
1743}
1744
1746{
1747 for (int i = 0; i < item_list.size(); ++i) {
1749 if (item.placeHolderItem != nullptr)
1750 continue;
1751 if (item.subinfo) {
1752 if (QLayoutItem *ret = item.subinfo->itemAt(x, index))
1753 return ret;
1754 } else if (item.widgetItem) {
1755 if ((*x)++ == index)
1756 return item.widgetItem;
1757 }
1758 }
1759 return nullptr;
1760}
1761
1763{
1764 for (int i = 0; i < item_list.size(); ++i) {
1766 if (item.placeHolderItem != nullptr)
1767 continue;
1768 else if (item.subinfo) {
1769 if (QLayoutItem *ret = item.subinfo->takeAt(x, index)) {
1770 unnest(i);
1771 return ret;
1772 }
1773 } else if (item.widgetItem) {
1774 if ((*x)++ == index) {
1775 item.placeHolderItem = new QPlaceHolderItem(item.widgetItem->widget());
1776 QLayoutItem *ret = item.widgetItem;
1777 item.widgetItem = nullptr;
1778 if (item.size != -1)
1780 return ret;
1781 }
1782 }
1783 }
1784 return nullptr;
1785}
1786
1787// Add a dock widget or dock widget group window to the item list
1789{
1790 // Do not add twice
1791 if (!indexOf(widget).isEmpty())
1792 return;
1793
1794 if (auto *dockWidget = qobject_cast<QDockWidget *>(widget)) {
1796 return;
1797 }
1798
1799 if (auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
1800 item_list.append(QDockAreaLayoutItem(new QDockWidgetGroupWindowItem(groupWindow)));
1801 return;
1802 }
1803
1804 qFatal("Coding error. Add supports only QDockWidget and QDockWidgetGroupWindow");
1805}
1806
1808{
1809 for (int i = 0; i < item_list.size(); ++i) {
1811 if (item.subinfo) {
1812 item.subinfo->deleteAllLayoutItems();
1813 } else {
1814 delete item.widgetItem;
1815 item.widgetItem = nullptr;
1816 }
1817 }
1818}
1819
1821{
1822#if QT_CONFIG(tabbar)
1823 if (tabbed) {
1824 stream << (uchar) TabMarker;
1825
1826 // write the index in item_list of the widget that's currently on top.
1827 quintptr id = currentTabId();
1828 int index = -1;
1829 for (int i = 0; i < item_list.size(); ++i) {
1830 if (tabId(item_list.at(i)) == id) {
1831 index = i;
1832 break;
1833 }
1834 }
1835 stream << index;
1836 } else
1837#endif // QT_CONFIG(tabbar)
1838 {
1840 }
1841
1842 stream << (uchar) o << int(item_list.size());
1843
1844 for (int i = 0; i < item_list.size(); ++i) {
1846 if (item.widgetItem != nullptr) {
1848 QWidget *w = item.widgetItem->widget();
1849 QString name = w->objectName();
1850 if (Q_UNLIKELY(name.isEmpty())) {
1851 qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%ls;",
1852 w, qUtf16Printable(w->windowTitle()));
1853 }
1854 stream << name;
1855
1856 uchar flags = 0;
1857 if (!w->isHidden())
1859 if (w->isWindow())
1861 stream << flags;
1862
1863 if (w->isWindow()) {
1864 const QRect geometry = w->geometry();
1865 stream << geometry.x() << geometry.y() << geometry.width() << geometry.height();
1866 } else {
1867 stream << item.pos << item.size << pick(o, item.minimumSize())
1868 << pick(o, item.maximumSize());
1869 }
1870 } else if (item.placeHolderItem != nullptr) {
1872 stream << item.placeHolderItem->objectName;
1873 uchar flags = 0;
1874 if (!item.placeHolderItem->hidden)
1876 if (item.placeHolderItem->window)
1878 stream << flags;
1879 if (item.placeHolderItem->window) {
1880 QRect r = item.placeHolderItem->topLevelRect;
1881 stream << r.x() << r.y() << r.width() << r.height();
1882 } else {
1883 stream << item.pos << item.size << (int)0 << (int)0;
1884 }
1885 } else if (item.subinfo != nullptr) {
1886 stream << (uchar) SequenceMarker << item.pos << item.size << pick(o, item.minimumSize()) << pick(o, item.maximumSize());
1887 item.subinfo->saveState(stream);
1888 }
1889 }
1890}
1891
1903
1904bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*> &widgets, bool testing)
1905{
1906 uchar marker;
1907 stream >> marker;
1909 return false;
1910
1911#if QT_CONFIG(tabbar)
1912 tabbed = marker == TabMarker;
1913
1914 int index = -1;
1915 if (tabbed)
1916 stream >> index;
1917#endif
1918
1919 uchar orientation;
1920 stream >> orientation;
1921 o = static_cast<Qt::Orientation>(orientation);
1922
1923 int cnt;
1924 stream >> cnt;
1925
1926 for (int i = 0; i < cnt; ++i) {
1927 uchar nextMarker;
1928 stream >> nextMarker;
1929 if (nextMarker == WidgetMarker) {
1930 QString name;
1931 uchar flags;
1932 stream >> name >> flags;
1933 if (name.isEmpty()) {
1934 int dummy;
1935 stream >> dummy >> dummy >> dummy >> dummy;
1936 continue;
1937 }
1938
1939 QDockWidget *widget = nullptr;
1940 for (int j = 0; j < widgets.size(); ++j) {
1941 if (widgets.at(j)->objectName() == name) {
1943 break;
1944 }
1945 }
1946
1947 if (widget == nullptr) {
1948 QPlaceHolderItem *placeHolder = new QPlaceHolderItem;
1949 QDockAreaLayoutItem item(placeHolder);
1950
1951 placeHolder->objectName = name;
1952 placeHolder->window = flags & StateFlagFloating;
1953 placeHolder->hidden = !(flags & StateFlagVisible);
1954 if (placeHolder->window) {
1955 int x, y, w, h;
1956 stream >> x >> y >> w >> h;
1957 placeHolder->topLevelRect = QRect(x, y, w, h);
1958 } else {
1959 int dummy;
1960 stream >> item.pos >> item.size >> dummy >> dummy;
1961 }
1962 if (item.size != -1)
1964 if (!testing)
1966 } else {
1968 if (flags & StateFlagFloating) {
1969 bool drawer = false;
1970
1971 if (!testing) {
1972 widget->hide();
1973 if (!drawer)
1974 widget->setFloating(true);
1975 }
1976
1977 int x, y, w, h;
1978 stream >> x >> y >> w >> h;
1979
1980 if (!testing)
1982
1983 if (!testing) {
1986 }
1987 } else {
1988 int dummy;
1989 stream >> item.pos >> item.size >> dummy >> dummy;
1990 if (!testing) {
1992 widget->setFloating(false);
1994 emit widget->dockLocationChanged(toDockWidgetArea(dockPos));
1995 }
1996 }
1997 if (testing) {
1998 //was it is not really added to the layout, we need to delete the object here
1999 delete item.widgetItem;
2000 item.widgetItem = nullptr;
2001 }
2002 }
2003 } else if (nextMarker == SequenceMarker) {
2004 int dummy;
2005#if !QT_CONFIG(tabbar)
2006 const int tabBarShape = 0;
2007#endif
2009 tabBarShape, mainWindow));
2010 stream >> item.pos >> item.size >> dummy >> dummy;
2011 //we need to make sure the element is in the list so the dock widget can eventually be docked correctly
2012 if (!testing)
2014
2015 //here we need to make sure we change the item in the item_list
2016 QDockAreaLayoutItem &lastItem = testing ? item : item_list.last();
2017
2018 if (!lastItem.subinfo->restoreState(stream, widgets, testing))
2019 return false;
2020
2021 } else {
2022 return false;
2023 }
2024 }
2025
2026#if QT_CONFIG(tabbar)
2027 if (!testing && tabbed && index >= 0 && index < item_list.size()) {
2028 updateTabBar();
2029 setCurrentTabId(tabId(item_list.at(index)));
2030 }
2031 if (!testing && *sep == 1)
2032 updateSeparatorWidgets();
2033#endif
2034
2035 return true;
2036}
2037
2038#if QT_CONFIG(tabbar)
2039void QDockAreaLayoutInfo::updateSeparatorWidgets() const
2040{
2041 if (tabbed) {
2043 return;
2044 }
2045
2046 int j = 0;
2047 for (int i = 0; i < item_list.size(); ++i) {
2049
2050 if (item.skip())
2051 continue;
2052
2053 int next = this->next(i);
2056 continue;
2057
2058 if (item.subinfo) {
2059 item.subinfo->updateSeparatorWidgets();
2060 }
2061
2062 if (next == -1)
2063 break;
2064
2065 QWidget *sepWidget;
2066 if (j < separatorWidgets.size()) {
2067 sepWidget = separatorWidgets.at(j);
2068 if (!sepWidget) {
2069 qWarning("QDockAreaLayoutInfo::updateSeparatorWidgets: null separator widget");
2070 sepWidget = mainWindowLayout()->getSeparatorWidget();
2071 separatorWidgets[j] = sepWidget;
2072 }
2073 } else {
2074 sepWidget = mainWindowLayout()->getSeparatorWidget();
2075 separatorWidgets.append(sepWidget);
2076 }
2077 j++;
2078
2079 Q_ASSERT(sepWidget);
2080 sepWidget->raise();
2081
2082 QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
2083 sepWidget->setGeometry(sepRect);
2084 sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
2085 sepWidget->show();
2086 }
2087
2088 for (int k = j; k < separatorWidgets.size(); ++k) {
2089 separatorWidgets[k]->hide();
2090 }
2092}
2093
2099void QDockAreaLayoutInfo::reparentWidgets(QWidget *parent)
2100{
2101 if (tabBar)
2102 tabBar->setParent(parent);
2103
2104 for (int i = 0; i < item_list.size(); ++i) {
2107 continue;
2108 if (item.subinfo)
2109 item.subinfo->reparentWidgets(parent);
2110 if (item.widgetItem) {
2111 QWidget *w = item.widgetItem->widget();
2112 if (qobject_cast<QDockWidgetGroupWindow *>(w))
2113 continue;
2114 if (w->parent() != parent) {
2115 bool hidden = w->isHidden();
2116 w->setParent(parent, w->windowFlags());
2117 if (!hidden)
2118 w->show();
2119 }
2120 }
2121 }
2122}
2123
2124//returns whether the tabbar is visible or not
2125bool QDockAreaLayoutInfo::updateTabBar() const
2126{
2127 if (!tabbed)
2128 return false;
2129
2130 QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this);
2131
2132 if (that->tabBar == nullptr) {
2133 that->tabBar = mainWindowLayout()->getTabBar();
2134 that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape));
2135 that->tabBar->setDrawBase(true);
2136 }
2137
2138 const QSignalBlocker blocker(tabBar);
2139 bool gap = false;
2140
2141 const quintptr oldCurrentId = currentTabId();
2142
2143 int tab_idx = 0;
2144 for (int i = 0; i < item_list.size(); ++i) {
2146 if (item.skip())
2147 continue;
2149 gap = true;
2150 continue;
2151 }
2152 if (item.widgetItem == nullptr)
2153 continue;
2154
2155 QDockWidget *dw = qobject_cast<QDockWidget*>(item.widgetItem->widget());
2156 QString title = dw->d_func()->fixedWindowTitle;
2157 quintptr id = tabId(item);
2158 if (tab_idx == tabBar->count()) {
2159 tabBar->insertTab(tab_idx, title);
2160#if QT_CONFIG(tooltip)
2161 tabBar->setTabToolTip(tab_idx, title);
2162#endif
2163 tabBar->setTabData(tab_idx, id);
2164 } else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) {
2165 if (tab_idx + 1 < tabBar->count()
2166 && qvariant_cast<quintptr>(tabBar->tabData(tab_idx + 1)) == id)
2167 tabBar->removeTab(tab_idx);
2168 else {
2169 tabBar->insertTab(tab_idx, title);
2170#if QT_CONFIG(tooltip)
2171 tabBar->setTabToolTip(tab_idx, title);
2172#endif
2173 tabBar->setTabData(tab_idx, id);
2174 }
2175 }
2176
2177 if (title != tabBar->tabText(tab_idx)) {
2178 tabBar->setTabText(tab_idx, title);
2179#if QT_CONFIG(tooltip)
2180 tabBar->setTabToolTip(tab_idx, title);
2181#endif
2182 }
2183
2184 ++tab_idx;
2185 }
2186
2187 while (tab_idx < tabBar->count()) {
2188 tabBar->removeTab(tab_idx);
2189 }
2190
2191 if (oldCurrentId > 0 && currentTabId() != oldCurrentId)
2192 that->setCurrentTabId(oldCurrentId);
2193
2194 if (QDockWidgetGroupWindow *dwgw = qobject_cast<QDockWidgetGroupWindow *>(tabBar->parent()))
2195 dwgw->adjustFlags();
2196
2197 //returns if the tabbar is visible or not
2198 return ( (gap ? 1 : 0) + tabBar->count()) > 1;
2199}
2200
2201void QDockAreaLayoutInfo::setTabBarShape(int shape)
2202{
2203 if (shape == tabBarShape)
2204 return;
2205 tabBarShape = shape;
2206 if (tabBar != nullptr)
2207 tabBar->setShape(static_cast<QTabBar::Shape>(shape));
2208
2209 for (int i = 0; i < item_list.size(); ++i) {
2211 if (item.subinfo != nullptr)
2212 item.subinfo->setTabBarShape(shape);
2213 }
2214}
2215
2216QSize QDockAreaLayoutInfo::tabBarMinimumSize() const
2217{
2218 if (!updateTabBar())
2219 return QSize(0, 0);
2220
2221 return tabBar->minimumSizeHint();
2222}
2223
2224QSize QDockAreaLayoutInfo::tabBarSizeHint() const
2225{
2226 if (!updateTabBar())
2227 return QSize(0, 0);
2228
2229 return tabBar->sizeHint();
2230}
2231
2232QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const
2233{
2234 QSet<QTabBar*> result;
2235
2236 if (tabbed) {
2237 updateTabBar();
2238 result.insert(tabBar);
2239 }
2240
2241 for (int i = 0; i < item_list.size(); ++i) {
2243 if (item.subinfo != nullptr)
2244 result += item.subinfo->usedTabBars();
2245 }
2246
2247 return result;
2248}
2249
2250// returns a set of all used separator widgets for this dockarelayout info
2251// and all subinfos
2252QSet<QWidget*> QDockAreaLayoutInfo::usedSeparatorWidgets() const
2253{
2254 QSet<QWidget*> result;
2255 const int numSeparatorWidgets = separatorWidgets.size();
2256 result.reserve(numSeparatorWidgets);
2257
2258 for (int i = 0; i < numSeparatorWidgets; ++i)
2260
2261 for (int i = 0; i < item_list.size(); ++i) {
2263 if (item.subinfo != nullptr)
2264 result += item.subinfo->usedSeparatorWidgets();
2265 }
2266
2267 return result;
2268}
2269
2270QRect QDockAreaLayoutInfo::tabContentRect() const
2271{
2272 if (!tabbed)
2273 return QRect();
2274
2275 QRect result = rect;
2276 QSize tbh = tabBarSizeHint();
2277
2278 if (!tbh.isNull()) {
2279 switch (tabBarShape) {
2282 result.adjust(0, tbh.height(), 0, 0);
2283 break;
2286 result.adjust(0, 0, 0, -tbh.height());
2287 break;
2290 result.adjust(0, 0, -tbh.width(), 0);
2291 break;
2294 result.adjust(tbh.width(), 0, 0, 0);
2295 break;
2296 default:
2297 break;
2298 }
2299 }
2300
2301 return result;
2302}
2303
2304int QDockAreaLayoutInfo::tabIndexToListIndex(int tabIndex) const
2305{
2306 Q_ASSERT(tabbed && tabBar);
2307 quintptr data = qvariant_cast<quintptr>(tabBar->tabData(tabIndex));
2308 for (int i = 0; i < item_list.size(); ++i) {
2309 if (tabId(item_list.at(i)) == data)
2310 return i;
2311 }
2312 return -1;
2313}
2314
2315void QDockAreaLayoutInfo::moveTab(int from, int to)
2316{
2317 item_list.move(tabIndexToListIndex(from), tabIndexToListIndex(to));
2318}
2319#endif // QT_CONFIG(tabbar)
2320
2321/******************************************************************************
2322** QDockAreaLayout
2323*/
2324
2350
2352{
2353 return rect.isValid();
2354}
2355
2357{
2359 int cnt = 0;
2360 for (int i = 0; i < QInternal::DockCount; ++i) {
2361 if (!docks[i].item_list.isEmpty())
2362 ++cnt;
2363 }
2364 stream << cnt;
2365 for (int i = 0; i < QInternal::DockCount; ++i) {
2366 if (docks[i].item_list.isEmpty())
2367 continue;
2368 stream << i << docks[i].rect.size();
2370 }
2371
2373
2374 for (int i = 0; i < 4; ++i)
2375 stream << static_cast<int>(corners[i]);
2376}
2377
2378bool QDockAreaLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &_dockwidgets, bool testing)
2379{
2380 QList<QDockWidget*> dockwidgets = _dockwidgets;
2381
2382 int cnt;
2383 stream >> cnt;
2384 for (int i = 0; i < cnt; ++i) {
2385 int pos;
2386 stream >> pos;
2387 QSize size;
2388 stream >> size;
2389 if (!testing) {
2390 docks[pos].rect = QRect(QPoint(0, 0), size);
2391 }
2392 if (!docks[pos].restoreState(stream, dockwidgets, testing)) {
2393 stream.setStatus(QDataStream::ReadCorruptData);
2394 return false;
2395 }
2396 }
2397
2398 QSize size;
2399 stream >> size;
2401
2402 bool ok = stream.status() == QDataStream::Ok;
2403
2404 if (ok) {
2405 int cornerData[4];
2406 for (int i = 0; i < 4; ++i)
2407 stream >> cornerData[i];
2408 if (stream.status() == QDataStream::Ok) {
2409 for (int i = 0; i < 4; ++i)
2410 corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]);
2411 }
2412
2413 if (!testing)
2414 fallbackToSizeHints = false;
2415 }
2416
2417 return ok;
2418}
2419
2420QList<int> QDockAreaLayout::indexOfPlaceHolder(const QString &objectName) const
2421{
2422 for (int i = 0; i < QInternal::DockCount; ++i) {
2423 QList<int> result = docks[i].indexOfPlaceHolder(objectName);
2424 if (!result.isEmpty()) {
2425 result.prepend(i);
2426 return result;
2427 }
2428 }
2429 return QList<int>();
2430}
2431
2433{
2434 for (int i = 0; i < QInternal::DockCount; ++i) {
2435 QList<int> result = docks[i].indexOf(dockWidget);
2436 if (!result.isEmpty()) {
2437 result.prepend(i);
2438 return result;
2439 }
2440 }
2441 return QList<int>();
2442}
2443
2444QList<int> QDockAreaLayout::gapIndex(const QPoint &pos, bool disallowTabs) const
2445{
2446 QMainWindow::DockOptions opts = mainWindow->dockOptions();
2447 bool nestingEnabled = opts & QMainWindow::AllowNestedDocks;
2449#if QT_CONFIG(tabbar)
2450 if (!disallowTabs) {
2455
2456 if (tabMode == QDockAreaLayoutInfo::ForceTabs)
2457 nestingEnabled = false;
2458 }
2459#endif
2460
2461
2462 for (int i = 0; i < QInternal::DockCount; ++i) {
2463 const QDockAreaLayoutInfo &info = docks[i];
2464
2465 if (!info.isEmpty() && info.rect.contains(pos)) {
2466 QList<int> result
2467 = docks[i].gapIndex(pos, nestingEnabled, tabMode);
2468 if (!result.isEmpty())
2469 result.prepend(i);
2470 return result;
2471 }
2472 }
2473
2474 for (int i = 0; i < QInternal::DockCount; ++i) {
2475 const QDockAreaLayoutInfo &info = docks[i];
2476
2477 if (info.isEmpty()) {
2478 const QRect r = gapRect(static_cast<QInternal::DockPosition>(i));
2479 if (r.contains(pos)) {
2480 if (opts & QMainWindow::ForceTabbedDocks && !info.item_list.isEmpty()) {
2481 //in case of ForceTabbedDocks, we pass -1 in order to force the gap to be tabbed
2482 //it mustn't be completely empty otherwise it won't work
2483 return QList<int>() << i << -1 << 0;
2484 } else {
2485 return QList<int>() << i << 0;
2486 }
2487 }
2488 }
2489 }
2490
2491 return QList<int>();
2492}
2493
2495{
2496 Q_ASSERT_X(mainWindow, "QDockAreaLayout::gapRect", "Called without valid mainWindow pointer.");
2497
2498 // Determine gap size depending on MainWindow size (QTBUG-101657)
2499 const QSize gapSize = (mainWindow->size()/2).boundedTo(QSize(EmptyDropAreaSize, EmptyDropAreaSize));
2500
2501 // Warn if main window is too small to create proper docks.
2502 // Do not fail because this can be triggered by a user making MainWindow too small
2503 if (mainWindow->height() < (2 * sep)) {
2504 qCWarning(lcQpaDockWidgets,
2505 "QDockAreaLayout::gapRect: Main window height %i is too small. Docking will not be possible.",
2506 mainWindow->height());
2507
2508 }
2509 if (mainWindow->width() < (2 * sep)) {
2510 qCWarning(lcQpaDockWidgets,
2511 "QDockAreaLayout::gapRect: Main window width %i is too small. Docking will not be possible.",
2512 mainWindow->width());
2513 }
2514
2515 // Calculate rectangle of requested dock
2516 switch (dockPos) {
2518 return QRect(rect.left(), rect.top(), gapSize.width(), rect.height());
2520 return QRect(rect.right() - gapSize.width(), rect.top(), gapSize.width(), rect.height());
2521 case QInternal::TopDock:
2522 return QRect(rect.left(), rect.top(), rect.width(), gapSize.height());
2524 return QRect(rect.left(), rect.bottom() - gapSize.height(), rect.width(), gapSize.height());
2526 break;
2527 }
2528 return QRect();
2529}
2530
2532{
2533 QList<int> result;
2534 for (int i = 0; i < QInternal::DockCount; ++i) {
2535 const QDockAreaLayoutInfo &info = docks[i];
2536 if (info.isEmpty())
2537 continue;
2539 if (!rect.isNull() && sep == 1)
2540 rect.adjust(-2, -2, 2, 2);
2541 if (rect.contains(pos) && !info.hasFixedSize()) {
2542 result << i;
2543 break;
2544 } else if (info.rect.contains(pos)) {
2546 if (!result.isEmpty()) {
2547 result.prepend(i);
2548 break;
2549 }
2550 }
2551 }
2552
2553 return result;
2554}
2555
2557{
2558 for (int i = 0; i < QInternal::DockCount; ++i) {
2560 return result;
2561 }
2562
2563 return nullptr;
2564}
2565
2567{
2568 Q_ASSERT(!path.isEmpty());
2569 const int index = path.first();
2571
2572 if (path.size() == 1)
2573 return &docks[index];
2574
2575 return docks[index].info(path.mid(1));
2576}
2577
2578const QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) const
2579{
2580 return const_cast<QDockAreaLayout*>(this)->info(path);
2581}
2582
2584{
2585 Q_ASSERT(!path.isEmpty());
2586 const int index = path.first();
2588 return docks[index].item(path.mid(1));
2589}
2590
2591QRect QDockAreaLayout::itemRect(const QList<int> &path) const
2592{
2593 Q_ASSERT(!path.isEmpty());
2594 const int index = path.first();
2596 return docks[index].itemRect(path.mid(1));
2597}
2598
2600{
2601 const QDockAreaLayoutInfo &dock = docks[index];
2602 if (dock.isEmpty())
2603 return QRect();
2604 QRect r = dock.rect;
2605 switch (index) {
2607 return QRect(r.right() + 1, r.top(), sep, r.height());
2609 return QRect(r.left() - sep, r.top(), sep, r.height());
2610 case QInternal::TopDock:
2611 return QRect(r.left(), r.bottom() + 1, r.width(), sep);
2613 return QRect(r.left(), r.top() - sep, r.width(), sep);
2614 default:
2615 break;
2616 }
2617 return QRect();
2618}
2619
2621{
2622 Q_ASSERT(!path.isEmpty());
2623
2624 const int index = path.first();
2626
2627 if (path.size() == 1)
2628 return separatorRect(index);
2629 else
2630 return docks[index].separatorRect(path.mid(1));
2631}
2632
2633bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
2634{
2635 Q_ASSERT(!path.isEmpty());
2636 const int index = path.first();
2638 return docks[index].insertGap(path.mid(1), dockWidgetItem);
2639}
2640
2642{
2643#if QT_CONFIG(tabbar)
2644 Q_ASSERT(!path.isEmpty());
2645 const int index = path.first();
2647 QLayoutItem *item = docks[index].plug(path.mid(1));
2648 docks[index].reparentWidgets(mainWindow);
2649 return item;
2650#else
2651 return nullptr;
2652#endif
2653}
2654
2656{
2657 Q_ASSERT(!path.isEmpty());
2658 const int index = path.first();
2660 return docks[index].unplug(path.mid(1));
2661}
2662
2663void QDockAreaLayout::remove(const QList<int> &path)
2664{
2665 Q_ASSERT(!path.isEmpty());
2666 const int index = path.first();
2668 docks[index].remove(path.mid(1));
2669}
2670
2672{
2673 QList<int> index = indexOfPlaceHolder(name);
2674 if (!index.isEmpty())
2675 remove(index);
2676 const auto groups =
2677 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
2678 for (QDockWidgetGroupWindow *dwgw : groups) {
2679 index = dwgw->layoutInfo()->indexOfPlaceHolder(name);
2680 if (!index.isEmpty()) {
2681 dwgw->layoutInfo()->remove(index);
2682 dwgw->destroyOrHideIfEmpty();
2683 }
2684 }
2685}
2686
2687static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); }
2688
2689void QDockAreaLayout::getGrid(QList<QLayoutStruct> *_ver_struct_list,
2690 QList<QLayoutStruct> *_hor_struct_list)
2691{
2692 QSize center_hint(0, 0);
2693 QSize center_min(0, 0);
2694 QSize center_max(0, 0);
2695 const bool have_central = centralWidgetItem != nullptr && !centralWidgetItem->isEmpty();
2696 if (have_central) {
2697 center_hint = centralWidgetRect.size();
2698 if (!center_hint.isValid())
2699 center_hint = centralWidgetItem->sizeHint();
2700 center_min = centralWidgetItem->minimumSize();
2701 center_max = centralWidgetItem->maximumSize();
2702 }
2703
2704 QRect center_rect = rect;
2705 if (!docks[QInternal::LeftDock].isEmpty())
2706 center_rect.setLeft(rect.left() + docks[QInternal::LeftDock].rect.width() + sep);
2707 if (!docks[QInternal::TopDock].isEmpty())
2708 center_rect.setTop(rect.top() + docks[QInternal::TopDock].rect.height() + sep);
2709 if (!docks[QInternal::RightDock].isEmpty())
2710 center_rect.setRight(rect.right() - docks[QInternal::RightDock].rect.width() - sep);
2711 if (!docks[QInternal::BottomDock].isEmpty())
2712 center_rect.setBottom(rect.bottom() - docks[QInternal::BottomDock].rect.height() - sep);
2713
2714 QSize left_hint = docks[QInternal::LeftDock].size();
2715 if (left_hint.isNull() || fallbackToSizeHints)
2716 left_hint = docks[QInternal::LeftDock].sizeHint();
2719 left_hint = left_hint.boundedTo(left_max).expandedTo(left_min);
2720
2721 QSize right_hint = docks[QInternal::RightDock].size();
2722 if (right_hint.isNull() || fallbackToSizeHints)
2723 right_hint = docks[QInternal::RightDock].sizeHint();
2726 right_hint = right_hint.boundedTo(right_max).expandedTo(right_min);
2727
2728 QSize top_hint = docks[QInternal::TopDock].size();
2729 if (top_hint.isNull() || fallbackToSizeHints)
2730 top_hint = docks[QInternal::TopDock].sizeHint();
2733 top_hint = top_hint.boundedTo(top_max).expandedTo(top_min);
2734
2735 QSize bottom_hint = docks[QInternal::BottomDock].size();
2736 if (bottom_hint.isNull() || fallbackToSizeHints)
2737 bottom_hint = docks[QInternal::BottomDock].sizeHint();
2740 bottom_hint = bottom_hint.boundedTo(bottom_max).expandedTo(bottom_min);
2741
2742 if (_ver_struct_list != nullptr) {
2743 QList<QLayoutStruct> &ver_struct_list = *_ver_struct_list;
2744 ver_struct_list.resize(3);
2745
2746 // top --------------------------------------------------
2747 ver_struct_list[0].init();
2748 ver_struct_list[0].stretch = 0;
2749 ver_struct_list[0].sizeHint = top_hint.height();
2750 ver_struct_list[0].minimumSize = top_min.height();
2751 ver_struct_list[0].maximumSize = top_max.height();
2752 ver_struct_list[0].expansive = false;
2753 ver_struct_list[0].empty = docks[QInternal::TopDock].isEmpty();
2754 ver_struct_list[0].pos = docks[QInternal::TopDock].rect.top();
2755 ver_struct_list[0].size = docks[QInternal::TopDock].rect.height();
2756
2757 // center --------------------------------------------------
2758 ver_struct_list[1].init();
2759 ver_struct_list[1].stretch = center_hint.height();
2760
2761 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
2763 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
2765 bool tr_significant = corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
2769
2770 int left = (tl_significant && bl_significant) ? left_hint.height() : 0;
2771 int right = (tr_significant && br_significant) ? right_hint.height() : 0;
2772 ver_struct_list[1].sizeHint = qMax(left, center_hint.height(), right);
2773
2774 left = (tl_significant && bl_significant) ? left_min.height() : 0;
2775 right = (tr_significant && br_significant) ? right_min.height() : 0;
2776 ver_struct_list[1].minimumSize = qMax(left, center_min.height(), right);
2777 ver_struct_list[1].maximumSize = center_max.height();
2778 ver_struct_list[1].expansive = have_central;
2779 ver_struct_list[1].empty = docks[QInternal::LeftDock].isEmpty()
2780 && !have_central
2782 ver_struct_list[1].pos = center_rect.top();
2783 ver_struct_list[1].size = center_rect.height();
2784
2785 // bottom --------------------------------------------------
2786 ver_struct_list[2].init();
2787 ver_struct_list[2].stretch = 0;
2788 ver_struct_list[2].sizeHint = bottom_hint.height();
2789 ver_struct_list[2].minimumSize = bottom_min.height();
2790 ver_struct_list[2].maximumSize = bottom_max.height();
2791 ver_struct_list[2].expansive = false;
2792 ver_struct_list[2].empty = docks[QInternal::BottomDock].isEmpty();
2793 ver_struct_list[2].pos = docks[QInternal::BottomDock].rect.top();
2794 ver_struct_list[2].size = docks[QInternal::BottomDock].rect.height();
2795
2796 for (int i = 0; i < 3; ++i) {
2797 ver_struct_list[i].sizeHint
2798 = qMax(ver_struct_list[i].sizeHint, ver_struct_list[i].minimumSize);
2799 }
2800 if (have_central && ver_struct_list[0].empty && ver_struct_list[2].empty)
2801 ver_struct_list[1].maximumSize = QWIDGETSIZE_MAX;
2802 }
2803
2804 if (_hor_struct_list != nullptr) {
2805 QList<QLayoutStruct> &hor_struct_list = *_hor_struct_list;
2806 hor_struct_list.resize(3);
2807
2808 // left --------------------------------------------------
2809 hor_struct_list[0].init();
2810 hor_struct_list[0].stretch = 0;
2811 hor_struct_list[0].sizeHint = left_hint.width();
2812 hor_struct_list[0].minimumSize = left_min.width();
2813 hor_struct_list[0].maximumSize = left_max.width();
2814 hor_struct_list[0].expansive = false;
2815 hor_struct_list[0].empty = docks[QInternal::LeftDock].isEmpty();
2816 hor_struct_list[0].pos = docks[QInternal::LeftDock].rect.left();
2817 hor_struct_list[0].size = docks[QInternal::LeftDock].rect.width();
2818
2819 // center --------------------------------------------------
2820 hor_struct_list[1].init();
2821 hor_struct_list[1].stretch = center_hint.width();
2822
2823 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
2825 bool tr_significant = corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
2827 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
2829 bool br_significant = corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
2831
2832 int top = (tl_significant && tr_significant) ? top_hint.width() : 0;
2833 int bottom = (bl_significant && br_significant) ? bottom_hint.width() : 0;
2834 hor_struct_list[1].sizeHint = qMax(top, center_hint.width(), bottom);
2835
2836 top = (tl_significant && tr_significant) ? top_min.width() : 0;
2837 bottom = (bl_significant && br_significant) ? bottom_min.width() : 0;
2838 hor_struct_list[1].minimumSize = qMax(top, center_min.width(), bottom);
2839
2840 hor_struct_list[1].maximumSize = center_max.width();
2841 hor_struct_list[1].expansive = have_central;
2842 hor_struct_list[1].empty = !have_central;
2843 hor_struct_list[1].pos = center_rect.left();
2844 hor_struct_list[1].size = center_rect.width();
2845
2846 // right --------------------------------------------------
2847 hor_struct_list[2].init();
2848 hor_struct_list[2].stretch = 0;
2849 hor_struct_list[2].sizeHint = right_hint.width();
2850 hor_struct_list[2].minimumSize = right_min.width();
2851 hor_struct_list[2].maximumSize = right_max.width();
2852 hor_struct_list[2].expansive = false;
2853 hor_struct_list[2].empty = docks[QInternal::RightDock].isEmpty();
2854 hor_struct_list[2].pos = docks[QInternal::RightDock].rect.left();
2855 hor_struct_list[2].size = docks[QInternal::RightDock].rect.width();
2856
2857 for (int i = 0; i < 3; ++i) {
2858 hor_struct_list[i].sizeHint
2859 = qMax(hor_struct_list[i].sizeHint, hor_struct_list[i].minimumSize);
2860 }
2861 if (have_central && hor_struct_list[0].empty && hor_struct_list[2].empty)
2862 hor_struct_list[1].maximumSize = QWIDGETSIZE_MAX;
2863
2864 }
2865}
2866
2867void QDockAreaLayout::setGrid(QList<QLayoutStruct> *ver_struct_list,
2868 QList<QLayoutStruct> *hor_struct_list)
2869{
2870
2871 // top ---------------------------------------------------
2872
2873 if (!docks[QInternal::TopDock].isEmpty()) {
2875 if (hor_struct_list != nullptr) {
2877 || docks[QInternal::LeftDock].isEmpty()
2878 ? rect.left() : hor_struct_list->at(1).pos);
2880 || docks[QInternal::RightDock].isEmpty()
2881 ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
2882 }
2883 if (ver_struct_list != nullptr) {
2884 r.setTop(rect.top());
2885 r.setBottom(ver_struct_list->at(1).pos - sep - 1);
2886 }
2889 }
2890
2891 // bottom ---------------------------------------------------
2892
2893 if (!docks[QInternal::BottomDock].isEmpty()) {
2895 if (hor_struct_list != nullptr) {
2897 || docks[QInternal::LeftDock].isEmpty()
2898 ? rect.left() : hor_struct_list->at(1).pos);
2900 || docks[QInternal::RightDock].isEmpty()
2901 ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
2902 }
2903 if (ver_struct_list != nullptr) {
2904 r.setTop(ver_struct_list->at(2).pos);
2905 r.setBottom(rect.bottom());
2906 }
2909 }
2910
2911 // left ---------------------------------------------------
2912
2913 if (!docks[QInternal::LeftDock].isEmpty()) {
2915 if (hor_struct_list != nullptr) {
2916 r.setLeft(rect.left());
2917 r.setRight(hor_struct_list->at(1).pos - sep - 1);
2918 }
2919 if (ver_struct_list != nullptr) {
2921 || docks[QInternal::TopDock].isEmpty()
2922 ? rect.top() : ver_struct_list->at(1).pos);
2924 || docks[QInternal::BottomDock].isEmpty()
2925 ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
2926 }
2929 }
2930
2931 // right ---------------------------------------------------
2932
2933 if (!docks[QInternal::RightDock].isEmpty()) {
2935 if (hor_struct_list != nullptr) {
2936 r.setLeft(hor_struct_list->at(2).pos);
2937 r.setRight(rect.right());
2938 }
2939 if (ver_struct_list != nullptr) {
2941 || docks[QInternal::TopDock].isEmpty()
2942 ? rect.top() : ver_struct_list->at(1).pos);
2944 || docks[QInternal::BottomDock].isEmpty()
2945 ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
2946 }
2949 }
2950
2951 // center ---------------------------------------------------
2952
2953 if (hor_struct_list != nullptr) {
2954 centralWidgetRect.setLeft(hor_struct_list->at(1).pos);
2955 centralWidgetRect.setWidth(hor_struct_list->at(1).size);
2956 }
2957 if (ver_struct_list != nullptr) {
2958 centralWidgetRect.setTop(ver_struct_list->at(1).pos);
2959 centralWidgetRect.setHeight(ver_struct_list->at(1).size);
2960 }
2961}
2962
2964{
2965 QList<QLayoutStruct> ver_struct_list(3);
2966 QList<QLayoutStruct> hor_struct_list(3);
2967 getGrid(&ver_struct_list, &hor_struct_list);
2968
2969 qGeomCalc(ver_struct_list, 0, 3, rect.top(), rect.height(), sep);
2970 qGeomCalc(hor_struct_list, 0, 3, rect.left(), rect.width(), sep);
2971
2972 setGrid(&ver_struct_list, &hor_struct_list);
2973}
2974
2976{
2977 for (int i = 0; i < QInternal::DockCount; ++i)
2978 docks[i].clear();
2979
2980 rect = QRect();
2982}
2983
2984template<typename SizePMF, typename CenterPMF>
2985QSize QDockAreaLayout::size_helper(SizePMF sizeFn, CenterPMF centerFn) const
2986{
2987 int left_sep = 0;
2988 int right_sep = 0;
2989 int top_sep = 0;
2990 int bottom_sep = 0;
2991
2992 if (centralWidgetItem != nullptr) {
2993 left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
2994 right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
2995 top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
2996 bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
2997 }
2998
2999 const QSize left = (docks[QInternal::LeftDock].*sizeFn)() + QSize(left_sep, 0);
3000 const QSize right = (docks[QInternal::RightDock].*sizeFn)() + QSize(right_sep, 0);
3001 const QSize top = (docks[QInternal::TopDock].*sizeFn)() + QSize(0, top_sep);
3002 const QSize bottom = (docks[QInternal::BottomDock].*sizeFn)() + QSize(0, bottom_sep);
3003 const QSize center = centralWidgetItem == nullptr
3004 ? QSize(0, 0) : (centralWidgetItem->*centerFn)();
3005
3006 int row1 = top.width();
3007 int row2 = left.width() + center.width() + right.width();
3008 int row3 = bottom.width();
3009 int col1 = left.height();
3010 int col2 = top.height() + center.height() + bottom.height();
3011 int col3 = right.height();
3012
3014 row1 += left.width();
3015 else
3016 col1 += top.height();
3017
3019 row1 += right.width();
3020 else
3021 col3 += top.height();
3022
3024 row3 += left.width();
3025 else
3026 col1 += bottom.height();
3027
3029 row3 += right.width();
3030 else
3031 col3 += bottom.height();
3032
3033 return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
3034}
3035
3040
3045
3055
3063{
3064 QScreen *screen = nullptr;
3065 if (QGuiApplication::primaryScreen()->virtualSiblings().size() > 1)
3067 if (!screen)
3068 screen = widget->screen();
3069
3070 const QRect screenRect = screen->geometry();
3071 if (screenRect.isValid()) {
3072 rect.setWidth(qMin(rect.width(), screenRect.width()));
3073 rect.setHeight(qMin(rect.height(), screenRect.height()));
3074 rect.moveLeft(qMax(rect.left(), screenRect.left()));
3075 rect.moveTop(qMax(rect.top(), screenRect.top()));
3076 rect.moveRight(qMin(rect.right(), screenRect.right()));
3077 rect.moveBottom(qMin(rect.bottom(), screenRect.bottom()));
3078 }
3079
3080 return rect;
3081}
3082
3084{
3085 QDockAreaLayoutItem *item = nullptr;
3086 const auto groups =
3087 mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
3088 for (QDockWidgetGroupWindow *dwgw : groups) {
3089 QList<int> index = dwgw->layoutInfo()->indexOfPlaceHolder(dockWidget->objectName());
3090 if (!index.isEmpty()) {
3091 dockWidget->setParent(dwgw);
3092 item = const_cast<QDockAreaLayoutItem *>(&dwgw->layoutInfo()->item(index));
3093 break;
3094 }
3095 }
3096 if (!item) {
3098 if (index.isEmpty())
3099 return false;
3100 item = const_cast<QDockAreaLayoutItem *>(&this->item(index));
3101 }
3102
3103 QPlaceHolderItem *placeHolder = item->placeHolderItem;
3104 Q_ASSERT(placeHolder != nullptr);
3105
3106 item->widgetItem = new QDockWidgetItem(dockWidget);
3107
3108 if (placeHolder->window) {
3109 const QRect r = constrainedRect(placeHolder->topLevelRect, dockWidget);
3110 dockWidget->d_func()->setWindowState(true, true, r);
3111 }
3112 dockWidget->setVisible(!placeHolder->hidden);
3113
3114 item->placeHolderItem = nullptr;
3115 delete placeHolder;
3116
3117 return true;
3118}
3119
3121 Qt::Orientation orientation)
3122{
3123 QLayoutItem *dockWidgetItem = new QDockWidgetItem(dockWidget);
3125 if (orientation == info.o || info.item_list.size() <= 1) {
3126 // empty dock areas, or dock areas containing exactly one widget can have their orientation
3127 // switched.
3128 info.o = orientation;
3129
3130 QDockAreaLayoutItem new_item(dockWidgetItem);
3131 info.item_list.append(new_item);
3132#if QT_CONFIG(tabbar)
3133 if (info.tabbed && !new_item.skip()) {
3134 info.updateTabBar();
3135 info.setCurrentTabId(tabId(new_item));
3136 }
3137#endif
3138 } else {
3139#if QT_CONFIG(tabbar)
3140 int tbshape = info.tabBarShape;
3141#else
3142 int tbshape = 0;
3143#endif
3144 QDockAreaLayoutInfo new_info(&sep, pos, orientation, tbshape, mainWindow);
3145 new_info.item_list.append(QDockAreaLayoutItem(new QDockAreaLayoutInfo(info)));
3146 new_info.item_list.append(QDockAreaLayoutItem(dockWidgetItem));
3147 info = new_info;
3148 }
3149
3151}
3152
3153#if QT_CONFIG(tabbar)
3154void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
3155{
3156 const QList<int> path = indexOf(first);
3157 if (path.isEmpty())
3158 return;
3159
3160 QDockAreaLayoutInfo *info = this->info(path);
3161 Q_ASSERT(info != nullptr);
3162 info->tab(path.last(), new QDockWidgetItem(second));
3163
3164 removePlaceHolder(second->objectName());
3165}
3166#endif // QT_CONFIG(tabbar)
3167
3168void QDockAreaLayout::resizeDocks(const QList<QDockWidget *> &docks,
3169 const QList<int> &sizes, Qt::Orientation o)
3170{
3171 if (Q_UNLIKELY(docks.size() != sizes.size())) {
3172 qWarning("QMainWidget::resizeDocks: size of the lists are not the same");
3173 return;
3174 }
3175 int count = docks.size();
3176 fallbackToSizeHints = false;
3177 for (int i = 0; i < count; ++i) {
3178 QList<int> path = indexOf(docks[i]);
3179 if (Q_UNLIKELY(path.isEmpty())) {
3180 qWarning("QMainWidget::resizeDocks: one QDockWidget is not part of the layout");
3181 continue;
3182 }
3183 int size = sizes[i];
3184 if (Q_UNLIKELY(size <= 0)) {
3185 qWarning("QMainWidget::resizeDocks: all sizes need to be larger than 0");
3186 size = 1;
3187 }
3188
3189 while (path.size() > 1) {
3190 QDockAreaLayoutInfo *info = this->info(path);
3191#if QT_CONFIG(tabbar)
3192 if (!info->tabbed && info->o == o) {
3193 info->item_list[path.constLast()].size = size;
3194 int totalSize = 0;
3195 for (const QDockAreaLayoutItem &item : std::as_const(info->item_list)) {
3196 if (!item.skip()) {
3197 if (totalSize != 0)
3198 totalSize += sep;
3199 totalSize += item.size == -1 ? pick(o, item.sizeHint()) : item.size;
3200 }
3201 }
3202 size = totalSize;
3203 }
3204#endif // QT_CONFIG(tabbar)
3205 path.removeLast();
3206 }
3207
3208 const int dockNum = path.constFirst();
3209 Q_ASSERT(dockNum < QInternal::DockCount);
3210 QRect &r = this->docks[dockNum].rect;
3211 QSize s = r.size();
3212 rpick(o, s) = size;
3213 r.setSize(s);
3214 }
3215}
3216
3219 Qt::Orientation orientation)
3220{
3221 const QList<int> path = indexOf(after);
3222 if (path.isEmpty())
3223 return;
3224
3225 QDockAreaLayoutInfo *info = this->info(path);
3226 Q_ASSERT(info != nullptr);
3227 info->split(path.last(), orientation, new QDockWidgetItem(dockWidget));
3228
3230}
3231
3232void QDockAreaLayout::apply(bool animate)
3233{
3235
3236 for (int i = 0; i < QInternal::DockCount; ++i)
3237 docks[i].apply(animate);
3238 if (centralWidgetItem != nullptr && !centralWidgetItem->isEmpty()) {
3240 animate);
3241 }
3242#if QT_CONFIG(tabbar)
3243 if (sep == 1)
3244 updateSeparatorWidgets();
3245#endif // QT_CONFIG(tabbar)
3246}
3247
3249 const QRegion &clip,
3250 const QPoint &mouse) const
3251{
3252 for (int i = 0; i < QInternal::DockCount; ++i) {
3253 const QDockAreaLayoutInfo &dock = docks[i];
3254 if (dock.isEmpty())
3255 continue;
3257 if (clip.contains(r) && !dock.hasFixedSize()) {
3258 Qt::Orientation opposite = dock.o == Qt::Horizontal
3260 paintSep(p, widget, r, opposite, r.contains(mouse));
3261 }
3262 if (clip.contains(dock.rect))
3263 dock.paintSeparators(p, widget, clip, mouse);
3264 }
3265}
3266
3268{
3270
3271 for (int i = 0; i < QInternal::DockCount; ++i) {
3272 const QDockAreaLayoutInfo &dock = docks[i];
3273 if (dock.isEmpty())
3274 continue;
3276 result |= dock.separatorRegion();
3277 }
3278
3279 return result;
3280}
3281
3282int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &origin,
3283 const QPoint &dest)
3284{
3285 int delta = 0;
3286 int index = separator.last();
3287
3288 if (separator.size() > 1) {
3289 QDockAreaLayoutInfo *info = this->info(separator);
3290 delta = pick(info->o, dest - origin);
3291 if (delta != 0)
3292 delta = info->separatorMove(index, delta);
3293 info->apply(false);
3294 return delta;
3295 }
3296
3297 QList<QLayoutStruct> list;
3298
3300 getGrid(nullptr, &list);
3301 else
3302 getGrid(&list, nullptr);
3303
3304 int sep_index = index == QInternal::LeftDock || index == QInternal::TopDock
3305 ? 0 : 1;
3308 : Qt::Vertical;
3309
3310 delta = pick(o, dest - origin);
3311 delta = separatorMoveHelper(list, sep_index, delta, sep);
3312
3313 fallbackToSizeHints = false;
3314
3316 setGrid(nullptr, &list);
3317 else
3318 setGrid(&list, nullptr);
3319
3320 apply(false);
3321
3322 return delta;
3323}
3324
3325int QDockAreaLayoutInfo::separatorMove(const QList<int> &separator, const QPoint &origin,
3326 const QPoint &dest)
3327{
3328 int delta = 0;
3329 int index = separator.last();
3330 QDockAreaLayoutInfo *info = this->info(separator);
3331 delta = pick(info->o, dest - origin);
3332 if (delta != 0)
3333 delta = info->separatorMove(index, delta);
3334 info->apply(false);
3335 return delta;
3336}
3337
3338#if QT_CONFIG(tabbar)
3339// Sets the correct positions for the separator widgets
3340// Allocates new separator widgets with getSeparatorWidget
3341void QDockAreaLayout::updateSeparatorWidgets() const
3342{
3343 int j = 0;
3344
3345 for (int i = 0; i < QInternal::DockCount; ++i) {
3346 const QDockAreaLayoutInfo &dock = docks[i];
3347 if (dock.isEmpty())
3348 continue;
3349
3350 QWidget *sepWidget;
3351 if (j < separatorWidgets.size()) {
3352 sepWidget = separatorWidgets.at(j);
3353 if (!sepWidget) {
3354 qWarning("QDockAreaLayout::updateSeparatorWidgets: null separator widget");
3355 sepWidget = qt_mainwindow_layout(mainWindow)->getSeparatorWidget();
3356 separatorWidgets[j] = sepWidget;
3357 }
3358 } else {
3359 sepWidget = qt_mainwindow_layout(mainWindow)->getSeparatorWidget();
3360 separatorWidgets.append(sepWidget);
3361 }
3362 j++;
3363
3364 Q_ASSERT(sepWidget);
3365 sepWidget->raise();
3366
3367 QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
3368 sepWidget->setGeometry(sepRect);
3369 sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
3370 sepWidget->show();
3371 }
3372 for (int i = j; i < separatorWidgets.size(); ++i)
3374
3376}
3377#endif // QT_CONFIG(tabbar)
3378
3380{
3381 Q_ASSERT(x != nullptr);
3382
3383 for (int i = 0; i < QInternal::DockCount; ++i) {
3384 const QDockAreaLayoutInfo &dock = docks[i];
3385 if (QLayoutItem *ret = dock.itemAt(x, index))
3386 return ret;
3387 }
3388
3389 if (centralWidgetItem && (*x)++ == index)
3390 return centralWidgetItem;
3391
3392 return nullptr;
3393}
3394
3396{
3397 Q_ASSERT(x != nullptr);
3398
3399 for (int i = 0; i < QInternal::DockCount; ++i) {
3400 QDockAreaLayoutInfo &dock = docks[i];
3401 if (QLayoutItem *ret = dock.takeAt(x, index))
3402 return ret;
3403 }
3404
3405 if (centralWidgetItem && (*x)++ == index) {
3407 centralWidgetItem = nullptr;
3408 return ret;
3409 }
3410
3411 return nullptr;
3412}
3413
3415{
3416 for (int i = 0; i < QInternal::DockCount; ++i)
3418}
3419
3420#if QT_CONFIG(tabbar)
3421QSet<QTabBar*> QDockAreaLayout::usedTabBars() const
3422{
3423 QSet<QTabBar*> result;
3424 for (int i = 0; i < QInternal::DockCount; ++i) {
3425 const QDockAreaLayoutInfo &dock = docks[i];
3426 result += dock.usedTabBars();
3427 }
3428 return result;
3429}
3430
3431// Returns the set of all used separator widgets
3432QSet<QWidget*> QDockAreaLayout::usedSeparatorWidgets() const
3433{
3434 QSet<QWidget*> result;
3435 const int numSeparators = separatorWidgets.size();
3436 result.reserve(numSeparators);
3437 for (int i = 0; i < numSeparators; ++i)
3439 for (int i = 0; i < QInternal::DockCount; ++i) {
3440 const QDockAreaLayoutInfo &dock = docks[i];
3441 result += dock.usedSeparatorWidgets();
3442 }
3443 return result;
3444}
3445#endif
3446
3447QRect QDockAreaLayout::gapRect(const QList<int> &path) const
3448{
3449 const QDockAreaLayoutInfo *info = this->info(path);
3450 if (info == nullptr)
3451 return QRect();
3452 int index = path.last();
3453 if (index < 0 || index >= info->item_list.size())
3454 return QRect();
3455 return info->itemRect(index, true);
3456}
3457
3459{
3460 QList<int> path = indexOf(w);
3461 if (path.isEmpty())
3462 return;
3463 QDockAreaLayoutItem &item = this->item(path);
3464 if (item.size != -1)
3466}
3467
3474
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore
\inmodule QtCore
QLayoutItem * plug(const QList< int > &path)
void split(int index, Qt::Orientation orientation, QLayoutItem *dockWidgetItem)
QMainWindowLayout * mainWindowLayout() const
QLayoutItem * takeAt(int *x, int index)
bool expansive(Qt::Orientation o) const
bool restoreState(QDataStream &stream, QList< QDockWidget * > &widgets, bool testing)
QRect separatorRect(int index) const
QDockWidget * apply(bool animate)
QInternal::DockPosition dockPos
QDockAreaLayoutItem & item(const QList< int > &path)
int next(int idx) const
bool onlyHasPlaceholders() const
void saveState(QDataStream &stream) const
void paintSeparators(QPainter *p, QWidget *widget, const QRegion &clip, const QPoint &mouse) const
QLayoutItem * itemAt(int *x, int index) const
QList< int > indexOf(QWidget *widget) const
QList< QDockAreaLayoutItem > item_list
void add(QWidget *widget)
bool insertGap(const QList< int > &path, QLayoutItem *dockWidgetItem)
QLayoutItem * unplug(const QList< int > &path)
QRect itemRect(int index, bool isGap=false) const
QList< int > findSeparator(const QPoint &pos) const
void remove(const QList< int > &path)
int separatorMove(int index, int delta)
QList< int > indexOfPlaceHolder(const QString &objectName) const
QDockAreaLayoutInfo * info(const QList< int > &path)
QRegion separatorRegion() const
QList< QWidget * > separatorWidgets
QList< int > gapIndex(const QPoint &pos, bool nestingEnabled, TabMode tabMode) const
int prev(int idx) const
bool hasGapItem(const QList< int > &path) const
QRect itemRect(const QList< int > &path) const
QSize size_helper(SizePMF sizeFn, CenterPMF centerFn) const
QLayoutItem * centralWidgetItem
QLayoutItem * itemAt(int *x, int index) const
QLayoutItem * unplug(const QList< int > &path)
QLayoutItem * plug(const QList< int > &path)
QList< int > gapIndex(const QPoint &pos, bool disallowTabs) const
QDockAreaLayoutInfo * info(const QList< int > &path)
void splitDockWidget(QDockWidget *after, QDockWidget *dockWidget, Qt::Orientation orientation)
QList< int > findSeparator(const QPoint &pos) const
bool restoreDockWidget(QDockWidget *dockWidget)
void setGrid(QList< QLayoutStruct > *ver_struct_list, QList< QLayoutStruct > *hor_struct_list)
QSize minimumSize() const
bool restoreState(QDataStream &stream, const QList< QDockWidget * > &widgets, bool testing=false)
void resizeDocks(const QList< QDockWidget * > &docks, const QList< int > &sizes, Qt::Orientation o)
QRect gapRect(const QList< int > &path) const
QDockAreaLayout(QMainWindow *win)
QSize sizeHint() const
void addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget, Qt::Orientation orientation)
void keepSize(QDockWidget *w)
QList< int > indexOfPlaceHolder(const QString &objectName) const
void remove(const QList< int > &path)
QDockAreaLayoutItem & item(const QList< int > &path)
QSize minimumStableSize() const
static QRect constrainedRect(QRect rect, QWidget *widget)
QRect separatorRect(int index) const
void removePlaceHolder(const QString &name)
void getGrid(QList< QLayoutStruct > *ver_struct_list, QList< QLayoutStruct > *hor_struct_list)
QMainWindow * mainWindow
QDockAreaLayoutInfo docks[4]
QRegion separatorRegion() const
int separatorMove(const QList< int > &separator, const QPoint &origin, const QPoint &dest)
Qt::DockWidgetArea corners[4]
bool insertGap(const QList< int > &path, QLayoutItem *dockWidgetItem)
void paintSeparators(QPainter *p, QWidget *widget, const QRegion &clip, const QPoint &mouse) const
void apply(bool animate)
QLayoutItem * takeAt(int *x, int index)
QList< QWidget * > separatorWidgets
void saveState(QDataStream &stream) const
QList< int > indexOf(QWidget *dockWidget) const
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-l...
Definition qdockwidget.h:20
void show()
Shows the item (items are visible by default).
QPointF pos() const
Returns the position of the item in parent coordinates.
QGraphicsWidget * window() const
qreal x() const
This convenience function is equivalent to calling pos().x().
GraphicsItemFlags flags() const
Returns this item's flags.
QScreen * primaryScreen
the primary (or default) screen of the application.
static QScreen * screenAt(const QPoint &point)
Returns the screen at point, or \nullptr if outside of any screen.
The QLayoutItem class provides an abstract item that a QLayout manipulates.
Definition qlayoutitem.h:25
virtual Qt::Orientations expandingDirections() const =0
Returns whether this layout item can make use of more space than sizeHint().
virtual QSize minimumSize() const =0
Implemented in subclasses to return the minimum size of this item.
virtual bool isEmpty() const =0
Implemented in subclasses to return whether this item is empty, i.e.
virtual QSize maximumSize() const =0
Implemented in subclasses to return the maximum size of this item.
virtual QWidget * widget() const
If this item manages a QWidget, returns that widget.
virtual QSize sizeHint() const =0
Implemented in subclasses to return the preferred size of this item.
qsizetype size() const noexcept
Definition qlist.h:397
T & last()
Definition qlist.h:648
void removeAt(qsizetype i)
Definition qlist.h:590
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
T takeAt(qsizetype i)
Definition qlist.h:609
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void move(qsizetype from, qsizetype to)
Definition qlist.h:610
qsizetype count() const noexcept
Definition qlist.h:398
void prepend(rvalue_ref t)
Definition qlist.h:473
void resize(qsizetype size)
Definition qlist.h:403
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
QWidgetAnimator widgetAnimator
The QMainWindow class provides a main application window.
Definition qmainwindow.h:25
DockOptions dockOptions
the docking behavior of QMainWindow
Definition qmainwindow.h:40
QString objectName
the name of this object
Definition qobject.h:107
QList< T > findChildren(QAnyStringView aName, Qt::FindChildOptions options=Qt::FindChildrenRecursively) const
Returns all children of this object with the given name that can be cast to type T,...
Definition qobject.h:164
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:373
constexpr void moveBottom(int pos) noexcept
Moves the rectangle vertically, leaving the rectangle's bottom edge at the given y coordinate.
Definition qrect.h:298
constexpr void moveRight(int pos) noexcept
Moves the rectangle horizontally, leaving the rectangle's right edge at the given x coordinate.
Definition qrect.h:292
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:170
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:164
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr void moveLeft(int pos) noexcept
Moves the rectangle horizontally, leaving the rectangle's left edge at the given x coordinate.
Definition qrect.h:286
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:855
constexpr void setLeft(int pos) noexcept
Sets the left edge of the rectangle to the given x coordinate.
Definition qrect.h:191
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr void setWidth(int w) noexcept
Sets the width of the rectangle to the given width.
Definition qrect.h:381
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
constexpr void setHeight(int h) noexcept
Sets the height of the rectangle to the given height.
Definition qrect.h:384
constexpr void moveTop(int pos) noexcept
Moves the rectangle vertically, leaving the rectangle's top edge at the given y coordinate.
Definition qrect.h:289
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:179
constexpr void setTop(int pos) noexcept
Sets the top edge of the rectangle to the given y coordinate.
Definition qrect.h:194
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
bool contains(const QPoint &p) const
Returns true if the region contains the point p; otherwise returns false.
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
QRect geometry
the screen's geometry in pixels
Definition qscreen.h:45
Exception-safe wrapper around QObject::blockSignals().
Definition qobject.h:483
\inmodule QtCore
Definition qsize.h:25
constexpr QSize boundedTo(const QSize &) const noexcept
Returns a size holding the minimum width and height of this size and the given otherSize.
Definition qsize.h:197
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
The QStyleOption class stores the parameters used by QStyle functions.
QStyle::State state
QPalette palette
@ State_MouseOver
Definition qstyle.h:80
@ State_Enabled
Definition qstyle.h:67
@ State_Horizontal
Definition qstyle.h:74
@ State_None
Definition qstyle.h:66
@ PM_DockWidgetSeparatorExtent
Definition qstyle.h:435
@ PE_IndicatorDockWidgetResizeHandle
Definition qstyle.h:132
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
Returns the value of the given pixel metric.
The QTabBar class provides a tab bar, e.g.
Definition qtabbar.h:19
Shape
This enum type lists the built-in shapes supported by QTabBar.
Definition qtabbar.h:42
@ RoundedSouth
Definition qtabbar.h:42
@ RoundedNorth
Definition qtabbar.h:42
@ TriangularEast
Definition qtabbar.h:43
@ RoundedWest
Definition qtabbar.h:42
@ TriangularSouth
Definition qtabbar.h:43
@ RoundedEast
Definition qtabbar.h:42
@ TriangularWest
Definition qtabbar.h:43
@ TriangularNorth
Definition qtabbar.h:43
void animate(QWidget *widget, const QRect &final_geometry, bool animate)
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setGeometry(int x, int y, int w, int h)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:886
void setParent(QWidget *parent)
Sets the parent of the widget to parent, and resets the window flags.
QSize size
the size of the widget excluding any window frame
Definition qwidget.h:113
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition qwidget.h:106
QLayout * layout() const
Returns the layout manager that is installed on this widget, or \nullptr if no layout manager is inst...
int width
the width of the widget excluding any window frame
Definition qwidget.h:114
void hide()
Hides the widget.
Definition qwidget.cpp:8135
int height
the height of the widget excluding any window frame
Definition qwidget.h:115
void setWindowState(Qt::WindowStates state)
Sets the window state to windowState.
Definition qwidget.cpp:2937
virtual void setVisible(bool visible)
Definition qwidget.cpp:8255
QStyle * style() const
Definition qwidget.cpp:2600
QScreen * screen() const
Returns the screen the widget is on.
Definition qwidget.cpp:2496
QOpenGLWidget * widget
[1]
rect
[4]
QStyleOptionButton opt
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ BottomLeftCorner
@ TopRightCorner
@ TopLeftCorner
@ BottomRightCorner
DockWidgetArea
@ BottomDockWidgetArea
@ NoDockWidgetArea
@ RightDockWidgetArea
@ LeftDockWidgetArea
@ TopDockWidgetArea
Orientation
Definition qnamespace.h:98
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
@ FindDirectChildrenOnly
#define Q_UNLIKELY(x)
static int grow(QLayoutStruct &ls, int delta)
QDebug operator<<(QDebug dbg, const QDockAreaLayoutItem *item)
static QRect dockedGeometry(QWidget *widget)
static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
static int realMinSize(const QDockAreaLayoutInfo &info)
static int qMax(int i1, int i2, int i3)
static int shrink(QLayoutStruct &ls, int delta)
static const int zero
static int separatorMoveHelper(QList< QLayoutStruct > &list, int index, int delta, int sep)
static QInternal::DockPosition dockPosHelper(const QRect &rect, const QPoint &_pos, Qt::Orientation o, bool nestingEnabled, QDockAreaLayoutInfo::TabMode tabMode)
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)
static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over)
static int realMaxSize(const QDockAreaLayoutInfo &info)
@ StateFlagVisible
@ StateFlagFloating
static int pick(bool vertical, const QSize &size)
static int perp(bool vertical, const QSize &size)
EGLStreamKHR stream
void qGeomCalc(QList< QLayoutStruct > &chain, int start, int count, int pos, int space, int spacer)
QT_BEGIN_NAMESPACE constexpr int QLAYOUTSIZE_MAX
Definition qlayoutitem.h:16
#define qWarning
Definition qlogging.h:166
#define qFatal
Definition qlogging.h:168
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
static int & rperp(Qt::Orientation o, QPoint &pos)
Definition qmenu_p.h:61
static int & rpick(Qt::Orientation o, QPoint &pos)
Definition qmenu_p.h:46
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLsizei GLuint * groups
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint left
GLint GLint bottom
GLbitfield flags
const GLchar * marker
GLuint name
GLint first
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLdouble s
[6]
Definition qopenglext.h:235
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
static constexpr QChar sep
#define qUtf16Printable(string)
Definition qstring.h:1543
QScreen * screen
[1]
Definition main.cpp:29
#define QT_CONFIG(feature)
#define emit
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
size_t quintptr
Definition qtypes.h:167
#define QWIDGETSIZE_MAX
Definition qwidget.h:917
QWidget * win
Definition settings.cpp:6
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
QList< QWidget * > widgets
[11]
QObject::connect nullptr
QVBoxLayout * layout
QString title
[35]
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QDockWidget * dockWidget
[0]
QHostInfo info
[0]
QPlaceHolderItem * placeHolderItem
QDockAreaLayoutItem(QLayoutItem *_widgetItem=nullptr)
bool expansive(Qt::Orientation o) const
bool hasFixedSize(Qt::Orientation o) const
QDockAreaLayoutInfo * subinfo
QDockAreaLayoutItem & operator=(const QDockAreaLayoutItem &other)
void init(int stretchFactor=0, int minSize=0)