on a142f21 help sign in
unity8/qml/Dash/DashNavigationButton.qml
233 lines 8.8 kB history raw
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU 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 General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17import QtQuick 2.2
18import Ubuntu.Components 1.1
20AbstractButton {
21 id: root
22 objectName: "dashNavigation"
24 // Set by parent
25 property var scope: null
26 property var scopeStyle: null
27 property color foregroundColor: Theme.palette.normal.baseText
28 property bool isAltNavigation: false
29 property bool showDivider: false
31 // Used by parent
32 readonly property var currentNavigation: scope && scope[hasNavigation] ? getNavigation(scope[currentNavigationId]) : null
33 readonly property alias listView: navigationListView
34 readonly property bool inverseMousePressed: inverseMouseArea.pressed
35 property bool showList: false
37 // Internal
38 // Are we drilling down the tree or up?
39 property bool isGoingBack: false
40 readonly property string hasNavigation: isAltNavigation ? "hasAltNavigation" : "hasNavigation"
41 readonly property string currentNavigationId: isAltNavigation ? "currentAltNavigationId" : "currentNavigationId"
42 function getNavigation(navId) {
43 if (isAltNavigation) {
44 return scope.getAltNavigation(navId);
45 } else {
46 return scope.getNavigation(navId);
47 }
48 }
50 visible: root.currentNavigation != null
52 onClicked: {
53 navigationListView.updateMaxHeight();
54 root.showList = !root.showList;
55 }
57 Label {
58 anchors.fill: parent
59 anchors.margins: units.gu(2)
60 anchors.rightMargin: units.gu(5)
61 verticalAlignment: Text.AlignVCenter
62 text: root.currentNavigation ? root.currentNavigation.label : ""
63 color: root.foregroundColor
64 elide: Text.ElideRight
65 maximumLineCount: 1
66 }
68 Icon {
69 anchors.verticalCenter: parent.verticalCenter
70 anchors.right: parent.right
71 anchors.rightMargin: units.gu(2)
72 name: showList ? "up" : "down"
73 height: units.gu(2)
74 width: height
75 color: root.foregroundColor
76 }
78 // navigationListView is outside root
79 ListView {
80 id: navigationListView
81 objectName: "navigationListView"
82 visible: height > 0
83 orientation: ListView.Horizontal
84 interactive: false
85 clip: root.width != windowWidth
86 model: ListModel {
87 id: navigationModel
88 // We have two roles
89 // navigationId: the navigation id of the navigation the list represents
90 // nullifyNavigation: overrides navigationId to be null
91 // This is used to "clear" the delegate when going "right" on the tree
92 }
93 anchors.top: root.bottom
94 property int maxHeight: -1
95 Component.onCompleted: updateMaxHeight();
96 function updateMaxHeight()
97 {
98 maxHeight = (windowHeight - mapToItem(null, 0, 0).y) - units.gu(8);
99 }
100 property int prevHeight: maxHeight
101 height: currentItem ? currentItem.height : maxHeight
102 onHeightChanged: {
103 if (root.showList) {
104 prevHeight = currentItem.desiredHeight;
105 }
106 }
107 highlightMoveDuration: UbuntuAnimation.FastDuration
108 delegate: DashNavigationList {
109 objectName: "navigation" + index
110 visible: height > 0
111 width: navigationListView.width
112 scopeStyle: root.scopeStyle
113 foregroundColor: root.foregroundColor
114 property real desiredHeight: {
115 if (root.showList) {
116 if (navigation && navigation.loaded && x == navigationListView.contentX)
117 {
118 navigationListView.updateMaxHeight();
119 return Math.min(implicitHeight, navigationListView.maxHeight);
120 } else {
121 return navigationListView.prevHeight;
122 }
123 } else {
124 return 0;
125 }
126 }
127 height: desiredHeight
128 navigation: (nullifyNavigation || !scope) ? null : getNavigation(navigationId)
129 currentNavigation: root.currentNavigation
130 onEnterNavigation: {
131 scope.setNavigationState(newNavigationId, isAltNavigation);
132 // We only need to add a new item to the model
133 // if we have children, otherwise just load it
134 if (hasChildren) {
135 isGoingBack = false;
136 navigationModel.append({"navigationId": newNavigationId, "nullifyNavigation": false});
137 navigationListView.currentIndex++;
138 } else {
139 showList = false;
140 }
141 }
142 onGoBackToParentClicked: {
143 if (navigationListView.currentIndex == 0) {
144 // This can happen if we jumped to the non root of a deep tree and the user
145 // is now going back, create space in the list for the list to move "left"
146 var aux = navigationListView.highlightMoveDuration;
147 navigationListView.highlightMoveDuration = 0;
148 navigationModel.insert(0, {"navigationId": navigation.parentNavigationId, "nullifyNavigation": false});
149 navigationListView.currentIndex = navigationListView.currentIndex + 1;
150 navigationListView.contentX = width * navigationListView.currentIndex;
151 navigationListView.highlightMoveDuration = aux;
152 }
154 scope.setNavigationState(navigation.parentNavigationId, isAltNavigation);
155 isGoingBack = true;
156 navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", false);
157 navigationListView.currentIndex--;
158 }
159 onAllNavigationClicked: {
160 showList = false;
161 if (root.currentNavigation.parentNavigationId == navigation.navigationId) {
162 // For leaves we have to go to the parent too
163 scope.setNavigationState(root.currentNavigation.parentNavigationId, isAltNavigation);
164 }
165 }
166 }
167 onContentXChanged: {
168 if (navigationListView.highlightMoveDuration == 0)
169 return;
171 if (contentX == width * navigationListView.currentIndex) {
172 if (isGoingBack) {
173 navigationModel.remove(navigationListView.currentIndex + 1);
174 } else {
175 navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", true);
176 }
177 }
178 }
179 }
181 Image {
182 anchors {
183 top: navigationListView.bottom
184 left: navigationListView.left
185 right: navigationListView.right
186 }
187 fillMode: Image.Stretch
188 source: "graphics/navigation_shadow.png"
189 visible: root.showList
190 }
192 property bool isFirstLoad: false
193 onScopeChanged: {
194 navigationModel.clear();
195 isFirstLoad = true;
196 }
197 function setNewNavigation() {
198 if (isFirstLoad && currentNavigation && currentNavigation.loaded) {
199 isFirstLoad = false;
200 if (currentNavigation.count > 0) {
201 navigationModel.append({"navigationId": scope[currentNavigationId], "nullifyNavigation": false});
202 } else {
203 navigationModel.append({"navigationId": currentNavigation.parentNavigationId, "nullifyNavigation": false});
204 }
205 }
206 }
207 Connections {
208 target: currentNavigation
209 onLoadedChanged: setNewNavigation();
210 }
211 onCurrentNavigationChanged: setNewNavigation();
213 InverseMouseArea {
214 id: inverseMouseArea
215 anchors.fill: navigationListView
216 enabled: root.showList
217 onPressed: root.showList = false
218 }
220 Rectangle {
221 visible: root.showDivider
222 anchors {
223 top: parent.top
224 topMargin: units.dp(1)
225 bottom: parent.bottom
226 left: parent.right
227 leftMargin: -units.dp(0.5)
228 }
229 width: units.dp(1)
230 color: root.foregroundColor
231 opacity: 0.2
232 }