MauiKit Controls

Page.qml
1/*
2 * Copyright 2019 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 QtQml
22import QtQuick.Controls
23import QtQuick.Layouts
24
25import org.mauikit.controls as Maui
26
27/**
28 * @inherit QtQuick.Controls.Pane
29 * @since org.mauikit.controls 1.0
30 *
31 * @brief A page with a header and footer, that can be flipped among many other features.
32 *
33 * <a href="https://doc.qt.io/qt-6/qml-qtquick-controls-pane.html">This control inherits from QQC2 Pane, to checkout its inherited properties refer to the Qt Docs.</a>
34 *
35 * This page has a predefined header and footer bars that by default are set to a MauiKit ToolBar.
36 * The header bar can be dynamically moved to the bottom area, under the footer, for better
37 * reachability on hand held devices like phones.
38 * @see ToolBar
39 *
40 * Any other item can replace the header and/or footer. And the default toolbars can be populated easily via the aliases:
41 * @see headBar
42 * @see footBar
43 *
44 * Thje following code snippet is a quick example for setting a custom header:
45 * @code
46 * Page
47 * {
48 * id: _page
49 *
50 * header: Rectangle
51 * {
52 * width: parent.width
53 * height: 40
54 * color: "pink"
55 * }
56 * }
57 * @endcode
58 *
59 * @image html Page/page_structure.png "A Page with a header and footer - and then the header moved to the bottom under the footer"
60
61 * @note The Page control supports the Controls attached properties for level, status and showCSD. By default a Page level is set to be Secondary, but if the Page has been set to display the Client Side Decoration buttons via `Controls.showCSD`, then it will be set as Primary. This `level` property is then propagated to the deafult header bar.
62 *
63 * @section features Features
64 *
65 * Among other features, the page can make use of a reference to a flickable element to allow to have "pull-back toolbar" behaviour, floating toolbars, etc.
66 *
67 * @subsection pullback-bars Pull-Back Bars
68 *
69 * Pull-back bars allow to expand the content area by pulling away the header or footer when content is being flicked/scrolled - which is useful on phone screens. To enable this behaviour you need to reference the Flickable element via the `flickable` property.
70 * @see flickable
71 *
72 * Then set the header/footer positioning properties to `ListView.PullBackHeader`. This property is automatically set to the default header if a flickable element has been assigned, so you can disable it by setting the property to `ListView.InlineHeader` instead.
73 * @see footerPositioning
74 * @see headerPositioning
75 *
76 * @subsection bars Bars Layout
77 *
78 * As mentioned before, the Page has a header and footer area- the header can be moved to the bottom via the alternate header property: `altHeader`. But you can also stack multiple bars vertically. So you can have two or more header/footer bars.
79 * @see altHeader
80 *
81 * To attach more bars use the header and footer columns property.
82 * @see headerColumn
83 * @see footerColumn
84 *
85 * @code
86 * Page
87 * {
88 * id: _page
89 *
90 * headerColumn: [
91 * Rectangle
92 * {
93 * width: parent.width
94 * height: 40
95 * color: "pink"
96 * },
97 *
98 * Rectangle
99 * {
100 * width: parent.width
101 * height: 40
102 * color: "yellow"
103 * }
104 * ]
105 * }
106 * @endcode
107 *
108 * The header/footer layout is handled by a Column control, which can be accessed via the aliases to tweak the spacing, for example.
109 * @see headerContainer
110 * @see footerContainer
111 *
112 * @image html Page/headerColumn.png "A Page with a default header bar and two rectangles stacked as part of the header column"
113 *
114 * @subsection floatingbars Floating & AutoHide
115 *
116 * The header and/or footer bars can be set to a floating position - which means they will flow over the page contents at the bottom and top. When this is enable a translucency effect will be applied to hint about the content being covered underneath.
117 * @see floatingFooter
118 * @see floatingHeader
119 *
120 * The bars can also be set to auto-hide, when the cursor moves out or shown again when the cursor enters the bar area.
121 * @see autoHideFooter
122 * @see autoHideHeader
123 *
124 * The time to trigger this actions can be tweaked using the delay properties.
125 * @see autoHideFooterDelay
126 * @see autoHideHeaderDelay
127 *
128 * And to finetune the target area which reacts to enter and exit events, use the margins property:
129 * @see autoHideFooterMargins
130 * @see autoHideHeaderMargins
131 *
132 * @image html Page/floating_header.png "A Page with a floating header - and a translucent effect"
133 *
134 * @section notes Notes
135 * This component is an alternative to the QQC2 Page control, where the header and footer can not be moved easily - and it adds a few more functionality.
136 *
137 * The padding properties will affect the header and footer, so if instead you meant to add internal padding to the page contents, you can use the margins properties.
138 *
139 * When used in a StackView or SwipeView, this Page emits two signals for the go forward/back actions, which can be consumed to pop or push pages.
140 * @see goBackTriggered
141 *
142 * @code
143 * Page
144 * {
145 * id: _page
146 *
147 * headBar.rightContent: Switch
148 * {
149 * text: "Alt Header"
150 * checked: _page.altHeader
151 * onToggled: _page.altHeader = checked
152 * }
153 * }
154 * @endcode
155 *
156 * @image html Page/alt_header_dark.png "An ApplicationWindow filled with a Page and with the CSD controls enabled"
157 *
158 * <a href="https://invent.kde.org/maui/mauikit/-/blob/qt6-2/examples/Page.qml">You can find a more complete example at this link.</a>
160 * @note This control supports the attached Controls.showCSD property to display the window control buttons when using CSD. This is only supported if used with the MauiKit ToolBar as the header bar - which is the default. If use with another header element, the window control buttons need to be added manually.
161 */
162Pane
163{
164 id: control
165
166 padding: 0
167 leftPadding: control.padding
168 rightPadding: control.padding
169 topPadding: control.padding
170 bottomPadding: control.padding
171
172 Maui.Theme.colorSet: Maui.Theme.View
173 Maui.Theme.inherit: false
174
175 Maui.Controls.showCSD: false
176 Maui.Controls.level: control.Maui.Controls.showCSD === true ? Maui.Controls.Primary : Maui.Controls.Secondary
177 Maui.Controls.flat: true
178
179 /**
180 * @brief The default content of the page.
181 * To position child elements use anchors or do it manually.
182 *
183 * @note This is a `default` property
184 *
185 * @property list<QtObject> Page::content
186 */
187 default property alias content: _content.data
188
189 /**
190 * @brief An alias to the actual page container.
191 * @property Item Page::pageContent
192 */
193 readonly property alias pageContent : _content
194
195 /**
196 *
197 * The actual height of the page contents without the header or footer bars height.
198 * @property int Page::internalHeight
199 */
200 readonly property alias internalHeight : _content.height
201
202 /**
203 * @brief A flickable element can be referenced in order to support the header and footer positioning options such as Inline, Pullback or floating.
204 * If a flickable is set, the page will modify its top or bottom margins properties.
205 * And watch for changes in the Flickable properties, such as contentX and contentY in order to support the formerly mentioned features.
206 */
207 property Flickable flickable : null
208
209 /**
210 * @brief The footer bar can be place static and always visible with the InlineFooter value, or moved along with the flickable contents when using the PullBackFooter value.
211 * This is only supported if a flickable element has been set.
212 * @see flickable
213 * By default this is set to InlineFooter.
214 *
215 * Possible values are:
216 * - ListView.PullBackFooter
217 * - ListView.InlineFooter
218 */
219 property int footerPositioning : ListView.InlineFooter
220
221 /**
222 * @brief The header bar can be place static and always visible with the InlineHeader value, or moved along with the flickable contents when using the PullBackHeader value.
223 * This is only supported if a flickable element has been set.
224 * @see flickable
225 *
226 * By default this is set to `InlineHeader` unless a Flickable has been attached, in which case it is set to `PullBackHeader`.
227 *
228 * Possible values are:
229 * - ListView.PullBackHeader
230 * - ListView.InlineHeader
231 */
232 property int headerPositioning : flickable ? ListView.PullBackHeader : ListView.InlineHeader
233
234
235 /**
236 * @brief Convinient way to change the color set of the default header.
237 * @code
238 * Page
239 * {
240 * headerColorSet: Theme.Complementary
241 * }
242 * @endcode
243 */
244 property int headerColorSet : altHeader ? Maui.Theme.Window : Maui.Theme.Header
245
246 /**
247 * @brief A title for the page.
248 * This title is shown in the middle of the default header bar if the show title property is set to true.
249 * @see showTitle
250 * The displayed title in the header bar won't wrap, but will elide in the middle.
251 */
252 property string title
253
254 /**
255 * @brief If a title is set and this is set to true, such title will be displayed in the default header bar in the middle.
256 */
257 property bool showTitle : true
258
259 /**
260 * @brief An alias to the default ToolBar as the header bar.
261 * The toolbar is a MauiKit ToolBar.
262 * @see ToolBar
263 * @property ToolBar Page::headBar
264 */
265 property alias headBar : _headBar
266
267 /**
268 * @brief An alias to the default ToolBar as the footer bar.
269 * The toolbar is a MauiKit ToolBar.
270 * @property ToolBar Page::footBar
271 */
272 property alias footBar: _footBar
274 /**
275 * @brief Quick way to add more children to the footer bar.
276 * The footer bar is handled by a Column.
277 * @property list<QtObject> Page::footerColumn
278 */
279 property alias footerColumn : _footerContent.data
280
281 /**
282 * @brief The actual container for all the footer bars.
283 * @property Column Page::footerContainer
284 */
285 property alias footerContainer : _footerContent
286
287 /**
288 * @brief Quick way to add more children to the header bar.
289 * The header bar is handled by a Colum.
290 * @property list<QtObject> Page::headerColumn
291 */
292 property alias headerColumn : _headerContent.data
293
294 /**
295 * @brief The actual container for all the header bars.
296 * @property Column Page::headerContainer
297 */
298 property alias headerContainer : _headerContent
299
300 /**
301 * @brief The page margins for the page contents.
302 * This margins do not affect the header or footer bars.
303 * By default this is set to 0
304 */
305 property int margins: 0
306
307 /**
308 * @brief Page left margins
309 */
310 property int leftMargin : margins
311
312 /**
313 * @brief Page right margins
314 */
315 property int rightMargin: margins
316
317 /**
318 * @brief Page top margins
319 */
320 property int topMargin: margins
321
322 /**
323 * @brief Page bottom margins
324 */
325 property int bottomMargin: margins
326
327 /**
328 * @brief If set to `true` the header bar will be positioned to the bottom under the footer bar.
329 * This makes sense in some cases for better reachability, or custom design patterns.
330 */
331 property bool altHeader : false
332
333 /**
334 * @brief If the header bar should autohide under certain given condition.
335 * To fine tune a enter/exit threshold, a margin can be set, and a time delay.
336 */
337 property bool autoHideHeader : false
338
339 /**
340 * @brief If the footer bar should autohide under certain given condition.
341 * To fine tune a enter/exit threshold, a margin can be set, and a time delay.
342 */
343 property bool autoHideFooter : false
345 /**
346 * @brief Size in pixels for the cursor enter/exit threshold for when the header should autohide.
347 * The default value is set to `Style.toolBarHeight`.
348 */
349 property int autoHideHeaderMargins : Maui.Style.toolBarHeight
350
351 /**
352 * @brief Size in pixels for the cursor enter/exit threshold for when the footer should autohide.
353 * The default value is set to `Style.toolBarHeight`.
354 */
355 property int autoHideFooterMargins : Maui.Style.toolBarHeight
356
357 /**
358 * @brief Span of time to hide the footer bar after the conditions have been met.
359 * If within the span of time the conditions changed then the timer gets reseted.
360 */
361 property int autoHideFooterDelay : Maui.Handy.isTouch ? 0 : 800
363 /**
364 * @brief Span of time to hide the header bar after the conditions have been met.
365 * If within the span of time the conditions changed then the timer gets reseted.
366 */
367 property int autoHideHeaderDelay : Maui.Handy.isTouch ? 0 : 800
368
369
370 /**
371 * @brief If the header bar should float over the page contents, if set- then the default footer bar will have a translucent `ShaderEffect` to hint about the content under it.
372 */
373 property bool floatingHeader : false
375 /**
376 * @brief If the footer bar should float over the page contents, if a flickable has been set then the default footer bar will have a translucent `ShaderEffect`
377 * to hint about the content under it.
378 */
379 property bool floatingFooter: false
380
381 /**
382 * @brief Emitted when the user has requested to go back by a gesture or keyboard shortcut.
383 */
384 signal goBackTriggered()
385
386 /**
387 * @brief Emitted when the user has requested to go forward by a gesture or keyboard shortcut.
388 */
389 signal goForwardTriggered()
390
391 QtObject
392 {
393 id: _private
394 property int topMargin : (!control.altHeader ? (control.floatingHeader ? 0 : _headerContent.implicitHeight) : 0) + control.topMargin
395 property int bottomMargin: ((control.floatingFooter && control.footerPositioning === ListView.InlineFooter ? 0 : _footerContent.implicitHeight) + (control.altHeader ? _headerContent.implicitHeight : 0))
396 }
397
398 onFlickableChanged:
399 {
400 returnToBounds()
401 }
402
403 Binding
404 {
405 when: control.floatingFooter && control.footerPositioning === ListView.InlineFooter && _footerContent.implicitHeight > 0
406 target: control.flickable
407 property: "bottomMargin"
408 value: _footerContent.implicitHeight
409 restoreMode: Binding.RestoreBindingOrValue
410 }
411
412 Connections
413 {
414 target: control.flickable ? control.flickable : null
415 ignoreUnknownSignals: true
416 enabled: control.flickable && ((control.header && control.headerPositioning === ListView.PullBackHeader) || (control.footer && control.footerPositioning === ListView.PullBackFooter))
417 property int oldContentY
418 property bool updatingContentY: false
419
420 function onContentYChanged()
421 {
422 _headerAnimation.enabled = false
423 _footerAnimation.enabled = false
424
425 if(!control.flickable.dragging && control.flickable.atYBeginning)
426 {
427 control.returnToBounds()
428 }
429
430 if (updatingContentY || !control.flickable || !control.flickable.dragging)
431 {
432 oldContentY = control.flickable.contentY;
433 return;
434 //TODO: merge
435 //if moves but not dragging, just update oldContentY
436 }
437
438 if(control.flickable.contentHeight < control.height)
439 {
440 return
441 }
442
443 var oldFHeight
444 var oldHHeight
445
446 if (control.footer && control.footerPositioning === ListView.PullBackFooter && control.footer.visible)
447 {
448 oldFHeight = control.footer.height
449 control.footer.height = Math.max(0,
450 Math.min(control.footer.implicitHeight,
451 control.footer.height + oldContentY - control.flickable.contentY));
452 }
453
454 if (control.header && control.headerPositioning === ListView.PullBackHeader && control.header.visible && !control.altHeader)
455 {
456 oldHHeight = control.header.height
457 control.header.height = Math.max(0,
458 Math.min(control.header.implicitHeight,
459 control.header.height + oldContentY - control.flickable.contentY));
460 }
461
462 //if the implicitHeight is changed, use that to simulate scroll
463 if (control.header && oldHHeight !== control.header.height && control.header.visible && !control.altHeader)
464 {
465 updatingContentY = true
466 control.flickable.contentY -= (oldHHeight - control.header.height)
467 updatingContentY = false
468
469 } else {
470 oldContentY = control.flickable.contentY
471 }
472 }
473
474 function onMovementEnded()
475 {
476 if (control.header && control.header.visible && control.headerPositioning === ListView.PullBackHeader && !control.altHeader)
477 {
478 _headerAnimation.enabled = true
479
480 if (control.header.height >= (control.header.implicitHeight/2) || control.flickable.atYBeginning )
481 {
482 control.header.height = control.header.implicitHeight
483
484 } else
485 {
486 control.header.height = 0
487 }
488 }
489
490 if (control.footer && control.footer.visible && control.footerPositioning === ListView.PullBackFooter)
491 {
492 _footerAnimation.enabled = true
493
494 if (control.footer.height >= (control.footer.implicitHeight/2) || control.flickable.atYEnd)
495 {
496 if(control.flickable.atYEnd)
497 {
498 control.footer.height = control.footer.implicitHeight
499
500 control.flickable.contentY = control.flickable.contentHeight - control.flickable.height
501 oldContentY = control.flickable.contentY
502 }else
503 {
504 control.footer.height = control.footer.implicitHeight
505
506 }
507
508 } else
509 {
510 control.footer.height = 0
511 }
512 }
513 }
514 }
515
516 /**
517 * @brief The main single header bar.
518 * By default this header is set to a MauiKit ToolBar, but it can be changed to any other item.
519 * @see ToolBar
520 */
521 property Item header : Maui.ToolBar
522 {
523 id: _headBar
524 visible: count > 0
525 width: visible ? _headerContent.width : 0
526 position: control.altHeader ? ToolBar.Footer : ToolBar.Header
527 Maui.Controls.showCSD: control.Maui.Controls.showCSD && control.Maui.Controls.showCSD === true && !control.altHeader
528 Maui.Controls.level: control.Maui.Controls.level
529 Maui.Controls.flat: control.Maui.Controls.flat
530 Maui.Controls.item: ShaderEffectSource
531 {
532 layer.enabled: GraphicsInfo.api !== GraphicsInfo.Software
533 // textureSize: Qt.size(_headBarBG.width * 0.2, _headBarBG.height * 0.2)
534 sourceItem: _content
535 sourceRect: _headBar.background ?
536 (control.floatingHeader ?
537 Qt.rect(0, (_headBar.position === ToolBar.Header ? 0 : _content.height - _headBar.background.height), _headBar.background.width, _headBar.background.height)
538 : Qt.rect(0, (_headBar.position === ToolBar.Header ? 0 - (_headerContent.implicitHeight) : _content.height), _headBar.background.width, _headBar.background.height))
539 : null
540 }
541
542 Binding on height
543 {
544 value: visible ? _headBar.implicitHeight : 0
545 restoreMode: Binding.RestoreBindingOrValue
546 }
547
548 Behavior on height
549 {
550 id: _headerAnimation
551 enabled: false
552 NumberAnimation
553 {
554 duration: Maui.Style.units.shortDuration
555 easing.type: Easing.InOutQuad
556 }
557 }
558
559 Component
560 {
561 id: _titleComponent
562
563 Label
564 {
565 id: _titleLabel
566 text: control.title
567 elide : Text.ElideRight
568 // font: Maui.Style.h2Font
569 horizontalAlignment : Text.AlignHCenter
570 verticalAlignment : Text.AlignVCenter
571 }
572 }
573
574 middleContent: Loader
575 {
576 visible: item
577 active: control.title && control.showTitle
578 sourceComponent: _titleComponent
579
580 asynchronous: true
581
582 Layout.fillWidth: true
583 Layout.fillHeight: true
584 Layout.maximumWidth: 200
585 Layout.alignment: Qt.AlignCenter
586 }
587 }
588
589 //Label
590 //{
591 //z: 999999999999
592 //color: "yellow"
593 //text: _footBar.visibleCount + " / " + _footBar.count + " - " + _footBar.height + " / " + footer.height + " - " + _footBar.visible + " / " + footer.visible + " / " + footer.height + " / " + _footerContent.implicitHeight + " / " + _footerContent.implicitHeight
594 //}
595
596 /**
597 * @brief The main single footer bar.
598 * By default this footer is set to a MauiKit ToolBar, but it can be changed to any other item.
599 * @see ToolBar
600 */
601 property Item footer : Maui.ToolBar
602 {
603 id: _footBar
604 visible: count > 0
605 width: visible ? _footerContent.width : 0
606 height: visible ? implicitHeight : 0
607
608 position: ToolBar.Footer
609
610 Maui.Controls.item: ShaderEffectSource
611 {
612 layer.enabled: GraphicsInfo.api !== GraphicsInfo.Software
613 //textureSize: Qt.size(_headBarBG.width * 0.2, _headBarBG.height * 0.2)
614 sourceItem: _content
615 sourceRect: _footBar.background ? (control.floatingFooter ? Qt.rect(0, _content.height - _footBar.background.height, _footBar.background.width, _footBar.background.height) : Qt.rect(0, _content.height, _footBar.background.width, _footBar.background.height)) : Qt.rect(0,0,0,0)
616 }
617
618 Behavior on height
619 {
620 id: _footerAnimation
621 enabled: false
622 NumberAnimation
623 {
624 duration: Maui.Style.units.shortDuration
625 easing.type: Easing.InOutQuad
626 }
627 }
628 }
629
630 states: [ State
631 {
632 when: !altHeader
633
634 AnchorChanges
635 {
636 target: _headerContent
637 anchors.top: parent.top
638 anchors.bottom: undefined
639 }
640
641 AnchorChanges
642 {
643 target: _footerContent
644 anchors.top: undefined
645 anchors.bottom: parent.bottom
646 }
647 },
648
649 State
650 {
651 when: altHeader
652
653 AnchorChanges
654 {
655 target: _headerContent
656 anchors.top: undefined
657 anchors.bottom: parent.bottom
658 }
659
660 AnchorChanges
661 {
662 target: _footerContent
663 anchors.top: undefined
664 anchors.bottom: _headerContent.top
665 }
666 } ]
667
668 onAutoHideHeaderChanged:
669 {
670 if(control.autoHideHeader)
671 {
672 pullBackHeader()
673 }else
674 {
675 pullDownHeader()
676 }
677 }
678
679 onAutoHideFooterChanged:
680 {
681 if(control.autoHideFooter)
682 {
683 pullBackFooter()
684 } else
685 {
686 pullDownFooter()
687 }
688 }
689 onAltHeaderChanged: pullDownHeader()
690
691
692 // Label
693 // {
694 // anchors.centerIn: _headerContent
695 // text: header.height + "/" + _headerContent.height + " - " + _layout.anchors.topMargin
696 // color: "orange"
697 // z: _headerContent.z + 1
698 // visible: header.visible
699 // }
700 //
701 // Label
702 // {
703 // anchors.centerIn: _footerContent
704 // text: footer.height + "/" + _footerContent.height + " - " + _layout.anchors.topMargin
705 // color: "orange"
706 // z: _footerContent.z + 9999
707 // }
708
709 contentItem: Item
710 {
711 Item
712 {
713 id: _content
714 anchors.fill: parent
715
716 anchors.topMargin: _private.topMargin
717 anchors.bottomMargin: _private.bottomMargin
718
719 anchors.leftMargin: control.leftMargin
720 anchors.rightMargin: control.rightMargin
721 }
722
723 Loader
724 {
725 active: control.Maui.Controls.showCSD === true && control.altHeader && !Maui.Handy.isMobile
726 asynchronous: true
727 width: parent.width
728
729 sourceComponent: Maui.ToolBar
730 {
731 anchors.top: parent.top
732 Maui.Controls.showCSD: true
733 background: Rectangle
734 {
735 Maui.Theme.colorSet: control.Maui.Theme.colorSet
736 Maui.Theme.inherit: false
737 opacity: 0.8
738 scale: -1 //for mirroring
739 gradient: Gradient {
740 orientation: Gradient.Horizontal
741 GradientStop { position: 0.0; color: Maui.Theme.backgroundColor }
742 GradientStop { position: 0.33; color: "transparent" }
743 GradientStop { position: 1.0; color: "transparent" }
744 }
745 }
746 }
747 }
748
749 Column
750 {
751 id: _headerContent
752 anchors.left: parent.left
753 anchors.right: parent.right
754 }
755
756 Column
757 {
758 id: _footerContent
759 anchors.left: parent.left
760 anchors.right: parent.right
761 }
762
763 Loader
764 {
765 anchors.fill: parent
766 asynchronous: true
767 sourceComponent: MouseArea // to support tbutton go back and forward
768 {
769 propagateComposedEvents: true
770 acceptedButtons: Qt.BackButton | Qt.ForwardButton
771 cursorShape: undefined
772
773 onPressed: (mouse) =>
774 {
775 mouse.accepted = false
776 if(mouse.button === Qt.BackButton)
777 {
778 control.goBackTriggered()
779 }
780
781 if(mouse.button === Qt.ForwardButton)
782 {
783 control.goForwardTriggered()
784 }
785 }
786 }
787 }
788
789 Loader
790 {
791 anchors.fill: parent
792 asynchronous: true
793 z: _content.z +1
794 active: (control.autoHideFooter || control.autoHideHeader ) && Maui.Handy.isTouch
795
796 sourceComponent: MouseArea
797 {
798 parent: _content
799 propagateComposedEvents: true
800 drag.filterChildren: true
801
802 Timer
803 {
804 id: doubleClickTimer
805 interval: 900
806 onTriggered:
807 {
808 if(control.autoHideHeader)
809 {
810 if(header.height !== 0)
811 {
812 _autoHideHeaderTimer.start()
813 _revealHeaderTimer.stop()
814
815 }else
816 {
817 _autoHideHeaderTimer.stop()
818 _revealHeaderTimer.start()
819 }
820 }
821
822 if(control.autoHideFooter)
823 {
824 if(footer.height !== 0)
825 {
826 _autoHideFooterTimer.start()
827
828 }else
829 {
830 pullDownFooter()
831 _autoHideFooterTimer.stop()
832 }
833 }
834 }
835 }
836
837 onPressed: (mouse) =>
838 {
839 doubleClickTimer.restart();
840 mouse.accepted = false
841 }
842 }
843 }
844
845 Loader
846 {
847 asynchronous: true
848 anchors.top: parent.top
849 anchors.left: parent.left
850 anchors.right: parent.right
851 height: active ? _headerContent.implicitHeight + control.autoHideHeaderMargins : 0
852 z: _content.z +1
853 active: control.autoHideHeader && !control.altHeader && !Maui.Handy.isTouch
854
855 sourceComponent: Item
856 {
857 HoverHandler
858 {
859 acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
860 // cursorShape: Qt.PointingHandCursor
861 blocking: true
862 // grabPermissions: PointerHandler.CanTakeOverFromAnything
863 onHoveredChanged:
864 {
865 if(!control.autoHideHeader || control.altHeader)
866 {
867 _autoHideHeaderTimer.stop()
868 return
869 }
870
871 if(!hovered)
872 {
873 _autoHideHeaderTimer.start()
874 _revealHeaderTimer.stop()
875
876 }else
877 {
878 _autoHideHeaderTimer.stop()
879 _revealHeaderTimer.start()
880 }
881 }
882 }
883 }
884 }
885
886 Loader
887 {
888 asynchronous: true
889 anchors.bottom: parent.bottom
890 anchors.left: parent.left
891 anchors.right: parent.right
892 height: active ? _footerContent.implicitHeight + control.autoHideFooterMargins : 0
893 z: _content.z + 1
894 active: control.autoHideFooter && !control.altHeader && !Maui.Handy.isTouch
895
896 sourceComponent: Item
897 {
898 HoverHandler
899 {
900 acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
901 blocking: true
902
903 onHoveredChanged:
904 { console.log("Hovered footer changed", hovered)
905
906 if(!control.autoHideFooter)
907 {
908 return
909 }
910
911 if(!hovered)
912 {
913 _autoHideFooterTimer.start()
914
915 }else
916 {
917 pullDownFooter()
918 _autoHideFooterTimer.stop()
919 }
920 }
921 }
922 }
923 }
924 }
925
926 Timer
927 {
928 id: _revealHeaderTimer
929 interval: autoHideHeaderDelay
930
931 onTriggered:
932 {
933 pullDownHeader()
934 }
935 }
936
937 Timer
938 {
939 id: _autoHideHeaderTimer
940 interval: autoHideHeaderDelay
941 onTriggered:
942 {
943 if(control.autoHideHeader)
944 {
945 pullBackHeader()
946 }
947
948 stop()
949 }
950 }
951
952 Timer
953 {
954 id: _autoHideFooterTimer
955 interval: control.autoHideFooterDelay
956 onTriggered:
957 {
958 if(control.autoHideFooter)
959 {
960 pullBackFooter()
961 }
962
963 stop()
964 }
965 }
966
967 //Keys.onBackPressed:
968 //{
969 //control.goBackTriggered();
970 //}
971
972 //Shortcut
973 //{
974 //sequence: "Forward"
975 //onActivated: control.goForwardTriggered();
976 //}
977
978 //Shortcut
979 //{
980 //sequence: StandardKey.Forward
981 //onActivated: control.goForwardTriggered();
982 //}
983
984 //Shortcut
985 //{
986 //sequence: StandardKey.Back
987 //onActivated: control.goBackTriggered();
988 //}
989
990
991 Component.onCompleted :
992 {
993 if(footer)
994 {
995 _footerContent.data.push(footer)
996 }
997
998 if(header)
999 {
1000 let data = [header]
1001
1002 for(var i in _headerContent.data)
1003 {
1004 data.push(_headerContent.data[i])
1005 }
1006 _headerContent.data = data
1007 }
1008 }
1009
1010 /**
1011 * @brief If the header or footer are hidden, invoking this method will make them show again
1012 */
1013 function returnToBounds()
1014 {
1015 if(control.header)
1016 {
1017 // pullDownHeader()
1018 }
1019
1020 if(control.footer)
1021 {
1022 // pullDownFooter()
1023 }
1024 }
1025
1026 /**
1027 * @brief Forces the header to be hidden by pulling it back
1028 */
1029 function pullBackHeader()
1030 {
1031 _headerAnimation.enabled = true
1032 header.height = 0
1033 }
1034
1035 /**
1036 * @brief Forces the header to be shown by pulling it back in place
1037 */
1038 function pullDownHeader()
1039 {
1040 _headerAnimation.enabled = true
1041 header.height = header.implicitHeight
1042 }
1043
1044 /**
1045 * @brief Forces the footer to be hidden by pulling it back
1046 */
1047 function pullBackFooter()
1048 {
1049 _footerAnimation.enabled = true
1050 footer.height= 0
1051 }
1052
1053 /**
1054 * @brief Forces the footer to be shown by pulling it back in place
1055 */
1056 function pullDownFooter()
1057 {
1058 _footerAnimation.enabled = true
1059 footer.height = footer.implicitHeight
1060 }
1061}
An alternative to QQC2 ToolBar, with a custom horizontal layout - divided into three main sections - ...
Definition ToolBar.qml:115
void stop(Ekos::AlignState mode)
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.