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
15#include "qtoolbar_p.h"
16
17/******************************************************************************
18** QToolBarAreaLayoutItem
19*/
20
22
23// qmainwindow.cpp
24extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *mainWindow);
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
757QInternal::DockPosition QToolBarAreaLayout::findToolBar(const QToolBar *toolBar) const
758{
759 for (int i = 0; i < QInternal::DockCount; ++i) {
760 const QToolBarAreaLayoutInfo &dock = docks[i];
761
762 for (int j = 0; j < dock.lines.size(); ++j) {
763 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
764
765 for (int k = 0; k < line.toolBarItems.size(); ++k) {
766 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar)
767 return static_cast<QInternal::DockPosition>(i);
768 }
769 }
770 }
771
772 return QInternal::DockCount;
773}
774
775QLayoutItem *QToolBarAreaLayout::insertToolBar(QToolBar *before, QToolBar *toolBar)
776{
777 QInternal::DockPosition pos = findToolBar(before);
778 if (pos == QInternal::DockCount)
779 return nullptr;
780
781 return docks[pos].insertToolBar(before, toolBar);
782}
783
784void QToolBarAreaLayout::removeToolBar(QToolBar *toolBar)
785{
786 QInternal::DockPosition pos = findToolBar(toolBar);
787 if (pos == QInternal::DockCount)
788 return;
789 docks[pos].removeToolBar(toolBar);
790}
791
792QLayoutItem *QToolBarAreaLayout::addToolBar(QInternal::DockPosition pos, QToolBar *toolBar)
793{
794 return docks[pos].insertToolBar(nullptr, toolBar);
795}
796
798{
799 QInternal::DockPosition pos = findToolBar(before);
800 if (pos == QInternal::DockCount)
801 return;
802 docks[pos].insertToolBarBreak(before);
803}
804
806{
807 QInternal::DockPosition pos = findToolBar(before);
808 if (pos == QInternal::DockCount)
809 return;
810 docks[pos].removeToolBarBreak(before);
811}
812
813void QToolBarAreaLayout::addToolBarBreak(QInternal::DockPosition pos)
814{
815 docks[pos].insertToolBarBreak(nullptr);
816}
817
818void QToolBarAreaLayout::moveToolBar(QToolBar *toolbar, int p)
819{
820 QInternal::DockPosition pos = findToolBar(toolbar);
821 if (pos == QInternal::DockCount)
822 return;
823 docks[pos].moveToolBar(toolbar, p);
824}
825
826
827void QToolBarAreaLayout::insertItem(QInternal::DockPosition pos, QLayoutItem *item)
828{
829 if (docks[pos].lines.isEmpty())
830 docks[pos].lines.append(QToolBarAreaLayoutLine(docks[pos].o));
831 docks[pos].lines.last().toolBarItems.append(item);
832}
833
834void QToolBarAreaLayout::insertItem(QToolBar *before, QLayoutItem *item)
835{
836 QInternal::DockPosition pos = findToolBar(before);
837 if (pos == QInternal::DockCount)
838 return;
839
840 docks[pos].insertItem(before, item);
841}
842
843void QToolBarAreaLayout::apply(bool animate)
844{
845 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
846 Q_ASSERT(layout != nullptr);
847
848 Qt::LayoutDirection dir = mainWindow->layoutDirection();
849
850 for (int i = 0; i < QInternal::DockCount; ++i) {
851 const QToolBarAreaLayoutInfo &dock = docks[i];
852
853 for (int j = 0; j < dock.lines.size(); ++j) {
854 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
855 if (line.skip())
856 continue;
857
858 for (int k = 0; k < line.toolBarItems.size(); ++k) {
859 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
860 if (item.skip() || item.gap)
861 continue;
862
863 QRect geo;
864 if (visible) {
865 if (line.o == Qt::Horizontal) {
866 geo.setTop(line.rect.top());
867 geo.setBottom(line.rect.bottom());
868 geo.setLeft(line.rect.left() + item.pos);
869 geo.setRight(line.rect.left() + item.pos + item.size - 1);
870 } else {
871 geo.setLeft(line.rect.left());
872 geo.setRight(line.rect.right());
873 geo.setTop(line.rect.top() + item.pos);
874 geo.setBottom(line.rect.top() + item.pos + item.size - 1);
875 }
876 }
877
878 QWidget *widget = item.widgetItem->widget();
879 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
880 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(toolBar->layout());
881 if (tbl->expanded) {
882 QPoint tr = geo.topRight();
883 QSize size = tbl->expandedSize(geo.size());
884 geo.setSize(size);
885 geo.moveTopRight(tr);
886 if (geo.bottom() > rect.bottom())
887 geo.moveBottom(rect.bottom());
888 if (geo.right() > rect.right())
889 geo.moveRight(rect.right());
890 if (geo.left() < 0)
891 geo.moveLeft(0);
892 if (geo.top() < 0)
893 geo.moveTop(0);
894 }
895 }
896
897 if (visible && dock.o == Qt::Horizontal)
898 geo = QStyle::visualRect(dir, line.rect, geo);
899
900 layout->widgetAnimator.animate(widget, geo, animate);
901 }
902 }
903 }
904}
905
906bool QToolBarAreaLayout::toolBarBreak(QToolBar *toolBar) const
907{
908 for (int i = 0; i < QInternal::DockCount; ++i) {
909 const QToolBarAreaLayoutInfo &dock = docks[i];
910
911 for (int j = 0; j < dock.lines.size(); ++j) {
912 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
913
914 for (int k = 0; k < line.toolBarItems.size(); ++k) {
915 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar)
916 return j > 0 && k == 0;
917 }
918 }
919 }
920
921 return false;
922}
923
924void QToolBarAreaLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
925{
926 for (int i = 0; i < QInternal::DockCount; ++i) {
927 const QToolBarAreaLayoutInfo &dock = docks[i];
928
929 for (int j = 0; j < dock.lines.size(); ++j) {
930 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
931
932 for (int k = 0; k < line.toolBarItems.size(); ++k) {
933 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar) {
934 if (line.toolBarItems.size() == 1)
935 option->positionWithinLine = QStyleOptionToolBar::OnlyOne;
936 else if (k == 0)
937 option->positionWithinLine = QStyleOptionToolBar::Beginning;
938 else if (k == line.toolBarItems.size() - 1)
939 option->positionWithinLine = QStyleOptionToolBar::End;
940 else
941 option->positionWithinLine = QStyleOptionToolBar::Middle;
942
943 if (dock.lines.size() == 1)
944 option->positionOfLine = QStyleOptionToolBar::OnlyOne;
945 else if (j == 0)
946 option->positionOfLine = QStyleOptionToolBar::Beginning;
947 else if (j == dock.lines.size() - 1)
948 option->positionOfLine = QStyleOptionToolBar::End;
949 else
950 option->positionOfLine = QStyleOptionToolBar::Middle;
951
952 return;
953 }
954 }
955 }
956 }
957}
958
959QList<int> QToolBarAreaLayout::indexOf(QWidget *toolBar) const
960{
961 QList<int> result;
962
963 bool found = false;
964
965 for (int i = 0; i < QInternal::DockCount; ++i) {
966 const QToolBarAreaLayoutInfo &dock = docks[i];
967
968 for (int j = 0; j < dock.lines.size(); ++j) {
969 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
970
971 for (int k = 0; k < line.toolBarItems.size(); ++k) {
972 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
973 if (!item.gap && item.widgetItem->widget() == toolBar) {
974 found = true;
975 result.prepend(k);
976 break;
977 }
978 }
979
980 if (found) {
981 result.prepend(j);
982 break;
983 }
984 }
985
986 if (found) {
987 result.prepend(i);
988 break;
989 }
990 }
991
992 return result;
993}
994
995//this functions returns the path to the possible gapindex for the position pos
996QList<int> QToolBarAreaLayout::gapIndex(const QPoint &pos) const
997{
998 Qt::LayoutDirection dir = mainWindow->layoutDirection();
999 int minDistance = 80; // when a dock area is empty, how "wide" is it?
1000 QList<int> ret; //return value
1001 for (int i = 0; i < QInternal::DockCount; ++i) {
1002 QPoint p = pos;
1003 if (docks[i].o == Qt::Horizontal)
1004 p = QStyle::visualPos(dir, docks[i].rect, p);
1005 QList<int> result = docks[i].gapIndex(p, &minDistance);
1006 if (!result.isEmpty()) {
1007 result.prepend(i);
1008 ret = result;
1009 }
1010 }
1011
1012 return ret;
1013}
1014
1016{
1017 for (int i = 0; i < QInternal::DockCount; ++i) {
1018 const QToolBarAreaLayoutInfo &dock = docks[i];
1019
1020 for (int j = 0; j < dock.lines.size(); ++j) {
1021 const QToolBarAreaLayoutLine &line = dock.lines[j];
1022
1023 for (int k = 0; k < line.toolBarItems.size(); k++) {
1024 if (line.toolBarItems[k].gap) {
1025 QList<int> result;
1026 result << i << j << k;
1027 return result;
1028 }
1029 }
1030 }
1031 }
1032 return QList<int>();
1033}
1034
1035bool QToolBarAreaLayout::insertGap(const QList<int> &path, QLayoutItem *item)
1036{
1037 Q_ASSERT(path.size() == 3);
1038 const int i = path.first();
1039 Q_ASSERT(i >= 0 && i < QInternal::DockCount);
1040 return docks[i].insertGap(path.mid(1), item);
1041}
1042
1043void QToolBarAreaLayout::remove(const QList<int> &path)
1044{
1045 Q_ASSERT(path.size() == 3);
1046 QToolBarAreaLayoutInfo &dock = docks[path.at(0)];
1047 QToolBarAreaLayoutLine &line = dock.lines[path.at(1)];
1048 line.toolBarItems.removeAt(path.at(2));
1049 if (line.toolBarItems.isEmpty())
1050 dock.lines.removeAt(path.at(1));
1051}
1052
1053void QToolBarAreaLayout::remove(QLayoutItem *item)
1054{
1055 for (int i = 0; i < QInternal::DockCount; ++i) {
1056 QToolBarAreaLayoutInfo &dock = docks[i];
1057
1058 for (int j = 0; j < dock.lines.size(); ++j) {
1059 QToolBarAreaLayoutLine &line = dock.lines[j];
1060
1061 for (int k = 0; k < line.toolBarItems.size(); k++) {
1062 if (line.toolBarItems[k].widgetItem == item) {
1063 line.toolBarItems.removeAt(k);
1064 if (line.toolBarItems.isEmpty())
1065 dock.lines.removeAt(j);
1066 return;
1067 }
1068 }
1069 }
1070 }
1071}
1072
1074{
1075 for (int i = 0; i < QInternal::DockCount; ++i)
1076 docks[i].clear();
1077 rect = QRect();
1078}
1079
1081{
1082 Q_ASSERT(path.size() == 3);
1083
1084 if (path.at(0) < 0 || path.at(0) >= QInternal::DockCount)
1085 return nullptr;
1086 QToolBarAreaLayoutInfo &info = docks[path.at(0)];
1087 if (path.at(1) < 0 || path.at(1) >= info.lines.size())
1088 return nullptr;
1089 QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1090 if (path.at(2) < 0 || path.at(2) >= line.toolBarItems.size())
1091 return nullptr;
1092 return &(line.toolBarItems[path.at(2)]);
1093}
1094
1095QRect QToolBarAreaLayout::itemRect(const QList<int> &path) const
1096{
1097 const int i = path.first();
1098
1099 QRect r = docks[i].itemRect(path.mid(1));
1100 if (docks[i].o == Qt::Horizontal)
1101 r = QStyle::visualRect(mainWindow->layoutDirection(),
1102 docks[i].rect, r);
1103 return r;
1104}
1105
1106QLayoutItem *QToolBarAreaLayout::plug(const QList<int> &path)
1107{
1108 QToolBarAreaLayoutItem *item = this->item(path);
1109 if (Q_UNLIKELY(!item)) {
1110 qWarning() << "No item at" << path;
1111 return nullptr;
1112 }
1113 Q_ASSERT(item->gap);
1114 Q_ASSERT(item->widgetItem != nullptr);
1115 item->gap = false;
1116 return item->widgetItem;
1117}
1118
1119QLayoutItem *QToolBarAreaLayout::unplug(const QList<int> &path, QToolBarAreaLayout *other)
1120{
1121 //other needs to be update as well
1122 Q_ASSERT(path.size() == 3);
1123 QToolBarAreaLayoutItem *item = this->item(path);
1124 Q_ASSERT(item);
1125
1126 //update the leading space here
1127 QToolBarAreaLayoutInfo &info = docks[path.at(0)];
1128 QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1129 if (item->size != pick(line.o, item->realSizeHint())) {
1130 //the item doesn't have its default size
1131 //so we'll give this to the next item
1132 int newExtraSpace = 0;
1133 //let's iterate over the siblings of the current item that pare placed before it
1134 //we need to find just the one before
1135 for (int i = path.at(2) - 1; i >= 0; --i) {
1136 QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
1137 if (!previous.skip()) {
1138 //we need to check if it has a previous element and a next one
1139 //the previous will get its size changed
1140 for (int j = path.at(2) + 1; j < line.toolBarItems.size(); ++j) {
1141 const QToolBarAreaLayoutItem &next = line.toolBarItems.at(j);
1142 if (!next.skip()) {
1143 newExtraSpace = next.pos - previous.pos - pick(line.o, previous.sizeHint());
1144 previous.resize(line.o, next.pos - previous.pos);
1145 break;
1146 }
1147 }
1148 break;
1149 }
1150 }
1151
1152 if (other) {
1153 QToolBarAreaLayoutInfo &info = other->docks[path.at(0)];
1154 QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1155 for (int i = path.at(2) - 1; i >= 0; --i) {
1156 QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
1157 if (!previous.skip()) {
1158 previous.resize(line.o, pick(line.o, previous.sizeHint()) + newExtraSpace);
1159 break;
1160 }
1161 }
1162
1163 }
1164 }
1165
1166 Q_ASSERT(!item->gap);
1167 item->gap = true;
1168 return item->widgetItem;
1169}
1170
1171static QRect unpackRect(uint geom0, uint geom1, bool *floating)
1172{
1173 *floating = geom0 & 1;
1174 if (!*floating)
1175 return QRect();
1176
1177 geom0 >>= 1;
1178
1179 int x = (int)(geom0 & 0x0000ffff) - 0x7FFF;
1180 int y = (int)(geom1 & 0x0000ffff) - 0x7FFF;
1181
1182 geom0 >>= 16;
1183 geom1 >>= 16;
1184
1185 int w = geom0 & 0x0000ffff;
1186 int h = geom1 & 0x0000ffff;
1187
1188 return QRect(x, y, w, h);
1189}
1190
1191static void packRect(uint *geom0, uint *geom1, const QRect &rect, bool floating)
1192{
1193 *geom0 = 0;
1194 *geom1 = 0;
1195
1196 if (!floating)
1197 return;
1198
1199 // The 0x7FFF is half of 0xFFFF. We add it so we can handle negative coordinates on
1200 // dual monitors. It's subtracted when unpacking.
1201
1202 *geom0 |= qMax(0, rect.width()) & 0x0000ffff;
1203 *geom1 |= qMax(0, rect.height()) & 0x0000ffff;
1204
1205 *geom0 <<= 16;
1206 *geom1 <<= 16;
1207
1208 *geom0 |= qMax(0, rect.x() + 0x7FFF) & 0x0000ffff;
1209 *geom1 |= qMax(0, rect.y() + 0x7FFF) & 0x0000ffff;
1210
1211 // yeah, we chop one bit off the width, but it still has a range up to 32512
1212
1213 *geom0 <<= 1;
1214 *geom0 |= 1;
1215}
1216
1217
1218void QToolBarAreaLayout::saveState(QDataStream &stream) const
1219{
1220 // save toolbar state
1221 stream << (uchar) ToolBarStateMarkerEx;
1222
1223 int lineCount = 0;
1224 for (int i = 0; i < QInternal::DockCount; ++i)
1225 lineCount += docks[i].lines.size();
1226
1227 stream << lineCount;
1228
1229 for (int i = 0; i < QInternal::DockCount; ++i) {
1230 const QToolBarAreaLayoutInfo &dock = docks[i];
1231
1232 for (int j = 0; j < dock.lines.size(); ++j) {
1233 const QToolBarAreaLayoutLine &line = dock.lines.at(j);
1234
1235 stream << i << int(line.toolBarItems.size());
1236
1237 for (int k = 0; k < line.toolBarItems.size(); ++k) {
1238 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
1239 QWidget *widget = const_cast<QLayoutItem*>(item.widgetItem)->widget();
1240 QString objectName = widget->objectName();
1241 if (Q_UNLIKELY(objectName.isEmpty())) {
1242 qWarning("QMainWindow::saveState(): 'objectName' not set for QToolBar %p '%s'",
1243 widget, widget->windowTitle().toLocal8Bit().constData());
1244 }
1245 stream << objectName;
1246 // we store information as:
1247 // 1st bit: 1 if shown
1248 // 2nd bit: 1 if orientation is vertical (default is horizontal)
1249 uchar shownOrientation = (uchar)!widget->isHidden();
1250 if (QToolBar * tb= qobject_cast<QToolBar*>(widget)) {
1251 if (tb->orientation() == Qt::Vertical)
1252 shownOrientation |= 2;
1253 }
1254 stream << shownOrientation;
1255 stream << item.pos;
1256 //we store the preferred size. If the use rdidn't resize the toolbars it will be -1
1257 stream << item.preferredSize;
1258
1259 uint geom0, geom1;
1260 packRect(&geom0, &geom1, widget->geometry(), widget->isWindow());
1261 stream << geom0 << geom1;
1262 }
1263 }
1264 }
1265}
1266
1267static inline int getInt(QDataStream &stream)
1268{
1269 int x;
1270 stream >> x;
1271 return x;
1272}
1273
1274
1275bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList<QToolBar*> &_toolBars, uchar tmarker, bool testing)
1276{
1277 QList<QToolBar*> toolBars = _toolBars;
1278 int lines;
1279 stream >> lines;
1280
1281 for (int j = 0; j < lines; ++j) {
1282 int pos;
1283 stream >> pos;
1284 if (pos < 0 || pos >= QInternal::DockCount)
1285 return false;
1286 int cnt;
1287 stream >> cnt;
1288
1289 QToolBarAreaLayoutInfo &dock = docks[pos];
1290 const bool applyingLayout = !testing;
1291 QToolBarAreaLayoutLine line(dock.o);
1292
1293 for (int k = 0; k < cnt; ++k) {
1295
1296 QString objectName;
1297 stream >> objectName;
1298 uchar shown;
1299 stream >> shown;
1300 item.pos = getInt(stream);
1301 item.size = getInt(stream);
1302
1303 /*
1304 4.3.0 added floating toolbars, but failed to add the ability to restore them.
1305 We need to store there geometry (four ints). We cannot change the format in a
1306 patch release (4.3.1) by adding ToolBarStateMarkerEx2 to signal extra data. So
1307 for now we'll pack it in the two legacy ints we no longer used in Qt4.3.0.
1308 In 4.4, we should add ToolBarStateMarkerEx2 and fix this properly.
1309 */
1310
1311 QRect rect;
1312 bool floating = false;
1313 uint geom0, geom1;
1314 geom0 = getInt(stream);
1315 if (tmarker == ToolBarStateMarkerEx) {
1316 geom1 = getInt(stream);
1317 rect = unpackRect(geom0, geom1, &floating);
1318 }
1319
1320 QToolBar *toolBar = nullptr;
1321 for (int x = 0; x < toolBars.size(); ++x) {
1322 if (toolBars.at(x)->objectName() == objectName) {
1323 toolBar = toolBars.takeAt(x);
1324 break;
1325 }
1326 }
1327 if (toolBar == nullptr) {
1328 continue;
1329 }
1330
1331 if (applyingLayout) {
1332 // Clear the previous widgetItem for the toolBar, so that it's
1333 // assigned correctly in QWidgetItemV2 constructor.
1334 auto *toolBarPrivate = QWidgetPrivate::get(toolBar);
1335 toolBarPrivate->widgetItem = nullptr;
1336 item.widgetItem = new QWidgetItemV2(toolBar);
1337 toolBar->setOrientation(floating ? ((shown & 2) ? Qt::Vertical : Qt::Horizontal) : dock.o);
1338 toolBar->setVisible(shown & 1);
1339 toolBar->d_func()->setWindowState(floating, false, rect);
1340
1341 item.preferredSize = item.size;
1342 line.toolBarItems.append(item);
1343 }
1344 }
1345
1346 if (applyingLayout) {
1347 dock.lines.append(line);
1348 }
1349 }
1350
1351
1352 return stream.status() == QDataStream::Ok;
1353}
1354
1356{
1357 for (int i = 0; i < QInternal::DockCount; ++i) {
1358 if (!docks[i].lines.isEmpty())
1359 return false;
1360 }
1361 return true;
1362}
1363
1364QT_END_NAMESPACE
friend class QWidget
Definition qpainter.h:431
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
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
bool restoreState(QDataStream &stream, const QList< QToolBar * > &toolBars, uchar tmarker, bool testing=false)
void insertItem(QInternal::DockPosition pos, QLayoutItem *item)
void removeToolBar(QToolBar *toolBar)
QLayoutItem * itemAt(int *x, int index) const
void insertToolBarBreak(QToolBar *before)
void apply(bool animate)
QInternal::DockPosition findToolBar(const QToolBar *toolBar) const
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
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)
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)