Kirigami-addons

FormComboBoxDelegate.qml
1/*
2 * Copyright 2022 Devin Lin <devin@kde.org>
3 * SPDX-License-Identifier: LGPL-2.0-or-later
4 */
5
6import QtQuick
7import QtQuick.Controls as QQC2
8import QtQuick.Layouts
9
10import org.kde.kirigami as Kirigami
11import org.kde.kirigamiaddons.delegates as Delegates
12
13/**
14 * @brief A Form delegate that corresponds to a combobox.
15 *
16 * This component is used for individual settings that can have multiple
17 * possible values shown in a vertical list, typically defined in a ::model.
18 *
19 * Many of its properties require familiarity with QtQuick.Controls.ComboBox.
20 *
21 * Use the inherited QtQuick.Controls.AbstractButton.text property to define
22 * the main text of the combobox.
23 *
24 * If you need a purely on/off toggle, use a FormSwitchDelegate instead.
25 *
26 * If you need an on/off/tristate toggle, use a FormCheckDelegate instead.
27 *
28 * If you need multiple toggles instead of multiple values for the same
29 * setting, consider using a FormRadioDelegate.
30 *
31 * @since KirigamiAddons 0.11.0
32 *
33 * @see QtQuick.Controls.AbstractButton
34 * @see FormSwitchDelegate
35 * @see FormCheckDelegate
36 * @see FormRadioDelegate
37 *
38 * @inherit AbstractFormDelegate
39 */
40AbstractFormDelegate {
41 id: controlRoot
42
43 /**
44 * @brief This signal is emitted when the item at @p index is activated
45 * by the user.
46 */
47 signal activated(int index)
48
49 /**
50 * @brief This signal is emitted when the Return or Enter key is pressed
51 * while an editable combo box is focused.
52 *
53 * @see editable
54 */
55 signal accepted()
56
57 /**
58 * @brief A label that contains secondary text that appears under the
59 * inherited text property.
60 *
61 * This provides additional information shown in a faint gray color.
62 *
63 * This is supposed to be a short text and the API user should avoid
64 * making it longer than two lines.
65 */
66 property string description: ""
67
68 /**
69 * @brief This property holds the value of the current item in the combobox.
70 */
71 property alias currentValue: combobox.currentValue
72
73 /**
74 * @brief This property holds the text of the current item in the combobox.
75 *
76 * @see displayText
77 */
78 property alias currentText: combobox.currentText
79
80 /**
81 * @brief This property holds the model providing data for the combobox.
82 *
83 * @see displayText
84 * @see QtQuick.Controls.ComboBox.model
85 * @see <a href="https://doc.qt.io/qt-6/qtquick-modelviewsdata-modelview.html">Models and Views in QtQuick</a>
86 */
87 property var model
88
89 /**
90 * @brief This property holds the `count` of the internal combobox.
91 *
92 * @see QtQuick.Controls.ComboBox.count
93 * @since Kirigami Addons 1.4.0
94 */
95 property alias count: combobox.count
96
97 /**
98 * @brief This property holds the `textRole` of the internal combobox.
99 *
100 * @see QtQuick.Controls.ComboBox.textRole
101 */
102 property alias textRole: combobox.textRole
103
104 /**
105 * @brief This property holds the `valueRole` of the internal combobox.
106 *
107 * @see QtQuick.Controls.ComboBox.valueRole
108 */
109 property alias valueRole: combobox.valueRole
110
111 /**
112 * @brief This property holds the `currentIndex` of the internal combobox.
113 *
114 * default: `-1` when the ::model has no data, `0` otherwise
115 *
116 * @see QtQuick.Controls.ComboBox.currentIndex
117 */
118 property alias currentIndex: combobox.currentIndex
120 /**
121 * @brief This property holds the `highlightedIndex` of the internal combobox.
122 *
123 * @see QtQuick.Controls.ComboBox.highlightedIndex
124 */
125 property alias highlightedIndex: combobox.highlightedIndex
126
127 /**
128 * @brief This property holds the `displayText` of the internal combobox.
129 *
130 * This can be used to slightly modify the text to be displayed in the combobox, for instance, by adding a string with the ::currentText.
132 * @see QtQuick.Controls.ComboBox.displayText
133 */
134 property alias displayText: combobox.displayText
135
136 /**
137 * @brief This property holds the `editable` property of the internal combobox.
138 *
139 * This turns the combobox editable, allowing the user to specify
140 * existing values or add new ones.
141 *
142 * Use this only when ::displayMode is set to
143 * FormComboBoxDelegate.ComboBox.
144 *
145 * @see QtQuick.Controls.ComboBox.editable
146 */
147 property alias editable: combobox.editable
148
149 /**
150 * @brief This property holds the `editText` property of the internal combobox.
151 *
152 * @see QtQuick.Controls.ComboBox.editText
153 */
154 property alias editText: combobox.editText
155
156 /** @brief The enum used to determine the ::displayMode. **/
157 enum DisplayMode {
158 /**
159 * A standard combobox component containing a vertical list of values.
160 */
161 ComboBox,
162 /**
163 * A button with similar appearance to a combobox that, when clicked,
164 * shows a Kirigami.OverlaySheet at the middle of the window
165 * containing a vertical list of values.
166 */
167 Dialog,
168 /**
169 * A button with similar appearance to a combobox that, when clicked,
170 * shows a Kirigami.ScrollablePage in a new window containing a
171 * vertical list of values.
172 */
173 Page
175
176 /**
177 * @brief This property holds what display mode the delegate should show as.
178 *
179 * Set this property to the desired ::DisplayMode.
180 *
181 * default: `FormComboBoxDelegate.ComboBox`
182 *
183 * @see DisplayMode
184 */
185 property int displayMode: Kirigami.Settings.isMobile ? FormComboBoxDelegate.Dialog : FormComboBoxDelegate.ComboBox
186
187 /**
188 * @brief The delegate component to use as entries in the combobox display mode.
189 */
190 property Component comboBoxDelegate: Delegates.RoundedItemDelegate {
191 implicitWidth: ListView.view ? ListView.view.width : Kirigami.Units.gridUnit * 16
192 text: controlRoot.textRole ? (Array.isArray(controlRoot.model) ? modelData[controlRoot.textRole] : model[controlRoot.textRole]) : modelData
193 highlighted: controlRoot.highlightedIndex === index
194 }
195
196 /**
197 * @brief The delegate component to use as entries for each value in the dialog and page display mode.
198 */
199 property Component dialogDelegate: Delegates.RoundedItemDelegate {
200 implicitWidth: ListView.view ? ListView.view.width : Kirigami.Units.gridUnit * 16
201 text: controlRoot.textRole ? (Array.isArray(controlRoot.model) ? modelData[controlRoot.textRole] : model[controlRoot.textRole]) : modelData
202 checked: controlRoot.currentIndex === index
203
204 Layout.topMargin: index == 0 ? Math.round(Kirigami.Units.smallSpacing / 2) : 0
206 onClicked: {
207 controlRoot.currentIndex = index;
208 controlRoot.activated(index);
209 controlRoot.closeDialog();
210 }
212
213 /**
214 * @brief This property holds the current status message type of
215 * the text field.
216 *
217 * This consists of an inline message with a colorful background
218 * and an appropriate icon.
219 *
220 * The status property will affect the color of ::statusMessage used.
221 *
222 * Accepted values:
223 * - `Kirigami.MessageType.Information` (blue color)
224 * - `Kirigami.MessageType.Positive` (green color)
225 * - `Kirigami.MessageType.Warning` (orange color)
226 * - `Kirigami.MessageType.Error` (red color)
227 *
228 * default: `Kirigami.MessageType.Information` if ::statusMessage is set,
229 * nothing otherwise.
230 *
231 * @see Kirigami.MessageType
232 * @since 1.5.0
233 */
234 property var status: Kirigami.MessageType.Information
235
236 /**
237 * @brief This property holds the current status message of
238 * the text field.
239 *
240 * If this property is not set, no ::status will be shown.
241 *
242 * @since 1.5.0
243 */
244 property string statusMessage: ""
245
246 /**
247 * @brief Closes the dialog or layer.
248 *
249 * This function can be used when reimplementing the ::page or ::dialog.
250 */
251 function closeDialog() {
252 if (_selectionPageItem) {
253 _selectionPageItem.closeDialog();
254 _selectionPageItem = null;
255 }
256
257 if (dialog) {
258 dialog.close();
259 }
260 }
261
262 property var _selectionPageItem: null
263 property real __indicatorMargin: controlRoot.indicator && controlRoot.indicator.visible && controlRoot.indicator.width > 0 ? controlRoot.spacing + indicator.width + controlRoot.spacing : 0
264
265 leftPadding: horizontalPadding + (!controlRoot.mirrored ? 0 : __indicatorMargin)
266 rightPadding: horizontalPadding + (controlRoot.mirrored ? 0 : __indicatorMargin)
267
268
269 // use connections instead of onClicked on root, so that users can supply
270 // their own behaviour.
271 Connections {
272 target: controlRoot
273 function onClicked() {
274 if (controlRoot.displayMode === FormComboBoxDelegate.Dialog) {
275 controlRoot.dialog.open();
276 } else if (controlRoot.displayMode === FormComboBoxDelegate.Page) {
277 controlRoot._selectionPageItem = controlRoot.QQC2.ApplicationWindow.window.pageStack.pushDialogLayer(page)
278 } else {
279 combobox.popup.open();
280 combobox.forceActiveFocus(Qt.PopupFocusReason);
281 }
282 }
283 }
284
285 /**
286 * @brief The dialog component used for the combobox.
287 *
288 * This property allows to override the internal dialog
289 * with a custom component.
290 */
291 property var dialog: Kirigami.Dialog {
292 id: dialog
293 showCloseButton: false
294 title: controlRoot.text
295 preferredWidth: Kirigami.Units.gridUnit * 16
296 parent: QQC2.Overlay.overlay
297
298 ColumnLayout {
299 spacing: 0
300
301 Repeater {
302 model: controlRoot.model
303 delegate: controlRoot.dialogDelegate
304 }
305
306 QQC2.TextField {
307 visible: controlRoot.editable
308 onTextChanged: controlRoot.editText = text;
309 Layout.fillWidth: true
310 }
311 }
312 }
313
314 /**
315 * @brief The page component used for the combobox, if applicable.
316 *
317 * This property allows to override the internal
318 * Kirigami.ScrollablePage with a custom component.
319 */
320 property Component page: Kirigami.ScrollablePage {
321 title: controlRoot.text
322
323 ListView {
324 spacing: 0
325 model: controlRoot.model
326 delegate: controlRoot.dialogDelegate
327
328 footer: QQC2.TextField {
329 visible: controlRoot.editable
330 onTextChanged: controlRoot.editText = text;
331 Layout.fillWidth: true
332 }
333 }
334 }
335
336 function indexOfValue(value) {
337 return combobox.indexOfValue(value);
338 }
339
340 focusPolicy: Qt.StrongFocus
341 Accessible.description: description
342 Accessible.onPressAction: controlRoot.clicked()
343
344 // Only have the mouse hover feedback if the combobox is the whole delegate itself
345 background: displayMode === FormComboBoxDelegate.ComboBox ? null : selectableBackground
346 FormDelegateBackground { id: selectableBackground; control: controlRoot }
347
348 contentItem: ColumnLayout {
349 spacing: Kirigami.Units.smallSpacing
350
351 RowLayout {
352 Layout.fillWidth: true
353 spacing: Kirigami.Units.smallSpacing
354
355 QQC2.Label {
356 Layout.fillWidth: true
357 text: controlRoot.text
358 elide: Text.ElideRight
359 color: controlRoot.enabled ? Kirigami.Theme.textColor : Kirigami.Theme.disabledTextColor
360 wrapMode: Text.Wrap
361 maximumLineCount: 2
362 Accessible.ignored: true
363 }
364
365 QQC2.Label {
366 Layout.alignment: Qt.AlignRight
367 Layout.rightMargin: Kirigami.Units.smallSpacing
368 color: Kirigami.Theme.disabledTextColor
369 text: controlRoot.displayText
370 visible: controlRoot.displayMode === FormComboBoxDelegate.Dialog || controlRoot.displayMode === FormComboBoxDelegate.Page
371 }
372
373 FormArrow {
374 Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
375 direction: Qt.DownArrow
376 visible: controlRoot.displayMode === FormComboBoxDelegate.Dialog || controlRoot.displayMode === FormComboBoxDelegate.Page
377 }
378 }
379
380 QQC2.ComboBox {
381 id: combobox
382 focusPolicy: Qt.NoFocus // provided by parent
383 model: controlRoot.model
384 visible: controlRoot.displayMode == FormComboBoxDelegate.ComboBox
385 delegate: controlRoot.comboBoxDelegate
386 currentIndex: controlRoot.currentIndex
387 onActivated: index => controlRoot.activated(index)
388 onAccepted: controlRoot.accepted()
389 popup.contentItem.clip: true
390 Layout.fillWidth: true
391 }
392
393 QQC2.Label {
394 visible: controlRoot.description !== ""
395 Layout.fillWidth: true
396 text: controlRoot.description
397 color: Kirigami.Theme.disabledTextColor
398 wrapMode: Text.Wrap
399 Accessible.ignored: true
400 }
401
402 Kirigami.InlineMessage {
403 visible: controlRoot.statusMessage.length > 0
404 Layout.topMargin: visible ? Kirigami.Units.smallSpacing : 0
405 Layout.fillWidth: true
406 text: controlRoot.statusMessage
407 type: controlRoot.status
408 }
409 }
410}
411
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:12:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.