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 
62 QT_BEGIN_NAMESPACE
63 
64 // qmainwindow.cpp
65 extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
66 
67 /******************************************************************************
68 ** QToolBarItem
69 */
70 
QToolBarItem(QWidget * widget)71 QToolBarItem::QToolBarItem(QWidget *widget)
72     : QWidgetItem(widget), action(nullptr), customWidget(false)
73 {
74 }
75 
isEmpty() const76 bool QToolBarItem::isEmpty() const
77 {
78     return action == nullptr || !action->isVisible();
79 }
80 
81 /******************************************************************************
82 ** QToolBarLayout
83 */
84 
QToolBarLayout(QWidget * parent)85 QToolBarLayout::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*>(parent);
90     if (!tb)
91         return;
92 
93     extension = new QToolBarExtension(tb);
94     extension->setFocusPolicy(Qt::NoFocus);
95     extension->hide();
96     QObject::connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
97                      extension, SLOT(setOrientation(Qt::Orientation)));
98 
99     setUsePopupMenu(qobject_cast<QMainWindow*>(tb->parentWidget()) == 0);
100 }
101 
~QToolBarLayout()102 QToolBarLayout::~QToolBarLayout()
103 {
104     while (!items.isEmpty()) {
105         QToolBarItem *item = items.takeFirst();
106         if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action)) {
107             if (item->customWidget)
108                 widgetAction->releaseWidget(item->widget());
109         }
110         delete item;
111     }
112 }
113 
updateMarginAndSpacing()114 void QToolBarLayout::updateMarginAndSpacing()
115 {
116     QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
117     if (!tb)
118         return;
119     QStyle *style = tb->style();
120     QStyleOptionToolBar opt;
121     tb->initStyleOption(&opt);
122     const int margin = style->pixelMetric(QStyle::PM_ToolBarItemMargin, &opt, tb)
123             + style->pixelMetric(QStyle::PM_ToolBarFrameWidth, &opt, tb);
124     setContentsMargins(margin, margin, margin, margin);
125     setSpacing(style->pixelMetric(QStyle::PM_ToolBarItemSpacing, &opt, tb));
126 }
127 
hasExpandFlag() const128 bool QToolBarLayout::hasExpandFlag() const
129 {
130     return expandFlag;
131 }
132 
setUsePopupMenu(bool set)133 void QToolBarLayout::setUsePopupMenu(bool set)
134 {
135     if (!dirty && ((popupMenu == nullptr) == set))
136         invalidate();
137     if (!set) {
138         QObject::connect(extension, SIGNAL(clicked(bool)),
139                         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(extension, SIGNAL(clicked(bool)),
146                             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 
checkUsePopupMenu()155 void QToolBarLayout::checkUsePopupMenu()
156 {
157     QToolBar *tb = static_cast<QToolBar *>(parent());
158     QMainWindow *mw = qobject_cast<QMainWindow *>(tb->parent());
159     Qt::Orientation o = tb->orientation();
160     setUsePopupMenu(!mw || tb->isFloating() || perp(o, expandedSize(mw->size())) >= perp(o, mw->size()));
161 }
162 
addItem(QLayoutItem *)163 void QToolBarLayout::addItem(QLayoutItem*)
164 {
165     qWarning("QToolBarLayout::addItem(): please use addAction() instead");
166     return;
167 }
168 
itemAt(int index) const169 QLayoutItem *QToolBarLayout::itemAt(int index) const
170 {
171     if (index < 0 || index >= items.count())
172         return nullptr;
173     return items.at(index);
174 }
175 
takeAt(int index)176 QLayoutItem *QToolBarLayout::takeAt(int index)
177 {
178     if (index < 0 || index >= items.count())
179         return nullptr;
180     QToolBarItem *item = items.takeAt(index);
181 
182     if (popupMenu)
183         popupMenu->removeAction(item->action);
184 
185     QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action);
186     if (widgetAction != nullptr && item->customWidget) {
187         widgetAction->releaseWidget(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 
insertAction(int index,QAction * action)198 void QToolBarLayout::insertAction(int index, QAction *action)
199 {
200     index = qMax(0, index);
201     index = qMin(items.count(), index);
202 
203     QToolBarItem *item = createItem(action);
204     if (item) {
205         items.insert(index, item);
206         invalidate();
207     }
208 }
209 
indexOf(QAction * action) const210 int 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 
count() const219 int QToolBarLayout::count() const
220 {
221     return items.count();
222 }
223 
isEmpty() const224 bool QToolBarLayout::isEmpty() const
225 {
226     if (dirty)
227         updateGeomArray();
228     return empty;
229 }
230 
invalidate()231 void QToolBarLayout::invalidate()
232 {
233     dirty = true;
234     QLayout::invalidate();
235 }
236 
expandingDirections() const237 Qt::Orientations QToolBarLayout::expandingDirections() const
238 {
239     if (dirty)
240         updateGeomArray();
241     QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
242     if (!tb)
243         return {};
244     Qt::Orientation o = tb->orientation();
245     return expanding ? Qt::Orientations(o) : Qt::Orientations{};
246 }
247 
movable() const248 bool QToolBarLayout::movable() const
249 {
250     QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
251     if (!tb)
252         return false;
253     QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
254     return tb->isMovable() && win != nullptr;
255 }
256 
updateGeomArray() const257 void QToolBarLayout::updateGeomArray() const
258 {
259     if (!dirty)
260         return;
261 
262     QToolBarLayout *that = const_cast<QToolBarLayout*>(this);
263 
264     QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
265     if (!tb)
266         return;
267     QStyle *style = tb->style();
268     QStyleOptionToolBar opt;
269     tb->initStyleOption(&opt);
270     const int handleExtent = movable()
271             ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
272     const QMargins margins = contentsMargins();
273     const int spacing = this->spacing();
274     const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
275     Qt::Orientation o = tb->orientation();
276 
277     that->minSize = QSize(0, 0);
278     that->hint = QSize(0, 0);
279     rperp(o, that->minSize) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb);
280     rperp(o, that->hint) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, 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, that->minSize) += pick(o, min);
309             int s = perp(o, minSize);
310             rperp(o, that->minSize) = qMax(s, perp(o, min));
311 
312             //we only add spacing before item (ie never before the first one)
313             rpick(o, that->hint) += (count == 0 ? 0 : spacing) + pick(o, hint);
314             s = perp(o, that->hint);
315             rperp(o, that->hint) = qMax(s, perp(o, hint));
316             ++count;
317         }
318 
319         a[i].sizeHint = pick(o, hint);
320         a[i].maximumSize = pick(o, max);
321         a[i].minimumSize = pick(o, 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, that->minSize) += handleExtent;
334     that->minSize += QSize(pick(Qt::Horizontal, margins), pick(Qt::Vertical, margins));
335     if (items.count() > 1)
336         rpick(o, that->minSize) += spacing + extensionExtent;
337 
338     rpick(o, that->hint) += handleExtent;
339     that->hint += QSize(pick(Qt::Horizontal, margins), pick(Qt::Vertical, margins));
340     that->dirty = false;
341 }
342 
defaultWidgetAction(QToolBarItem * item)343 static bool defaultWidgetAction(QToolBarItem *item)
344 {
345     QWidgetAction *a = qobject_cast<QWidgetAction*>(item->action);
346     return a != nullptr && a->defaultWidget() == item->widget();
347 }
348 
updateMacBorderMetrics()349 void 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 
setGeometry(const QRect & rect)382 void QToolBarLayout::setGeometry(const QRect &rect)
383 {
384     QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
385     if (!tb)
386         return;
387     QStyle *style = tb->style();
388     QStyleOptionToolBar opt;
389     tb->initStyleOption(&opt);
390     const QMargins margins = contentsMargins();
391     const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, 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(rect.size());
401 
402     if (expanded || animating || ranOutOfSpace) {
403         Qt::ToolBarArea area = Qt::TopToolBarArea;
404         if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget()))
405             area = win->toolBarArea(tb);
406         QSize hint = sizeHint();
407 
408         QPoint pos;
409         rpick(o, pos) = pick(o, rect.bottomRight()) -
410                 pick(o, QSize(margins.bottom(), margins.right())) - extensionExtent + 2;
411         if (area == Qt::LeftToolBarArea || area == Qt::TopToolBarArea)
412             rperp(o, pos) = perp(o, rect.topLeft()) +
413                     perp(o, QSize(margins.top(), margins.left()));
414         else
415             rperp(o, pos) = perp(o, rect.bottomRight()) -
416                     perp(o, QSize(margins.bottom(), margins.right())) -
417                     (perp(o, hint) - perp(o, margins)) + 1;
418         QSize size;
419         rpick(o, size) = extensionExtent;
420         rperp(o, size) = perp(o, hint) - perp(o, margins);
421         QRect r(pos, size);
422 
423         if (o == Qt::Horizontal)
424             r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, 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 
layoutActions(const QSize & size)436 bool 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*>(parentWidget());
446     if (!tb)
447         return false;
448     QStyle *style = tb->style();
449     QStyleOptionToolBar opt;
450     tb->initStyleOption(&opt);
451     const int handleExtent = movable()
452             ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
453     const QMargins margins = contentsMargins();
454     const int spacing = this->spacing();
455     const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
456     Qt::Orientation o = tb->orientation();
457     bool extensionMenuContainsOnlyWidgetActions = true;
458 
459     int space = pick(o, rect.size()) - pick(o, 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, rect.topLeft()) + perp(o, 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(rowHeight, perp(o, 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(a, start, i - start + (expansiveRow ? 0 : 1), 0,
518                     space - (ranOutOfSpace ? (extensionExtent + spacing) : 0),
519                     spacing);
520 
521         for (int j = start; j < i; ++j) {
522             QToolBarItem *item = items.at(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, 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, rect.size()) - perp(o, margins);
539             QRect r(pos, size);
540 
541             if (o == Qt::Horizontal)
542                 r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, 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(j);
553                 if (!item->widget()->isHidden())
554                     hideWidgets << item->widget();
555                 if (popupMenu) {
556                     if (!defaultWidgetAction(item)) {
557                         popupMenu->addAction(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 
expandedSize(const QSize & size) const584 QSize QToolBarLayout::expandedSize(const QSize &size) const
585 {
586     if (dirty)
587         updateGeomArray();
588 
589     QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
590     if (!tb)
591         return QSize(0, 0);
592     QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
593     Qt::Orientation o = tb->orientation();
594     QStyle *style = tb->style();
595     QStyleOptionToolBar opt;
596     tb->initStyleOption(&opt);
597     const int handleExtent = movable()
598             ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
599     const QMargins margins = contentsMargins();
600     const int spacing = this->spacing();
601     const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, 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(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(space, min_w - pick(o, margins) - handleExtent);
620     if (win != nullptr)
621         space = qMin(space, pick(o, win->size()) - pick(o, 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(rowHeight, perp(o, 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(size, w);
651         h += rowHeight + spacing;
652     }
653 
654     w += pick(Qt::Horizontal, margins) + handleExtent + spacing + extensionExtent;
655     w = qMax(w, min_w);
656     if (win != nullptr)
657         w = qMin(w, pick(o, win->size()));
658     h += pick(Qt::Vertical, margins) - spacing; //there is no spacing before the first row
659 
660     QSize result;
661     rpick(o, result) = w;
662     rperp(o, result) = h;
663     return result;
664 }
665 
setExpanded(bool exp)666 void QToolBarLayout::setExpanded(bool exp)
667 {
668     QWidget *tb = qobject_cast<QToolBar*>(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*>(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(win);
684         if (expanded) {
685             tb->raise();
686         } else {
687             QList<int> path = layout->layoutState.indexOf(tb);
688             if (!path.isEmpty()) {
689                 QRect rect = layout->layoutState.itemRect(path);
690                 layoutActions(rect.size());
691             }
692         }
693         layout->layoutState.toolBarAreaLayout.apply(animating);
694     }
695 }
696 
minimumSize() const697 QSize QToolBarLayout::minimumSize() const
698 {
699     if (dirty)
700         updateGeomArray();
701     return minSize;
702 }
703 
sizeHint() const704 QSize QToolBarLayout::sizeHint() const
705 {
706     if (dirty)
707         updateGeomArray();
708     return hint;
709 }
710 
createItem(QAction * action)711 QToolBarItem *QToolBarLayout::createItem(QAction *action)
712 {
713     bool customWidget = false;
714     bool standardButtonWidget = false;
715     QWidget *widget = nullptr;
716     QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
717     if (!tb)
718         return (QToolBarItem *)nullptr;
719 
720     if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action)) {
721         widget = widgetAction->requestWidget(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(tb, SIGNAL(orientationChanged(Qt::Orientation)),
729                 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(tb, SIGNAL(iconSizeChanged(QSize)),
740                          button, SLOT(setIconSize(QSize)));
741         QObject::connect(tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
742                          button, SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));
743         button->setDefaultAction(action);
744         QObject::connect(button, SIGNAL(triggered(QAction*)), 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 
758 QT_END_NAMESPACE
759 
760 #include "moc_qtoolbarlayout_p.cpp"
761