1// Copyright (C) 2020 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 "qquicklabsplatformmenuitemgroup_p.h"
5#include "qquicklabsplatformmenuitem_p.h"
6
7QT_BEGIN_NAMESPACE
8
9/*!
10 \qmltype MenuItemGroup
11 \inherits QtObject
12//! \instantiates QQuickLabsPlatformMenuItemGroup
13 \inqmlmodule Qt.labs.platform
14 \since 5.8
15 \brief A group for managing native menu items.
16
17 The MenuItemGroup groups native menu items together.
18
19 MenuItemGroup is exclusive by default. In an exclusive menu item
20 group, only one item can be checked at any time; checking another
21 item automatically unchecks the previously checked one. MenuItemGroup
22 can be configured as non-exclusive, which is particularly useful for
23 showing, hiding, enabling and disabling items together as a group.
24
25 The most straight-forward way to use MenuItemGroup is to assign
26 a list of items.
27
28 \code
29 Menu {
30 id: verticalMenu
31 title: qsTr("Vertical")
32
33 MenuItemGroup {
34 id: verticalGroup
35 items: verticalMenu.items
36 }
37
38 MenuItem { text: qsTr("Top"); checkable: true }
39 MenuItem { text: qsTr("Center"); checked: true }
40 MenuItem { text: qsTr("Bottom"); checkable: true }
41 }
42 \endcode
43
44 The same menu may sometimes contain items that should not be included
45 in the same exclusive group. Such cases are best handled using the
46 \l {MenuItem::group}{group} property.
47
48 \code
49 Menu {
50 id: horizontalMenu
51 title: qsTr("Horizontal")
52
53 MenuItemGroup {
54 id: horizontalGroup
55 }
56
57 MenuItem {
58 checked: true
59 text: qsTr("Left")
60 group: horizontalGroup
61 }
62 MenuItem {
63 checkable: true
64 text: qsTr("Center")
65 group: horizontalGroup
66 }
67 MenuItem {
68 text: qsTr("Right")
69 checkable: true
70 group: horizontalGroup
71 }
72
73 MenuItem { separator: true }
74 MenuItem { text: qsTr("Justify"); checkable: true }
75 MenuItem { text: qsTr("Absolute"); checkable: true }
76 }
77 \endcode
78
79 More advanced use cases can be handled using the addItem() and
80 removeItem() methods.
81
82 \labs
83
84 \sa MenuItem
85*/
86
87/*!
88 \qmlsignal Qt.labs.platform::MenuItemGroup::triggered(MenuItem item)
89
90 This signal is emitted when an \a item in the group is triggered by the user.
91
92 \sa MenuItem::triggered()
93*/
94
95/*!
96 \qmlsignal Qt.labs.platform::MenuItemGroup::hovered(MenuItem item)
97
98 This signal is emitted when an \a item in the group is hovered by the user.
99
100 \sa MenuItem::hovered()
101*/
102
103QQuickLabsPlatformMenuItemGroup::QQuickLabsPlatformMenuItemGroup(QObject *parent)
104 : QObject(parent), m_enabled(true), m_visible(true), m_exclusive(true), m_checkedItem(nullptr)
105{
106}
107
108QQuickLabsPlatformMenuItemGroup::~QQuickLabsPlatformMenuItemGroup()
109{
110 clear();
111}
112
113/*!
114 \qmlproperty bool Qt.labs.platform::MenuItemGroup::enabled
115
116 This property holds whether the group is enabled. The default value is \c true.
117
118 The enabled state of the group affects the enabled state of each item in the group,
119 except that explicitly disabled items are not enabled even if the group is enabled.
120*/
121bool QQuickLabsPlatformMenuItemGroup::isEnabled() const
122{
123 return m_enabled;
124}
125
126void QQuickLabsPlatformMenuItemGroup::setEnabled(bool enabled)
127{
128 if (m_enabled == enabled)
129 return;
130
131 m_enabled = enabled;
132 emit enabledChanged();
133
134 for (QQuickLabsPlatformMenuItem *item : std::as_const(t&: m_items)) {
135 if (item->m_enabled) {
136 item->sync();
137 emit item->enabledChanged();
138 }
139 }
140}
141
142/*!
143 \qmlproperty bool Qt.labs.platform::MenuItemGroup::visible
144
145 This property holds whether the group is visible. The default value is \c true.
146
147 The visibility of the group affects the visibility of each item in the group,
148 except that explicitly hidden items are not visible even if the group is visible.
149*/
150bool QQuickLabsPlatformMenuItemGroup::isVisible() const
151{
152 return m_visible;
153}
154
155void QQuickLabsPlatformMenuItemGroup::setVisible(bool visible)
156{
157 if (m_visible == visible)
158 return;
159
160 m_visible = visible;
161 emit visibleChanged();
162
163 for (QQuickLabsPlatformMenuItem *item : std::as_const(t&: m_items)) {
164 if (item->m_visible) {
165 item->sync();
166 emit item->visibleChanged();
167 }
168 }
169}
170
171/*!
172 \qmlproperty bool Qt.labs.platform::MenuItemGroup::exclusive
173
174 This property holds whether the group is exclusive. The default value is \c true.
175
176 In an exclusive menu item group, only one item can be checked at any time;
177 checking another item automatically unchecks the previously checked one.
178*/
179bool QQuickLabsPlatformMenuItemGroup::isExclusive() const
180{
181 return m_exclusive;
182}
183
184void QQuickLabsPlatformMenuItemGroup::setExclusive(bool exclusive)
185{
186 if (m_exclusive == exclusive)
187 return;
188
189 m_exclusive = exclusive;
190 emit exclusiveChanged();
191
192 for (QQuickLabsPlatformMenuItem *item : std::as_const(t&: m_items))
193 item->sync();
194}
195
196/*!
197 \qmlproperty MenuItem Qt.labs.platform::MenuItemGroup::checkedItem
198
199 This property holds the currently checked item in the group, or \c null if no item is checked.
200*/
201QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenuItemGroup::checkedItem() const
202{
203 return m_checkedItem;
204}
205
206void QQuickLabsPlatformMenuItemGroup::setCheckedItem(QQuickLabsPlatformMenuItem *item)
207{
208 if (m_checkedItem == item)
209 return;
210
211 if (m_checkedItem)
212 m_checkedItem->setChecked(false);
213
214 m_checkedItem = item;
215 emit checkedItemChanged();
216
217 if (item)
218 item->setChecked(true);
219}
220
221/*!
222 \qmlproperty list<MenuItem> Qt.labs.platform::MenuItemGroup::items
223
224 This property holds the list of items in the group.
225*/
226QQmlListProperty<QQuickLabsPlatformMenuItem> QQuickLabsPlatformMenuItemGroup::items()
227{
228 return QQmlListProperty<QQuickLabsPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear);
229}
230
231/*!
232 \qmlmethod void Qt.labs.platform::MenuItemGroup::addItem(MenuItem item)
233
234 Adds an \a item to the group.
235*/
236void QQuickLabsPlatformMenuItemGroup::addItem(QQuickLabsPlatformMenuItem *item)
237{
238 if (!item || m_items.contains(t: item))
239 return;
240
241 m_items.append(t: item);
242 item->setGroup(this);
243
244 connect(sender: item, signal: &QQuickLabsPlatformMenuItem::checkedChanged, context: this, slot: &QQuickLabsPlatformMenuItemGroup::updateCurrent);
245 connect(sender: item, signal: &QQuickLabsPlatformMenuItem::triggered, context: this, slot: &QQuickLabsPlatformMenuItemGroup::activateItem);
246 connect(sender: item, signal: &QQuickLabsPlatformMenuItem::hovered, context: this, slot: &QQuickLabsPlatformMenuItemGroup::hoverItem);
247
248 if (m_exclusive && item->isChecked())
249 setCheckedItem(item);
250
251 emit itemsChanged();
252}
253
254/*!
255 \qmlmethod void Qt.labs.platform::MenuItemGroup::removeItem(MenuItem item)
256
257 Removes an \a item from the group.
258*/
259void QQuickLabsPlatformMenuItemGroup::removeItem(QQuickLabsPlatformMenuItem *item)
260{
261 if (!item || !m_items.contains(t: item))
262 return;
263
264 m_items.removeOne(t: item);
265 item->setGroup(nullptr);
266
267 disconnect(sender: item, signal: &QQuickLabsPlatformMenuItem::checkedChanged, receiver: this, slot: &QQuickLabsPlatformMenuItemGroup::updateCurrent);
268 disconnect(sender: item, signal: &QQuickLabsPlatformMenuItem::triggered, receiver: this, slot: &QQuickLabsPlatformMenuItemGroup::activateItem);
269 disconnect(sender: item, signal: &QQuickLabsPlatformMenuItem::hovered, receiver: this, slot: &QQuickLabsPlatformMenuItemGroup::hoverItem);
270
271 if (m_checkedItem == item)
272 setCheckedItem(nullptr);
273
274 emit itemsChanged();
275}
276
277/*!
278 \qmlmethod void Qt.labs.platform::MenuItemGroup::clear()
279
280 Removes all items from the group.
281*/
282void QQuickLabsPlatformMenuItemGroup::clear()
283{
284 if (m_items.isEmpty())
285 return;
286
287 for (QQuickLabsPlatformMenuItem *item : std::as_const(t&: m_items)) {
288 item->setGroup(nullptr);
289 disconnect(sender: item, signal: &QQuickLabsPlatformMenuItem::checkedChanged, receiver: this, slot: &QQuickLabsPlatformMenuItemGroup::updateCurrent);
290 disconnect(sender: item, signal: &QQuickLabsPlatformMenuItem::triggered, receiver: this, slot: &QQuickLabsPlatformMenuItemGroup::activateItem);
291 disconnect(sender: item, signal: &QQuickLabsPlatformMenuItem::hovered, receiver: this, slot: &QQuickLabsPlatformMenuItemGroup::hoverItem);
292 }
293
294 setCheckedItem(nullptr);
295
296 m_items.clear();
297 emit itemsChanged();
298}
299
300QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenuItemGroup::findCurrent() const
301{
302 for (QQuickLabsPlatformMenuItem *item : m_items) {
303 if (item->isChecked())
304 return item;
305 }
306 return nullptr;
307}
308
309void QQuickLabsPlatformMenuItemGroup::updateCurrent()
310{
311 if (!m_exclusive)
312 return;
313
314 QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem*>(object: sender());
315 if (item && item->isChecked())
316 setCheckedItem(item);
317}
318
319void QQuickLabsPlatformMenuItemGroup::activateItem()
320{
321 QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem*>(object: sender());
322 if (item)
323 emit triggered(item);
324}
325
326void QQuickLabsPlatformMenuItemGroup::hoverItem()
327{
328 QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem*>(object: sender());
329 if (item)
330 emit hovered(item);
331}
332
333void QQuickLabsPlatformMenuItemGroup::items_append(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop, QQuickLabsPlatformMenuItem *item)
334{
335 QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
336 group->addItem(item);
337}
338
339qsizetype QQuickLabsPlatformMenuItemGroup::items_count(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop)
340{
341 QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
342 return group->m_items.size();
343}
344
345QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenuItemGroup::items_at(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop, qsizetype index)
346{
347 QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
348 return group->m_items.value(i: index);
349}
350
351void QQuickLabsPlatformMenuItemGroup::items_clear(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop)
352{
353 QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
354 group->clear();
355}
356
357QT_END_NAMESPACE
358
359#include "moc_qquicklabsplatformmenuitemgroup_p.cpp"
360

source code of qtdeclarative/src/labs/platform/qquicklabsplatformmenuitemgroup.cpp