Lomiri
Loading...
Searching...
No Matches
IndicatorItem.qml
1/*
2 * Copyright 2013-2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.15
18import QtQml 2.15
19import Lomiri.Components 1.3
20import Lomiri.Settings.Components 0.1
21import QMenuModel 1.0
22
23IndicatorDelegate {
24 id: root
25
26 property string identifier
27 property alias title: indicatorName.text
28 property alias leftLabel: leftLabelItem.text
29 property alias rightLabel: rightLabelItem.text
30 property var icons: undefined
31 property bool expanded: false
32 property bool finishedExpanding: false
33 property bool selected: false
34 property real iconHeight: units.gu(2)
35 readonly property color color: {
36 if (!expanded) return theme.palette.normal.backgroundText;
37 if (!selected) return theme.palette.disabled.backgroundText;
38 return theme.palette.normal.backgroundText;
39 }
40
41 Behavior on x {
42 enabled: expanded && finishedExpanding && !stateTransition.running
43 NumberAnimation { duration: LomiriAnimation.SnapDuration }
44 }
45
46 implicitWidth: mainItems.width
47
48 // Prevent ListView from removing us from the view while expanding.
49 // If we're the PanelBar's initial item, our removal will make it lose
50 // track of us and cause its positioning to go wrong.
51 ListView.delayRemove: stateTransition.running
52
53 MouseArea {
54 readonly property int stepUp: 1
55 readonly property int stepDown: -1
56
57 anchors.fill: parent
58 acceptedButtons: Qt.MiddleButton
59 onClicked: {
60 if ((!expanded || selected) && secondaryAction.valid) {
61 secondaryAction.activate();
62 }
63 }
64 onWheel: {
65 if ((!expanded || selected) && scrollAction.valid) {
66 scrollAction.activate(wheel.angleDelta.y > 0 ? stepUp : stepDown);
67 }
68 }
69 }
70
71 Item {
72 id: mainItems
73 anchors.centerIn: parent
74
75 width: leftLabelItem.width + iconsItem.width + rightLabelItem.width
76 implicitHeight: units.gu(2)
77
78 Label {
79 id: leftLabelItem
80 objectName: "leftLabel"
81
82 anchors {
83 left: mainItems.left
84 verticalCenter: parent.verticalCenter
85 }
86 width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
87 horizontalAlignment: Text.AlignHCenter
88
89 opacity: 1.0
90 font.family: "Noto Sans"
91 fontSize: "medium"
92 font.weight: Font.Light
93 color: root.color
94 Behavior on color { ColorAnimation { duration: LomiriAnimation.FastDuration; easing: LomiriAnimation.StandardEasing } }
95 }
96
97 Item {
98 id: iconsItem
99 objectName: "icons"
100
101 width: iconRow.width > 0 ? iconRow.width + units.gu(1) : 0
102 anchors {
103 left: leftLabelItem.right
104 verticalCenter: parent.verticalCenter
105 }
106
107 Row {
108 id: iconRow
109 anchors.centerIn: iconsItem
110 spacing: units.gu(1)
111
112 Repeater {
113 id: iconRepeater
114 objectName: "iconRepeater"
115
116 model: d.useFallbackIcon ? [ "image://theme/settings" ] : root.icons
117
118 Icon {
119 id: itemImage
120 objectName: "icon"+index
121 height: iconHeight
122 // FIXME Workaround for bug https://bugs.launchpad.net/lomiri/+source/lomiri-ui-toolkit/+bug/1421293
123 width: implicitWidth > 0 && implicitHeight > 0 ? (implicitWidth / implicitHeight * height) : implicitWidth;
124 source: modelData
125 color: root.color
126 Behavior on color { ColorAnimation { duration: LomiriAnimation.FastDuration; easing: LomiriAnimation.StandardEasing } }
127
128 // Workaround indicators getting stretched/squished when (un)plugging external/virtual monitor
129 onHeightChanged: {
130 source = ""
131 source = modelData
132 }
133 }
134 }
135 }
136 }
137
138 Label {
139 id: rightLabelItem
140 objectName: "rightLabel"
141
142 anchors {
143 left: iconsItem.right
144 verticalCenter: parent.verticalCenter
145 }
146 width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
147 horizontalAlignment: Text.AlignHCenter
148
149 opacity: 1.0
150 font.family: "Noto Sans"
151 fontSize: "medium"
152 font.weight: Font.Light
153 color: root.color
154 Behavior on color { ColorAnimation { duration: LomiriAnimation.FastDuration; easing: LomiriAnimation.StandardEasing } }
155 }
156 }
157
158 Label {
159 id: indicatorName
160 objectName: "indicatorName"
161
162 anchors.top: mainItems.bottom
163 anchors.topMargin: units.gu(0.5)
164 anchors.horizontalCenter: parent.horizontalCenter
165 width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
166
167 text: identifier
168 fontSize: "x-small"
169 font.weight: Font.Light
170 horizontalAlignment: Text.AlignHCenter
171 opacity: 0
172 color: root.color
173 Behavior on color { ColorAnimation { duration: LomiriAnimation.FastDuration; easing: LomiriAnimation.StandardEasing } }
174 }
175
176 StateGroup {
177 objectName: "indicatorItemState"
178
179 states: [
180 State {
181 name: "minimised"
182 when: !expanded && ((icons && icons.length > 0) || leftLabel !== "" || rightLabel !== "")
183 PropertyChanges { target: indicatorName; opacity: 0}
184 },
185
186 State {
187 name: "minimised_fallback"
188 when: !expanded && (!icons || icons.length === 0) && leftLabel == "" && rightLabel == ""
189 PropertyChanges { target: indicatorName; opacity: 0}
190 PropertyChanges { target: d; useFallbackIcon: true }
191 },
192
193 State {
194 name: "expanded"
195 PropertyChanges { target: indicatorName; visible: true; opacity: 1}
196 PropertyChanges { target: mainItems; anchors.verticalCenterOffset: -units.gu(1) }
197 },
198
199 State {
200 name: "expanded_icon"
201 extend: "expanded"
202 when: expanded && (icons && icons.length > 0)
203 AnchorChanges { target: iconsItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
204 AnchorChanges { target: leftLabelItem; anchors.left: undefined; anchors.right: iconsItem.left }
205 PropertyChanges { target: leftLabelItem; opacity: 0 }
206 PropertyChanges { target: leftLabelItem; opacity: 0 }
207 PropertyChanges { target: rightLabelItem; opacity: 0 }
208 PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(iconsItem.width, indicatorName.width)) }
209 },
210
211 State {
212 name: "expanded_fallback"
213 extend: "expanded"
214 when: expanded && (!icons || icons.length === 0) && leftLabel == "" && rightLabel == ""
215 PropertyChanges { target: d; useFallbackIcon: true }
216 AnchorChanges { target: iconsItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
217 AnchorChanges { target: leftLabelItem; anchors.left: undefined; anchors.right: iconsItem.left }
218 PropertyChanges { target: leftLabelItem; opacity: 0 }
219 PropertyChanges { target: leftLabelItem; opacity: 0 }
220 PropertyChanges { target: rightLabelItem; opacity: 0 }
221 PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(iconsItem.width, indicatorName.width)) }
222 },
223
224 State {
225 name: "expanded_rightLabel"
226 extend: "expanded"
227 when: expanded && (!icons || icons.length === 0) && rightLabel !== ""
228 AnchorChanges { target: rightLabelItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
229 PropertyChanges { target: iconsItem; opacity: 0 }
230 PropertyChanges { target: leftLabelItem; opacity: 0 }
231 PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(rightLabelItem.width, indicatorName.width)) }
232 },
233
234 State {
235 name: "expanded_leftLabel"
236 extend: "expanded"
237 when: expanded && (!icons || icons.length === 0) && leftLabel !== ""
238 AnchorChanges { target: leftLabelItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
239 PropertyChanges { target: iconsItem; opacity: 0 }
240 PropertyChanges { target: rightLabelItem; opacity: 0 }
241 PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(leftLabelItem.width, indicatorName.width)) }
242 }
243 ]
244
245 transitions: [
246 Transition {
247 id: stateTransition
248 PropertyAction { target: d; property: "useFallbackIcon" }
249 AnchorAnimation {
250 targets: [ mainItems, iconsItem, leftLabelItem, rightLabelItem ]
251 duration: LomiriAnimation.SnapDuration; easing: LomiriAnimation.StandardEasing
252 }
253 PropertyAnimation {
254 targets: [ root, mainItems, iconsItem, leftLabelItem, rightLabelItem, indicatorName ]
255 properties: "width, opacity, anchors.verticalCenterOffset";
256 duration: LomiriAnimation.SnapDuration; easing: LomiriAnimation.StandardEasing
257 }
258 }
259 ]
260 }
261
262 rootActionState.onUpdated: {
263 if (rootActionState == undefined) {
264 title = "";
265 leftLabel = "";
266 rightLabel = "";
267 icons = undefined;
268 return;
269 }
270
271 title = rootActionState.title ? rootActionState.title : rootActionState.accessibleName;
272 leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
273 rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
274 icons = rootActionState.icons;
275 }
276
277 QtObject {
278 id: d
279
280 property bool useFallbackIcon: false
281 property var shouldIndicatorBeShown: undefined
282
283 onShouldIndicatorBeShownChanged: {
284 if (shouldIndicatorBeShown !== undefined) {
285 submenuAction.changeState(shouldIndicatorBeShown);
286 }
287 }
288 }
289
290 AyatanaMenuAction {
291 id: secondaryAction
292 model: menuModel
293 index: 0
294 name: rootActionState.secondaryAction
295 }
296
297 AyatanaMenuAction {
298 id: scrollAction
299 model: menuModel
300 index: 0
301 name: rootActionState.scrollAction
302 }
303
304 AyatanaMenuAction {
305 id: submenuAction
306 model: menuModel
307 index: 0
308 name: rootActionState.submenuAction
309 }
310
311 Binding {
312 target: d
313 property: "shouldIndicatorBeShown"
314 restoreMode: Binding.RestoreBinding
315 when: submenuAction.valid
316 value: root.selected && root.expanded
317 }
318}