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

source code of qtbase/src/widgets/widgets/qtoolbar.cpp