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 The default value is style dependent (determined by the
544 QStyle::SH_ToolBar_Movable style hint), and is \c true for most styles.
545
546 This property only makes sense if the toolbar is in a
547 QMainWindow.
548
549 \sa allowedAreas
550*/
551
552void QToolBar::setMovable(bool movable)
553{
554 Q_D(QToolBar);
555 if (!movable == !d->movable)
556 return;
557 d->movable = movable;
558 d->layout->invalidate();
559 emit movableChanged(d->movable);
560}
561
562bool QToolBar::isMovable() const
563{
564 Q_D(const QToolBar);
565 return d->movable;
566}
567
568/*!
569 \property QToolBar::floatable
570 \brief whether the toolbar can be dragged and dropped as an independent window.
571
572 The default is true.
573*/
574bool QToolBar::isFloatable() const
575{
576 Q_D(const QToolBar);
577 return d->floatable;
578}
579
580void QToolBar::setFloatable(bool floatable)
581{
582 Q_D(QToolBar);
583 d->floatable = floatable;
584}
585
586/*!
587 \property QToolBar::floating
588 \brief whether the toolbar is an independent window.
589
590 By default, this property is \c true.
591
592 \sa QWidget::isWindow()
593*/
594bool QToolBar::isFloating() const
595{
596 return isWindow();
597}
598
599/*!
600 \property QToolBar::allowedAreas
601 \brief areas where the toolbar may be placed
602
603 The default is Qt::AllToolBarAreas.
604
605 This property only makes sense if the toolbar is in a
606 QMainWindow.
607
608 \sa movable
609*/
610
611void QToolBar::setAllowedAreas(Qt::ToolBarAreas areas)
612{
613 Q_D(QToolBar);
614 areas &= Qt::ToolBarArea_Mask;
615 if (areas == d->allowedAreas)
616 return;
617 d->allowedAreas = areas;
618 emit allowedAreasChanged(d->allowedAreas);
619}
620
621Qt::ToolBarAreas QToolBar::allowedAreas() const
622{
623 Q_D(const QToolBar);
624 return d->allowedAreas;
625}
626
627/*! \property QToolBar::orientation
628 \brief orientation of the toolbar
629
630 The default is Qt::Horizontal.
631
632 This function should not be used when the toolbar is managed
633 by QMainWindow. You can use QMainWindow::addToolBar() or
634 QMainWindow::insertToolBar() if you wish to move a toolbar that
635 is already added to a main window to another Qt::ToolBarArea.
636*/
637
638void QToolBar::setOrientation(Qt::Orientation orientation)
639{
640 Q_D(QToolBar);
641 if (orientation == d->orientation)
642 return;
643
644 d->orientation = orientation;
645
646 if (orientation == Qt::Vertical)
647 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
648 else
649 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
650
651 d->layout->invalidate();
652 d->layout->activate();
653
654 emit orientationChanged(d->orientation);
655}
656
657Qt::Orientation QToolBar::orientation() const
658{ Q_D(const QToolBar); return d->orientation; }
659
660/*!
661 \property QToolBar::iconSize
662 \brief size of icons in the toolbar.
663
664 The default size is determined by the application's style and is
665 derived from the QStyle::PM_ToolBarIconSize pixel metric. It is
666 the maximum size an icon can have. Icons of smaller size will not
667 be scaled up.
668*/
669
670QSize QToolBar::iconSize() const
671{ Q_D(const QToolBar); return d->iconSize; }
672
673void QToolBar::setIconSize(const QSize &iconSize)
674{
675 Q_D(QToolBar);
676 QSize sz = iconSize;
677 if (!sz.isValid()) {
678 QMainWindow *mw = qobject_cast<QMainWindow *>(parentWidget());
679 if (mw && mw->layout()) {
680 QLayout *layout = mw->layout();
681 int i = 0;
682 QLayoutItem *item = nullptr;
683 do {
684 item = layout->itemAt(i++);
685 if (item && (item->widget() == this))
686 sz = mw->iconSize();
687 } while (!sz.isValid() && item != nullptr);
688 }
689 }
690 if (!sz.isValid()) {
691 const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, this);
692 sz = QSize(metric, metric);
693 }
694 if (d->iconSize != sz) {
695 d->iconSize = sz;
696 setMinimumSize(0, 0);
697 emit iconSizeChanged(d->iconSize);
698 }
699 d->explicitIconSize = iconSize.isValid();
700
701 d->layout->invalidate();
702}
703
704/*!
705 \property QToolBar::toolButtonStyle
706 \brief the style of toolbar buttons
707
708 This property defines the style of all tool buttons that are added
709 as \l{QAction}s. Note that if you add a QToolButton with the
710 addWidget() method, it will not get this button style.
711
712 To have the style of toolbuttons follow the system settings, set this property to Qt::ToolButtonFollowStyle.
713 On Unix, the user settings from the desktop environment will be used.
714 On other platforms, Qt::ToolButtonFollowStyle means icon only.
715
716 The default is Qt::ToolButtonIconOnly.
717*/
718
719Qt::ToolButtonStyle QToolBar::toolButtonStyle() const
720{ Q_D(const QToolBar); return d->toolButtonStyle; }
721
722void QToolBar::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
723{
724 Q_D(QToolBar);
725 d->explicitToolButtonStyle = true;
726 if (d->toolButtonStyle == toolButtonStyle)
727 return;
728 d->toolButtonStyle = toolButtonStyle;
729 setMinimumSize(0, 0);
730 emit toolButtonStyleChanged(d->toolButtonStyle);
731}
732
733/*!
734 Removes all actions from the toolbar.
735
736 \sa removeAction()
737*/
738void QToolBar::clear()
739{
740 QList<QAction *> actions = this->actions();
741 for(int i = 0; i < actions.size(); i++)
742 removeAction(actions.at(i));
743}
744
745/*!
746 Adds a separator to the end of the toolbar.
747
748 \sa insertSeparator()
749*/
750QAction *QToolBar::addSeparator()
751{
752 QAction *action = new QAction(this);
753 action->setSeparator(true);
754 addAction(action);
755 return action;
756}
757
758/*!
759 Inserts a separator into the toolbar in front of the toolbar
760 item associated with the \a before action.
761
762 \sa addSeparator()
763*/
764QAction *QToolBar::insertSeparator(QAction *before)
765{
766 QAction *action = new QAction(this);
767 action->setSeparator(true);
768 insertAction(before, action);
769 return action;
770}
771
772/*!
773 Adds the given \a widget to the toolbar as the toolbar's last
774 item.
775
776 The toolbar takes ownership of \a widget.
777
778 If you add a QToolButton with this method, the toolbar's
779 Qt::ToolButtonStyle will not be respected.
780
781 \note You should use QAction::setVisible() to change the
782 visibility of the widget. Using QWidget::setVisible(),
783 QWidget::show() and QWidget::hide() does not work.
784
785 \sa insertWidget()
786*/
787QAction *QToolBar::addWidget(QWidget *widget)
788{
789 QWidgetAction *action = new QWidgetAction(this);
790 action->setDefaultWidget(widget);
791 action->d_func()->autoCreated = true;
792 addAction(action);
793 return action;
794}
795
796/*!
797 Inserts the given \a widget in front of the toolbar item
798 associated with the \a before action.
799
800 Note: You should use QAction::setVisible() to change the
801 visibility of the widget. Using QWidget::setVisible(),
802 QWidget::show() and QWidget::hide() does not work.
803
804 \sa addWidget()
805*/
806QAction *QToolBar::insertWidget(QAction *before, QWidget *widget)
807{
808 QWidgetAction *action = new QWidgetAction(this);
809 action->setDefaultWidget(widget);
810 action->d_func()->autoCreated = true;
811 insertAction(before, action);
812 return action;
813}
814
815/*!
816 \internal
817
818 Returns the geometry of the toolbar item associated with the given
819 \a action, or an invalid QRect if no matching item is found.
820*/
821QRect QToolBar::actionGeometry(QAction *action) const
822{
823 Q_D(const QToolBar);
824
825 int index = d->layout->indexOf(action);
826 if (index == -1)
827 return QRect();
828 return d->layout->itemAt(index)->widget()->geometry();
829}
830
831/*!
832 Returns the action at point \a p. This function returns zero if no
833 action was found.
834
835 \sa QWidget::childAt()
836*/
837QAction *QToolBar::actionAt(const QPoint &p) const
838{
839 Q_D(const QToolBar);
840 QWidget *widget = childAt(p);
841 int index = d->layout->indexOf(widget);
842 if (index == -1)
843 return nullptr;
844 QLayoutItem *item = d->layout->itemAt(index);
845 return static_cast<QToolBarItem*>(item)->action;
846}
847
848/*! \fn QAction *QToolBar::actionAt(int x, int y) const
849 \overload
850
851 Returns the action at the point \a x, \a y. This function returns
852 zero if no action was found.
853*/
854
855/*! \reimp */
856void QToolBar::actionEvent(QActionEvent *event)
857{
858 Q_D(QToolBar);
859 auto action = static_cast<QAction *>(event->action());
860 QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action);
861
862 switch (event->type()) {
863 case QEvent::ActionAdded: {
864 Q_ASSERT_X(widgetAction == nullptr || d->layout->indexOf(widgetAction) == -1,
865 "QToolBar", "widgets cannot be inserted multiple times");
866
867 // reparent the action to this toolbar if it has been created
868 // using the addAction(text) etc. convenience functions, to
869 // preserve Qt 4.1.x behavior. The widget is already
870 // reparented to us due to the createWidget call inside
871 // createItem()
872 if (widgetAction != nullptr && widgetAction->d_func()->autoCreated)
873 widgetAction->setParent(this);
874
875 int index = d->layout->count();
876 if (event->before()) {
877 index = d->layout->indexOf(event->before());
878 Q_ASSERT_X(index != -1, "QToolBar::insertAction", "internal error");
879 }
880 d->layout->insertAction(index, action);
881 break;
882 }
883
884 case QEvent::ActionChanged:
885 d->layout->invalidate();
886 break;
887
888 case QEvent::ActionRemoved: {
889 int index = d->layout->indexOf(action);
890 if (index != -1) {
891 delete d->layout->takeAt(index);
892 }
893 break;
894 }
895
896 default:
897 Q_ASSERT_X(false, "QToolBar::actionEvent", "internal error");
898 }
899}
900
901/*! \reimp */
902void QToolBar::changeEvent(QEvent *event)
903{
904 Q_D(QToolBar);
905 switch (event->type()) {
906 case QEvent::WindowTitleChange:
907 d->toggleViewAction->setText(windowTitle());
908 break;
909 case QEvent::StyleChange:
910 d->layout->invalidate();
911 if (!d->explicitIconSize) {
912 QStyleOptionToolBar opt;
913 initStyleOption(&opt);
914 const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, &opt, this);
915 setIconSize({metric, metric});
916 d->explicitIconSize = false;
917 }
918 d->layout->updateMarginAndSpacing();
919 break;
920 case QEvent::LayoutDirectionChange:
921 d->layout->invalidate();
922 break;
923 default:
924 break;
925 }
926 QWidget::changeEvent(event);
927}
928
929/*! \reimp */
930void QToolBar::paintEvent(QPaintEvent *)
931{
932 Q_D(QToolBar);
933
934 QPainter p(this);
935 QStyle *style = this->style();
936 QStyleOptionToolBar opt;
937 initStyleOption(&opt);
938
939 if (d->layout->expanded || d->layout->animating || isWindow()) {
940 //if the toolbar is expended, we need to fill the background with the window color
941 //because some styles may expects that.
942 p.fillRect(opt.rect, palette().window());
943 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
944 style->drawPrimitive(QStyle::PE_FrameMenu, &opt, &p, this);
945 } else {
946 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
947 }
948
949 opt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &opt, this);
950 if (opt.rect.isValid())
951 style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
952}
953
954/*
955 Checks if an expanded toolbar has to wait for this popup to close before
956 the toolbar collapses. This is true if
957 1) the popup has the toolbar in its parent chain,
958 2) the popup is a menu whose menuAction is somewhere in the toolbar.
959*/
960static bool waitForPopup(QToolBar *tb, QWidget *popup)
961{
962 if (popup == nullptr || popup->isHidden())
963 return false;
964
965 QWidget *w = popup;
966 while (w != nullptr) {
967 if (w == tb)
968 return true;
969 w = w->parentWidget();
970 }
971
972 QMenu *menu = qobject_cast<QMenu*>(popup);
973 if (menu == nullptr)
974 return false;
975
976 const QAction *action = menu->menuAction();
977 for (auto object : action->associatedObjects()) {
978 if (QWidget *widget = qobject_cast<QWidget*>(object)) {
979 if (waitForPopup(tb, widget))
980 return true;
981 }
982 }
983
984 return false;
985}
986
987#ifdef Q_OS_MACOS
988static void enableMacToolBar(QToolBar *toolbar, bool enable)
989{
990 auto *mainWindow = qobject_cast<QMainWindow *>(toolbar->window());
991 if (!mainWindow)
992 return;
993
994 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
995 layout->setUnifiedToolBarAreaEnabled(toolbar, enable);
996}
997#endif
998
999
1000/*! \reimp */
1001bool QToolBar::event(QEvent *event)
1002{
1003 Q_D(QToolBar);
1004
1005 switch (event->type()) {
1006 case QEvent::Timer:
1007 if (d->waitForPopupTimer.timerId() == static_cast<QTimerEvent*>(event)->timerId()) {
1008 QWidget *w = QApplication::activePopupWidget();
1009 if (!waitForPopup(this, w)) {
1010 d->waitForPopupTimer.stop();
1011 if (!this->underMouse())
1012 d->layout->setExpanded(false);
1013 }
1014 }
1015 break;
1016 case QEvent::Hide:
1017 if (!isHidden())
1018 break;
1019 Q_FALLTHROUGH();
1020 case QEvent::Show:
1021 d->toggleViewAction->setChecked(event->type() == QEvent::Show);
1022#ifdef Q_OS_MACOS
1023 enableMacToolBar(this, event->type() == QEvent::Show);
1024#endif
1025 emit visibilityChanged(event->type() == QEvent::Show);
1026 break;
1027 case QEvent::ParentChange:
1028 d->layout->checkUsePopupMenu();
1029 break;
1030
1031 case QEvent::MouseButtonPress: {
1032 if (d->mousePressEvent(static_cast<QMouseEvent*>(event)))
1033 return true;
1034 break;
1035 }
1036 case QEvent::MouseButtonRelease:
1037 if (d->mouseReleaseEvent(static_cast<QMouseEvent*>(event)))
1038 return true;
1039 break;
1040 case QEvent::HoverEnter:
1041 case QEvent::HoverLeave:
1042 // there's nothing special to do here and we don't want to update the whole widget
1043 return true;
1044 case QEvent::HoverMove: {
1045#ifndef QT_NO_CURSOR
1046 QHoverEvent *e = static_cast<QHoverEvent*>(event);
1047 QStyleOptionToolBar opt;
1048 initStyleOption(&opt);
1049 if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->position().toPoint()))
1050 setCursor(Qt::SizeAllCursor);
1051 else
1052 unsetCursor();
1053#endif
1054 break;
1055 }
1056 case QEvent::MouseMove:
1057 if (d->mouseMoveEvent(static_cast<QMouseEvent*>(event)))
1058 return true;
1059 break;
1060 case QEvent::Leave:
1061 if (d->state != nullptr && d->state->dragging) {
1062#ifdef Q_OS_WIN
1063 // This is a workaround for losing the mouse on Vista.
1064 QPoint pos = QCursor::pos();
1065 QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
1066 QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
1067 d->mouseMoveEvent(&fake);
1068#endif
1069 } else {
1070 if (!d->layout->expanded)
1071 break;
1072
1073 QWidget *w = QApplication::activePopupWidget();
1074 if (waitForPopup(this, w)) {
1075 d->waitForPopupTimer.start(POPUP_TIMER_INTERVAL, this);
1076 break;
1077 }
1078
1079 d->waitForPopupTimer.stop();
1080 d->layout->setExpanded(false);
1081 break;
1082 }
1083 break;
1084 default:
1085 break;
1086 }
1087 return QWidget::event(event);
1088}
1089
1090/*!
1091 Returns a checkable action that can be used to show or hide this
1092 toolbar.
1093
1094 The action's text is set to the toolbar's window title.
1095
1096 \sa QAction::text, QWidget::windowTitle
1097*/
1098QAction *QToolBar::toggleViewAction() const
1099{ Q_D(const QToolBar); return d->toggleViewAction; }
1100
1101/*!
1102 \since 4.2
1103
1104 Returns the widget associated with the specified \a action.
1105
1106 \sa addWidget()
1107*/
1108QWidget *QToolBar::widgetForAction(QAction *action) const
1109{
1110 Q_D(const QToolBar);
1111
1112 int index = d->layout->indexOf(action);
1113 if (index == -1)
1114 return nullptr;
1115
1116 return d->layout->itemAt(index)->widget();
1117}
1118
1119extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
1120
1121/*!
1122 \internal
1123*/
1124void QToolBar::initStyleOption(QStyleOptionToolBar *option) const
1125{
1126 Q_D(const QToolBar);
1127
1128 if (!option)
1129 return;
1130
1131 option->initFrom(this);
1132 if (orientation() == Qt::Horizontal)
1133 option->state |= QStyle::State_Horizontal;
1134 option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, nullptr, this);
1135 option->features = d->layout->movable()
1136 ? QStyleOptionToolBar::Movable
1137 : QStyleOptionToolBar::None;
1138 // if the tool bar is not in a QMainWindow, this will make the painting right
1139 option->toolBarArea = Qt::NoToolBarArea;
1140
1141 // Add more styleoptions if the toolbar has been added to a mainwindow.
1142 QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
1143
1144 if (!mainWindow)
1145 return;
1146
1147 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
1148 Q_ASSERT_X(layout != nullptr, "QToolBar::initStyleOption()",
1149 "QMainWindow->layout() != QMainWindowLayout");
1150
1151 layout->getStyleOptionInfo(option, const_cast<QToolBar *>(this));
1152}
1153
1154QT_END_NAMESPACE
1155
1156#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:960
#define POPUP_TIMER_INTERVAL
Definition qtoolbar.cpp:34