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 QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface();
328 if (!nativeInterface)
330 QPlatformNativeInterface::NativeResourceForIntegrationFunction function =
331 nativeInterface->nativeResourceFunctionForIntegration(
"registerContentBorderArea");
335 QPoint upper = tb->mapToParent(rect.topLeft());
336 QPoint lower = tb->mapToParent(rect.bottomLeft() + QPoint(0, 1));
338 typedef void (*RegisterContentBorderAreaFunction)(QWindow *window,
void *identifier,
int upper,
int lower);
339 if (mainWindow->toolBarArea(tb) == Qt::TopToolBarArea) {
340 (
reinterpret_cast<RegisterContentBorderAreaFunction>(QFunctionPointer(function)))(
341 tb->window()->windowHandle(), tb, upper.y(), lower.y());
343 (
reinterpret_cast<RegisterContentBorderAreaFunction>(QFunctionPointer(function)))(
344 tb->window()->windowHandle(), tb, 0, 0);
349void QToolBarLayout::setGeometry(
const QRect &rect)
351 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
354 QStyle *style = tb->style();
355 QStyleOptionToolBar opt;
356 tb->initStyleOption(&opt);
357 const QMargins margins = contentsMargins();
358 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
359 Qt::Orientation o = tb->orientation();
361 QLayout::setGeometry(rect);
363 updateMacBorderMetrics();
365 bool ranOutOfSpace =
false;
367 ranOutOfSpace = layoutActions(rect.size());
369 if (expanded || animating || ranOutOfSpace) {
370 Qt::ToolBarArea area = Qt::TopToolBarArea;
371 if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget()))
372 area = win->toolBarArea(tb);
373 QSize hint = sizeHint();
376 rpick(o, pos) = pick(o, rect.bottomRight()) -
377 pick(o, QSize(margins.bottom(), margins.right())) - extensionExtent + 2;
378 if (area == Qt::LeftToolBarArea || area == Qt::TopToolBarArea)
379 rperp(o, pos) = perp(o, rect.topLeft()) +
380 perp(o, QSize(margins.top(), margins.left()));
382 rperp(o, pos) = perp(o, rect.bottomRight()) -
383 perp(o, QSize(margins.bottom(), margins.right())) -
384 (perp(o, hint) - perp(o, margins)) + 1;
386 rpick(o, size) = extensionExtent;
387 rperp(o, size) = perp(o, hint) - perp(o, margins);
390 if (o == Qt::Horizontal)
391 r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
393 extension->setGeometry(r);
395 if (extension->isHidden())
398 if (!extension->isHidden())
403bool QToolBarLayout::layoutActions(
const QSize &size)
408 QRect rect(0, 0, size.width(), size.height());
410 QList<QWidget*> showWidgets, hideWidgets;
412 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
415 QStyle *style = tb->style();
416 QStyleOptionToolBar opt;
417 tb->initStyleOption(&opt);
418 const int handleExtent = movable()
419 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
420 const QMargins margins = contentsMargins();
421 const int spacing =
this->spacing();
422 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
423 Qt::Orientation o = tb->orientation();
424 bool extensionMenuContainsOnlyWidgetActions =
true;
426 int space = pick(o, rect.size()) - pick(o, margins) - handleExtent;
433 bool ranOutOfSpace =
false;
435 int rowPos = perp(o, rect.topLeft()) + perp(o, QSize(margins.top(), margins.left()));
437 while (i < items.size()) {
438 QList<QLayoutStruct> a = geomArray;
446 bool expansiveRow =
false;
447 for (; i < items.size(); ++i) {
451 int newSize = size + (count == 0 ? 0 : spacing) + a[i].minimumSize;
452 if (prev != -1 && newSize > space) {
454 ranOutOfSpace =
true;
457 if (count > 1 && size + spacing + extensionExtent > space)
463 rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
464 expansiveRow = expansiveRow || a[i].expansive;
466 maximumSize += spacing + (a[i].expansive ? a[i].maximumSize : a[i].smartSizeHint());
473 a[i].maximumSize = QWIDGETSIZE_MAX;
474 a[i].minimumSize = 0;
475 a[i].expansive =
true;
479 if (expansiveRow && maximumSize < space) {
480 expansiveRow =
false;
481 a[i].maximumSize = space - maximumSize;
484 qGeomCalc(a, start, i - start + (expansiveRow ? 0 : 1), 0,
485 space - (ranOutOfSpace ? (extensionExtent + spacing) : 0),
488 for (
int j = start; j < i; ++j) {
489 QToolBarItem *item = items.at(j);
492 if (!item->widget()->isHidden())
493 hideWidgets << item->widget();
498 rpick(o, pos) = pick(o, QSize(margins.top(), margins.left())) + handleExtent + a[j].pos;
499 rperp(o, pos) = rowPos;
501 rpick(o, size) = a[j].size;
503 rperp(o, size) = rowHeight;
505 rperp(o, size) = perp(o, rect.size()) - perp(o, margins);
508 if (o == Qt::Horizontal)
509 r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
511 item->setGeometry(r);
513 if (item->widget()->isHidden())
514 showWidgets << item->widget();
518 for (
int j = i; j < items.size(); ++j) {
519 QToolBarItem *item = items.at(j);
520 if (!item->widget()->isHidden())
521 hideWidgets << item->widget();
523 if (!defaultWidgetAction(item)) {
524 popupMenu->addAction(item->action);
525 extensionMenuContainsOnlyWidgetActions =
false;
532 rowPos += rowHeight + spacing;
540 extension->setEnabled(popupMenu ==
nullptr || !extensionMenuContainsOnlyWidgetActions);
543 for (
int i = 0; i < showWidgets.size(); ++i)
544 showWidgets.at(i)->show();
545 for (
int i = 0; i < hideWidgets.size(); ++i)
546 hideWidgets.at(i)->hide();
548 return ranOutOfSpace;
551QSize QToolBarLayout::expandedSize(
const QSize &size)
const
556 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
559 QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
560 Qt::Orientation o = tb->orientation();
561 QStyle *style = tb->style();
562 QStyleOptionToolBar opt;
563 tb->initStyleOption(&opt);
564 const int handleExtent = movable()
565 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
566 const QMargins margins = contentsMargins();
567 const int spacing =
this->spacing();
568 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
572 for (
int x = 0; x < items.size(); ++x) {
573 if (!geomArray[x].empty) {
574 total_w += (count == 0 ? 0 : spacing) + geomArray[x].minimumSize;
581 int min_w = pick(o, size);
582 int rows = (
int)qSqrt(qreal(count));
585 int space = total_w/rows + spacing + extensionExtent;
586 space = qMax(space, min_w - pick(o, margins) - handleExtent);
588 space = qMin(space, pick(o, win->size()) - pick(o, margins) - handleExtent);
593 while (i < items.size()) {
598 for (; i < items.size(); ++i) {
599 if (geomArray[i].empty)
602 int newSize = size + (count == 0 ? 0 : spacing) + geomArray[i].minimumSize;
603 rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
604 if (prev != -1 && newSize > space) {
605 if (count > 1 && size + spacing + extensionExtent > space) {
606 size -= spacing + geomArray[prev].minimumSize;
618 h += rowHeight + spacing;
621 w += pick(Qt::Horizontal, margins) + handleExtent + spacing + extensionExtent;
624 w = qMin(w, pick(o, win->size()));
625 h += pick(Qt::Vertical, margins) - spacing;
628 rpick(o, result) = w;
629 rperp(o, result) = h;
633void QToolBarLayout::setExpanded(
bool exp)
635 QWidget *tb = qobject_cast<QToolBar*>(parentWidget());
638 if (exp == expanded && !tb->isWindow())
642 extension->setChecked(expanded);
644 if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget())) {
645#if !QT_CONFIG(dockwidget)
648 animating = !tb->isWindow() && win->isAnimated();
650 QMainWindowLayout *layout = qt_mainwindow_layout(win);
654 QList<
int> path = layout->layoutState.indexOf(tb);
655 if (!path.isEmpty()) {
656 QRect rect = layout->layoutState.itemRect(path);
657 layoutActions(rect.size());
660 layout->layoutState.toolBarAreaLayout.apply(animating);
664QSize QToolBarLayout::minimumSize()
const
671QSize QToolBarLayout::sizeHint()
const
678QToolBarItem *QToolBarLayout::createItem(QAction *action)
680 bool customWidget =
false;
681 bool standardButtonWidget =
false;
682 QWidget *widget =
nullptr;
683 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
685 return (QToolBarItem *)
nullptr;
687 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action)) {
688 widget = widgetAction->requestWidget(tb);
689 if (widget !=
nullptr) {
690 widget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
693 }
else if (action->isSeparator()) {
694 QToolBarSeparator *sep =
new QToolBarSeparator(tb);
695 connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
696 sep, SLOT(setOrientation(Qt::Orientation)));
701 QToolButton *button =
new QToolButton(tb);
702 button->setAutoRaise(
true);
703 button->setFocusPolicy(Qt::NoFocus);
704 button->setIconSize(tb->iconSize());
705 button->setToolButtonStyle(tb->toolButtonStyle());
706 QObject::connect(tb, SIGNAL(iconSizeChanged(QSize)),
707 button, SLOT(setIconSize(QSize)));
708 QObject::connect(tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
709 button, SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));
710 button->setDefaultAction(action);
711 QObject::connect(button, SIGNAL(triggered(QAction*)), tb, SIGNAL(actionTriggered(QAction*)));
713 standardButtonWidget =
true;
717 QToolBarItem *result =
new QToolBarItem(widget);
718 if (standardButtonWidget)
719 result->setAlignment(Qt::AlignJustify);
720 result->customWidget = customWidget;
721 result->action = action;
727#include "moc_qtoolbarlayout_p.cpp"
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)