Kirigami2

BreadcrumbControl.qml
1/*
2 * SPDX-FileCopyrightText: 2018 Marco Martin <mart@kde.org>
3 * SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8import QtQuick
9import QtQuick.Layouts
10import org.kde.kirigami as Kirigami
11
12ListView {
13 id: root
14
15 readonly property Kirigami.PageRow pageRow: {
16 // This is fetched from breadcrumbLoader in PageRowGlobalToolBarUI.qml
17 const pr = parent?.pageRow ?? null;
18 return pr as Kirigami.PageRow;
19 }
20
21 currentIndex: {
22 if (!pageRow) {
23 return -1;
24 }
25 // This ListView is eventually consistent with PageRow, so it has to
26 // force-refresh currentIndex when its count finally catches up,
27 // otherwise currentIndex might get reset and stuck at -1.
28 void count;
29 // TODO: This "eventual consistency" causes Behavior on contentX to
30 // scroll from the start each time a page is added. Besides, simple
31 // number is not the most efficient model, because ListView
32 // recreates all delegates when number changes.
33
34 if (pageRow.layers.depth > 1) {
35 // First layer (index 0) is the main columnView.
36 // Since it is ignored, depth has to be adjusted by 1.
37 // In case of layers, current index is always the last one,
38 // which is one less than their count, thus minus another 1.
39 return pageRow.layers.depth - 2;
40 } else {
41 return pageRow.currentIndex;
42 }
43 }
44
45 // This function exists outside of delegate, so that when popping layers
46 // the JavaScript execution context won't be destroyed along with delegate.
47 function selectIndex(index: int) {
48 if (!pageRow) {
49 return;
50 }
51 if (pageRow.layers.depth > 1) {
52 // First layer (index 0) is the main columnView.
53 // Since it is ignored, index has to be adjusted by 1.
54 // We want to pop anything after selected index,
55 // turning selected layer into current one, thus plus another 1.
56 while (pageRow.layers.depth > index + 2) {
57 pageRow.layers.pop();
58 }
59 } else {
60 pageRow.currentIndex = index;
61 }
62 }
63
64 contentHeight: height
65 clip: true
66 orientation: ListView.Horizontal
67 boundsBehavior: Flickable.StopAtBounds
68 interactive: Kirigami.Settings.hasTransientTouchInput
69
70 contentX: {
71 if (!currentItem) {
72 return 0;
73 }
74 // preferred position: current item is centered within viewport
75 const preferredPosition = currentItem.x + (currentItem.width - width) / 2;
76
77 // Note: Order of min/max is important. Make sure to test on all sorts
78 // and sizes before committing changes to this formula.
79 if (LayoutMirroring.enabled) {
80 // In a mirrored ListView contentX starts from left edge and increases to the left.
81 const maxLeftPosition = -contentWidth;
82 const minRightPosition = -width;
83 return Math.round(Math.min(minRightPosition, Math.max(preferredPosition, maxLeftPosition)));
84 } else {
85 const minLeftPosition = 0;
86 const maxRightPosition = contentWidth - width;
87 return Math.round(Math.max(minLeftPosition, Math.min(preferredPosition, maxRightPosition)));
88 }
89 }
90
91 Behavior on contentX {
92 NumberAnimation {
93 duration: Kirigami.Units.longDuration
94 easing.type: Easing.InOutQuad
95 }
96 }
97
98 model: {
99 if (!root.pageRow) {
100 return null;
101 }
102 if (root.pageRow.layers.depth > 1) {
103 // First layer (index 0) is the main columnView; ignore it.
104 return root.pageRow.layers.depth - 1;
105 } else {
106 return root.pageRow.depth;
107 }
108 }
109
110 delegate: MouseArea {
111 id: delegate
112
113 required property int index
114
115 // We can't use Kirigami.Page here instead of Item since we now accept
116 // pushing PageRow to a new layer.
117 readonly property Item page: {
118 if (!root.pageRow) {
119 return null;
120 }
121 if (root.pageRow.layers.depth > 1) {
122 // First layer (index 0) is the main columnView.
123 // Since it is ignored, index has to be adjusted by 1.
124 return pageRow.layers.get(index + 1);
125 } else {
126 return pageRow.get(index);
127 }
128 }
129
130
131 width: Math.ceil(layout.implicitWidth)
132 height: ListView.view?.height ?? 0
133
134 hoverEnabled: !Kirigami.Settings.tabletMode
135
136 onClicked: mouse => {
137 root.selectIndex(index);
138 }
139
140 // background
141 Rectangle {
142 color: Kirigami.Theme.highlightColor
143 anchors.fill: parent
144 radius: Kirigami.Units.cornerRadius
145 opacity: root.count > 1 && parent.containsMouse ? 0.1 : 0
146 }
147
148 // content
149 RowLayout {
150 id: layout
151 anchors.fill: parent
152 spacing: 0
153
154 Kirigami.Icon {
155 visible: delegate.index > 0
156 Layout.alignment: Qt.AlignVCenter
157 Layout.preferredHeight: Kirigami.Units.iconSizes.small
158 Layout.preferredWidth: Kirigami.Units.iconSizes.small
159 isMask: true
160 color: Kirigami.Theme.textColor
161 source: LayoutMirroring.enabled ? "go-next-symbolic-rtl" : "go-next-symbolic"
162 }
163 Kirigami.Heading {
164 Layout.leftMargin: Kirigami.Units.largeSpacing
165 Layout.rightMargin: Kirigami.Units.largeSpacing
166 color: Kirigami.Theme.textColor
167 verticalAlignment: Text.AlignVCenter
168 wrapMode: Text.NoWrap
169 text: delegate.page?.title ?? ""
170 opacity: delegate.ListView.isCurrentItem ? 1 : 0.4
171 }
172 }
173 }
174}
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:56:52 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.