Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtoolbararealayout.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <QWidgetItem>
6#include <QToolBar>
7#include <QStyleOption>
8#include <QApplication>
9#include <qdebug.h>
10
14#include "qtoolbar_p.h"
15
16/******************************************************************************
17** QToolBarAreaLayoutItem
18*/
19
21
22// qmainwindow.cpp
23extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *mainWindow);
24using StateMarkers = QMainWindowLayoutState::StateMarkers;
25
27{
28 if (skip())
29 return QSize(0, 0);
30 return qSmartMinSize(static_cast<QWidgetItem*>(widgetItem));
31}
32
34{
35 if (skip())
36 return QSize(0, 0);
37
38 return realSizeHint();
39}
40
41//returns the real size hint not taking into account the visibility of the widget
43{
44 QWidget *wid = widgetItem->widget();
45 QSize s = wid->sizeHint().expandedTo(wid->minimumSizeHint());
46 if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
47 s.setWidth(0);
48 if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
49 s.setHeight(0);
50 s = s.boundedTo(wid->maximumSize())
51 .expandedTo(wid->minimumSize());
52 return s;
53}
54
56{
57 if (gap)
58 return false;
59 return widgetItem == nullptr || widgetItem->isEmpty();
60}
61
62/******************************************************************************
63** QToolBarAreaLayoutLine
64*/
65
67 : o(orientation)
68{
69}
70
72{
73 int a = 0, b = 0;
74 for (int i = 0; i < toolBarItems.size(); ++i) {
75 const QToolBarAreaLayoutItem &item = toolBarItems.at(i);
76 if (item.skip())
77 continue;
78
79 QSize sh = item.sizeHint();
80 a += item.preferredSize > 0 ? item.preferredSize : pick(o, sh);
81 b = qMax(b, perp(o, sh));
82 }
83
84 QSize result;
85 rpick(o, result) = a;
86 rperp(o, result) = b;
87
88 return result;
89}
90
92{
93 int a = 0, b = 0;
94 for (int i = 0; i < toolBarItems.size(); ++i) {
95 const QToolBarAreaLayoutItem &item = toolBarItems[i];
96 if (item.skip())
97 continue;
98
99 QSize ms = item.minimumSize();
100 a += pick(o, ms);
101 b = qMax(b, perp(o, ms));
102 }
103
104 QSize result;
105 rpick(o, result) = a;
106 rperp(o, result) = b;
107
108 return result;
109}
110
112{
113 int last = -1;
114 int min = pick(o, minimumSize());
115 int space = pick(o, rect.size());
116 int extra = qMax(0, space - min);
117
118 for (int i = 0; i < toolBarItems.size(); ++i) {
119 QToolBarAreaLayoutItem &item = toolBarItems[i];
120 if (item.skip())
121 continue;
122
123 if (QToolBarLayout *tblayout = qobject_cast<QToolBarLayout*>(item.widgetItem->widget()->layout()))
124 tblayout->checkUsePopupMenu();
125
126 const int itemMin = pick(o, item.minimumSize());
127 //preferredSize is the default if it is set, otherwise, we take the sizehint
128 item.size = item.preferredSize > 0 ? item.preferredSize : pick(o, item.sizeHint());
129
130 //the extraspace is the space above the item minimum sizehint
131 const int extraSpace = qMin(item.size - itemMin, extra);
132 item.size = itemMin + extraSpace; //that is the real size
133
134 extra -= extraSpace;
135
136 last = i;
137 }
138
139 // calculate the positions from the sizes
140 int pos = 0;
141 for (int i = 0; i < toolBarItems.size(); ++i) {
142 QToolBarAreaLayoutItem &item = toolBarItems[i];
143 if (item.skip())
144 continue;
145
146 item.pos = pos;
147 if (i == last) // stretch the last item to the end of the line
148 item.size = qMax(0, pick(o, rect.size()) - item.pos);
149 pos += item.size;
150 }
151}
152
154{
155 for (int i = 0; i < toolBarItems.size(); ++i) {
156 if (!toolBarItems.at(i).skip())
157 return false;
158 }
159 return true;
160}
161
162/******************************************************************************
163** QToolBarAreaLayoutInfo
164*/
165
167 : dockPos(pos), dirty(false)
168{
169 switch (pos) {
170 case QInternal::LeftDock:
171 case QInternal::RightDock:
172 o = Qt::Vertical;
173 break;
174 case QInternal::TopDock:
175 case QInternal::BottomDock:
176 o = Qt::Horizontal;
177 break;
178 default:
179 o = Qt::Horizontal;
180 break;
181 }
182}
183
185{
186 int a = 0, b = 0;
187 for (int i = 0; i < lines.size(); ++i) {
188 const QToolBarAreaLayoutLine &l = lines.at(i);
189 if (l.skip())
190 continue;
191
192 QSize hint = l.sizeHint();
193 a = qMax(a, pick(o, hint));
194 b += perp(o, hint);
195 }
196
197 QSize result;
198 rpick(o, result) = a;
199 rperp(o, result) = b;
200
201 return result;
202}
203
205{
206 int a = 0, b = 0;
207 for (int i = 0; i < lines.size(); ++i) {
208 const QToolBarAreaLayoutLine &l = lines.at(i);
209 if (l.skip())
210 continue;
211
212 QSize m = l.minimumSize();
213 a = qMax(a, pick(o, m));
214 b += perp(o, m);
215 }
216
217 QSize result;
218 rpick(o, result) = a;
219 rperp(o, result) = b;
220
221 return result;
222}
223
225{
226 dirty = false;
227
228 int b = 0;
229
230 bool reverse = dockPos == QInternal::RightDock || dockPos == QInternal::BottomDock;
231
232 int i = reverse ? lines.size() - 1 : 0;
233 for (;;) {
234 if ((reverse && i < 0) || (!reverse && i == lines.size()))
235 break;
236
237 QToolBarAreaLayoutLine &l = lines[i];
238 if (!l.skip()) {
239 if (o == Qt::Horizontal) {
240 l.rect.setLeft(rect.left());
241 l.rect.setRight(rect.right());
242 l.rect.setTop(b + rect.top());
243 b += l.sizeHint().height();
244 l.rect.setBottom(b - 1 + rect.top());
245 } else {
246 l.rect.setTop(rect.top());
247 l.rect.setBottom(rect.bottom());
248 l.rect.setLeft(b + rect.left());
249 b += l.sizeHint().width();
250 l.rect.setRight(b - 1 + rect.left());
251 }
252
254 }
255
256 i += reverse ? -1 : 1;
257 }
258}
259
260QLayoutItem *QToolBarAreaLayoutInfo::insertToolBar(QToolBar *before, QToolBar *toolBar)
261{
262 toolBar->setOrientation(o);
263 QLayoutItem *item = new QWidgetItemV2(toolBar);
264 insertItem(before, item);
265 return item;
266}
267
268void QToolBarAreaLayoutInfo::insertItem(QToolBar *before, QLayoutItem *item)
269{
270 if (before == nullptr) {
271 if (lines.isEmpty())
272 lines.append(QToolBarAreaLayoutLine(o));
273 lines.last().toolBarItems.append(item);
274 return;
275 }
276
277 for (int j = 0; j < lines.size(); ++j) {
278 QToolBarAreaLayoutLine &line = lines[j];
279
280 for (int k = 0; k < line.toolBarItems.size(); ++k) {
281 if (line.toolBarItems.at(k).widgetItem->widget() == before) {
282 line.toolBarItems.insert(k, item);
283 return;
284 }
285 }
286 }
287}
288
289void QToolBarAreaLayoutInfo::removeToolBar(QToolBar *toolBar)
290{
291 for (int j = 0; j < lines.size(); ++j) {
292 QToolBarAreaLayoutLine &line = lines[j];
293
294 for (int k = 0; k < line.toolBarItems.size(); ++k) {
295 QToolBarAreaLayoutItem &item = line.toolBarItems[k];
296 if (item.widgetItem->widget() == toolBar) {
297 delete item.widgetItem;
298 item.widgetItem = nullptr;
299 line.toolBarItems.removeAt(k);
300
301 if (line.toolBarItems.isEmpty() && j < lines.size() - 1)
302 lines.removeAt(j);
303
304 return;
305 }
306 }
307 }
308}
309
311{
312 if (before == nullptr) {
313 if (!lines.isEmpty() && lines.constLast().toolBarItems.isEmpty())
314 return;
315 lines.append(QToolBarAreaLayoutLine(o));
316 return;
317 }
318
319 for (int j = 0; j < lines.size(); ++j) {
320 QToolBarAreaLayoutLine &line = lines[j];
321
322 for (int k = 0; k < line.toolBarItems.size(); ++k) {
323 if (line.toolBarItems.at(k).widgetItem->widget() == before) {
324 if (k == 0)
325 return;
326
327 QToolBarAreaLayoutLine newLine(o);
328 newLine.toolBarItems = line.toolBarItems.mid(k);
329 line.toolBarItems = line.toolBarItems.mid(0, k);
330 lines.insert(j + 1, newLine);
331
332 return;
333 }
334 }
335 }
336}
337
339{
340 for (int j = 0; j < lines.size(); ++j) {
341 const QToolBarAreaLayoutLine &line = lines.at(j);
342
343 for (int k = 0; k < line.toolBarItems.size(); ++k) {
344 if (line.toolBarItems.at(k).widgetItem->widget() == before) {
345 if (k != 0)
346 return;
347 if (j == 0)
348 return;
349
350 lines[j - 1].toolBarItems += lines[j].toolBarItems;
351 lines.removeAt(j);
352
353 return;
354 }
355 }
356 }
357}
358
359void QToolBarAreaLayoutInfo::moveToolBar(QToolBar *toolbar, int pos)
360{
361 if (dirty)
363
364 dirty = true;
365
366 if (o == Qt::Vertical)
367 pos -= rect.top();
368
369 //here we actually update the preferredSize for the line containing the toolbar so that we move it
370 for (int j = 0; j < lines.size(); ++j) {
371 QToolBarAreaLayoutLine &line = lines[j];
372
373 int previousIndex = -1;
374 int minPos = 0;
375 for (int k = 0; k < line.toolBarItems.size(); ++k) {
376 QToolBarAreaLayoutItem &current = line.toolBarItems[k];
377 if (current.widgetItem->widget() == toolbar) {
378 int newPos = current.pos;
379
380 if (previousIndex >= 0) {
381 QToolBarAreaLayoutItem &previous = line.toolBarItems[previousIndex];
382 if (pos < current.pos) {
383 newPos = qMax(pos, minPos);
384 } else {
385 //we check the max value for the position (until everything at the right is "compressed")
386 int maxPos = pick(o, rect.size());
387 for(int l = k; l < line.toolBarItems.size(); ++l) {
388 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(l);
389 if (!item.skip()) {
390 maxPos -= pick(o, item.minimumSize());
391 }
392 }
393 newPos = qMin(pos, maxPos);
394 }
395
396 //extra is the number of pixels to add to the previous toolbar
397 int extra = newPos - current.pos;
398
399 //we check if the previous is near its size hint
400 //in which case we try to stick to it
401 const int diff = pick(o, previous.sizeHint()) - (previous.size + extra);
402 if (qAbs(diff) < QApplication::startDragDistance()) {
403 //we stick to the default place and size
404 extra += diff;
405 }
406
407 //update for the current item
408 current.extendSize(line.o, -extra);
409
410 if (extra >= 0) {
411 previous.extendSize(line.o, extra);
412 } else {
413 //we need to push the toolbars on the left starting with previous
414 extra = -extra; // we just need to know the number of pixels
415 ///at this point we need to get extra pixels from the toolbars at the left
416 for(int l = previousIndex; l >=0; --l) {
417 QToolBarAreaLayoutItem &item = line.toolBarItems[l];
418 if (!item.skip()) {
419 const int minPreferredSize = pick(o, item.minimumSize());
420 const int margin = item.size - minPreferredSize;
421 if (margin < extra) {
422 item.resize(line.o, minPreferredSize);
423 extra -= margin;
424 } else {
425 item.extendSize(line.o, -extra);
426 extra = 0;
427 }
428 }
429 }
430 Q_ASSERT(extra == 0);
431 }
432 } else {
433 //the item is the first one, it should be at position 0
434 }
435
436 return;
437
438 } else if (!current.skip()) {
439 previousIndex = k;
440 minPos += pick(o, current.minimumSize());
441 }
442 }
443 }
444}
445
446
447QList<int> QToolBarAreaLayoutInfo::gapIndex(const QPoint &pos, int *minDistance) const
448{
449 if (rect.contains(pos)) {
450 // <pos> is in QToolBarAreaLayout coordinates.
451 // <item.pos> is in local dockarea coordinates (see ~20 lines below)
452 // Since we're comparing p with item.pos, we put them in the same coordinate system.
453 const int p = pick(o, pos - rect.topLeft());
454
455 for (int j = 0; j < lines.size(); ++j) {
456 const QToolBarAreaLayoutLine &line = lines.at(j);
457 if (line.skip())
458 continue;
459 if (!line.rect.contains(pos))
460 continue;
461
462 int k = 0;
463 for (; k < line.toolBarItems.size(); ++k) {
464 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
465 if (item.skip())
466 continue;
467
468 int size = qMin(item.size, pick(o, item.sizeHint()));
469
470 if (p > item.pos + size)
471 continue;
472 if (p > item.pos + size/2)
473 ++k;
474 break;
475 }
476
477 QList<int> result;
478 result << j << k;
479 *minDistance = 0; //we found a perfect match
480 return result;
481 }
482 } else {
483 const int dist = distance(pos);
484 //it will only return a path if the minDistance is higher than the current distance
485 if (dist >= 0 && *minDistance > dist) {
486 *minDistance = dist;
487
488 QList<int> result;
489 result << lines.size() << 0;
490 return result;
491 }
492 }
493
494 return QList<int>();
495}
496
497bool QToolBarAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *item)
498{
499 Q_ASSERT(path.size() == 2);
500 int j = path.first();
501 if (j == lines.size())
502 lines.append(QToolBarAreaLayoutLine(o));
503
504 QToolBarAreaLayoutLine &line = lines[j];
505 const int k = path.at(1);
506
507 QToolBarAreaLayoutItem gap_item;
508 gap_item.gap = true;
509 gap_item.widgetItem = item;
510
511 //update the previous item's preferred size
512 for(int p = k - 1 ; p >= 0; --p) {
513 QToolBarAreaLayoutItem &previous = line.toolBarItems[p];
514 if (!previous.skip()) {
515 //we found the previous one
516 int previousSizeHint = pick(line.o, previous.sizeHint());
517 int previousExtraSpace = previous.size - previousSizeHint;
518
519 if (previousExtraSpace > 0) {
520 //in this case we reset the space
521 previous.preferredSize = -1;
522 previous.size = previousSizeHint;
523
524 gap_item.resize(o, previousExtraSpace);
525 }
526
527 break;
528 }
529 }
530
531 line.toolBarItems.insert(k, gap_item);
532 return true;
533
534}
535
537{
538 lines.clear();
539 rect = QRect();
540}
541
542QRect QToolBarAreaLayoutInfo::itemRect(const QList<int> &path) const
543{
544 Q_ASSERT(path.size() == 2);
545 int j = path.at(0);
546 int k = path.at(1);
547
548 const QToolBarAreaLayoutLine &line = lines.at(j);
549 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
550
551 QRect result = line.rect;
552
553 if (o == Qt::Horizontal) {
554 result.setLeft(item.pos + line.rect.left());
555 result.setWidth(item.size);
556 } else {
557 result.setTop(item.pos + line.rect.top());
558 result.setHeight(item.size);
559 }
560
561 return result;
562}
563
564int QToolBarAreaLayoutInfo::distance(const QPoint &pos) const
565{
566 switch (dockPos) {
567 case QInternal::LeftDock:
568 if (pos.y() > 0 && pos.y() < rect.bottom())
569 return pos.x() - rect.right();
570 break;
571 case QInternal::RightDock:
572 if (pos.y() > 0 && pos.y() < rect.bottom())
573 return rect.left() - pos.x();
574 break;
575 case QInternal::TopDock:
576 if (pos.x() > 0 && pos.x() < rect.right())
577 return pos.y() - rect.bottom();
578 break;
579 case QInternal::BottomDock:
580 if (pos.x() > 0 && pos.x() < rect.right())
581 return rect.top() - pos.y();
582 break;
583
584 case QInternal::DockCount:
585 break;
586 }
587 return -1;
588}
589
590/******************************************************************************
591** QToolBarAreaLayout
592*/
593
594QToolBarAreaLayout::QToolBarAreaLayout(const QMainWindow *win) : mainWindow(win), visible(true)
595{
596 for (int i = 0; i < QInternal::DockCount; ++i) {
597 QInternal::DockPosition pos = static_cast<QInternal::DockPosition>(i);
598 docks[i] = QToolBarAreaLayoutInfo(pos);
599 }
600}
601
603{
604 if (!visible)
605 return rect;
606
607 QSize left_hint = docks[QInternal::LeftDock].sizeHint();
608 QSize right_hint = docks[QInternal::RightDock].sizeHint();
609 QSize top_hint = docks[QInternal::TopDock].sizeHint();
610 QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
611
612 QRect center = rect.adjusted(left_hint.width(), top_hint.height(),
613 -right_hint.width(), -bottom_hint.height());
614
615 docks[QInternal::TopDock].rect = QRect(rect.left(), rect.top(),
616 rect.width(), top_hint.height());
617 docks[QInternal::LeftDock].rect = QRect(rect.left(), center.top(),
618 left_hint.width(), center.height());
619 docks[QInternal::RightDock].rect = QRect(center.right() + 1, center.top(),
620 right_hint.width(), center.height());
621 docks[QInternal::BottomDock].rect = QRect(rect.left(), center.bottom() + 1,
622 rect.width(), bottom_hint.height());
623
624 docks[QInternal::TopDock].fitLayout();
625 docks[QInternal::LeftDock].fitLayout();
626 docks[QInternal::RightDock].fitLayout();
627 docks[QInternal::BottomDock].fitLayout();
628
629 return center;
630}
631
632QSize QToolBarAreaLayout::minimumSize(const QSize &centerMin) const
633{
634 if (!visible)
635 return centerMin;
636
637 QSize result = centerMin;
638
639 QSize left_min = docks[QInternal::LeftDock].minimumSize();
640 QSize right_min = docks[QInternal::RightDock].minimumSize();
641 QSize top_min = docks[QInternal::TopDock].minimumSize();
642 QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
643
644 result.setWidth(qMax(top_min.width(), result.width()));
645 result.setWidth(qMax(bottom_min.width(), result.width()));
646 result.setHeight(qMax(left_min.height(), result.height()));
647 result.setHeight(qMax(right_min.height(), result.height()));
648
649 result.rwidth() += left_min.width() + right_min.width();
650 result.rheight() += top_min.height() + bottom_min.height();
651
652 return result;
653}
654
655QSize QToolBarAreaLayout::sizeHint(const QSize &centerHint) const
656{
657 if (!visible)
658 return centerHint;
659
660 QSize result = centerHint;
661
662 QSize left_hint = docks[QInternal::LeftDock].sizeHint();
663 QSize right_hint = docks[QInternal::RightDock].sizeHint();
664 QSize top_hint = docks[QInternal::TopDock].sizeHint();
665 QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
666
667 result.setWidth(qMax(top_hint.width(), result.width()));
668 result.setWidth(qMax(bottom_hint.width(), result.width()));
669 result.setHeight(qMax(left_hint.height(), result.height()));
670 result.setHeight(qMax(right_hint.height(), result.height()));
671
672 result.rwidth() += left_hint.width() + right_hint.width();
673 result.rheight() += top_hint.height() + bottom_hint.height();
674
675 return result;
676}
677
678QRect QToolBarAreaLayout::rectHint(const QRect &r) const
679{
680 int coef = visible ? 1 : -1;
681
682 QRect result = r;
683
684 QSize left_hint = docks[QInternal::LeftDock].sizeHint();
685 QSize right_hint = docks[QInternal::RightDock].sizeHint();
686 QSize top_hint = docks[QInternal::TopDock].sizeHint();
687 QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
688
689 result.adjust(-left_hint.width()*coef, -top_hint.height()*coef,
690 right_hint.width()*coef, bottom_hint.height()*coef);
691
692 return result;
693}
694
695QLayoutItem *QToolBarAreaLayout::itemAt(int *x, int index) const
696{
697 Q_ASSERT(x != nullptr);
698
699 for (int i = 0; i < QInternal::DockCount; ++i) {
700 const QToolBarAreaLayoutInfo &dock = docks[i];
701
702 for (int j = 0; j < dock.lines.size(); ++j) {
703 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
704
705 for (int k = 0; k < line.toolBarItems.size(); ++k) {
706 if ((*x)++ == index)
707 return line.toolBarItems.at(k).widgetItem;
708 }
709 }
710 }
711
712 return nullptr;
713}
714
715QLayoutItem *QToolBarAreaLayout::takeAt(int *x, int index)
716{
717 Q_ASSERT(x != nullptr);
718
719 for (int i = 0; i < QInternal::DockCount; ++i) {
720 QToolBarAreaLayoutInfo &dock = docks[i];
721
722 for (int j = 0; j < dock.lines.size(); ++j) {
723 QToolBarAreaLayoutLine &line = dock.lines[j];
724
725 for (int k = 0; k < line.toolBarItems.size(); ++k) {
726 if ((*x)++ == index) {
727 QLayoutItem *result = line.toolBarItems.takeAt(k).widgetItem;
728 if (line.toolBarItems.isEmpty())
729 dock.lines.removeAt(j);
730 return result;
731 }
732 }
733 }
734 }
735
736 return nullptr;
737}
738
740{
741 for (int i = 0; i < QInternal::DockCount; ++i) {
742 QToolBarAreaLayoutInfo &dock = docks[i];
743
744 for (int j = 0; j < dock.lines.size(); ++j) {
745 QToolBarAreaLayoutLine &line = dock.lines[j];
746
747 for (int k = 0; k < line.toolBarItems.size(); ++k) {
748 QToolBarAreaLayoutItem &item = line.toolBarItems[k];
749 if (!item.gap)
750 delete item.widgetItem;
751 item.widgetItem = nullptr;
752 }
753 }
754 }
755}
756
758{
759 for (std::size_t i = 0; i < docks.size(); ++i) {
760 const QToolBarAreaLayoutInfo &dock = docks[i];
761 for (const auto &line : dock.lines) {
762 for (const auto &item : line.toolBarItems) {
763 if (item.widgetItem->widget() == toolBar)
764 return static_cast<QInternal::DockPosition>(i);
765 }
766 }
767 }
768 return {};
769}
770
771QLayoutItem *QToolBarAreaLayout::insertToolBar(QToolBar *before, QToolBar *toolBar)
772{
773 if (auto pos = findToolBar(before))
774 return docks[*pos].insertToolBar(before, toolBar);
775 return nullptr;
776}
777
778void QToolBarAreaLayout::removeToolBar(QToolBar *toolBar)
779{
780 if (auto pos = findToolBar(toolBar))
781 docks[*pos].removeToolBar(toolBar);
782}
783
784QLayoutItem *QToolBarAreaLayout::addToolBar(QInternal::DockPosition pos, QToolBar *toolBar)
785{
786 return docks[pos].insertToolBar(nullptr, toolBar);
787}
788
790{
791 if (auto pos = findToolBar(before))
792 docks[*pos].insertToolBarBreak(before);
793}
794
796{
797 if (auto pos = findToolBar(before))
798 docks[*pos].removeToolBarBreak(before);
799}
800
801void QToolBarAreaLayout::addToolBarBreak(QInternal::DockPosition pos)
802{
803 docks[pos].insertToolBarBreak(nullptr);
804}
805
806void QToolBarAreaLayout::moveToolBar(QToolBar *toolbar, int p)
807{
808 if (auto pos = findToolBar(toolbar))
809 docks[*pos].moveToolBar(toolbar, p);
810}
811
812
813void QToolBarAreaLayout::insertItem(QInternal::DockPosition pos, QLayoutItem *item)
814{
815 if (docks[pos].lines.isEmpty())
816 docks[pos].lines.append(QToolBarAreaLayoutLine(docks[pos].o));
817 docks[pos].lines.last().toolBarItems.append(item);
818}
819
820void QToolBarAreaLayout::insertItem(QToolBar *before, QLayoutItem *item)
821{
822 if (auto pos = findToolBar(before))
823 docks[*pos].insertItem(before, item);
824}
825
826void QToolBarAreaLayout::apply(QWidgetAnimator::AnimationRule rule)
827{
828 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
829 Q_ASSERT(layout != nullptr);
830
831 Qt::LayoutDirection dir = mainWindow->layoutDirection();
832
833 for (int i = 0; i < QInternal::DockCount; ++i) {
834 const QToolBarAreaLayoutInfo &dock = docks[i];
835
836 for (int j = 0; j < dock.lines.size(); ++j) {
837 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
838 if (line.skip())
839 continue;
840
841 for (int k = 0; k < line.toolBarItems.size(); ++k) {
842 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
843 if (item.skip() || item.gap)
844 continue;
845
846 QRect geo;
847 if (visible) {
848 if (line.o == Qt::Horizontal) {
849 geo.setTop(line.rect.top());
850 geo.setBottom(line.rect.bottom());
851 geo.setLeft(line.rect.left() + item.pos);
852 geo.setRight(line.rect.left() + item.pos + item.size - 1);
853 } else {
854 geo.setLeft(line.rect.left());
855 geo.setRight(line.rect.right());
856 geo.setTop(line.rect.top() + item.pos);
857 geo.setBottom(line.rect.top() + item.pos + item.size - 1);
858 }
859 }
860
861 QWidget *widget = item.widgetItem->widget();
862 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
863 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(toolBar->layout());
864 if (tbl->expanded) {
865 QPoint tr = geo.topRight();
866 QSize size = tbl->expandedSize(geo.size());
867 geo.setSize(size);
868 geo.moveTopRight(tr);
869 if (geo.bottom() > rect.bottom())
870 geo.moveBottom(rect.bottom());
871 if (geo.right() > rect.right())
872 geo.moveRight(rect.right());
873 if (geo.left() < 0)
874 geo.moveLeft(0);
875 if (geo.top() < 0)
876 geo.moveTop(0);
877 }
878 }
879
880 if (visible && dock.o == Qt::Horizontal)
881 geo = QStyle::visualRect(dir, line.rect, geo);
882
883 layout->widgetAnimator.animate(widget, geo, rule);
884 }
885 }
886 }
887}
888
889bool QToolBarAreaLayout::toolBarBreak(QToolBar *toolBar) const
890{
891 for (int i = 0; i < QInternal::DockCount; ++i) {
892 const QToolBarAreaLayoutInfo &dock = docks[i];
893
894 for (int j = 0; j < dock.lines.size(); ++j) {
895 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
896
897 for (int k = 0; k < line.toolBarItems.size(); ++k) {
898 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar)
899 return j > 0 && k == 0;
900 }
901 }
902 }
903
904 return false;
905}
906
907void QToolBarAreaLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
908{
909 for (int i = 0; i < QInternal::DockCount; ++i) {
910 const QToolBarAreaLayoutInfo &dock = docks[i];
911
912 for (int j = 0; j < dock.lines.size(); ++j) {
913 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
914
915 for (int k = 0; k < line.toolBarItems.size(); ++k) {
916 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar) {
917 if (line.toolBarItems.size() == 1)
918 option->positionWithinLine = QStyleOptionToolBar::OnlyOne;
919 else if (k == 0)
920 option->positionWithinLine = QStyleOptionToolBar::Beginning;
921 else if (k == line.toolBarItems.size() - 1)
922 option->positionWithinLine = QStyleOptionToolBar::End;
923 else
924 option->positionWithinLine = QStyleOptionToolBar::Middle;
925
926 if (dock.lines.size() == 1)
927 option->positionOfLine = QStyleOptionToolBar::OnlyOne;
928 else if (j == 0)
929 option->positionOfLine = QStyleOptionToolBar::Beginning;
930 else if (j == dock.lines.size() - 1)
931 option->positionOfLine = QStyleOptionToolBar::End;
932 else
933 option->positionOfLine = QStyleOptionToolBar::Middle;
934
935 return;
936 }
937 }
938 }
939 }
940}
941
942QList<int> QToolBarAreaLayout::indexOf(QWidget *toolBar) const
943{
944 QList<int> result;
945
946 bool found = false;
947
948 for (int i = 0; i < QInternal::DockCount; ++i) {
949 const QToolBarAreaLayoutInfo &dock = docks[i];
950
951 for (int j = 0; j < dock.lines.size(); ++j) {
952 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
953
954 for (int k = 0; k < line.toolBarItems.size(); ++k) {
955 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
956 if (!item.gap && item.widgetItem->widget() == toolBar) {
957 found = true;
958 result.prepend(k);
959 break;
960 }
961 }
962
963 if (found) {
964 result.prepend(j);
965 break;
966 }
967 }
968
969 if (found) {
970 result.prepend(i);
971 break;
972 }
973 }
974
975 return result;
976}
977
978//this functions returns the path to the possible gapindex for the position pos
979QList<int> QToolBarAreaLayout::gapIndex(const QPoint &pos) const
980{
981 Qt::LayoutDirection dir = mainWindow->layoutDirection();
982 int minDistance = 80; // when a dock area is empty, how "wide" is it?
983 QList<int> ret; //return value
984 for (int i = 0; i < QInternal::DockCount; ++i) {
985 QPoint p = pos;
986 if (docks[i].o == Qt::Horizontal)
987 p = QStyle::visualPos(dir, docks[i].rect, p);
988 QList<int> result = docks[i].gapIndex(p, &minDistance);
989 if (!result.isEmpty()) {
990 result.prepend(i);
991 ret = result;
992 }
993 }
994
995 return ret;
996}
997
999{
1000 for (int i = 0; i < QInternal::DockCount; ++i) {
1001 const QToolBarAreaLayoutInfo &dock = docks[i];
1002
1003 for (int j = 0; j < dock.lines.size(); ++j) {
1004 const QToolBarAreaLayoutLine &line = dock.lines[j];
1005
1006 for (int k = 0; k < line.toolBarItems.size(); k++) {
1007 if (line.toolBarItems[k].gap) {
1008 QList<int> result;
1009 result << i << j << k;
1010 return result;
1011 }
1012 }
1013 }
1014 }
1015 return QList<int>();
1016}
1017
1018bool QToolBarAreaLayout::insertGap(const QList<int> &path, QLayoutItem *item)
1019{
1020 Q_ASSERT(path.size() == 3);
1021 const int i = path.first();
1022 Q_ASSERT(i >= 0 && i < QInternal::DockCount);
1023 return docks[i].insertGap(path.mid(1), item);
1024}
1025
1026void QToolBarAreaLayout::remove(const QList<int> &path)
1027{
1028 Q_ASSERT(path.size() == 3);
1029 QToolBarAreaLayoutInfo &dock = docks[path.at(0)];
1030 QToolBarAreaLayoutLine &line = dock.lines[path.at(1)];
1031 line.toolBarItems.removeAt(path.at(2));
1032 if (line.toolBarItems.isEmpty())
1033 dock.lines.removeAt(path.at(1));
1034}
1035
1036void QToolBarAreaLayout::remove(QLayoutItem *item)
1037{
1038 for (int i = 0; i < QInternal::DockCount; ++i) {
1039 QToolBarAreaLayoutInfo &dock = docks[i];
1040
1041 for (int j = 0; j < dock.lines.size(); ++j) {
1042 QToolBarAreaLayoutLine &line = dock.lines[j];
1043
1044 for (int k = 0; k < line.toolBarItems.size(); k++) {
1045 if (line.toolBarItems[k].widgetItem == item) {
1046 line.toolBarItems.removeAt(k);
1047 if (line.toolBarItems.isEmpty())
1048 dock.lines.removeAt(j);
1049 return;
1050 }
1051 }
1052 }
1053 }
1054}
1055
1057{
1058 for (int i = 0; i < QInternal::DockCount; ++i)
1059 docks[i].clear();
1060 rect = QRect();
1061}
1062
1064{
1065 Q_ASSERT(path.size() == 3);
1066
1067 if (path.at(0) < 0 || path.at(0) >= QInternal::DockCount)
1068 return nullptr;
1069 QToolBarAreaLayoutInfo &info = docks[path.at(0)];
1070 if (path.at(1) < 0 || path.at(1) >= info.lines.size())
1071 return nullptr;
1072 QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1073 if (path.at(2) < 0 || path.at(2) >= line.toolBarItems.size())
1074 return nullptr;
1075 return &(line.toolBarItems[path.at(2)]);
1076}
1077
1078QRect QToolBarAreaLayout::itemRect(const QList<int> &path) const
1079{
1080 const int i = path.first();
1081
1082 QRect r = docks[i].itemRect(path.mid(1));
1083 if (docks[i].o == Qt::Horizontal)
1084 r = QStyle::visualRect(mainWindow->layoutDirection(),
1085 docks[i].rect, r);
1086 return r;
1087}
1088
1089QLayoutItem *QToolBarAreaLayout::plug(const QList<int> &path)
1090{
1091 QToolBarAreaLayoutItem *item = this->item(path);
1092 if (Q_UNLIKELY(!item)) {
1093 qWarning() << "No item at" << path;
1094 return nullptr;
1095 }
1096 Q_ASSERT(item->gap);
1097 Q_ASSERT(item->widgetItem != nullptr);
1098 item->gap = false;
1099 return item->widgetItem;
1100}
1101
1102QLayoutItem *QToolBarAreaLayout::unplug(const QList<int> &path, QToolBarAreaLayout *other)
1103{
1104 //other needs to be update as well
1105 Q_ASSERT(path.size() == 3);
1106 QToolBarAreaLayoutItem *item = this->item(path);
1107 Q_ASSERT(item);
1108
1109 //update the leading space here
1110 QToolBarAreaLayoutInfo &info = docks[path.at(0)];
1111 QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1112 if (item->size != pick(line.o, item->realSizeHint())) {
1113 //the item doesn't have its default size
1114 //so we'll give this to the next item
1115 int newExtraSpace = 0;
1116 //let's iterate over the siblings of the current item that pare placed before it
1117 //we need to find just the one before
1118 for (int i = path.at(2) - 1; i >= 0; --i) {
1119 QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
1120 if (!previous.skip()) {
1121 //we need to check if it has a previous element and a next one
1122 //the previous will get its size changed
1123 for (int j = path.at(2) + 1; j < line.toolBarItems.size(); ++j) {
1124 const QToolBarAreaLayoutItem &next = line.toolBarItems.at(j);
1125 if (!next.skip()) {
1126 newExtraSpace = next.pos - previous.pos - pick(line.o, previous.sizeHint());
1127 previous.resize(line.o, next.pos - previous.pos);
1128 break;
1129 }
1130 }
1131 break;
1132 }
1133 }
1134
1135 if (other) {
1136 QToolBarAreaLayoutInfo &info = other->docks[path.at(0)];
1137 QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1138 for (int i = path.at(2) - 1; i >= 0; --i) {
1139 QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
1140 if (!previous.skip()) {
1141 previous.resize(line.o, pick(line.o, previous.sizeHint()) + newExtraSpace);
1142 break;
1143 }
1144 }
1145
1146 }
1147 }
1148
1149 Q_ASSERT(!item->gap);
1150 item->gap = true;
1151 return item->widgetItem;
1152}
1153
1154static QRect unpackRect(uint geom0, uint geom1, bool *floating)
1155{
1156 *floating = geom0 & 1;
1157 if (!*floating)
1158 return QRect();
1159
1160 geom0 >>= 1;
1161
1162 int x = (int)(geom0 & 0x0000ffff) - 0x7FFF;
1163 int y = (int)(geom1 & 0x0000ffff) - 0x7FFF;
1164
1165 geom0 >>= 16;
1166 geom1 >>= 16;
1167
1168 int w = geom0 & 0x0000ffff;
1169 int h = geom1 & 0x0000ffff;
1170
1171 return QRect(x, y, w, h);
1172}
1173
1174static void packRect(uint *geom0, uint *geom1, const QRect &rect, bool floating)
1175{
1176 *geom0 = 0;
1177 *geom1 = 0;
1178
1179 if (!floating)
1180 return;
1181
1182 // The 0x7FFF is half of 0xFFFF. We add it so we can handle negative coordinates on
1183 // dual monitors. It's subtracted when unpacking.
1184
1185 *geom0 |= qMax(0, rect.width()) & 0x0000ffff;
1186 *geom1 |= qMax(0, rect.height()) & 0x0000ffff;
1187
1188 *geom0 <<= 16;
1189 *geom1 <<= 16;
1190
1191 *geom0 |= qMax(0, rect.x() + 0x7FFF) & 0x0000ffff;
1192 *geom1 |= qMax(0, rect.y() + 0x7FFF) & 0x0000ffff;
1193
1194 // yeah, we chop one bit off the width, but it still has a range up to 32512
1195
1196 *geom0 <<= 1;
1197 *geom0 |= 1;
1198}
1199
1200
1201void QToolBarAreaLayout::saveState(QDataStream &stream) const
1202{
1203 // save toolbar state
1204 stream << static_cast<uchar>(StateMarkers::ToolBarEx);
1205
1206 int lineCount = 0;
1207 for (int i = 0; i < QInternal::DockCount; ++i)
1208 lineCount += docks[i].lines.size();
1209
1210 stream << lineCount;
1211
1212 for (int i = 0; i < QInternal::DockCount; ++i) {
1213 const QToolBarAreaLayoutInfo &dock = docks[i];
1214
1215 for (int j = 0; j < dock.lines.size(); ++j) {
1216 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
1217
1218 stream << i << int(line.toolBarItems.size());
1219
1220 for (int k = 0; k < line.toolBarItems.size(); ++k) {
1221 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
1222 QWidget *widget = const_cast<QLayoutItem*>(item.widgetItem)->widget();
1223 QString objectName = widget->objectName();
1224 if (Q_UNLIKELY(objectName.isEmpty())) {
1225 qWarning("QMainWindow::saveState(): 'objectName' not set for QToolBar %p '%s'",
1226 widget, widget->windowTitle().toLocal8Bit().constData());
1227 }
1228 stream << objectName;
1229 // we store information as:
1230 // 1st bit: 1 if shown
1231 // 2nd bit: 1 if orientation is vertical (default is horizontal)
1232 uchar shownOrientation = (uchar)!widget->isHidden();
1233 if (QToolBar * tb= qobject_cast<QToolBar*>(widget)) {
1234 if (tb->orientation() == Qt::Vertical)
1235 shownOrientation |= 2;
1236 }
1237 stream << shownOrientation;
1238 stream << item.pos;
1239 //we store the preferred size. If the use rdidn't resize the toolbars it will be -1
1240 stream << item.preferredSize;
1241
1242 uint geom0, geom1;
1243 packRect(&geom0, &geom1, widget->geometry(), widget->isWindow());
1244 stream << geom0 << geom1;
1245 }
1246 }
1247 }
1248}
1249
1250static inline int getInt(QDataStream &stream)
1251{
1252 int x;
1253 stream >> x;
1254 return x;
1255}
1256
1257
1258bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList<QToolBar*> &_toolBars, uchar tmarker, QInternal::CallMode callMode)
1259{
1260 const auto marker = static_cast<StateMarkers>(tmarker);
1261 const bool testing = callMode == QInternal::Testing;
1262 QList<QToolBar*> toolBars = _toolBars;
1263 int lines;
1264 stream >> lines;
1265
1266 for (int j = 0; j < lines; ++j) {
1267 int pos;
1268 stream >> pos;
1269 if (pos < 0 || pos >= QInternal::DockCount)
1270 return false;
1271 int cnt;
1272 stream >> cnt;
1273
1274 QToolBarAreaLayoutInfo &dock = docks[pos];
1275 const bool applyingLayout = !testing;
1276 QToolBarAreaLayoutLine line(dock.o);
1277
1278 for (int k = 0; k < cnt; ++k) {
1280
1281 QString objectName;
1282 stream >> objectName;
1283 uchar shown;
1284 stream >> shown;
1285 item.pos = getInt(stream);
1286 item.size = getInt(stream);
1287
1288 /*
1289 4.3.0 added floating toolbars, but failed to add the ability to restore them.
1290 We need to store there geometry (four ints). We cannot change the format in a
1291 patch release (4.3.1) by adding ToolBarStateMarkerEx2 to signal extra data. So
1292 for now we'll pack it in the two legacy ints we no longer used in Qt4.3.0.
1293 In 4.4, we should add ToolBarStateMarkerEx2 and fix this properly.
1294 */
1295
1296 QRect rect;
1297 bool floating = false;
1298 uint geom0, geom1;
1299 geom0 = getInt(stream);
1300 if (marker == StateMarkers::ToolBarEx) {
1301 geom1 = getInt(stream);
1302 rect = unpackRect(geom0, geom1, &floating);
1303 }
1304
1305 QToolBar *toolBar = nullptr;
1306 for (int x = 0; x < toolBars.size(); ++x) {
1307 if (toolBars.at(x)->objectName() == objectName) {
1308 toolBar = toolBars.takeAt(x);
1309 break;
1310 }
1311 }
1312 if (toolBar == nullptr) {
1313 continue;
1314 }
1315
1316 if (applyingLayout) {
1317 // Clear the previous widgetItem for the toolBar, so that it's
1318 // assigned correctly in QWidgetItemV2 constructor.
1319 auto *toolBarPrivate = QWidgetPrivate::get(toolBar);
1320 toolBarPrivate->widgetItem = nullptr;
1321 item.widgetItem = new QWidgetItemV2(toolBar);
1322 toolBar->setOrientation(floating ? ((shown & 2) ? Qt::Vertical : Qt::Horizontal) : dock.o);
1323 toolBar->setVisible(shown & 1);
1324 toolBar->d_func()->setWindowState(floating, false, rect);
1325
1326 item.preferredSize = item.size;
1327 line.toolBarItems.append(item);
1328 }
1329 }
1330
1331 if (applyingLayout) {
1332 dock.lines.append(line);
1333 }
1334 }
1335
1336
1337 return stream.status() == QDataStream::Ok;
1338}
1339
1341{
1342 for (int i = 0; i < QInternal::DockCount; ++i) {
1343 if (!docks[i].lines.isEmpty())
1344 return false;
1345 }
1346 return true;
1347}
1348
1349QT_END_NAMESPACE
void insertToolBarBreak(QToolBar *before)
void insertItem(QToolBar *before, QLayoutItem *item)
void removeToolBar(QToolBar *toolBar)
void removeToolBarBreak(QToolBar *before)
QLayoutItem * insertToolBar(QToolBar *before, QToolBar *toolBar)
QToolBarAreaLayoutInfo(QInternal::DockPosition pos=QInternal::TopDock)
QList< int > gapIndex(const QPoint &pos, int *maxDistance) const
void moveToolBar(QToolBar *toolbar, int pos)
bool insertGap(const QList< int > &path, QLayoutItem *item)
QRect itemRect(const QList< int > &path) const
int distance(const QPoint &pos) const
QToolBarAreaLayoutLine(Qt::Orientation orientation)
bool insertGap(const QList< int > &path, QLayoutItem *item)
const QMainWindow * mainWindow
QList< int > indexOf(QWidget *toolBar) const
QSize sizeHint(const QSize &center) const
void removeToolBarBreak(QToolBar *before)
QSize minimumSize(const QSize &centerMin) const
QLayoutItem * unplug(const QList< int > &path, QToolBarAreaLayout *other)
void remove(QLayoutItem *item)
QLayoutItem * insertToolBar(QToolBar *before, QToolBar *toolBar)
void getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
void insertItem(QInternal::DockPosition pos, QLayoutItem *item)
void apply(QWidgetAnimator::AnimationRule rule)
QRect rectHint(const QRect &r) const
void removeToolBar(QToolBar *toolBar)
QLayoutItem * itemAt(int *x, int index) const
bool restoreState(QDataStream &stream, const QList< QToolBar * > &toolBars, uchar tmarker, QInternal::CallMode callMode)
void insertToolBarBreak(QToolBar *before)
QToolBarAreaLayoutItem * item(const QList< int > &path)
QRect itemRect(const QList< int > &path) const
QToolBarAreaLayout(const QMainWindow *win)
QLayoutItem * takeAt(int *x, int index)
void saveState(QDataStream &stream) const
QLayoutItem * addToolBar(QInternal::DockPosition pos, QToolBar *toolBar)
QList< int > currentGapIndex() const
bool toolBarBreak(QToolBar *toolBar) const
std::optional< QInternal::DockPosition > findToolBar(const QToolBar *toolBar) const
void remove(const QList< int > &path)
void addToolBarBreak(QInternal::DockPosition pos)
QLayoutItem * plug(const QList< int > &path)
void insertItem(QToolBar *before, QLayoutItem *item)
QList< int > gapIndex(const QPoint &pos) const
void moveToolBar(QToolBar *toolbar, int pos)
Combined button and popup list for selecting options.
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)
static QRect unpackRect(uint geom0, uint geom1, bool *floating)
static void packRect(uint *geom0, uint *geom1, const QRect &rect, bool floating)
static int getInt(QDataStream &stream)