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