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