on aa5da49 help sign in
unity8/qml/Dash/DashNavigationButton.qml
221 lines 8.0 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 property bool showList: false
36 // Internal
37 // Are we drilling down the tree or up?
38 property bool isGoingBack: false
39 readonly property string hasNavigation: isAltNavigation ? "hasAltNavigation" : "hasNavigation"
40 readonly property string currentNavigationId: isAltNavigation ? "currentAltNavigationId" : "currentNavigationId"
41 function getNavigation(navId) {
42 if (isAltNavigation) {
43 return scope.getAltNavigation(navId);
44 } else {
45 return scope.getNavigation(navId);
46 }
47 }
49 visible: root.currentNavigation != null
51 onClicked: {
52 navigationListView.updateMaxHeight();
53 root.showList = !root.showList;
54 }
56 Label {
57 anchors.fill: parent
58 anchors.margins: units.gu(2)
59 verticalAlignment: Text.AlignVCenter
60 text: root.currentNavigation ? root.currentNavigation.label : ""
61 color: root.foregroundColor
62 }
64 Icon {
65 anchors.verticalCenter: parent.verticalCenter
66 anchors.right: parent.right
67 anchors.rightMargin: units.gu(2)
68 name: showList ? "up" : "down"
69 height: units.gu(2)
70 width: height
71 color: root.foregroundColor
72 }
74 // navigationListView is outside root
75 ListView {
76 id: navigationListView
77 objectName: "navigationListView"
78 orientation: ListView.Horizontal
79 interactive: false
80 clip: root.width != windowWidth
81 model: ListModel {
82 id: navigationModel
83 // We have two roles
84 // navigationId: the navigation id of the navigation the list represents
85 // nullifyNavigation: overrides navigationId to be null
86 // This is used to "clear" the delegate when going "right" on the tree
87 }
88 anchors.top: root.bottom
89 property int maxHeight: -1
90 Component.onCompleted: updateMaxHeight();
91 function updateMaxHeight()
92 {
93 maxHeight = (windowHeight - mapToItem(null, 0, 0).y) - units.gu(8);
94 }
95 property int prevHeight: maxHeight
96 height: currentItem ? currentItem.height : maxHeight
97 onHeightChanged: {
98 if (root.showList) {
99 prevHeight = currentItem.desiredHeight;
100 }
101 }
102 highlightMoveDuration: UbuntuAnimation.FastDuration
103 delegate: DashNavigationList {
104 objectName: "navigation" + index
105 visible: height != 0
106 width: navigationListView.width
107 scopeStyle: root.scopeStyle
108 foregroundColor: root.foregroundColor
109 property real desiredHeight: {
110 if (root.showList) {
111 if (navigation && navigation.loaded && x == navigationListView.contentX)
112 {
113 navigationListView.updateMaxHeight();
114 return Math.min(implicitHeight, navigationListView.maxHeight);
115 } else {
116 return navigationListView.prevHeight;
117 }
118 } else {
119 return 0;
120 }
121 }
122 height: desiredHeight
123 navigation: (nullifyNavigation || !scope) ? null : getNavigation(navigationId)
124 currentNavigation: root.currentNavigation
125 onEnterNavigation: {
126 scope.setNavigationState(newNavigationId, isAltNavigation);
127 // We only need to add a new item to the model
128 // if we have children, otherwise just load it
129 if (hasChildren) {
130 isGoingBack = false;
131 navigationModel.append({"navigationId": newNavigationId, "nullifyNavigation": false});
132 navigationListView.currentIndex++;
133 } else {
134 showList = false;
135 }
136 }
137 onGoBackToParentClicked: {
138 scope.setNavigationState(navigation.parentNavigationId, isAltNavigation);
139 isGoingBack = true;
140 navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", false);
141 navigationListView.currentIndex--;
142 }
143 onAllNavigationClicked: {
144 showList = false;
145 if (root.currentNavigation.parentNavigationId == navigation.navigationId) {
146 // For leaves we have to go to the parent too
147 scope.setNavigationState(root.currentNavigation.parentNavigationId, isAltNavigation);
148 }
149 }
150 }
151 onContentXChanged: {
152 if (contentX == width * navigationListView.currentIndex) {
153 if (isGoingBack) {
154 navigationModel.remove(navigationListView.currentIndex + 1);
155 } else {
156 navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", true);
157 }
158 }
159 }
160 }
162 Image {
163 anchors {
164 top: navigationListView.bottom
165 left: navigationListView.left
166 right: navigationListView.right
167 }
168 fillMode: Image.Stretch
169 source: "graphics/navigation_shadow.png"
170 visible: root.showList
171 }
173 onScopeChanged: {
174 navigationModel.clear();
175 if (scope && scope[hasNavigation]) {
176 navigationModel.append({"navigationId": scope[currentNavigationId], "nullifyNavigation": false});
177 }
178 }
180 Connections {
181 target: scope
182 // This is duplicated since we can't have something based on the dynamic hasNavigation string property
183 onHasNavigationChanged: {
184 if (!root.isAltNavigation) {
185 if (scope.hasNavigation) {
186 navigationModel.append({"navigationId": scope.currentNavigationId, "nullifyNavigation": false});
187 } else {
188 navigationModel.clear();
189 }
190 }
191 }
192 onHasAltNavigationChanged: {
193 if (root.isAltNavigation) {
194 if (scope.hasAltNavigation) {
195 navigationModel.append({"navigationId": scope.currentAltNavigationId, "nullifyNavigation": false});
196 } else {
197 navigationModel.clear();
198 }
199 }
200 }
201 }
203 InverseMouseArea {
204 anchors.fill: navigationListView
205 enabled: root.showList
206 onClicked: root.showList = false
207 }
209 Rectangle {
210 visible: root.showDivider
211 anchors {
212 top: parent.top
213 bottom: parent.bottom
214 left: parent.right
215 leftMargin: -units.dp(1)
216 }
217 width: units.dp(2)
218 color: root.foregroundColor
219 opacity: 0.3
220 }