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 "qquickmenuitem_p.h"
5#include "qquickmenuitem_p_p.h"
6#include "qquickmenu_p_p.h"
7#include "qquickdeferredexecute_p_p.h"
8
9#include <QtGui/qpa/qplatformtheme.h>
10#include <QtQuick/private/qquickevents_p_p.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \qmltype MenuItem
16 \inherits AbstractButton
17//! \nativetype QQuickMenuItem
18 \inqmlmodule QtQuick.Controls
19 \since 5.7
20 \ingroup qtquickcontrols-menus
21 \brief Presents an item within a Menu.
22
23 MenuItem is a convenience type that implements the AbstractButton API,
24 providing a familiar way to respond to menu items being \l triggered, for
25 example.
26
27 MenuItem inherits its API from AbstractButton. For instance, you can set
28 \l {AbstractButton::text}{text} and \l {Icons in Qt Quick Controls}{icon}
29 using the AbstractButton API.
30
31 \code
32 Button {
33 id: fileButton
34 text: "File"
35 onClicked: menu.open()
36
37 Menu {
38 id: menu
39
40 MenuItem {
41 text: "New..."
42 onTriggered: document.reset()
43 }
44 MenuItem {
45 text: "Open..."
46 onTriggered: openDialog.open()
47 }
48 MenuItem {
49 text: "Save"
50 onTriggered: saveDialog.open()
51 }
52 }
53 }
54 \endcode
55
56 \sa {Customizing Menu}, Menu, {Menu Controls}
57*/
58
59/*!
60 \qmlproperty bool QtQuick.Controls::MenuItem::textPadding
61 \readonly
62 \since 6.8
63
64 This property holds the maximum \l implicitTextPadding found
65 among all the menu items inside the same \l menu.
66
67 This property can be used by the style to ensure that all MenuItems
68 inside the same Menu end up aligned with respect to the
69 \l {AbstractButton::} {text}.
70
71 A \l Menu can consist of meny different MenuItems, some can be checkable,
72 some can have an icon, and some will just contain text. And very often,
73 a style wants to make sure that the text inside all of them ends up
74 left-aligned (or right-aligned for \l {Control::} {mirrored} items).
75 By letting each MenuItem assign its own minimum text padding to
76 \l implicitTextPadding (taking icons and checkmarks into account), but
77 using \l textPadding to actually position the
78 \l {AbstractButton::} {text}, all MenuItems should end up being aligned
79
80 In order for this to work, all MenuItems should set \l implicitTextPadding
81 to be the minimum space needed from the left edge of the
82 \l {Control::} {contentItem} to the text.
83
84 \sa implicitTextPadding
85*/
86
87/*!
88 \qmlproperty bool QtQuick.Controls::MenuItem::implicitTextPadding
89 \since 6.8
90
91 This property holds the minimum space needed from the left edge of the
92 \l {Control::} {contentItem} to the text. It's used to calculate a common
93 \l textPadding among all the MenuItems inside a \l Menu.
94
95 \sa textPadding
96*/
97
98void QQuickMenuItemPrivate::setMenu(QQuickMenu *newMenu)
99{
100 Q_Q(QQuickMenuItem);
101 if (menu == newMenu)
102 return;
103
104 menu = newMenu;
105 emit q->menuChanged();
106}
107
108void QQuickMenuItemPrivate::setSubMenu(QQuickMenu *newSubMenu)
109{
110 Q_Q(QQuickMenuItem);
111 if (subMenu == newSubMenu)
112 return;
113
114 if (subMenu) {
115 QObject::disconnect(sender: subMenu, signal: &QQuickMenu::titleChanged, receiver: q, slot: &QQuickAbstractButton::setText);
116 QObject::disconnect(sender: subMenu, signal: &QQuickMenu::iconChanged, receiver: q, slot: &QQuickAbstractButton::setIcon);
117 QObjectPrivate::disconnect(sender: subMenu, signal: &QQuickPopup::enabledChanged, receiverPrivate: this, slot: &QQuickMenuItemPrivate::updateEnabled);
118 }
119
120 if (newSubMenu) {
121 QObject::connect(sender: newSubMenu, signal: &QQuickMenu::titleChanged, context: q, slot: &QQuickAbstractButton::setText);
122 QObject::connect(sender: newSubMenu, signal: &QQuickMenu::iconChanged, context: q, slot: &QQuickAbstractButton::setIcon);
123 QObjectPrivate::connect(sender: newSubMenu, signal: &QQuickPopup::enabledChanged, receiverPrivate: this, slot: &QQuickMenuItemPrivate::updateEnabled);
124 q->setText(newSubMenu->title());
125 q->setIcon(newSubMenu->icon());
126 }
127
128 subMenu = newSubMenu;
129 updateEnabled();
130 emit q->subMenuChanged();
131}
132
133void QQuickMenuItemPrivate::updateEnabled()
134{
135 Q_Q(QQuickMenuItem);
136 q->setEnabled(subMenu && subMenu->isEnabled());
137}
138
139static inline QString arrowName() { return QStringLiteral("arrow"); }
140
141void QQuickMenuItemPrivate::cancelArrow()
142{
143 Q_Q(QQuickAbstractButton);
144 quickCancelDeferred(object: q, property: arrowName());
145}
146
147void QQuickMenuItemPrivate::executeArrow(bool complete)
148{
149 Q_Q(QQuickMenuItem);
150 if (arrow.wasExecuted())
151 return;
152
153 if (!arrow || complete)
154 quickBeginDeferred(object: q, property: arrowName(), delegate&: arrow);
155 if (complete)
156 quickCompleteDeferred(object: q, property: arrowName(), delegate&: arrow);
157}
158
159bool QQuickMenuItemPrivate::acceptKeyClick(Qt::Key key) const
160{
161 return key == Qt::Key_Return || key == Qt::Key_Enter
162 || QQuickAbstractButtonPrivate::acceptKeyClick(key);
163}
164
165QPalette QQuickMenuItemPrivate::defaultPalette() const
166{
167 return QQuickTheme::palette(scope: QQuickTheme::Menu);
168}
169
170/*!
171 \qmlsignal void QtQuick.Controls::MenuItem::triggered()
172
173 This signal is emitted when the menu item is triggered by the user.
174*/
175
176QQuickMenuItem::QQuickMenuItem(QQuickItem *parent)
177 : QQuickAbstractButton(*(new QQuickMenuItemPrivate), parent)
178{
179 connect(sender: this, signal: &QQuickAbstractButton::clicked, context: this, slot: &QQuickMenuItem::triggered);
180}
181
182/*!
183 \qmlproperty bool QtQuick.Controls::MenuItem::highlighted
184
185 This property holds whether the menu item is highlighted by the user.
186
187 A menu item can be highlighted by mouse hover or keyboard navigation.
188
189 The default value is \c false.
190
191 \sa Menu::currentIndex
192*/
193bool QQuickMenuItem::isHighlighted() const
194{
195 Q_D(const QQuickMenuItem);
196 return d->highlighted;
197}
198
199void QQuickMenuItem::setHighlighted(bool highlighted)
200{
201 Q_D(QQuickMenuItem);
202 if (highlighted == d->highlighted)
203 return;
204
205 d->highlighted = highlighted;
206 emit highlightedChanged();
207}
208
209/*!
210 \since QtQuick.Controls 2.3 (Qt 5.10)
211 \qmlproperty Item QtQuick.Controls::MenuItem::arrow
212
213 This property holds the sub-menu arrow item.
214
215 \sa {Customizing Menu}
216*/
217QQuickItem *QQuickMenuItem::arrow() const
218{
219 QQuickMenuItemPrivate *d = const_cast<QQuickMenuItemPrivate *>(d_func());
220 if (!d->arrow)
221 d->executeArrow();
222 return d->arrow;
223}
224
225void QQuickMenuItem::setArrow(QQuickItem *arrow)
226{
227 Q_D(QQuickMenuItem);
228 if (d->arrow == arrow)
229 return;
230
231 if (!d->arrow.isExecuting())
232 d->cancelArrow();
233
234 QQuickControlPrivate::hideOldItem(item: d->arrow);
235 d->arrow = arrow;
236 if (arrow && !arrow->parentItem())
237 arrow->setParentItem(this);
238 if (!d->arrow.isExecuting())
239 emit arrowChanged();
240}
241
242/*!
243 \since QtQuick.Controls 2.3 (Qt 5.10)
244 \qmlproperty Menu QtQuick.Controls::MenuItem::menu
245 \readonly
246
247 This property holds the menu that contains this menu item,
248 or \c null if the item is not in a menu.
249*/
250QQuickMenu *QQuickMenuItem::menu() const
251{
252 Q_D(const QQuickMenuItem);
253 return d->menu;
254}
255
256/*!
257 \since QtQuick.Controls 2.3 (Qt 5.10)
258 \qmlproperty Menu QtQuick.Controls::MenuItem::subMenu
259 \readonly
260
261 This property holds the sub-menu that this item presents in
262 the parent menu, or \c null if this item is not a sub-menu item.
263*/
264QQuickMenu *QQuickMenuItem::subMenu() const
265{
266 Q_D(const QQuickMenuItem);
267 return d->subMenu;
268}
269
270void QQuickMenuItem::componentComplete()
271{
272 Q_D(QQuickMenuItem);
273 d->executeArrow(complete: true);
274 QQuickAbstractButton::componentComplete();
275}
276
277QFont QQuickMenuItem::defaultFont() const
278{
279 return QQuickTheme::font(scope: QQuickTheme::Menu);
280}
281
282qreal QQuickMenuItem::implicitTextPadding() const
283{
284 return d_func()->implicitTextPadding;
285}
286
287void QQuickMenuItem::setImplicitTextPadding(qreal newImplicitTextPadding)
288{
289 Q_D(QQuickMenuItem);
290 if (qFuzzyCompare(p1: d->implicitTextPadding, p2: newImplicitTextPadding))
291 return;
292 d->implicitTextPadding = newImplicitTextPadding;
293 emit implicitTextPaddingChanged();
294}
295
296qreal QQuickMenuItem::textPadding() const
297{
298 Q_D(const QQuickMenuItem);
299 return d->menu ? QQuickMenuPrivate::get(menu: d->menu)->textPadding : 0;
300}
301
302#if QT_CONFIG(accessibility)
303QAccessible::Role QQuickMenuItem::accessibleRole() const
304{
305 return QAccessible::MenuItem;
306}
307#endif
308
309#ifndef QT_NO_DEBUG_STREAM
310QDebug operator<<(QDebug debug, const QQuickMenuItem *menuItem)
311{
312 QDebugStateSaver saver(debug);
313 debug.nospace();
314 if (!menuItem) {
315 debug << "QQuickMenuItem(nullptr)";
316 return debug;
317 }
318
319 debug << menuItem->metaObject()->className() << '(' << static_cast<const void *>(menuItem);
320 if (!menuItem->objectName().isEmpty())
321 debug << ", name=" << menuItem->objectName();
322 debug << ", text=" << menuItem->text();
323 debug << ')';
324 return debug;
325}
326#endif // QT_NO_DEBUG_STREAM
327
328QT_END_NAMESPACE
329
330#include "moc_qquickmenuitem_p.cpp"
331

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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