5#include <qapplication.h>
7#include <qwidgetaction.h>
9#include <qstyleoption.h>
10#if QT_CONFIG(toolbutton)
11#include <qtoolbutton.h>
17#include <qpa/qplatformnativeinterface.h>
21#if QT_CONFIG(toolbutton)
22#include "qtoolbarextension_p.h"
33
34
47
48
50QToolBarLayout::QToolBarLayout(QWidget *parent)
51 : QLayout(parent), expanded(
false), animating(
false), dirty(
true),
52 expanding(
false), empty(
true), expandFlag(
false), popupMenu(
nullptr)
54 QToolBar *tb = qobject_cast<QToolBar*>(parent);
58 extension =
new QToolBarExtension(tb);
59 extension->setFocusPolicy(Qt::NoFocus);
61 QObject::connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
62 extension, SLOT(setOrientation(Qt::Orientation)));
64 setUsePopupMenu(qobject_cast<QMainWindow*>(tb->parentWidget()) == 0);
67QToolBarLayout::~QToolBarLayout()
69 while (!items.isEmpty()) {
70 QToolBarItem *item = items.takeFirst();
71 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action)) {
72 if (item->customWidget)
73 widgetAction->releaseWidget(item->widget());
79void QToolBarLayout::updateMarginAndSpacing()
81 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
84 QStyle *style = tb->style();
85 QStyleOptionToolBar opt;
86 tb->initStyleOption(&opt);
87 const int margin = style->pixelMetric(QStyle::PM_ToolBarItemMargin, &opt, tb)
88 + style->pixelMetric(QStyle::PM_ToolBarFrameWidth, &opt, tb);
89 setContentsMargins(margin, margin, margin, margin);
90 setSpacing(style->pixelMetric(QStyle::PM_ToolBarItemSpacing, &opt, tb));
93bool QToolBarLayout::hasExpandFlag()
const
98void QToolBarLayout::setUsePopupMenu(
bool set)
100 if (!dirty && ((popupMenu ==
nullptr) == set))
103 QObject::connect(extension, SIGNAL(clicked(
bool)),
104 this, SLOT(setExpanded(
bool)), Qt::UniqueConnection);
105 extension->setPopupMode(QToolButton::DelayedPopup);
106 extension->setMenu(
nullptr);
110 QObject::disconnect(extension, SIGNAL(clicked(
bool)),
111 this, SLOT(setExpanded(
bool)));
112 extension->setPopupMode(QToolButton::InstantPopup);
114 popupMenu =
new QMenu(extension);
116 extension->setMenu(popupMenu);
120void QToolBarLayout::checkUsePopupMenu()
122 QToolBar *tb =
static_cast<QToolBar *>(parent());
123 QMainWindow *mw = qobject_cast<QMainWindow *>(tb->parent());
124 Qt::Orientation o = tb->orientation();
125 setUsePopupMenu(!mw || tb->isFloating() || perp(o, expandedSize(mw->size())) >= perp(o, mw->size()));
128void QToolBarLayout::addItem(QLayoutItem*)
130 qWarning(
"QToolBarLayout::addItem(): please use addAction() instead");
134QLayoutItem *QToolBarLayout::itemAt(
int index)
const
136 if (index < 0 || index >= items.size())
138 return items.at(index);
141QLayoutItem *QToolBarLayout::takeAt(
int index)
143 if (index < 0 || index >= items.size())
145 QToolBarItem *item = items.takeAt(index);
148 popupMenu->removeAction(item->action);
150 QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action);
151 if (widgetAction !=
nullptr && item->customWidget) {
152 widgetAction->releaseWidget(item->widget());
155 item->widget()->hide();
156 item->widget()->deleteLater();
163void QToolBarLayout::insertAction(
int index, QAction *action)
165 index = qMax(0, index);
166 index = qMin(items.size(), index);
168 QToolBarItem *item = createItem(action);
170 items.insert(index, item);
175int QToolBarLayout::indexOf(
const QAction *action)
const
177 for (
int i = 0; i < items.size(); ++i) {
178 if (items.at(i)->action == action)
184int QToolBarLayout::count()
const
189bool QToolBarLayout::isEmpty()
const
196void QToolBarLayout::invalidate()
199 QLayout::invalidate();
202Qt::Orientations QToolBarLayout::expandingDirections()
const
206 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
209 Qt::Orientation o = tb->orientation();
210 return expanding ? Qt::Orientations(o) : Qt::Orientations{};
213bool QToolBarLayout::movable()
const
215 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
218 QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
219 return tb->isMovable() && win !=
nullptr;
222void QToolBarLayout::updateGeomArray()
const
227 QToolBarLayout *that =
const_cast<QToolBarLayout*>(
this);
229 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
232 QStyle *style = tb->style();
233 QStyleOptionToolBar opt;
234 tb->initStyleOption(&opt);
235 const int handleExtent = movable()
236 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
237 const QMargins margins = contentsMargins();
238 const int spacing =
this->spacing();
239 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
240 Qt::Orientation o = tb->orientation();
242 that->minSize = QSize(0, 0);
243 that->hint = QSize(0, 0);
244 rperp(o, that->minSize) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb);
245 rperp(o, that->hint) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb);
247 that->expanding =
false;
250 QList<QLayoutStruct> a(items.size() + 1);
253 for (
int i = 0; i < items.size(); ++i) {
254 QToolBarItem *item = items.at(i);
256 QSize max = item->maximumSize();
257 QSize min = item->minimumSize();
258 QSize hint = item->sizeHint();
259 Qt::Orientations exp = item->expandingDirections();
260 bool empty = item->isEmpty();
262 that->expanding = expanding || exp & o;
265 if (item->widget()) {
266 if ((item->widget()->sizePolicy().horizontalPolicy() & QSizePolicy::ExpandFlag)) {
267 that->expandFlag =
true;
273 rpick(o, that->minSize) += pick(o, min);
274 int s = perp(o, minSize);
275 rperp(o, that->minSize) = qMax(s, perp(o, min));
278 rpick(o, that->hint) += (count == 0 ? 0 : spacing) + pick(o, hint);
279 s = perp(o, that->hint);
280 rperp(o, that->hint) = qMax(s, perp(o, hint));
284 a[i].sizeHint = pick(o, hint);
285 a[i].maximumSize = pick(o, max);
286 a[i].minimumSize = pick(o, min);
287 a[i].expansive = exp & o;
288 if (o == Qt::Horizontal)
289 a[i].stretch = item->widget()->sizePolicy().horizontalStretch();
291 a[i].stretch = item->widget()->sizePolicy().verticalStretch();
296 that->empty = count == 0;
298 rpick(o, that->minSize) += handleExtent;
299 that->minSize += QSize(pick(Qt::Horizontal, margins), pick(Qt::Vertical, margins));
300 if (items.size() > 1)
301 rpick(o, that->minSize) += spacing + extensionExtent;
303 rpick(o, that->hint) += handleExtent;
304 that->hint += QSize(pick(Qt::Horizontal, margins), pick(Qt::Vertical, margins));
310 QWidgetAction *a = qobject_cast<QWidgetAction*>(item->action);
311 return a !=
nullptr && a->defaultWidget() == item->widget();
314void QToolBarLayout::updateMacBorderMetrics()
317 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
321 QRect rect = geometry();
323 QMainWindow *mainWindow = qobject_cast<QMainWindow*>(tb->parentWidget());
324 if (!mainWindow || !mainWindow->isWindow() || !mainWindow->unifiedTitleAndToolBarOnMac())
327 extern QMainWindowLayout *qt_mainwindow_layout(
const QMainWindow *window);
328 auto *mainWindowLayout = qt_mainwindow_layout(mainWindow);
330 QPoint upper = tb->mapToParent(rect.topLeft());
331 QPoint lower = tb->mapToParent(rect.bottomLeft() + QPoint(0, 1));
333 if (mainWindow->toolBarArea(tb) == Qt::TopToolBarArea)
334 mainWindowLayout->registerUnifiedToolBarArea(tb, upper.y(), lower.y());
336 mainWindowLayout->registerUnifiedToolBarArea(tb, 0, 0);
340void QToolBarLayout::setGeometry(
const QRect &rect)
342 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
345 QStyle *style = tb->style();
346 QStyleOptionToolBar opt;
347 tb->initStyleOption(&opt);
348 const QMargins margins = contentsMargins();
349 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
350 Qt::Orientation o = tb->orientation();
352 QLayout::setGeometry(rect);
354 updateMacBorderMetrics();
356 bool ranOutOfSpace =
false;
358 ranOutOfSpace = layoutActions(rect.size());
360 if (expanded || animating || ranOutOfSpace) {
361 Qt::ToolBarArea area = Qt::TopToolBarArea;
362 if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget()))
363 area = win->toolBarArea(tb);
364 QSize hint = sizeHint();
367 rpick(o, pos) = pick(o, rect.bottomRight()) -
368 pick(o, QSize(margins.bottom(), margins.right())) - extensionExtent + 2;
369 if (area == Qt::LeftToolBarArea || area == Qt::TopToolBarArea)
370 rperp(o, pos) = perp(o, rect.topLeft()) +
371 perp(o, QSize(margins.top(), margins.left()));
373 rperp(o, pos) = perp(o, rect.bottomRight()) -
374 perp(o, QSize(margins.bottom(), margins.right())) -
375 (perp(o, hint) - perp(o, margins)) + 1;
377 rpick(o, size) = extensionExtent;
378 rperp(o, size) = perp(o, hint) - perp(o, margins);
381 if (o == Qt::Horizontal)
382 r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
384 extension->setGeometry(r);
386 if (extension->isHidden())
389 if (!extension->isHidden())
394bool QToolBarLayout::layoutActions(
const QSize &size)
399 QRect rect(0, 0, size.width(), size.height());
401 QList<QWidget*> showWidgets, hideWidgets;
403 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
406 QStyle *style = tb->style();
407 QStyleOptionToolBar opt;
408 tb->initStyleOption(&opt);
409 const int handleExtent = movable()
410 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
411 const QMargins margins = contentsMargins();
412 const int spacing =
this->spacing();
413 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
414 Qt::Orientation o = tb->orientation();
415 bool extensionMenuContainsOnlyWidgetActions =
true;
417 int space = pick(o, rect.size()) - pick(o, margins) - handleExtent;
424 bool ranOutOfSpace =
false;
426 int rowPos = perp(o, rect.topLeft()) + perp(o, QSize(margins.top(), margins.left()));
428 while (i < items.size()) {
429 QList<QLayoutStruct> a = geomArray;
437 bool expansiveRow =
false;
438 for (; i < items.size(); ++i) {
442 int newSize = size + (count == 0 ? 0 : spacing) + a[i].minimumSize;
443 if (prev != -1 && newSize > space) {
445 ranOutOfSpace =
true;
448 if (count > 1 && size + spacing + extensionExtent > space)
454 rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
455 expansiveRow = expansiveRow || a[i].expansive;
457 maximumSize += spacing + (a[i].expansive ? a[i].maximumSize : a[i].smartSizeHint());
464 a[i].maximumSize = QWIDGETSIZE_MAX;
465 a[i].minimumSize = 0;
466 a[i].expansive =
true;
470 if (expansiveRow && maximumSize < space) {
471 expansiveRow =
false;
472 a[i].maximumSize = space - maximumSize;
475 qGeomCalc(a, start, i - start + (expansiveRow ? 0 : 1), 0,
476 space - (ranOutOfSpace ? (extensionExtent + spacing) : 0),
479 for (
int j = start; j < i; ++j) {
480 QToolBarItem *item = items.at(j);
483 if (!item->widget()->isHidden())
484 hideWidgets << item->widget();
489 rpick(o, pos) = pick(o, QSize(margins.top(), margins.left())) + handleExtent + a[j].pos;
490 rperp(o, pos) = rowPos;
492 rpick(o, size) = a[j].size;
494 rperp(o, size) = rowHeight;
496 rperp(o, size) = perp(o, rect.size()) - perp(o, margins);
499 if (o == Qt::Horizontal)
500 r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
502 item->setGeometry(r);
504 if (item->widget()->isHidden())
505 showWidgets << item->widget();
509 for (
int j = i; j < items.size(); ++j) {
510 QToolBarItem *item = items.at(j);
511 if (!item->widget()->isHidden())
512 hideWidgets << item->widget();
514 if (!defaultWidgetAction(item)) {
515 popupMenu->addAction(item->action);
516 extensionMenuContainsOnlyWidgetActions =
false;
523 rowPos += rowHeight + spacing;
531 extension->setEnabled(popupMenu ==
nullptr || !extensionMenuContainsOnlyWidgetActions);
534 for (
int i = 0; i < showWidgets.size(); ++i)
535 showWidgets.at(i)->show();
536 for (
int i = 0; i < hideWidgets.size(); ++i)
537 hideWidgets.at(i)->hide();
539 return ranOutOfSpace;
542QSize QToolBarLayout::expandedSize(
const QSize &size)
const
547 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
550 QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
551 Qt::Orientation o = tb->orientation();
552 QStyle *style = tb->style();
553 QStyleOptionToolBar opt;
554 tb->initStyleOption(&opt);
555 const int handleExtent = movable()
556 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
557 const QMargins margins = contentsMargins();
558 const int spacing =
this->spacing();
559 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
563 for (
int x = 0; x < items.size(); ++x) {
564 if (!geomArray[x].empty) {
565 total_w += (count == 0 ? 0 : spacing) + geomArray[x].minimumSize;
572 int min_w = pick(o, size);
573 int rows = (
int)qSqrt(qreal(count));
576 int space = total_w/rows + spacing + extensionExtent;
577 space = qMax(space, min_w - pick(o, margins) - handleExtent);
579 space = qMin(space, pick(o, win->size()) - pick(o, margins) - handleExtent);
584 while (i < items.size()) {
589 for (; i < items.size(); ++i) {
590 if (geomArray[i].empty)
593 int newSize = size + (count == 0 ? 0 : spacing) + geomArray[i].minimumSize;
594 rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
595 if (prev != -1 && newSize > space) {
596 if (count > 1 && size + spacing + extensionExtent > space) {
597 size -= spacing + geomArray[prev].minimumSize;
609 h += rowHeight + spacing;
612 w += pick(Qt::Horizontal, margins) + handleExtent + spacing + extensionExtent;
615 w = qMin(w, pick(o, win->size()));
616 h += pick(Qt::Vertical, margins) - spacing;
619 rpick(o, result) = w;
620 rperp(o, result) = h;
624void QToolBarLayout::setExpanded(
bool exp)
626 QWidget *tb = qobject_cast<QToolBar*>(parentWidget());
629 if (exp == expanded && !tb->isWindow())
633 extension->setChecked(expanded);
635 if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget())) {
636#if !QT_CONFIG(dockwidget)
639 animating = !tb->isWindow() && win->isAnimated();
641 QMainWindowLayout *layout = qt_mainwindow_layout(win);
645 QList<
int> path = layout->layoutState.indexOf(tb);
646 if (!path.isEmpty()) {
647 QRect rect = layout->layoutState.itemRect(path);
648 layoutActions(rect.size());
651 const auto rule = animating ? QWidgetAnimator::AnimationRule::Run
652 : QWidgetAnimator::AnimationRule::Stop;
653 layout->layoutState.toolBarAreaLayout.apply(rule);
657QSize QToolBarLayout::minimumSize()
const
664QSize QToolBarLayout::sizeHint()
const
671QToolBarItem *QToolBarLayout::createItem(QAction *action)
673 bool customWidget =
false;
674 bool standardButtonWidget =
false;
675 QWidget *widget =
nullptr;
676 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
678 return (QToolBarItem *)
nullptr;
680 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action)) {
681 widget = widgetAction->requestWidget(tb);
682 if (widget !=
nullptr) {
683 widget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
686 }
else if (action->isSeparator()) {
687 QToolBarSeparator *sep =
new QToolBarSeparator(tb);
688 connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
689 sep, SLOT(setOrientation(Qt::Orientation)));
694 QToolButton *button =
new QToolButton(tb);
695 button->setAutoRaise(
true);
696 button->setFocusPolicy(Qt::NoFocus);
697 button->setIconSize(tb->iconSize());
698 button->setToolButtonStyle(tb->toolButtonStyle());
699 QObject::connect(tb, SIGNAL(iconSizeChanged(QSize)),
700 button, SLOT(setIconSize(QSize)));
701 QObject::connect(tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
702 button, SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));
703 button->setDefaultAction(action);
704 QObject::connect(button, SIGNAL(triggered(QAction*)), tb, SIGNAL(actionTriggered(QAction*)));
706 standardButtonWidget =
true;
710 QToolBarItem *result =
new QToolBarItem(widget);
711 if (standardButtonWidget)
712 result->setAlignment(Qt::AlignJustify);
713 result->customWidget = customWidget;
714 result->action = action;
720#include "moc_qtoolbarlayout_p.cpp"
Combined button and popup list for selecting options.
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)