1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWidgets module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <qapplication.h>
41#include <qaction.h>
42#include <qwidgetaction.h>
43#include <qtoolbar.h>
44#include <qstyleoption.h>
45#if QT_CONFIG(toolbutton)
46#include <qtoolbutton.h>
47#endif
48#include <qmenu.h>
49#include <qdebug.h>
50#include <qmath.h>
51#ifdef Q_OS_MACOS
52#include <qpa/qplatformnativeinterface.h>
53#endif
54
55#include "qmainwindowlayout_p.h"
56#if QT_CONFIG(toolbutton)
57#include "qtoolbarextension_p.h"
58#endif
59#include "qtoolbarlayout_p.h"
60#include "qtoolbarseparator_p.h"
61
62QT_BEGIN_NAMESPACE
63
64// qmainwindow.cpp
65extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
66
67/******************************************************************************
68** QToolBarItem
69*/
70
71QToolBarItem::QToolBarItem(QWidget *widget)
72 : QWidgetItem(widget), action(nullptr), customWidget(false)
73{
74}
75
76bool QToolBarItem::isEmpty() const
77{
78 return action == nullptr || !action->isVisible();
79}
80
81/******************************************************************************
82** QToolBarLayout
83*/
84
85QToolBarLayout::QToolBarLayout(QWidget *parent)
86 : QLayout(parent), expanded(false), animating(false), dirty(true),
87 expanding(false), empty(true), expandFlag(false), popupMenu(nullptr)
88{
89 QToolBar *tb = qobject_cast<QToolBar*>(object: parent);
90 if (!tb)
91 return;
92
93 extension = new QToolBarExtension(tb);
94 extension->setFocusPolicy(Qt::NoFocus);
95 extension->hide();
96 QObject::connect(sender: tb, SIGNAL(orientationChanged(Qt::Orientation)),
97 receiver: extension, SLOT(setOrientation(Qt::Orientation)));
98
99 setUsePopupMenu(qobject_cast<QMainWindow*>(object: tb->parentWidget()) == 0);
100}
101
102QToolBarLayout::~QToolBarLayout()
103{
104 while (!items.isEmpty()) {
105 QToolBarItem *item = items.takeFirst();
106 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(object: item->action)) {
107 if (item->customWidget)
108 widgetAction->releaseWidget(widget: item->widget());
109 }
110 delete item;
111 }
112}
113
114void QToolBarLayout::updateMarginAndSpacing()
115{
116 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
117 if (!tb)
118 return;
119 QStyle *style = tb->style();
120 QStyleOptionToolBar opt;
121 tb->initStyleOption(option: &opt);
122 const int margin = style->pixelMetric(metric: QStyle::PM_ToolBarItemMargin, option: &opt, widget: tb)
123 + style->pixelMetric(metric: QStyle::PM_ToolBarFrameWidth, option: &opt, widget: tb);
124 setContentsMargins(left: margin, top: margin, right: margin, bottom: margin);
125 setSpacing(style->pixelMetric(metric: QStyle::PM_ToolBarItemSpacing, option: &opt, widget: tb));
126}
127
128bool QToolBarLayout::hasExpandFlag() const
129{
130 return expandFlag;
131}
132
133void QToolBarLayout::setUsePopupMenu(bool set)
134{
135 if (!dirty && ((popupMenu == nullptr) == set))
136 invalidate();
137 if (!set) {
138 QObject::connect(sender: extension, SIGNAL(clicked(bool)),
139 receiver: this, SLOT(setExpanded(bool)), Qt::UniqueConnection);
140 extension->setPopupMode(QToolButton::DelayedPopup);
141 extension->setMenu(nullptr);
142 delete popupMenu;
143 popupMenu = nullptr;
144 } else {
145 QObject::disconnect(sender: extension, SIGNAL(clicked(bool)),
146 receiver: this, SLOT(setExpanded(bool)));
147 extension->setPopupMode(QToolButton::InstantPopup);
148 if (!popupMenu) {
149 popupMenu = new QMenu(extension);
150 }
151 extension->setMenu(popupMenu);
152 }
153}
154
155void QToolBarLayout::checkUsePopupMenu()
156{
157 QToolBar *tb = static_cast<QToolBar *>(parent());
158 QMainWindow *mw = qobject_cast<QMainWindow *>(object: tb->parent());
159 Qt::Orientation o = tb->orientation();
160 setUsePopupMenu(!mw || tb->isFloating() || perp(o, size: expandedSize(size: mw->size())) >= perp(o, size: mw->size()));
161}
162
163void QToolBarLayout::addItem(QLayoutItem*)
164{
165 qWarning(msg: "QToolBarLayout::addItem(): please use addAction() instead");
166 return;
167}
168
169QLayoutItem *QToolBarLayout::itemAt(int index) const
170{
171 if (index < 0 || index >= items.count())
172 return nullptr;
173 return items.at(i: index);
174}
175
176QLayoutItem *QToolBarLayout::takeAt(int index)
177{
178 if (index < 0 || index >= items.count())
179 return nullptr;
180 QToolBarItem *item = items.takeAt(i: index);
181
182 if (popupMenu)
183 popupMenu->removeAction(action: item->action);
184
185 QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(object: item->action);
186 if (widgetAction != nullptr && item->customWidget) {
187 widgetAction->releaseWidget(widget: item->widget());
188 } else {
189 // destroy the QToolButton/QToolBarSeparator
190 item->widget()->hide();
191 item->widget()->deleteLater();
192 }
193
194 invalidate();
195 return item;
196}
197
198void QToolBarLayout::insertAction(int index, QAction *action)
199{
200 index = qMax(a: 0, b: index);
201 index = qMin(a: items.count(), b: index);
202
203 QToolBarItem *item = createItem(action);
204 if (item) {
205 items.insert(i: index, t: item);
206 invalidate();
207 }
208}
209
210int QToolBarLayout::indexOf(QAction *action) const
211{
212 for (int i = 0; i < items.count(); ++i) {
213 if (items.at(i)->action == action)
214 return i;
215 }
216 return -1;
217}
218
219int QToolBarLayout::count() const
220{
221 return items.count();
222}
223
224bool QToolBarLayout::isEmpty() const
225{
226 if (dirty)
227 updateGeomArray();
228 return empty;
229}
230
231void QToolBarLayout::invalidate()
232{
233 dirty = true;
234 QLayout::invalidate();
235}
236
237Qt::Orientations QToolBarLayout::expandingDirections() const
238{
239 if (dirty)
240 updateGeomArray();
241 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
242 if (!tb)
243 return {};
244 Qt::Orientation o = tb->orientation();
245 return expanding ? Qt::Orientations(o) : Qt::Orientations{};
246}
247
248bool QToolBarLayout::movable() const
249{
250 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
251 if (!tb)
252 return false;
253 QMainWindow *win = qobject_cast<QMainWindow*>(object: tb->parentWidget());
254 return tb->isMovable() && win != nullptr;
255}
256
257void QToolBarLayout::updateGeomArray() const
258{
259 if (!dirty)
260 return;
261
262 QToolBarLayout *that = const_cast<QToolBarLayout*>(this);
263
264 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
265 if (!tb)
266 return;
267 QStyle *style = tb->style();
268 QStyleOptionToolBar opt;
269 tb->initStyleOption(option: &opt);
270 const int handleExtent = movable()
271 ? style->pixelMetric(metric: QStyle::PM_ToolBarHandleExtent, option: &opt, widget: tb) : 0;
272 const QMargins margins = contentsMargins();
273 const int spacing = this->spacing();
274 const int extensionExtent = style->pixelMetric(metric: QStyle::PM_ToolBarExtensionExtent, option: &opt, widget: tb);
275 Qt::Orientation o = tb->orientation();
276
277 that->minSize = QSize(0, 0);
278 that->hint = QSize(0, 0);
279 rperp(o, size&: that->minSize) = style->pixelMetric(metric: QStyle::PM_ToolBarHandleExtent, option: &opt, widget: tb);
280 rperp(o, size&: that->hint) = style->pixelMetric(metric: QStyle::PM_ToolBarHandleExtent, option: &opt, widget: tb);
281
282 that->expanding = false;
283 that->empty = false;
284
285 QVector<QLayoutStruct> a(items.count() + 1); // + 1 for the stretch
286
287 int count = 0;
288 for (int i = 0; i < items.count(); ++i) {
289 QToolBarItem *item = items.at(i);
290
291 QSize max = item->maximumSize();
292 QSize min = item->minimumSize();
293 QSize hint = item->sizeHint();
294 Qt::Orientations exp = item->expandingDirections();
295 bool empty = item->isEmpty();
296
297 that->expanding = expanding || exp & o;
298
299
300 if (item->widget()) {
301 if ((item->widget()->sizePolicy().horizontalPolicy() & QSizePolicy::ExpandFlag)) {
302 that->expandFlag = true;
303 }
304 }
305
306 if (!empty) {
307 if (count == 0) // the minimum size only displays one widget
308 rpick(o, size&: that->minSize) += pick(o, size: min);
309 int s = perp(o, size: minSize);
310 rperp(o, size&: that->minSize) = qMax(a: s, b: perp(o, size: min));
311
312 //we only add spacing before item (ie never before the first one)
313 rpick(o, size&: that->hint) += (count == 0 ? 0 : spacing) + pick(o, size: hint);
314 s = perp(o, size: that->hint);
315 rperp(o, size&: that->hint) = qMax(a: s, b: perp(o, size: hint));
316 ++count;
317 }
318
319 a[i].sizeHint = pick(o, size: hint);
320 a[i].maximumSize = pick(o, size: max);
321 a[i].minimumSize = pick(o, size: min);
322 a[i].expansive = exp & o;
323 if (o == Qt::Horizontal)
324 a[i].stretch = item->widget()->sizePolicy().horizontalStretch();
325 else
326 a[i].stretch = item->widget()->sizePolicy().verticalStretch();
327 a[i].empty = empty;
328 }
329
330 that->geomArray = a;
331 that->empty = count == 0;
332
333 rpick(o, size&: that->minSize) += handleExtent;
334 that->minSize += QSize(pick(o: Qt::Horizontal, m: margins), pick(o: Qt::Vertical, m: margins));
335 if (items.count() > 1)
336 rpick(o, size&: that->minSize) += spacing + extensionExtent;
337
338 rpick(o, size&: that->hint) += handleExtent;
339 that->hint += QSize(pick(o: Qt::Horizontal, m: margins), pick(o: Qt::Vertical, m: margins));
340 that->dirty = false;
341}
342
343static bool defaultWidgetAction(QToolBarItem *item)
344{
345 QWidgetAction *a = qobject_cast<QWidgetAction*>(object: item->action);
346 return a != nullptr && a->defaultWidget() == item->widget();
347}
348
349void QToolBarLayout::updateMacBorderMetrics()
350{
351#ifdef Q_OS_MACOS
352 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
353 if (!tb)
354 return;
355
356 QRect rect = geometry();
357
358 QMainWindow *mainWindow = qobject_cast<QMainWindow*>(tb->parentWidget());
359 if (!mainWindow || !mainWindow->isWindow() || !mainWindow->unifiedTitleAndToolBarOnMac())
360 return;
361
362 QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface();
363 if (!nativeInterface)
364 return; // Not Cocoa platform plugin.
365 QPlatformNativeInterface::NativeResourceForIntegrationFunction function =
366 nativeInterface->nativeResourceFunctionForIntegration("registerContentBorderArea");
367 if (!function)
368 return; // Not Cocoa platform plugin.
369
370 QPoint upper = tb->mapToParent(rect.topLeft());
371 QPoint lower = tb->mapToParent(rect.bottomLeft() + QPoint(0, 1));
372
373 typedef void (*RegisterContentBorderAreaFunction)(QWindow *window, void *identifier, int upper, int lower);
374 if (mainWindow->toolBarArea(tb) == Qt::TopToolBarArea) {
375 (reinterpret_cast<RegisterContentBorderAreaFunction>(function))(tb->window()->windowHandle(), tb, upper.y(), lower.y());
376 } else {
377 (reinterpret_cast<RegisterContentBorderAreaFunction>(function))(tb->window()->windowHandle(), tb, 0, 0);
378 }
379#endif
380}
381
382void QToolBarLayout::setGeometry(const QRect &rect)
383{
384 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
385 if (!tb)
386 return;
387 QStyle *style = tb->style();
388 QStyleOptionToolBar opt;
389 tb->initStyleOption(option: &opt);
390 const QMargins margins = contentsMargins();
391 const int extensionExtent = style->pixelMetric(metric: QStyle::PM_ToolBarExtensionExtent, option: &opt, widget: tb);
392 Qt::Orientation o = tb->orientation();
393
394 QLayout::setGeometry(rect);
395
396 updateMacBorderMetrics();
397
398 bool ranOutOfSpace = false;
399 if (!animating)
400 ranOutOfSpace = layoutActions(size: rect.size());
401
402 if (expanded || animating || ranOutOfSpace) {
403 Qt::ToolBarArea area = Qt::TopToolBarArea;
404 if (QMainWindow *win = qobject_cast<QMainWindow*>(object: tb->parentWidget()))
405 area = win->toolBarArea(toolbar: tb);
406 QSize hint = sizeHint();
407
408 QPoint pos;
409 rpick(o, pos) = pick(o, pos: rect.bottomRight()) -
410 pick(o, size: QSize(margins.bottom(), margins.right())) - extensionExtent + 2;
411 if (area == Qt::LeftToolBarArea || area == Qt::TopToolBarArea)
412 rperp(o, pos) = perp(o, pos: rect.topLeft()) +
413 perp(o, size: QSize(margins.top(), margins.left()));
414 else
415 rperp(o, pos) = perp(o, pos: rect.bottomRight()) -
416 perp(o, size: QSize(margins.bottom(), margins.right())) -
417 (perp(o, size: hint) - perp(o, m: margins)) + 1;
418 QSize size;
419 rpick(o, size) = extensionExtent;
420 rperp(o, size) = perp(o, size: hint) - perp(o, m: margins);
421 QRect r(pos, size);
422
423 if (o == Qt::Horizontal)
424 r = QStyle::visualRect(direction: parentWidget()->layoutDirection(), boundingRect: rect, logicalRect: r);
425
426 extension->setGeometry(r);
427
428 if (extension->isHidden())
429 extension->show();
430 } else {
431 if (!extension->isHidden())
432 extension->hide();
433 }
434}
435
436bool QToolBarLayout::layoutActions(const QSize &size)
437{
438 if (dirty)
439 updateGeomArray();
440
441 QRect rect(0, 0, size.width(), size.height());
442
443 QList<QWidget*> showWidgets, hideWidgets;
444
445 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
446 if (!tb)
447 return false;
448 QStyle *style = tb->style();
449 QStyleOptionToolBar opt;
450 tb->initStyleOption(option: &opt);
451 const int handleExtent = movable()
452 ? style->pixelMetric(metric: QStyle::PM_ToolBarHandleExtent, option: &opt, widget: tb) : 0;
453 const QMargins margins = contentsMargins();
454 const int spacing = this->spacing();
455 const int extensionExtent = style->pixelMetric(metric: QStyle::PM_ToolBarExtensionExtent, option: &opt, widget: tb);
456 Qt::Orientation o = tb->orientation();
457 bool extensionMenuContainsOnlyWidgetActions = true;
458
459 int space = pick(o, size: rect.size()) - pick(o, m: margins) - handleExtent;
460 if (space <= 0)
461 return false; // nothing to do.
462
463 if(popupMenu)
464 popupMenu->clear();
465
466 bool ranOutOfSpace = false;
467 int rows = 0;
468 int rowPos = perp(o, pos: rect.topLeft()) + perp(o, size: QSize(margins.top(), margins.left()));
469 int i = 0;
470 while (i < items.count()) {
471 QVector<QLayoutStruct> a = geomArray;
472
473 int start = i;
474 int size = 0;
475 int prev = -1;
476 int rowHeight = 0;
477 int count = 0;
478 int maximumSize = 0;
479 bool expansiveRow = false;
480 for (; i < items.count(); ++i) {
481 if (a[i].empty)
482 continue;
483
484 int newSize = size + (count == 0 ? 0 : spacing) + a[i].minimumSize;
485 if (prev != -1 && newSize > space) {
486 if (rows == 0)
487 ranOutOfSpace = true;
488 // do we have to move the previous item to the next line to make space for
489 // the extension button?
490 if (count > 1 && size + spacing + extensionExtent > space)
491 i = prev;
492 break;
493 }
494
495 if (expanded)
496 rowHeight = qMax(a: rowHeight, b: perp(o, size: items.at(i)->sizeHint()));
497 expansiveRow = expansiveRow || a[i].expansive;
498 size = newSize;
499 maximumSize += spacing + (a[i].expansive ? a[i].maximumSize : a[i].smartSizeHint());
500 prev = i;
501 ++count;
502 }
503
504 // stretch at the end
505 a[i].sizeHint = 0;
506 a[i].maximumSize = QWIDGETSIZE_MAX;
507 a[i].minimumSize = 0;
508 a[i].expansive = true;
509 a[i].stretch = 0;
510 a[i].empty = true;
511
512 if (expansiveRow && maximumSize < space) {
513 expansiveRow = false;
514 a[i].maximumSize = space - maximumSize;
515 }
516
517 qGeomCalc(chain&: a, start, count: i - start + (expansiveRow ? 0 : 1), pos: 0,
518 space: space - (ranOutOfSpace ? (extensionExtent + spacing) : 0),
519 spacer: spacing);
520
521 for (int j = start; j < i; ++j) {
522 QToolBarItem *item = items.at(i: j);
523
524 if (a[j].empty) {
525 if (!item->widget()->isHidden())
526 hideWidgets << item->widget();
527 continue;
528 }
529
530 QPoint pos;
531 rpick(o, pos) = pick(o, size: QSize(margins.top(), margins.left())) + handleExtent + a[j].pos;
532 rperp(o, pos) = rowPos;
533 QSize size;
534 rpick(o, size) = a[j].size;
535 if (expanded)
536 rperp(o, size) = rowHeight;
537 else
538 rperp(o, size) = perp(o, size: rect.size()) - perp(o, m: margins);
539 QRect r(pos, size);
540
541 if (o == Qt::Horizontal)
542 r = QStyle::visualRect(direction: parentWidget()->layoutDirection(), boundingRect: rect, logicalRect: r);
543
544 item->setGeometry(r);
545
546 if (item->widget()->isHidden())
547 showWidgets << item->widget();
548 }
549
550 if (!expanded) {
551 for (int j = i; j < items.count(); ++j) {
552 QToolBarItem *item = items.at(i: j);
553 if (!item->widget()->isHidden())
554 hideWidgets << item->widget();
555 if (popupMenu) {
556 if (!defaultWidgetAction(item)) {
557 popupMenu->addAction(action: item->action);
558 extensionMenuContainsOnlyWidgetActions = false;
559 }
560 }
561 }
562 break;
563 }
564
565 rowPos += rowHeight + spacing;
566 ++rows;
567 }
568
569 // if we are using a popup menu, not the expadning toolbar effect, we cannot move custom
570 // widgets into the menu. If only custom widget actions are chopped off, the popup menu
571 // is empty. So we show the little extension button to show something is chopped off,
572 // but we make it disabled.
573 extension->setEnabled(popupMenu == nullptr || !extensionMenuContainsOnlyWidgetActions);
574
575 // we have to do the show/hide here, because it triggers more calls to setGeometry :(
576 for (int i = 0; i < showWidgets.count(); ++i)
577 showWidgets.at(i)->show();
578 for (int i = 0; i < hideWidgets.count(); ++i)
579 hideWidgets.at(i)->hide();
580
581 return ranOutOfSpace;
582}
583
584QSize QToolBarLayout::expandedSize(const QSize &size) const
585{
586 if (dirty)
587 updateGeomArray();
588
589 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
590 if (!tb)
591 return QSize(0, 0);
592 QMainWindow *win = qobject_cast<QMainWindow*>(object: tb->parentWidget());
593 Qt::Orientation o = tb->orientation();
594 QStyle *style = tb->style();
595 QStyleOptionToolBar opt;
596 tb->initStyleOption(option: &opt);
597 const int handleExtent = movable()
598 ? style->pixelMetric(metric: QStyle::PM_ToolBarHandleExtent, option: &opt, widget: tb) : 0;
599 const QMargins margins = contentsMargins();
600 const int spacing = this->spacing();
601 const int extensionExtent = style->pixelMetric(metric: QStyle::PM_ToolBarExtensionExtent, option: &opt, widget: tb);
602
603 int total_w = 0;
604 int count = 0;
605 for (int x = 0; x < items.count(); ++x) {
606 if (!geomArray[x].empty) {
607 total_w += (count == 0 ? 0 : spacing) + geomArray[x].minimumSize;
608 ++count;
609 }
610 }
611 if (count == 0)
612 return QSize(0, 0);
613
614 int min_w = pick(o, size);
615 int rows = (int)qSqrt(v: qreal(count));
616 if (rows == 1)
617 ++rows; // we want to expand to at least two rows
618 int space = total_w/rows + spacing + extensionExtent;
619 space = qMax(a: space, b: min_w - pick(o, m: margins) - handleExtent);
620 if (win != nullptr)
621 space = qMin(a: space, b: pick(o, size: win->size()) - pick(o, m: margins) - handleExtent);
622
623 int w = 0;
624 int h = 0;
625 int i = 0;
626 while (i < items.count()) {
627 int count = 0;
628 int size = 0;
629 int prev = -1;
630 int rowHeight = 0;
631 for (; i < items.count(); ++i) {
632 if (geomArray[i].empty)
633 continue;
634
635 int newSize = size + (count == 0 ? 0 : spacing) + geomArray[i].minimumSize;
636 rowHeight = qMax(a: rowHeight, b: perp(o, size: items.at(i)->sizeHint()));
637 if (prev != -1 && newSize > space) {
638 if (count > 1 && size + spacing + extensionExtent > space) {
639 size -= spacing + geomArray[prev].minimumSize;
640 i = prev;
641 }
642 break;
643 }
644
645 size = newSize;
646 prev = i;
647 ++count;
648 }
649
650 w = qMax(a: size, b: w);
651 h += rowHeight + spacing;
652 }
653
654 w += pick(o: Qt::Horizontal, m: margins) + handleExtent + spacing + extensionExtent;
655 w = qMax(a: w, b: min_w);
656 if (win != nullptr)
657 w = qMin(a: w, b: pick(o, size: win->size()));
658 h += pick(o: Qt::Vertical, m: margins) - spacing; //there is no spacing before the first row
659
660 QSize result;
661 rpick(o, size&: result) = w;
662 rperp(o, size&: result) = h;
663 return result;
664}
665
666void QToolBarLayout::setExpanded(bool exp)
667{
668 QWidget *tb = qobject_cast<QToolBar*>(object: parentWidget());
669 if (!tb)
670 return;
671 if (exp == expanded && !tb->isWindow())
672 return;
673
674 expanded = exp;
675 extension->setChecked(expanded);
676
677 if (QMainWindow *win = qobject_cast<QMainWindow*>(object: tb->parentWidget())) {
678#if !QT_CONFIG(dockwidget)
679 animating = false;
680#else
681 animating = !tb->isWindow() && win->isAnimated();
682#endif
683 QMainWindowLayout *layout = qt_mainwindow_layout(window: win);
684 if (expanded) {
685 tb->raise();
686 } else {
687 QList<int> path = layout->layoutState.indexOf(widget: tb);
688 if (!path.isEmpty()) {
689 QRect rect = layout->layoutState.itemRect(path);
690 layoutActions(size: rect.size());
691 }
692 }
693 layout->layoutState.toolBarAreaLayout.apply(animate: animating);
694 }
695}
696
697QSize QToolBarLayout::minimumSize() const
698{
699 if (dirty)
700 updateGeomArray();
701 return minSize;
702}
703
704QSize QToolBarLayout::sizeHint() const
705{
706 if (dirty)
707 updateGeomArray();
708 return hint;
709}
710
711QToolBarItem *QToolBarLayout::createItem(QAction *action)
712{
713 bool customWidget = false;
714 bool standardButtonWidget = false;
715 QWidget *widget = nullptr;
716 QToolBar *tb = qobject_cast<QToolBar*>(object: parentWidget());
717 if (!tb)
718 return (QToolBarItem *)nullptr;
719
720 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(object: action)) {
721 widget = widgetAction->requestWidget(parent: tb);
722 if (widget != nullptr) {
723 widget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
724 customWidget = true;
725 }
726 } else if (action->isSeparator()) {
727 QToolBarSeparator *sep = new QToolBarSeparator(tb);
728 connect(sender: tb, SIGNAL(orientationChanged(Qt::Orientation)),
729 receiver: sep, SLOT(setOrientation(Qt::Orientation)));
730 widget = sep;
731 }
732
733 if (!widget) {
734 QToolButton *button = new QToolButton(tb);
735 button->setAutoRaise(true);
736 button->setFocusPolicy(Qt::NoFocus);
737 button->setIconSize(tb->iconSize());
738 button->setToolButtonStyle(tb->toolButtonStyle());
739 QObject::connect(sender: tb, SIGNAL(iconSizeChanged(QSize)),
740 receiver: button, SLOT(setIconSize(QSize)));
741 QObject::connect(sender: tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
742 receiver: button, SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));
743 button->setDefaultAction(action);
744 QObject::connect(sender: button, SIGNAL(triggered(QAction*)), receiver: tb, SIGNAL(actionTriggered(QAction*)));
745 widget = button;
746 standardButtonWidget = true;
747 }
748
749 widget->hide();
750 QToolBarItem *result = new QToolBarItem(widget);
751 if (standardButtonWidget)
752 result->setAlignment(Qt::AlignJustify);
753 result->customWidget = customWidget;
754 result->action = action;
755 return result;
756}
757
758QT_END_NAMESPACE
759
760#include "moc_qtoolbarlayout_p.cpp"
761

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