1// Copyright (C) 2017 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
4#include "qquickmenubaritem_p.h"
5#include "qquickmenubaritem_p_p.h"
6#include "qquickmenubar_p.h"
7#include "qquickmenu_p.h"
8
9QT_BEGIN_NAMESPACE
10
11/*!
12 \qmltype MenuBarItem
13 \inherits AbstractButton
14//! \nativetype QQuickMenuBarItem
15 \inqmlmodule QtQuick.Controls
16 \since 5.10
17 \ingroup qtquickcontrols-menus
18 \brief Presents a drop-down menu within a MenuBar.
19
20 MenuBarItem presents a Menu within a MenuBar. The respective drop-down menu
21 is shown when a MenuBarItem is \l triggered via keyboard, mouse, or touch.
22
23 \image qtquickcontrols-menubar.png
24
25 MenuBarItem is used as a default \l {MenuBar::}{delegate} type for MenuBar.
26 Notice that it is not necessary to declare MenuBarItem instances by hand when
27 using MenuBar. It is sufficient to declare Menu instances as children of the
28 MenuBar and the respective items are created automatically.
29
30 \sa {Customizing MenuBar}, MenuBar, {Menu Controls}
31*/
32
33/*!
34 \qmlsignal void QtQuick.Controls::MenuBarItem::triggered()
35
36 This signal is emitted when the menu bar item is triggered by the user.
37*/
38
39void QQuickMenuBarItemPrivate::setMenuBar(QQuickMenuBar *newMenuBar)
40{
41 Q_Q(QQuickMenuBarItem);
42 if (menuBar == newMenuBar)
43 return;
44
45 menuBar = newMenuBar;
46 emit q->menuBarChanged();
47}
48
49void QQuickMenuBarItemPrivate::accessiblePressAction()
50{
51 // This is inspired by the code in keyReleaseEvent
52
53 Q_Q(QQuickMenuBarItem);
54
55 // We override these event functions so that we can emit triggered here.
56 // We can't just connect clicked to triggered, because that would cause mouse clicks
57 // to open the menu, when only presses should.
58 emit q->triggered();
59}
60
61bool QQuickMenuBarItemPrivate::handlePress(const QPointF &point, ulong timestamp)
62{
63 Q_Q(QQuickMenuBarItem);
64 const bool handled = QQuickAbstractButtonPrivate::handlePress(point, timestamp);
65 if (!handled)
66 return false;
67
68 const bool wasTouchPress = touchId != -1;
69 if (!wasTouchPress) {
70 // Open the menu when it's a mouse press.
71 emit q->triggered();
72 }
73
74 return true;
75}
76
77bool QQuickMenuBarItemPrivate::handleRelease(const QPointF &point, ulong timestamp)
78{
79 Q_Q(QQuickMenuBarItem);
80 const bool wasTouchPress = touchId != -1;
81 const bool handled = QQuickAbstractButtonPrivate::handleRelease(point, timestamp);
82 if (!handled)
83 return false;
84
85 if (wasDoubleClick || !wasTouchPress) {
86 // Don't open the menu on mouse release, as it should be done on press.
87 return handled;
88 }
89
90 if (wasTouchPress) {
91 // Open the menu.
92 emit q->triggered();
93 }
94
95 return true;
96}
97
98QPalette QQuickMenuBarItemPrivate::defaultPalette() const
99{
100 return QQuickTheme::palette(scope: QQuickTheme::MenuBar);
101}
102
103QQuickMenuBarItem::QQuickMenuBarItem(QQuickItem *parent)
104 : QQuickAbstractButton(*(new QQuickMenuBarItemPrivate), parent)
105{
106 setFocusPolicy(Qt::NoFocus);
107 d_func()->setSizePolicy(horizontalPolicy: QLayoutPolicy::Fixed, verticalPolicy: QLayoutPolicy::Fixed);
108}
109
110/*!
111 \qmlproperty Menu QtQuick.Controls::MenuBarItem::menuBar
112 \readonly
113
114 This property holds the menu bar that contains this item,
115 or \c null if the item is not in a menu bar.
116*/
117QQuickMenuBar *QQuickMenuBarItem::menuBar() const
118{
119 Q_D(const QQuickMenuBarItem);
120 return d->menuBar;
121}
122
123/*!
124 \qmlproperty Menu QtQuick.Controls::MenuBarItem::menu
125
126 This property holds the menu that this item presents in a
127 menu bar, or \c null if this item does not have a menu.
128*/
129QQuickMenu *QQuickMenuBarItem::menu() const
130{
131 Q_D(const QQuickMenuBarItem);
132 return d->menu;
133}
134
135void QQuickMenuBarItem::setMenu(QQuickMenu *menu)
136{
137 Q_D(QQuickMenuBarItem);
138 if (d->menu == menu)
139 return;
140
141 if (d->menu)
142 disconnect(sender: d->menu, signal: &QQuickMenu::titleChanged, receiver: this, slot: &QQuickAbstractButton::setText);
143
144 if (menu) {
145 setText(menu->title());
146 menu->setY(height());
147 menu->setParentItem(this);
148 menu->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent);
149 connect(sender: menu, signal: &QQuickMenu::titleChanged, context: this, slot: &QQuickAbstractButton::setText);
150 }
151
152 d->menu = menu;
153 emit menuChanged();
154}
155
156/*!
157 \qmlproperty bool QtQuick.Controls::MenuBarItem::highlighted
158
159 This property holds whether the menu bar item is highlighted by the user.
160
161 A menu bar item can be highlighted by mouse hover or keyboard navigation.
162
163 The default value is \c false.
164*/
165bool QQuickMenuBarItem::isHighlighted() const
166{
167 Q_D(const QQuickMenuBarItem);
168 return d->highlighted;
169}
170
171void QQuickMenuBarItem::setHighlighted(bool highlighted)
172{
173 Q_D(QQuickMenuBarItem);
174 if (highlighted == d->highlighted)
175 return;
176
177 d->highlighted = highlighted;
178 emit highlightedChanged();
179}
180
181bool QQuickMenuBarItem::event(QEvent *event)
182{
183#if QT_CONFIG(shortcut)
184 Q_D(QQuickMenuBarItem);
185 if (event->type() == QEvent::Shortcut) {
186 auto *shortcutEvent = static_cast<QShortcutEvent *>(event);
187 if (shortcutEvent->shortcutId() == d->shortcutId) {
188 d->trigger();
189 emit triggered();
190 return true;
191 }
192 }
193#endif
194 return QQuickControl::event(event);
195}
196
197void QQuickMenuBarItem::keyPressEvent(QKeyEvent *event)
198{
199 Q_D(QQuickMenuBarItem);
200 QQuickControl::keyPressEvent(event);
201 if (d->acceptKeyClick(key: static_cast<Qt::Key>(event->key()))) {
202 d->setPressPoint(d->centerPressPoint());
203 setPressed(true);
204 emit pressed();
205 event->accept();
206 }
207}
208
209void QQuickMenuBarItem::keyReleaseEvent(QKeyEvent *event)
210{
211 Q_D(QQuickMenuBarItem);
212 QQuickControl::keyReleaseEvent(event);
213 if (d->pressed && d->acceptKeyClick(key: static_cast<Qt::Key>(event->key()))) {
214 setPressed(false);
215 emit released();
216 d->trigger();
217 // We override these event functions so that we can emit triggered here.
218 // We can't just connect clicked to triggered, because that would cause mouse clicks
219 // to open the menu, when only presses should.
220 emit triggered();
221 event->accept();
222 }
223}
224
225void QQuickMenuBarItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
226{
227 Q_D(QQuickMenuBarItem);
228 QQuickAbstractButton::geometryChange(newGeometry, oldGeometry);
229 if (d->menu)
230 d->menu->setY(newGeometry.height());
231}
232
233QFont QQuickMenuBarItem::defaultFont() const
234{
235 return QQuickTheme::font(scope: QQuickTheme::MenuBar);
236}
237
238#if QT_CONFIG(accessibility)
239QAccessible::Role QQuickMenuBarItem::accessibleRole() const
240{
241 return QAccessible::MenuBar;
242}
243#endif
244
245QT_END_NAMESPACE
246
247#include "moc_qquickmenubaritem_p.cpp"
248

source code of qtdeclarative/src/quicktemplates/qquickmenubaritem.cpp