Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtoolbar.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qtoolbar.h"
6
7#include <qapplication.h>
8#if QT_CONFIG(draganddrop)
9#include <qdrag.h>
10#endif
11#include <qevent.h>
12#include <qlayout.h>
13#include <qmainwindow.h>
14#include <qmenu.h>
15#include <qmimedata.h>
16#include <qstylepainter.h>
17#include <qstyleoption.h>
18#include <qtoolbutton.h>
19#include <qwidgetaction.h>
20#include <private/qwidgetaction_p.h>
21#include <private/qmainwindowlayout_p.h>
22#include <private/qhighdpiscaling_p.h>
23
24#ifdef Q_OS_MACOS
25#include <qpa/qplatformnativeinterface.h>
26#endif
27
28#include "qtoolbar_p.h"
31
32#include "qdebug.h"
33
34#define POPUP_TIMER_INTERVAL 500
35
37
38using namespace Qt::StringLiterals;
39
40// qmainwindow.cpp
41extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
42
43/******************************************************************************
44** QToolBarPrivate
45*/
46
47void QToolBarPrivate::init()
48{
49 Q_Q(QToolBar);
50 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
51 q->setBackgroundRole(QPalette::Button);
52 q->setAttribute(Qt::WA_Hover);
53 q->setAttribute(Qt::WA_X11NetWmWindowTypeToolBar);
54
55 QStyle *style = q->style();
56 int e = style->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, q);
57 iconSize = QSize(e, e);
58
59 layout = new QToolBarLayout(q);
60 layout->updateMarginAndSpacing();
61
62 toggleViewAction = new QAction(q);
63 toggleViewAction->setCheckable(true);
64 q->setMovable(q->style()->styleHint(QStyle::SH_ToolBar_Movable, nullptr, q ));
65 QObject::connect(toggleViewAction, SIGNAL(triggered(bool)), q, SLOT(_q_toggleView(bool)));
66}
67
69{
70 Q_Q(QToolBar);
71 if (b == q->isHidden()) {
72 if (b)
73 q->show();
74 else
75 q->close();
76 }
77}
78
79void QToolBarPrivate::_q_updateIconSize(const QSize &sz)
80{
81 Q_Q(QToolBar);
82 if (!explicitIconSize) {
83 // iconSize not explicitly set
84 q->setIconSize(sz);
85 explicitIconSize = false;
86 }
87}
88
89void QToolBarPrivate::_q_updateToolButtonStyle(Qt::ToolButtonStyle style)
90{
91 Q_Q(QToolBar);
93 q->setToolButtonStyle(style);
95 }
96}
97
98void QToolBarPrivate::updateWindowFlags(bool floating, bool unplug)
99{
100 Q_Q(QToolBar);
101 Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
102
103 flags |= Qt::FramelessWindowHint;
104
105#if QT_CONFIG(draganddrop)
106 // If we are performing a platform drag the flag is not needed and we want to avoid recreating
107 // the platform window when it would be removed later
108 if (unplug && !QMainWindowLayout::needsPlatformDrag())
109 flags |= Qt::X11BypassWindowManagerHint;
110#else
111 Q_UNUSED(unplug);
112#endif
113
114 q->setWindowFlags(flags);
115}
116
117void QToolBarPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
118{
119 Q_Q(QToolBar);
120 bool visible = !q->isHidden();
121 bool wasFloating = q->isFloating(); // ...is also currently using popup menus
122
123 updateWindowFlags(floating, unplug);
124
125 if (floating != wasFloating)
126 layout->checkUsePopupMenu();
127
128 if (!rect.isNull())
129 q->setGeometry(rect);
130
131 if (visible)
132 q->show();
133
134 if (floating != wasFloating)
135 emit q->topLevelChanged(floating);
136}
137
138void QToolBarPrivate::initDrag(const QPoint &pos)
139{
140 Q_Q(QToolBar);
141
142 if (state != nullptr)
143 return;
144
145 QMainWindow *win = qobject_cast<QMainWindow*>(parent);
146 Q_ASSERT(win != nullptr);
147 QMainWindowLayout *layout = qt_mainwindow_layout(win);
148 Q_ASSERT(layout != nullptr);
149 if (layout->pluggingWidget != nullptr) // the main window is animating a docking operation
150 return;
151
152 state = new DragState;
153 state->pressPos = pos;
154 state->dragging = false;
155 state->moving = false;
156 state->widgetItem = nullptr;
157
158 if (q->isRightToLeft())
159 state->pressPos = QPoint(q->width() - state->pressPos.x(), state->pressPos.y());
160}
161
162void QToolBarPrivate::startDrag(bool moving)
163{
164 Q_Q(QToolBar);
165
166 Q_ASSERT(state != nullptr);
167
168 if ((moving && state->moving) || state->dragging)
169 return;
170
171 QMainWindow *win = qobject_cast<QMainWindow*>(parent);
172 Q_ASSERT(win != nullptr);
173 QMainWindowLayout *layout = qt_mainwindow_layout(win);
174 Q_ASSERT(layout != nullptr);
175
176#if QT_CONFIG(draganddrop)
177 const bool wasFloating = q->isFloating();
178#endif
179
180 if (!moving) {
181 state->widgetItem = layout->unplug(q, QDockWidgetPrivate::DragScope::Group);
182 Q_ASSERT(state->widgetItem != nullptr);
183 }
184 state->dragging = !moving;
185 state->moving = moving;
186
187#if QT_CONFIG(draganddrop)
188 if (QMainWindowLayout::needsPlatformDrag() && state->dragging) {
189 auto result = layout->performPlatformWidgetDrag(state->widgetItem, state->pressPos);
190 if (result == Qt::IgnoreAction && !wasFloating) {
191 layout->revert(state->widgetItem);
192 delete state;
193 state = nullptr;
194 } else {
195 endDrag();
196 }
197 }
198#endif
199}
200
202{
203 Q_Q(QToolBar);
204 Q_ASSERT(state != nullptr);
205
206 q->releaseMouse();
207
208 if (state->dragging) {
209 QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
210 Q_ASSERT(layout != nullptr);
211
212 if (!layout->plug(state->widgetItem)) {
213 if (q->isFloatable()) {
214 layout->restore(QInternal::KeepSavedState);
215 setWindowState(true); // gets rid of the X11BypassWindowManager window flag
216 // and activates the resizer
217 q->activateWindow();
218 } else {
219 layout->revert(state->widgetItem);
220 }
221 }
222 }
223
224 delete state;
225 state = nullptr;
226}
227
228bool QToolBarPrivate::mousePressEvent(QMouseEvent *event)
229{
230 Q_Q(QToolBar);
231 QStyleOptionToolBar opt;
232 q->initStyleOption(&opt);
233 if (q->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, q).contains(event->position().toPoint()) == false) {
234#ifdef Q_OS_MACOS
235 // When using the unified toolbar on OS X, the user can click and
236 // drag between toolbar contents to move the window. Make this work by
237 // implementing the standard mouse-dragging code and then call
238 // window->move() in mouseMoveEvent below.
239 if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parent)) {
240 if (mainWindow->toolBarArea(q) == Qt::TopToolBarArea
241 && mainWindow->unifiedTitleAndToolBarOnMac()
242 && q->childAt(event->pos()) == 0) {
243 macWindowDragging = true;
244 macWindowDragPressPosition = event->pos();
245 return true;
246 }
247 }
248#endif
249 return false;
250 }
251
252 if (event->button() != Qt::LeftButton)
253 return true;
254
255 if (!layout->movable())
256 return true;
257
258 initDrag(event->position().toPoint());
259 return true;
260}
261
263{
264#if QT_CONFIG(draganddrop)
265 // if we are peforming a platform drag ignore the release here and end the drag when the actual
266 // drag ends.
267 if (QMainWindowLayout::needsPlatformDrag())
268 return false;
269#endif
270
271 if (state != nullptr) {
272 endDrag();
273 return true;
274 } else {
275#ifdef Q_OS_MACOS
276 if (!macWindowDragging)
277 return false;
278 macWindowDragging = false;
279 macWindowDragPressPosition = QPoint();
280 return true;
281#endif
282 return false;
283 }
284}
285
286bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event)
287{
288 Q_Q(QToolBar);
289
290 if (!state) {
291#ifdef Q_OS_MACOS
292 if (!macWindowDragging)
293 return false;
294 QWidget *w = q->window();
295 const QPoint delta = event->pos() - macWindowDragPressPosition;
296 w->move(w->pos() + delta);
297 return true;
298#endif
299 return false;
300 }
301
302 QMainWindow *win = qobject_cast<QMainWindow*>(parent);
303 if (win == nullptr)
304 return true;
305
306 QMainWindowLayout *layout = qt_mainwindow_layout(win);
307 Q_ASSERT(layout != nullptr);
308
309 if (layout->pluggingWidget == nullptr
310 && (event->position().toPoint() - state->pressPos).manhattanLength() > QApplication::startDragDistance()) {
311 const bool wasDragging = state->dragging;
312 const auto evPos = event->position().toPoint();
313 const bool moving = !q->isWindow() && (orientation == Qt::Vertical ?
314 evPos.x() >= 0 && evPos.x() < q->width() :
315 evPos.y() >= 0 && evPos.y() < q->height());
316
317 startDrag(moving);
318 if (!moving && !wasDragging)
319 q->grabMouse();
320 }
321
322 if (!state) {
323 q->releaseMouse();
324 return true;
325 }
326
327 if (state->dragging) {
328 QPoint pos = event->globalPosition().toPoint();
329 // if we are right-to-left, we move so as to keep the right edge the same distance
330 // from the mouse
331 if (q->isLeftToRight())
332 pos -= state->pressPos;
333 else
334 pos += QPoint(state->pressPos.x() - q->width(), -state->pressPos.y());
335
336 q->move(pos);
337 layout->hover(state->widgetItem, event->globalPosition().toPoint());
338 } else if (state->moving) {
339
340 const QPoint rtl(q->width() - state->pressPos.x(), state->pressPos.y()); //for RTL
341 const QPoint globalPressPos = q->mapToGlobal(q->isRightToLeft() ? rtl : state->pressPos);
342 int pos = 0;
343
344 const QWindow *handle = q->window() ? q->window()->windowHandle() : nullptr;
345 const QPoint delta = handle
346 ? QHighDpi::fromNativePixels(event->globalPosition(), handle).toPoint()
347 - QHighDpi::fromNativePixels(globalPressPos, handle)
348 : event->globalPosition().toPoint() - globalPressPos;
349
350 if (orientation == Qt::Vertical) {
351 pos = q->y() + delta.y();
352 } else {
353 if (q->isRightToLeft()) {
354 pos = win->width() - q->width() - q->x() - delta.x();
355 } else {
356 pos = q->x() + delta.x();
357 }
358 }
359
360 layout->moveToolBar(q, pos);
361 }
362 return true;
363}
364
365void QToolBarPrivate::unplug(const QRect &_r)
366{
367 Q_Q(QToolBar);
368 QRect r = _r;
369 r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
370 setWindowState(true, true, r);
371 layout->setExpanded(false);
372}
373
374void QToolBarPrivate::plug(const QRect &r)
375{
376 setWindowState(false, false, r);
377}
378
379/******************************************************************************
380** QToolBar
381*/
382
383/*!
384 \class QToolBar
385
386 \brief The QToolBar class provides a movable panel that contains a
387 set of controls.
388
389 \ingroup mainwindow-classes
390 \inmodule QtWidgets
391
392 A toolbar is typically created by calling
393 \l QMainWindow::addToolBar(const QString &title), but it can also
394 be added as the first widget in a QVBoxLayout, for example.
395
396 Toolbar buttons are added by adding \e actions, using addAction()
397 or insertAction(). Groups of buttons can be separated using
398 addSeparator() or insertSeparator(). If a toolbar button is not
399 appropriate, a widget can be inserted instead using addWidget() or
400 insertWidget(). Examples of suitable widgets are QSpinBox,
401 QDoubleSpinBox, and QComboBox. When a toolbar button is pressed, it
402 emits the actionTriggered() signal.
403
404 A toolbar can be fixed in place in a particular area (e.g., at the
405 top of the window), or it can be movable between toolbar areas;
406 see setMovable(), isMovable(), allowedAreas() and isAreaAllowed().
407
408 When a toolbar is resized in such a way that it is too small to
409 show all the items it contains, an extension button will appear as
410 the last item in the toolbar. Pressing the extension button will
411 pop up a menu containing the items that do not currently fit in
412 the toolbar.
413
414 When a QToolBar is not a child of a QMainWindow, it loses the ability
415 to populate the extension pop up with widgets added to the toolbar using
416 addWidget(). Please use widget actions created by inheriting QWidgetAction
417 and implementing QWidgetAction::createWidget() instead.
418
419 \sa QToolButton, QMenu, QAction
420*/
421
422/*!
423 \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const
424
425 Returns \c true if this toolbar is dockable in the given \a area;
426 otherwise returns \c false.
427*/
428
429/*!
430 \fn void QToolBar::actionTriggered(QAction *action)
431
432 This signal is emitted when an action in this toolbar is triggered.
433 This happens when the action's tool button is pressed, or when the
434 action is triggered in some other way outside the toolbar. The parameter
435 holds the triggered \a action.
436*/
437
438/*!
439 \fn void QToolBar::allowedAreasChanged(Qt::ToolBarAreas allowedAreas)
440
441 This signal is emitted when the collection of allowed areas for the
442 toolbar is changed. The new areas in which the toolbar can be positioned
443 are specified by \a allowedAreas.
444
445 \sa allowedAreas
446*/
447
448/*!
449 \fn void QToolBar::iconSizeChanged(const QSize &iconSize)
450
451 This signal is emitted when the icon size is changed. The \a
452 iconSize parameter holds the toolbar's new icon size.
453
454 \sa iconSize, QMainWindow::iconSize
455*/
456
457/*!
458 \fn void QToolBar::movableChanged(bool movable)
459
460 This signal is emitted when the toolbar becomes movable or fixed.
461 If the toolbar can be moved, \a movable is true; otherwise it is
462 false.
463
464 \sa movable
465*/
466
467/*!
468 \fn void QToolBar::orientationChanged(Qt::Orientation orientation)
469
470 This signal is emitted when the orientation of the toolbar changes.
471 The \a orientation parameter holds the toolbar's new orientation.
472
473 \sa orientation
474*/
475
476/*!
477 \fn void QToolBar::toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle)
478
479 This signal is emitted when the tool button style is changed. The
480 \a toolButtonStyle parameter holds the toolbar's new tool button
481 style.
482
483 \sa toolButtonStyle, QMainWindow::toolButtonStyle
484*/
485
486/*!
487 \since 4.6
488
489 \fn void QToolBar::topLevelChanged(bool topLevel)
490
491 This signal is emitted when the \l floating property changes.
492 The \a topLevel parameter is true if the toolbar is now floating;
493 otherwise it is false.
494
495 \sa isWindow()
496*/
497
498
499/*!
500 \fn void QToolBar::visibilityChanged(bool visible)
501 \since 4.7
502
503 This signal is emitted when the toolbar becomes \a visible (or
504 invisible). This happens when the widget is hidden or shown.
505*/
506
507/*!
508 Constructs a QToolBar with the given \a parent.
509*/
510QToolBar::QToolBar(QWidget *parent)
511 : QWidget(*new QToolBarPrivate, parent, { })
512{
513 Q_D(QToolBar);
514 d->init();
515}
516
517/*!
518 Constructs a QToolBar with the given \a parent.
519
520 The given window \a title identifies the toolbar and is shown in
521 the context menu provided by QMainWindow.
522
523 \sa setWindowTitle()
524*/
525QToolBar::QToolBar(const QString &title, QWidget *parent)
526 : QToolBar(parent)
527{
528 setWindowTitle(title);
529}
530
531
532/*!
533 Destroys the toolbar.
534*/
535QToolBar::~QToolBar()
536{
537}
538
539/*! \property QToolBar::movable
540 \brief whether the user can move the toolbar within the toolbar area,
541 or between toolbar areas.
542
543 By default, this property is \c true.
544
545 This property only makes sense if the toolbar is in a
546 QMainWindow.
547
548 \sa allowedAreas
549*/
550
551void QToolBar::setMovable(bool movable)
552{
553 Q_D(QToolBar);
554 if (!movable == !d->movable)
555 return;
556 d->movable = movable;
557 d->layout->invalidate();
558 emit movableChanged(d->movable);
559}
560
561bool QToolBar::isMovable() const
562{
563 Q_D(const QToolBar);
564 return d->movable;
565}
566
567/*!
568 \property QToolBar::floatable
569 \brief whether the toolbar can be dragged and dropped as an independent window.
570
571 The default is true.
572*/
573bool QToolBar::isFloatable() const
574{
575 Q_D(const QToolBar);
576 return d->floatable;
577}
578
579void QToolBar::setFloatable(bool floatable)
580{
581 Q_D(QToolBar);
582 d->floatable = floatable;
583}
584
585/*!
586 \property QToolBar::floating
587 \brief whether the toolbar is an independent window.
588
589 By default, this property is \c true.
590
591 \sa QWidget::isWindow()
592*/
593bool QToolBar::isFloating() const
594{
595 return isWindow();
596}
597
598/*!
599 \property QToolBar::allowedAreas
600 \brief areas where the toolbar may be placed
601
602 The default is Qt::AllToolBarAreas.
603
604 This property only makes sense if the toolbar is in a
605 QMainWindow.
606
607 \sa movable
608*/
609
610void QToolBar::setAllowedAreas(Qt::ToolBarAreas areas)
611{
612 Q_D(QToolBar);
613 areas &= Qt::ToolBarArea_Mask;
614 if (areas == d->allowedAreas)
615 return;
616 d->allowedAreas = areas;
617 emit allowedAreasChanged(d->allowedAreas);
618}
619
620Qt::ToolBarAreas QToolBar::allowedAreas() const
621{
622 Q_D(const QToolBar);
623 return d->allowedAreas;
624}
625
626/*! \property QToolBar::orientation
627 \brief orientation of the toolbar
628
629 The default is Qt::Horizontal.
630
631 This function should not be used when the toolbar is managed
632 by QMainWindow. You can use QMainWindow::addToolBar() or
633 QMainWindow::insertToolBar() if you wish to move a toolbar that
634 is already added to a main window to another Qt::ToolBarArea.
635*/
636
637void QToolBar::setOrientation(Qt::Orientation orientation)
638{
639 Q_D(QToolBar);
640 if (orientation == d->orientation)
641 return;
642
643 d->orientation = orientation;
644
645 if (orientation == Qt::Vertical)
646 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
647 else
648 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
649
650 d->layout->invalidate();
651 d->layout->activate();
652
653 emit orientationChanged(d->orientation);
654}
655
656Qt::Orientation QToolBar::orientation() const
657{ Q_D(const QToolBar); return d->orientation; }
658
659/*!
660 \property QToolBar::iconSize
661 \brief size of icons in the toolbar.
662
663 The default size is determined by the application's style and is
664 derived from the QStyle::PM_ToolBarIconSize pixel metric. It is
665 the maximum size an icon can have. Icons of smaller size will not
666 be scaled up.
667*/
668
669QSize QToolBar::iconSize() const
670{ Q_D(const QToolBar); return d->iconSize; }
671
672void QToolBar::setIconSize(const QSize &iconSize)
673{
674 Q_D(QToolBar);
675 QSize sz = iconSize;
676 if (!sz.isValid()) {
677 QMainWindow *mw = qobject_cast<QMainWindow *>(parentWidget());
678 if (mw && mw->layout()) {
679 QLayout *layout = mw->layout();
680 int i = 0;
681 QLayoutItem *item = nullptr;
682 do {
683 item = layout->itemAt(i++);
684 if (item && (item->widget() == this))
685 sz = mw->iconSize();
686 } while (!sz.isValid() && item != nullptr);
687 }
688 }
689 if (!sz.isValid()) {
690 const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, this);
691 sz = QSize(metric, metric);
692 }
693 if (d->iconSize != sz) {
694 d->iconSize = sz;
695 setMinimumSize(0, 0);
696 emit iconSizeChanged(d->iconSize);
697 }
698 d->explicitIconSize = iconSize.isValid();
699
700 d->layout->invalidate();
701}
702
703/*!
704 \property QToolBar::toolButtonStyle
705 \brief the style of toolbar buttons
706
707 This property defines the style of all tool buttons that are added
708 as \l{QAction}s. Note that if you add a QToolButton with the
709 addWidget() method, it will not get this button style.
710
711 To have the style of toolbuttons follow the system settings, set this property to Qt::ToolButtonFollowStyle.
712 On Unix, the user settings from the desktop environment will be used.
713 On other platforms, Qt::ToolButtonFollowStyle means icon only.
714
715 The default is Qt::ToolButtonIconOnly.
716*/
717
718Qt::ToolButtonStyle QToolBar::toolButtonStyle() const
719{ Q_D(const QToolBar); return d->toolButtonStyle; }
720
721void QToolBar::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
722{
723 Q_D(QToolBar);
724 d->explicitToolButtonStyle = true;
725 if (d->toolButtonStyle == toolButtonStyle)
726 return;
727 d->toolButtonStyle = toolButtonStyle;
728 setMinimumSize(0, 0);
729 emit toolButtonStyleChanged(d->toolButtonStyle);
730}
731
732/*!
733 Removes all actions from the toolbar.
734
735 \sa removeAction()
736*/
737void QToolBar::clear()
738{
739 QList<QAction *> actions = this->actions();
740 for(int i = 0; i < actions.size(); i++)
741 removeAction(actions.at(i));
742}
743
744/*!
745 Adds a separator to the end of the toolbar.
746
747 \sa insertSeparator()
748*/
749QAction *QToolBar::addSeparator()
750{
751 QAction *action = new QAction(this);
752 action->setSeparator(true);
753 addAction(action);
754 return action;
755}
756
757/*!
758 Inserts a separator into the toolbar in front of the toolbar
759 item associated with the \a before action.
760
761 \sa addSeparator()
762*/
763QAction *QToolBar::insertSeparator(QAction *before)
764{
765 QAction *action = new QAction(this);
766 action->setSeparator(true);
767 insertAction(before, action);
768 return action;
769}
770
771/*!
772 Adds the given \a widget to the toolbar as the toolbar's last
773 item.
774
775 The toolbar takes ownership of \a widget.
776
777 If you add a QToolButton with this method, the toolbar's
778 Qt::ToolButtonStyle will not be respected.
779
780 \note You should use QAction::setVisible() to change the
781 visibility of the widget. Using QWidget::setVisible(),
782 QWidget::show() and QWidget::hide() does not work.
783
784 \sa insertWidget()
785*/
786QAction *QToolBar::addWidget(QWidget *widget)
787{
788 QWidgetAction *action = new QWidgetAction(this);
789 action->setDefaultWidget(widget);
790 action->d_func()->autoCreated = true;
791 addAction(action);
792 return action;
793}
794
795/*!
796 Inserts the given \a widget in front of the toolbar item
797 associated with the \a before action.
798
799 Note: You should use QAction::setVisible() to change the
800 visibility of the widget. Using QWidget::setVisible(),
801 QWidget::show() and QWidget::hide() does not work.
802
803 \sa addWidget()
804*/
805QAction *QToolBar::insertWidget(QAction *before, QWidget *widget)
806{
807 QWidgetAction *action = new QWidgetAction(this);
808 action->setDefaultWidget(widget);
809 action->d_func()->autoCreated = true;
810 insertAction(before, action);
811 return action;
812}
813
814/*!
815 \internal
816
817 Returns the geometry of the toolbar item associated with the given
818 \a action, or an invalid QRect if no matching item is found.
819*/
820QRect QToolBar::actionGeometry(QAction *action) const
821{
822 Q_D(const QToolBar);
823
824 int index = d->layout->indexOf(action);
825 if (index == -1)
826 return QRect();
827 return d->layout->itemAt(index)->widget()->geometry();
828}
829
830/*!
831 Returns the action at point \a p. This function returns zero if no
832 action was found.
833
834 \sa QWidget::childAt()
835*/
836QAction *QToolBar::actionAt(const QPoint &p) const
837{
838 Q_D(const QToolBar);
839 QWidget *widget = childAt(p);
840 int index = d->layout->indexOf(widget);
841 if (index == -1)
842 return nullptr;
843 QLayoutItem *item = d->layout->itemAt(index);
844 return static_cast<QToolBarItem*>(item)->action;
845}
846
847/*! \fn QAction *QToolBar::actionAt(int x, int y) const
848 \overload
849
850 Returns the action at the point \a x, \a y. This function returns
851 zero if no action was found.
852*/
853
854/*! \reimp */
855void QToolBar::actionEvent(QActionEvent *event)
856{
857 Q_D(QToolBar);
858 auto action = static_cast<QAction *>(event->action());
859 QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action);
860
861 switch (event->type()) {
862 case QEvent::ActionAdded: {
863 Q_ASSERT_X(widgetAction == nullptr || d->layout->indexOf(widgetAction) == -1,
864 "QToolBar", "widgets cannot be inserted multiple times");
865
866 // reparent the action to this toolbar if it has been created
867 // using the addAction(text) etc. convenience functions, to
868 // preserve Qt 4.1.x behavior. The widget is already
869 // reparented to us due to the createWidget call inside
870 // createItem()
871 if (widgetAction != nullptr && widgetAction->d_func()->autoCreated)
872 widgetAction->setParent(this);
873
874 int index = d->layout->count();
875 if (event->before()) {
876 index = d->layout->indexOf(event->before());
877 Q_ASSERT_X(index != -1, "QToolBar::insertAction", "internal error");
878 }
879 d->layout->insertAction(index, action);
880 break;
881 }
882
883 case QEvent::ActionChanged:
884 d->layout->invalidate();
885 break;
886
887 case QEvent::ActionRemoved: {
888 int index = d->layout->indexOf(action);
889 if (index != -1) {
890 delete d->layout->takeAt(index);
891 }
892 break;
893 }
894
895 default:
896 Q_ASSERT_X(false, "QToolBar::actionEvent", "internal error");
897 }
898}
899
900/*! \reimp */
901void QToolBar::changeEvent(QEvent *event)
902{
903 Q_D(QToolBar);
904 switch (event->type()) {
905 case QEvent::WindowTitleChange:
906 d->toggleViewAction->setText(windowTitle());
907 break;
908 case QEvent::StyleChange:
909 d->layout->invalidate();
910 if (!d->explicitIconSize) {
911 QStyleOptionToolBar opt;
912 initStyleOption(&opt);
913 const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, &opt, this);
914 setIconSize({metric, metric});
915 d->explicitIconSize = false;
916 }
917 d->layout->updateMarginAndSpacing();
918 break;
919 case QEvent::LayoutDirectionChange:
920 d->layout->invalidate();
921 break;
922 default:
923 break;
924 }
925 QWidget::changeEvent(event);
926}
927
928/*! \reimp */
929void QToolBar::paintEvent(QPaintEvent *)
930{
931 Q_D(QToolBar);
932
933 QPainter p(this);
934 QStyle *style = this->style();
935 QStyleOptionToolBar opt;
936 initStyleOption(&opt);
937
938 if (d->layout->expanded || d->layout->animating || isWindow()) {
939 //if the toolbar is expended, we need to fill the background with the window color
940 //because some styles may expects that.
941 p.fillRect(opt.rect, palette().window());
942 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
943 style->drawPrimitive(QStyle::PE_FrameMenu, &opt, &p, this);
944 } else {
945 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
946 }
947
948 opt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &opt, this);
949 if (opt.rect.isValid())
950 style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
951}
952
953/*
954 Checks if an expanded toolbar has to wait for this popup to close before
955 the toolbar collapses. This is true if
956 1) the popup has the toolbar in its parent chain,
957 2) the popup is a menu whose menuAction is somewhere in the toolbar.
958*/
959static bool waitForPopup(QToolBar *tb, QWidget *popup)
960{
961 if (popup == nullptr || popup->isHidden())
962 return false;
963
964 QWidget *w = popup;
965 while (w != nullptr) {
966 if (w == tb)
967 return true;
968 w = w->parentWidget();
969 }
970
971 QMenu *menu = qobject_cast<QMenu*>(popup);
972 if (menu == nullptr)
973 return false;
974
975 const QAction *action = menu->menuAction();
976 for (auto object : action->associatedObjects()) {
977 if (QWidget *widget = qobject_cast<QWidget*>(object)) {
978 if (waitForPopup(tb, widget))
979 return true;
980 }
981 }
982
983 return false;
984}
985
986#ifdef Q_OS_MACOS
987static void enableMacToolBar(QToolBar *toolbar, bool enable)
988{
989 auto *mainWindow = qobject_cast<QMainWindow *>(toolbar->window());
990 if (!mainWindow)
991 return;
992
993 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
994 layout->setUnifiedToolBarAreaEnabled(toolbar, enable);
995}
996#endif
997
998
999/*! \reimp */
1000bool QToolBar::event(QEvent *event)
1001{
1002 Q_D(QToolBar);
1003
1004 switch (event->type()) {
1005 case QEvent::Timer:
1006 if (d->waitForPopupTimer.timerId() == static_cast<QTimerEvent*>(event)->timerId()) {
1007 QWidget *w = QApplication::activePopupWidget();
1008 if (!waitForPopup(this, w)) {
1009 d->waitForPopupTimer.stop();
1010 if (!this->underMouse())
1011 d->layout->setExpanded(false);
1012 }
1013 }
1014 break;
1015 case QEvent::Hide:
1016 if (!isHidden())
1017 break;
1018 Q_FALLTHROUGH();
1019 case QEvent::Show:
1020 d->toggleViewAction->setChecked(event->type() == QEvent::Show);
1021#ifdef Q_OS_MACOS
1022 enableMacToolBar(this, event->type() == QEvent::Show);
1023#endif
1024 emit visibilityChanged(event->type() == QEvent::Show);
1025 break;
1026 case QEvent::ParentChange:
1027 d->layout->checkUsePopupMenu();
1028 break;
1029
1030 case QEvent::MouseButtonPress: {
1031 if (d->mousePressEvent(static_cast<QMouseEvent*>(event)))
1032 return true;
1033 break;
1034 }
1035 case QEvent::MouseButtonRelease:
1036 if (d->mouseReleaseEvent(static_cast<QMouseEvent*>(event)))
1037 return true;
1038 break;
1039 case QEvent::HoverEnter:
1040 case QEvent::HoverLeave:
1041 // there's nothing special to do here and we don't want to update the whole widget
1042 return true;
1043 case QEvent::HoverMove: {
1044#ifndef QT_NO_CURSOR
1045 QHoverEvent *e = static_cast<QHoverEvent*>(event);
1046 QStyleOptionToolBar opt;
1047 initStyleOption(&opt);
1048 if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->position().toPoint()))
1049 setCursor(Qt::SizeAllCursor);
1050 else
1051 unsetCursor();
1052#endif
1053 break;
1054 }
1055 case QEvent::MouseMove:
1056 if (d->mouseMoveEvent(static_cast<QMouseEvent*>(event)))
1057 return true;
1058 break;
1059 case QEvent::Leave:
1060 if (d->state != nullptr && d->state->dragging) {
1061#ifdef Q_OS_WIN
1062 // This is a workaround for losing the mouse on Vista.
1063 QPoint pos = QCursor::pos();
1064 QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
1065 QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
1066 d->mouseMoveEvent(&fake);
1067#endif
1068 } else {
1069 if (!d->layout->expanded)
1070 break;
1071
1072 QWidget *w = QApplication::activePopupWidget();
1073 if (waitForPopup(this, w)) {
1074 d->waitForPopupTimer.start(POPUP_TIMER_INTERVAL, this);
1075 break;
1076 }
1077
1078 d->waitForPopupTimer.stop();
1079 d->layout->setExpanded(false);
1080 break;
1081 }
1082 break;
1083 default:
1084 break;
1085 }
1086 return QWidget::event(event);
1087}
1088
1089/*!
1090 Returns a checkable action that can be used to show or hide this
1091 toolbar.
1092
1093 The action's text is set to the toolbar's window title.
1094
1095 \sa QAction::text, QWidget::windowTitle
1096*/
1097QAction *QToolBar::toggleViewAction() const
1098{ Q_D(const QToolBar); return d->toggleViewAction; }
1099
1100/*!
1101 \since 4.2
1102
1103 Returns the widget associated with the specified \a action.
1104
1105 \sa addWidget()
1106*/
1107QWidget *QToolBar::widgetForAction(QAction *action) const
1108{
1109 Q_D(const QToolBar);
1110
1111 int index = d->layout->indexOf(action);
1112 if (index == -1)
1113 return nullptr;
1114
1115 return d->layout->itemAt(index)->widget();
1116}
1117
1118extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
1119
1120/*!
1121 \internal
1122*/
1123void QToolBar::initStyleOption(QStyleOptionToolBar *option) const
1124{
1125 Q_D(const QToolBar);
1126
1127 if (!option)
1128 return;
1129
1130 option->initFrom(this);
1131 if (orientation() == Qt::Horizontal)
1132 option->state |= QStyle::State_Horizontal;
1133 option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, nullptr, this);
1134 option->features = d->layout->movable()
1135 ? QStyleOptionToolBar::Movable
1136 : QStyleOptionToolBar::None;
1137 // if the tool bar is not in a QMainWindow, this will make the painting right
1138 option->toolBarArea = Qt::NoToolBarArea;
1139
1140 // Add more styleoptions if the toolbar has been added to a mainwindow.
1141 QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
1142
1143 if (!mainWindow)
1144 return;
1145
1146 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
1147 Q_ASSERT_X(layout != nullptr, "QToolBar::initStyleOption()",
1148 "QMainWindow->layout() != QMainWindowLayout");
1149
1150 layout->getStyleOptionInfo(option, const_cast<QToolBar *>(this));
1151}
1152
1153QT_END_NAMESPACE
1154
1155#include "moc_qtoolbar.cpp"
bool explicitToolButtonStyle
Definition qtoolbar_p.h:53
void plug(const QRect &r)
Definition qtoolbar.cpp:374
void updateWindowFlags(bool floating, bool unplug=false)
Definition qtoolbar.cpp:98
void startDrag(bool moving=false)
Definition qtoolbar.cpp:162
bool mousePressEvent(QMouseEvent *e)
Definition qtoolbar.cpp:228
void unplug(const QRect &r)
Definition qtoolbar.cpp:365
QToolBarLayout * layout
Definition qtoolbar_p.h:63
void _q_toggleView(bool b)
Definition qtoolbar.cpp:68
void setWindowState(bool floating, bool unplug=false, const QRect &rect=QRect())
Definition qtoolbar.cpp:117
bool mouseMoveEvent(QMouseEvent *e)
Definition qtoolbar.cpp:286
bool explicitIconSize
Definition qtoolbar_p.h:52
void _q_updateToolButtonStyle(Qt::ToolButtonStyle style)
Definition qtoolbar.cpp:89
bool mouseReleaseEvent(QMouseEvent *e)
Definition qtoolbar.cpp:262
DragState * state
Definition qtoolbar_p.h:71
void initDrag(const QPoint &pos)
Definition qtoolbar.cpp:138
void _q_updateIconSize(const QSize &sz)
Definition qtoolbar.cpp:79
QAction * toggleViewAction
Definition qtoolbar_p.h:61
Combined button and popup list for selecting options.
QMainWindowLayout * qt_mainwindow_layout(const QMainWindow *window)
static bool waitForPopup(QToolBar *tb, QWidget *popup)
Definition qtoolbar.cpp:959
#define POPUP_TIMER_INTERVAL
Definition qtoolbar.cpp:34