MauiKit Controls

ListBrowser.qml
1/*
2 * Copyright 2018 Camilo Higuita <milo.h@aol.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick
21import QtQuick.Controls
22
23import org.mauikit.controls as Maui
24
25/**
26 * @inherit QtQuick.Item
27 * @brief A browser view with a list layout.
28 * <a href="https://doc.qt.io/qt-6/qml-qtquick-controls-item.html">This controls inherits from QQC2 Item, to checkout its inherited properties refer to the Qt Docs.</a>
29 *
30 * This component might seem similar to QQC2 ListView - and it does uses it underneath - but this one includes a few more predefined elements, such as a placeholder element, pinch to zoom gestures, lasso selection support, and some predefined behaviour.
31 *
32 * @section structure Structure
33 * The browser has a dedicated placeholder element handled by MauiKit Holder, where a message can be set when the view is on a determined state the user should be warned about, such as if the view is empty, or not search results were found.
34 * @see Holder
35 *
36 * The lasso selection feature works with a mouse or a track-pad, and allows to select multiple items in the browser-view that are under the lasso rectangle area. A signal is emitted when the selection has been triggered - this is when the lasso rectangle is released - sending as an argument an array of numbers representing the indexes of the selected items.
37 * @see itemsSelected
38 *
39 * @note Consider using as the delegate elements the MauiKit ListBrowserDelegate.
40 *
41 * To position the delegates you can use the ListView attached properties, such as `ListView.view.width` to set the width of the delegate correctly.
42 *
43 * @image html Browsers/listbrowser.png
44 *
45 * @code
46 * Maui.ListBrowser
47 * {
48 * anchors.fill: parent
49 * model: 60
50 *
51 * enableLassoSelection: true
52 * onItemsSelected: (indexes) => console.log(indexes)
53 *
54 * delegate: Maui.ListBrowserDelegate
55 * {
56 * width: ListView.view.width
57 * label1.text: "An example delegate."
58 * label2.text: "Using the MauiKit ListBrowser."
59 *
60 * iconSource: "folder"
61 * }
62 * }
63 * @endcode
64 *
65 * <a href="https://invent.kde.org/maui/mauikit/-/blob/qt6-2/examples/ListBrowser.qml">You can find a more complete example at this link.</a>
66 */
67Item
68{
69 id: control
70 focus: true
71 clip: false
72
73 implicitHeight: contentHeight + topPadding + bottomPadding
74 implicitWidth: contentWidth + leftPadding + rightPadding
75
76 /**
77 * @brief The model to be used to populate the browsing view.
78 * @property var ListBrowser::model
79 */
80 property alias model : _listView.model
81
82 /**
83 * @brief The component to be used as the delegate.
84 * @note Consider using the MauiKit delegate controls, such as ListBrowserDelegate, ListDelegate or LabelDelegate.
85 * @property Component ListBrowser::delegate
86 */
87 property alias delegate : _listView.delegate
88
89 /**
90 * @brief The section group property to set the ListView sections.
91 * Refer to the Qt documentation on the ListView section.
92 * @property section ListBrowser::section
93 */
94 property alias section : _listView.section
95
96 /**
97 * @brief The position of the view contents on the Y axis.
98 * @property double ListBrowser::contentY
99 */
100 property alias contentY: _listView.contentY
101
102 /**
103 * @brief The position of the view contents on the X axis.
104 * @property double ListBrowser::contentY
105 */
106 property alias contentX: _listView.contentX
108 /**
109 * @brief The index number of the current element selected.
110 * @note To no break any binding, use the `setCurrentIndex` function.
111 * @property int ListBrowser::currentIndex
112 */
113 property alias currentIndex : _listView.currentIndex
114
115 /**
116 * @brief The current item selected.
117 * @property Item ListBrowser::currentItem
118 */
119 property alias currentItem : _listView.currentItem
120
121 /**
122 * @brief The total amount of elements listed in the view.
123 * @property int ListBrowser::count
124 */
125 property alias count : _listView.count
126
127 /**
128 * @brief The cache buffer.
129 * Refer to the QQC2 ListView for proper documentation.
130 * @property int ListBrowser::cacheBuffer
131 */
132 property alias cacheBuffer : _listView.cacheBuffer
133
134 /**
135 * @brief The orientation of the list view.
136 * By default this is set to `ListView.Vertical`.
137 * @property enum ListBrowser::orientation
138 */
139 property alias orientation: _listView.orientation
140
141 /**
142 * @brief How to snap the elements of the list view while scrolling.
143 * @note See Qt documentation.
144 * @property enum ListBrowser::snapMode
145 */
146 property alias snapMode: _listView.snapMode
147
148 /**
149 * @brief The spacing between the elements in the list view.
150 * By default this is set to `Style.defaultSpacing`
151 * @property int ListBrowser::spacing
152 */
153 property alias spacing: _listView.spacing
154
155 /**
156 * @brief An alias to access the QQC2 ListView.
157 * @property ListView ListBrowser::flickable
158 */
159 readonly property alias flickable : _listView
160
161 /**
162 * @brief An alias to access the QQC2 ScrollView.
163 * @property ScrollView ListBrowser::scrollView
164 */
165 readonly property alias scrollView : _scrollView
166
167 /**
168 * @brief The total height of all the elements listed in the view.
169 * @property int ListBrowser::contentHeight
170 */
171 property alias contentHeight : _listView.contentHeight
173 /**
174 * @brief The total width of all the elements.
175 * @property int ListBrowser::contentWidth
176 */
177 property alias contentWidth : _listView.contentWidth
179 /**
180 * @brief Whether the view is positioned at the end on the Y axis.
181 * Meant to be used if the view `orientation` has been set to vertical.
182 * @property bool ListBrowser::atYEnd
183 */
184 readonly property alias atYEnd : _listView.atYEnd
185
186 /**
187 * @brief Whether the view is positioned at the beginning on the Y axis.
188 * Meant to be used if the view `orientation` has been set to vertical.
189 * @property bool ListBrowser::atYBeginning
190 */
191 readonly property alias atYBeginning : _listView.atYBeginning
192
193 /**
194 * @brief The top padding.
195 * @see padding
196 * @property int ListBrowser::topPadding
197 */
198 property alias topPadding: _scrollView.topPadding
199
200 /**
201 * @brief The bottom padding.
202 * @see padding
203 * @property int ListBrowser::bottomPadding
204 */
205 property alias bottomPadding: _scrollView.bottomPadding
206
207 /**
208 * @brief The right padding.
209 * @see padding
210 * @property int ListBrowser::rightPadding
211 */
212 property alias rightPadding: _scrollView.rightPadding
213
214 /**
215 * @brief The left padding.
216 * @see padding
217 * @property int ListBrowser::leftPadding
218 */
219 property alias leftPadding: _scrollView.leftPadding
220
221 /**
222 * @brief The total padding all around the list view. The padding is added to the ScrollView.
223 * This is the same as setting `scrollView.padding`.
224 * @property int ListBrowser::padding
225 */
226 property alias padding: _scrollView.padding
227
228 /**
229 * @brief The policy of the vertical scroll bar from the scroll view.
230 * @see scrollView
231 * The default value of this is picked based on the Style property `Style.scrollBarPolicy`, unless the orientation of the view is set to horizontal, in which case this is set to 'ScrollBar.AlwaysOff`.
232 * Possible values are:
233 * - ScrollBar.AlwaysOff
234 * - ScrollBar.AlwaysOn
235 * - ScrollBar.AsNeeded
236 */
237 property int verticalScrollBarPolicy:
238 {
239 if(control.orientation === ListView.Horizontal)
240 return ScrollBar.AlwaysOff
241
242 switch(Maui.Style.scrollBarPolicy)
243 {
244 case Maui.Style.AlwaysOn: return ScrollBar.AlwaysOn;
245 case Maui.Style.AlwaysOff: return ScrollBar.AlwaysOff;
246 case Maui.Style.AsNeeded: return ScrollBar.AsNeeded;
247 case Maui.Style.AutoHide: return ScrollBar.AsNeeded;
248 }
249 }
250
251 /**
252 * @brief The policy of the horizontal scroll bar from the scroll view.
253 * @see scrollView
254 * The default value of this is picked based on the Style property `Style.scrollBarPolicy`, unless the orientation of the view is set to vertical, in which case this is set to 'ScrollBar.AlwaysOff`.
255 * Possible values are:
256 * - ScrollBar.AlwaysOff
257 * - ScrollBar.AlwaysOn
258 * - ScrollBar.AsNeeded
259 */
260 property int horizontalScrollBarPolicy:
261 {
262 if(control.orientation === ListView.Vertical)
263 return ScrollBar.AlwaysOff
265 switch(Maui.Style.scrollBarPolicy)
266 {
267 case Maui.Style.AlwaysOn: return ScrollBar.AlwaysOn;
268 case Maui.Style.AlwaysOff: return ScrollBar.AlwaysOff;
269 case Maui.Style.AsNeeded: return ScrollBar.AsNeeded;
270 case Maui.Style.AutoHide: return ScrollBar.AsNeeded;
271 }
272 }
273
274 /**
275 * @brief An alias to access the placeholder properties. This is handled by a MauiKit Holder.
276 * @see Holder::title
277 * @see Holder::body
278 *
279 * @property Holder ListBrowser::holder
280 */
281 property alias holder : _holder
282
283 /**
284 * @brief Whether to enable the lasso selection, to select multiple items.
285 * By default this is set to `false`.
286 * @see itemsSelected
287 */
288 property bool enableLassoSelection : false
290 /**
291 * @brief
292 */
293 property bool selectionMode: false
294
295 /**
296 * @brief An alias to the lasso rectangle.
297 * @property Rectangle ListBrowser::lassoRec
298 */
299 readonly property alias lassoRec : selectLayer
300
301 /**
302 * @brief The header section of the ListView element.
303 * @see flickable
304 * @property Component ListBrowser::header
305 */
306 property alias header : _listView.header
307
308 /**
309 * @brief The footer section of the ListView element
310 * @see flickable
311 * @property Component ListBrowser::footer
312 */
313 property alias footer : _listView.footer
314
315 /**
316 * @brief The actual width of the view-port. This is the actual width without any padding.
317 * @property int ListBrowser::availableWidth
318 */
319 readonly property alias availableWidth: _listView.width
320
321 /**
322 * @brief The actual height of the view-port. This is the actual height without any padding.
323 * @property int ListBrowser::availableHeight
324 */
325 readonly property alias availableHeight: _listView.height
326
327 /**
328 * @brief Emitted when the lasso selection has been released.
329 * @param indexes A array of index numbers is sent as the argument, representing the index value of the items under the lasso rectangle area.
330 */
331 signal itemsSelected(var indexes)
332
333 /**
334 * @brief Emitted when an empty space of the background area has been clicked.
335 * @param mouse Object with information about the click event.
336 */
337 signal areaClicked(var mouse)
338
339 /**
340 * @brief Emitted when an empty space of the area area background has been right clicked.
341 */
342 signal areaRightClicked()
343
344 /**
345 * @brief Emitted when a physical key from the device has been pressed.
346 * @param event The object with information about the event.
347 */
348 signal keyPress(var event)
349
350 Keys.enabled : true
351 Keys.forwardTo : _listView
352
354 {
355 id: _scrollView
356 anchors.fill: parent
357 clip: control.clip
358 focus: true
359 padding: Maui.Style.contentMargins
360 Maui.Controls.orientation: _listView.orientation
361
362 ScrollBar.horizontal.policy: control.horizontalScrollBarPolicy
363 ScrollBar.vertical.policy: control.verticalScrollBarPolicy
364
365 contentHeight: _listView.contentHeight
367
368 ListView
369 {
370 id: _listView
371 focus: true
372 clip: control.clip
373
374 property var selectedIndexes : []
375
376 spacing: Maui.Style.defaultSpacing
377
378 snapMode: ListView.NoSnap
379
380 displayMarginBeginning: Maui.Style.toolBarHeight * 4
381 displayMarginEnd: Maui.Style.toolBarHeight * 4
382
383 boundsBehavior: Flickable.StopAtBounds
384 boundsMovement: Flickable.StopAtBounds
385
386 interactive: Maui.Handy.hasTransientTouchInput
387 highlightFollowsCurrentItem: true
388 highlightMoveDuration: 0
389 highlightResizeDuration : 0
390
391 keyNavigationEnabled : true
392 keyNavigationWraps : true
393
394 Keys.onPressed: (event) => control.keyPress(event)
395
396 Maui.Holder
397 {
398 id: _holder
399 visible: false
400 anchors.fill : parent
401 Keys.forwardTo: _listView
402 anchors.topMargin: _listView.headerItem ? _listView.headerItem.height : 0
403 anchors.bottomMargin: _listView.footerItem ? _listView.footerItem.height : 0
404 }
405
406 Item
407 {
408 anchors.fill: parent
409 z: parent.z-1
410 clip: false
411
412 Loader
413 {
414 asynchronous: true
415 anchors.fill: parent
416 // active: !Maui.Handy.hasTransientTouchInput && !Maui.Handy.isMobile
417
418 sourceComponent: MouseArea
419 {
420 id: _mouseArea
421
422 propagateComposedEvents: true
423 preventStealing: true
424 scrollGestureEnabled: false
425 acceptedButtons: Qt.RightButton | Qt.LeftButton
426
427 onClicked: (mouse) =>
428 {
429 console.log("Area clicked")
430
431 control.areaClicked(mouse)
432 control.forceActiveFocus()
433
434 if(mouse.button === Qt.RightButton)
435 {
436 control.areaRightClicked()
437 mouse.accepted = true
438 return
439 }
440 }
441
442 onPositionChanged: (mouse) =>
443 {
444 if(_mouseArea.pressed && control.enableLassoSelection && selectLayer.visible)
445 {
446 if(mouseX >= selectLayer.newX)
447 {
448 selectLayer.width = (mouseX + 10) < (control.x + control.width) ? (mouseX - selectLayer.x) : selectLayer.width;
449 } else {
450 selectLayer.x = mouseX < control.x ? control.x : mouseX;
451 selectLayer.width = selectLayer.newX - selectLayer.x;
452 }
453
454 if(mouseY >= selectLayer.newY) {
455 selectLayer.height = (mouseY + 10) < (control.y + control.height) ? (mouseY - selectLayer.y) : selectLayer.height;
456 if(!_listView.atYEnd && mouseY > (control.y + control.height))
457 _listView.contentY += 10
458 } else {
459 selectLayer.y = mouseY < control.y ? control.y : mouseY;
460 selectLayer.height = selectLayer.newY - selectLayer.y;
461
462 if(!_listView.atYBeginning && selectLayer.y === 0)
463 _listView.contentY -= 10
464 }
465 }
466 }
467
468 onPressed: (mouse) =>
469 {
470 console.log("MOUSE EVENT SOURCE", mouse.source)
471 if (mouse.source === Qt.MouseEventNotSynthesized && control.enableLassoSelection && mouse.button === Qt.LeftButton && control.count > 0)
472 {
473 selectLayer.visible = true;
474 selectLayer.x = mouseX;
475 selectLayer.y = mouseY;
476 selectLayer.newX = mouseX;
477 selectLayer.newY = mouseY;
478 selectLayer.width = 0
479 selectLayer.height = 0;
480 }
481 }
482
483 onPressAndHold: (mouse) =>
484 {
485 if ( mouse.source !== Qt.MouseEventNotSynthesized && control.enableLassoSelection && !selectLayer.visible && !Maui.Handy.hasTransientTouchInput && !Maui.Handy.isAndroid)
486 {
487 selectLayer.visible = true;
488 selectLayer.x = mouseX;
489 selectLayer.y = mouseY;
490 selectLayer.newX = mouseX;
491 selectLayer.newY = mouseY;
492 selectLayer.width = 0
493 selectLayer.height = 0;
494 mouse.accepted = true
495 }else
496 {
497 mouse.accepted = false
498 }
499 }
500
501 onReleased: (mouse) =>
502 {
503 if(mouse.button !== Qt.LeftButton || !control.enableLassoSelection || !selectLayer.visible)
504 {
505 mouse.accepted = false
506 return;
507 }
508
509 if(selectLayer.y > _listView.contentHeight)
510 {
511 return selectLayer.reset();
512 }
513
514 var lassoIndexes = []
515 var limitY = mouse.y === lassoRec.y ? lassoRec.y+lassoRec.height : mouse.y
516 var y = lassoRec.y
517 for(y; y < limitY; y+=10)
518 {
519 const index = _listView.indexAt(_listView.width/2,y+_listView.contentY)
520 if(!lassoIndexes.includes(index) && index>-1 && index< _listView.count)
521 lassoIndexes.push(index)
522 }
523
524 control.itemsSelected(lassoIndexes)
525 console.log("INDEXES << " , lassoIndexes, lassoRec.y, limitY)
526 selectLayer.reset()
527 }
528 }
529 }
530 }
531
532 Maui.Rectangle
533 {
534 id: selectLayer
535 property int newX: 0
536 property int newY: 0
537 height: 0
538 width: 0
539 x: 0
540 y: 0
541 visible: false
542 color: Qt.rgba(control.Maui.Theme.highlightColor.r,control.Maui.Theme.highlightColor.g, control.Maui.Theme.highlightColor.b, 0.2)
543 opacity: 0.7
544
545 borderColor: control.Maui.Theme.highlightColor
546 borderWidth: 2
547 solidBorder: false
548
549 function reset()
550 {
551 selectLayer.x = 0;
552 selectLayer.y = 0;
553 selectLayer.newX = 0;
554 selectLayer.newY = 0;
555 selectLayer.visible = false;
556 selectLayer.width = 0;
557 selectLayer.height = 0;
558 }
559 }
560 }
561 }
562}
563
564
void itemsSelected(var indexes)
Emitted when the lasso selection has been released.
void areaClicked(var mouse)
Emitted when an empty space of the background area has been clicked.
alias contentWidth
The total width of all the elements.
alias holder
An alias to access the placeholder properties.
bool enableLassoSelection
Whether to enable the lasso selection, to select multiple items.
void keyPress(var event)
Emitted when a physical key from the device has been pressed.
alias contentHeight
The total height of all the elements listed in the view.
alias spacing
The spacing between the elements in the list view.
void areaRightClicked()
Emitted when an empty space of the area area background has been right clicked.
alias snapMode
How to snap the elements of the list view while scrolling.
int horizontalScrollBarPolicy
The policy of the horizontal scroll bar from the scroll view.
alias availableWidth
The actual width of the view-port.
alias lassoRec
An alias to the lasso rectangle.
alias padding
The total padding all around the list view.
alias header
The header section of the ListView element.
alias availableHeight
The actual height of the view-port.
alias footer
The footer section of the ListView element.
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri May 2 2025 11:57:11 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.