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