4#include <qapplication.h>
6#include <qwidgetaction.h>
8#include <qstyleoption.h>
9#if QT_CONFIG(toolbutton)
10#include <qtoolbutton.h>
16#include <qpa/qplatformnativeinterface.h>
20#if QT_CONFIG(toolbutton)
21#include "qtoolbarextension_p.h"
32
33
46
47
49QToolBarLayout::QToolBarLayout(QWidget *parent)
50 : QLayout(parent), expanded(
false), animating(
false), dirty(
true),
51 expanding(
false), empty(
true), expandFlag(
false), popupMenu(
nullptr)
53 QToolBar *tb = qobject_cast<QToolBar*>(parent);
57 extension =
new QToolBarExtension(tb);
58 extension->setFocusPolicy(Qt::NoFocus);
60 QObject::connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
61 extension, SLOT(setOrientation(Qt::Orientation)));
63 setUsePopupMenu(qobject_cast<QMainWindow*>(tb->parentWidget()) == 0);
66QToolBarLayout::~QToolBarLayout()
68 while (!items.isEmpty()) {
69 QToolBarItem *item = items.takeFirst();
70 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action)) {
71 if (item->customWidget)
72 widgetAction->releaseWidget(item->widget());
78void QToolBarLayout::updateMarginAndSpacing()
80 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
83 QStyle *style = tb->style();
84 QStyleOptionToolBar opt;
85 tb->initStyleOption(&opt);
86 const int margin = style->pixelMetric(QStyle::PM_ToolBarItemMargin, &opt, tb)
87 + style->pixelMetric(QStyle::PM_ToolBarFrameWidth, &opt, tb);
88 setContentsMargins(margin, margin, margin, margin);
89 setSpacing(style->pixelMetric(QStyle::PM_ToolBarItemSpacing, &opt, tb));
92bool QToolBarLayout::hasExpandFlag()
const
97void QToolBarLayout::setUsePopupMenu(
bool set)
99 if (!dirty && ((popupMenu ==
nullptr) == set))
102 QObject::connect(extension, SIGNAL(clicked(
bool)),
103 this, SLOT(setExpanded(
bool)), Qt::UniqueConnection);
104 extension->setPopupMode(QToolButton::DelayedPopup);
105 extension->setMenu(
nullptr);
109 QObject::disconnect(extension, SIGNAL(clicked(
bool)),
110 this, SLOT(setExpanded(
bool)));
111 extension->setPopupMode(QToolButton::InstantPopup);
113 popupMenu =
new QMenu(extension);
115 extension->setMenu(popupMenu);
119void QToolBarLayout::checkUsePopupMenu()
121 QToolBar *tb =
static_cast<QToolBar *>(parent());
122 QMainWindow *mw = qobject_cast<QMainWindow *>(tb->parent());
123 Qt::Orientation o = tb->orientation();
124 setUsePopupMenu(!mw || tb->isFloating() || perp(o, expandedSize(mw->size())) >= perp(o, mw->size()));
127void QToolBarLayout::addItem(QLayoutItem*)
129 qWarning(
"QToolBarLayout::addItem(): please use addAction() instead");
133QLayoutItem *QToolBarLayout::itemAt(
int index)
const
135 if (index < 0 || index >= items.size())
137 return items.at(index);
140QLayoutItem *QToolBarLayout::takeAt(
int index)
142 if (index < 0 || index >= items.size())
144 QToolBarItem *item = items.takeAt(index);
147 popupMenu->removeAction(item->action);
149 QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action);
150 if (widgetAction !=
nullptr && item->customWidget) {
151 widgetAction->releaseWidget(item->widget());
154 item->widget()->hide();
155 item->widget()->deleteLater();
162void QToolBarLayout::insertAction(
int index, QAction *action)
164 index = qMax(0, index);
165 index = qMin(items.size(), index);
167 QToolBarItem *item = createItem(action);
169 items.insert(index, item);
174int QToolBarLayout::indexOf(
const QAction *action)
const
176 for (
int i = 0; i < items.size(); ++i) {
177 if (items.at(i)->action == action)
183int QToolBarLayout::count()
const
188bool QToolBarLayout::isEmpty()
const
195void QToolBarLayout::invalidate()
198 QLayout::invalidate();
201Qt::Orientations QToolBarLayout::expandingDirections()
const
205 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
208 Qt::Orientation o = tb->orientation();
209 return expanding ? Qt::Orientations(o) : Qt::Orientations{};
212bool QToolBarLayout::movable()
const
214 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
217 QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
218 return tb->isMovable() && win !=
nullptr;
221void QToolBarLayout::updateGeomArray()
const
226 QToolBarLayout *that =
const_cast<QToolBarLayout*>(
this);
228 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
231 QStyle *style = tb->style();
232 QStyleOptionToolBar opt;
233 tb->initStyleOption(&opt);
234 const int handleExtent = movable()
235 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
236 const QMargins margins = contentsMargins();
237 const int spacing =
this->spacing();
238 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
239 Qt::Orientation o = tb->orientation();
241 that->minSize = QSize(0, 0);
242 that->hint = QSize(0, 0);
243 rperp(o, that->minSize) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb);
244 rperp(o, that->hint) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb);
246 that->expanding =
false;
249 QList<QLayoutStruct> a(items.size() + 1);
252 for (
int i = 0; i < items.size(); ++i) {
253 QToolBarItem *item = items.at(i);
255 QSize max = item->maximumSize();
256 QSize min = item->minimumSize();
257 QSize hint = item->sizeHint();
258 Qt::Orientations exp = item->expandingDirections();
259 bool empty = item->isEmpty();
261 that->expanding = expanding || exp & o;
264 if (item->widget()) {
265 if ((item->widget()->sizePolicy().horizontalPolicy() & QSizePolicy::ExpandFlag)) {
266 that->expandFlag =
true;
272 rpick(o, that->minSize) += pick(o, min);
273 int s = perp(o, minSize);
274 rperp(o, that->minSize) = qMax(s, perp(o, min));
277 rpick(o, that->hint) += (count == 0 ? 0 : spacing) + pick(o, hint);
278 s = perp(o, that->hint);
279 rperp(o, that->hint) = qMax(s, perp(o, hint));
283 a[i].sizeHint = pick(o, hint);
284 a[i].maximumSize = pick(o, max);
285 a[i].minimumSize = pick(o, min);
286 a[i].expansive = exp & o;
287 if (o == Qt::Horizontal)
288 a[i].stretch = item->widget()->sizePolicy().horizontalStretch();
290 a[i].stretch = item->widget()->sizePolicy().verticalStretch();
295 that->empty = count == 0;
297 rpick(o, that->minSize) += handleExtent;
298 that->minSize += QSize(pick(Qt::Horizontal, margins), pick(Qt::Vertical, margins));
299 if (items.size() > 1)
300 rpick(o, that->minSize) += spacing + extensionExtent;
302 rpick(o, that->hint) += handleExtent;
303 that->hint += QSize(pick(Qt::Horizontal, margins), pick(Qt::Vertical, margins));
309 QWidgetAction *a = qobject_cast<QWidgetAction*>(item->action);
310 return a !=
nullptr && a->defaultWidget() == item->widget();
313void QToolBarLayout::updateMacBorderMetrics()
316 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
320 QRect rect = geometry();
322 QMainWindow *mainWindow = qobject_cast<QMainWindow*>(tb->parentWidget());
323 if (!mainWindow || !mainWindow->isWindow() || !mainWindow->unifiedTitleAndToolBarOnMac())
326 QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface();
327 if (!nativeInterface)
329 QPlatformNativeInterface::NativeResourceForIntegrationFunction function =
330 nativeInterface->nativeResourceFunctionForIntegration(
"registerContentBorderArea");
334 QPoint upper = tb->mapToParent(rect.topLeft());
335 QPoint lower = tb->mapToParent(rect.bottomLeft() + QPoint(0, 1));
337 typedef void (*RegisterContentBorderAreaFunction)(QWindow *window,
void *identifier,
int upper,
int lower);
338 if (mainWindow->toolBarArea(tb) == Qt::TopToolBarArea) {
339 (
reinterpret_cast<RegisterContentBorderAreaFunction>(function))(tb->window()->windowHandle(), tb, upper.y(), lower.y());
341 (
reinterpret_cast<RegisterContentBorderAreaFunction>(function))(tb->window()->windowHandle(), tb, 0, 0);
346void QToolBarLayout::setGeometry(
const QRect &rect)
348 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
351 QStyle *style = tb->style();
352 QStyleOptionToolBar opt;
353 tb->initStyleOption(&opt);
354 const QMargins margins = contentsMargins();
355 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
356 Qt::Orientation o = tb->orientation();
358 QLayout::setGeometry(rect);
360 updateMacBorderMetrics();
362 bool ranOutOfSpace =
false;
364 ranOutOfSpace = layoutActions(rect.size());
366 if (expanded || animating || ranOutOfSpace) {
367 Qt::ToolBarArea area = Qt::TopToolBarArea;
368 if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget()))
369 area = win->toolBarArea(tb);
370 QSize hint = sizeHint();
373 rpick(o, pos) = pick(o, rect.bottomRight()) -
374 pick(o, QSize(margins.bottom(), margins.right())) - extensionExtent + 2;
375 if (area == Qt::LeftToolBarArea || area == Qt::TopToolBarArea)
376 rperp(o, pos) = perp(o, rect.topLeft()) +
377 perp(o, QSize(margins.top(), margins.left()));
379 rperp(o, pos) = perp(o, rect.bottomRight()) -
380 perp(o, QSize(margins.bottom(), margins.right())) -
381 (perp(o, hint) - perp(o, margins)) + 1;
383 rpick(o, size) = extensionExtent;
384 rperp(o, size) = perp(o, hint) - perp(o, margins);
387 if (o == Qt::Horizontal)
388 r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
390 extension->setGeometry(r);
392 if (extension->isHidden())
395 if (!extension->isHidden())
400bool QToolBarLayout::layoutActions(
const QSize &size)
405 QRect rect(0, 0, size.width(), size.height());
407 QList<QWidget*> showWidgets, hideWidgets;
409 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
412 QStyle *style = tb->style();
413 QStyleOptionToolBar opt;
414 tb->initStyleOption(&opt);
415 const int handleExtent = movable()
416 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
417 const QMargins margins = contentsMargins();
418 const int spacing =
this->spacing();
419 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
420 Qt::Orientation o = tb->orientation();
421 bool extensionMenuContainsOnlyWidgetActions =
true;
423 int space = pick(o, rect.size()) - pick(o, margins) - handleExtent;
430 bool ranOutOfSpace =
false;
432 int rowPos = perp(o, rect.topLeft()) + perp(o, QSize(margins.top(), margins.left()));
434 while (i < items.size()) {
435 QList<QLayoutStruct> a = geomArray;
443 bool expansiveRow =
false;
444 for (; i < items.size(); ++i) {
448 int newSize = size + (count == 0 ? 0 : spacing) + a[i].minimumSize;
449 if (prev != -1 && newSize > space) {
451 ranOutOfSpace =
true;
454 if (count > 1 && size + spacing + extensionExtent > space)
460 rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
461 expansiveRow = expansiveRow || a[i].expansive;
463 maximumSize += spacing + (a[i].expansive ? a[i].maximumSize : a[i].smartSizeHint());
470 a[i].maximumSize = QWIDGETSIZE_MAX;
471 a[i].minimumSize = 0;
472 a[i].expansive =
true;
476 if (expansiveRow && maximumSize < space) {
477 expansiveRow =
false;
478 a[i].maximumSize = space - maximumSize;
481 qGeomCalc(a, start, i - start + (expansiveRow ? 0 : 1), 0,
482 space - (ranOutOfSpace ? (extensionExtent + spacing) : 0),
485 for (
int j = start; j < i; ++j) {
486 QToolBarItem *item = items.at(j);
489 if (!item->widget()->isHidden())
490 hideWidgets << item->widget();
495 rpick(o, pos) = pick(o, QSize(margins.top(), margins.left())) + handleExtent + a[j].pos;
496 rperp(o, pos) = rowPos;
498 rpick(o, size) = a[j].size;
500 rperp(o, size) = rowHeight;
502 rperp(o, size) = perp(o, rect.size()) - perp(o, margins);
505 if (o == Qt::Horizontal)
506 r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
508 item->setGeometry(r);
510 if (item->widget()->isHidden())
511 showWidgets << item->widget();
515 for (
int j = i; j < items.size(); ++j) {
516 QToolBarItem *item = items.at(j);
517 if (!item->widget()->isHidden())
518 hideWidgets << item->widget();
520 if (!defaultWidgetAction(item)) {
521 popupMenu->addAction(item->action);
522 extensionMenuContainsOnlyWidgetActions =
false;
529 rowPos += rowHeight + spacing;
537 extension->setEnabled(popupMenu ==
nullptr || !extensionMenuContainsOnlyWidgetActions);
540 for (
int i = 0; i < showWidgets.size(); ++i)
541 showWidgets.at(i)->show();
542 for (
int i = 0; i < hideWidgets.size(); ++i)
543 hideWidgets.at(i)->hide();
545 return ranOutOfSpace;
548QSize QToolBarLayout::expandedSize(
const QSize &size)
const
553 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
556 QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
557 Qt::Orientation o = tb->orientation();
558 QStyle *style = tb->style();
559 QStyleOptionToolBar opt;
560 tb->initStyleOption(&opt);
561 const int handleExtent = movable()
562 ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
563 const QMargins margins = contentsMargins();
564 const int spacing =
this->spacing();
565 const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
569 for (
int x = 0; x < items.size(); ++x) {
570 if (!geomArray[x].empty) {
571 total_w += (count == 0 ? 0 : spacing) + geomArray[x].minimumSize;
578 int min_w = pick(o, size);
579 int rows = (
int)qSqrt(qreal(count));
582 int space = total_w/rows + spacing + extensionExtent;
583 space = qMax(space, min_w - pick(o, margins) - handleExtent);
585 space = qMin(space, pick(o, win->size()) - pick(o, margins) - handleExtent);
590 while (i < items.size()) {
595 for (; i < items.size(); ++i) {
596 if (geomArray[i].empty)
599 int newSize = size + (count == 0 ? 0 : spacing) + geomArray[i].minimumSize;
600 rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
601 if (prev != -1 && newSize > space) {
602 if (count > 1 && size + spacing + extensionExtent > space) {
603 size -= spacing + geomArray[prev].minimumSize;
615 h += rowHeight + spacing;
618 w += pick(Qt::Horizontal, margins) + handleExtent + spacing + extensionExtent;
621 w = qMin(w, pick(o, win->size()));
622 h += pick(Qt::Vertical, margins) - spacing;
625 rpick(o, result) = w;
626 rperp(o, result) = h;
630void QToolBarLayout::setExpanded(
bool exp)
632 QWidget *tb = qobject_cast<QToolBar*>(parentWidget());
635 if (exp == expanded && !tb->isWindow())
639 extension->setChecked(expanded);
641 if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget())) {
642#if !QT_CONFIG(dockwidget)
645 animating = !tb->isWindow() && win->isAnimated();
647 QMainWindowLayout *layout = qt_mainwindow_layout(win);
651 QList<
int> path = layout->layoutState.indexOf(tb);
652 if (!path.isEmpty()) {
653 QRect rect = layout->layoutState.itemRect(path);
654 layoutActions(rect.size());
657 layout->layoutState.toolBarAreaLayout.apply(animating);
661QSize QToolBarLayout::minimumSize()
const
668QSize QToolBarLayout::sizeHint()
const
675QToolBarItem *QToolBarLayout::createItem(QAction *action)
677 bool customWidget =
false;
678 bool standardButtonWidget =
false;
679 QWidget *widget =
nullptr;
680 QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
682 return (QToolBarItem *)
nullptr;
684 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action)) {
685 widget = widgetAction->requestWidget(tb);
686 if (widget !=
nullptr) {
687 widget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
690 }
else if (action->isSeparator()) {
691 QToolBarSeparator *sep =
new QToolBarSeparator(tb);
692 connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
693 sep, SLOT(setOrientation(Qt::Orientation)));
698 QToolButton *button =
new QToolButton(tb);
699 button->setAutoRaise(
true);
700 button->setFocusPolicy(Qt::NoFocus);
701 button->setIconSize(tb->iconSize());
702 button->setToolButtonStyle(tb->toolButtonStyle());
703 QObject::connect(tb, SIGNAL(iconSizeChanged(QSize)),
704 button, SLOT(setIconSize(QSize)));
705 QObject::connect(tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
706 button, SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));
707 button->setDefaultAction(action);
708 QObject::connect(button, SIGNAL(triggered(QAction*)), tb, SIGNAL(actionTriggered(QAction*)));
710 standardButtonWidget =
true;
714 QToolBarItem *result =
new QToolBarItem(widget);
715 if (standardButtonWidget)
716 result->setAlignment(Qt::AlignJustify);
717 result->customWidget = customWidget;
718 result->action = action;
724#include "moc_qtoolbarlayout_p.cpp"
Combined button and popup list for selecting options.
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)