2 * Copyright (C) 2013 Canonical, Ltd.
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.
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.
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/>.
18import Ubuntu.Components 0.1
19import Ubuntu.Gestures 0.1
20import Unity.Indicators 0.1 as Indicators
23import "../Components/ListItems"
29 property real openedHeight: units.gu(71)
30 property int panelHeight: units.gu(3)
31 property bool pinnedMode: true //should be set true if indicators menu can cover whole screen
32 property alias overFlowWidth: indicatorRow.overFlowWidth
33 property alias showAll: indicatorRow.showAll
34 // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
35 property string profile: "phone"
37 readonly property real hintValue: panelHeight + menuContent.headerHeight
38 readonly property int lockThreshold: openedHeight / 2
39 property bool fullyOpened: height == openedHeight
40 property bool partiallyOpened: height > panelHeight && !fullyOpened
41 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
42 property bool contentEnabled: true
43 property bool initalizeItem: true
44 readonly property alias content: menuContent
45 property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
47 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
48 // use its own values. Need to ask design about this.
49 showAnimation: StandardAnimation {
53 easing.type: Easing.OutCubic
55 // Re-size if we've changed the openHeight while shown.
57 if (indicators.shown) {
63 hideAnimation: StandardAnimation {
67 easing.type: Easing.OutCubic
71 onHeightChanged: updateRevealProgressState(indicators.height - panelHeight, true)
73 function updateRevealProgressState(revealProgress, enableRelease) {
74 if (!showAnimation.running && !hideAnimation.running) {
75 if (revealProgress === 0) {
76 indicators.state = "initial";
77 } else if (revealProgress > 0 && revealProgress <= hintValue) {
78 indicators.state = "hint";
79 } else if (revealProgress > hintValue && revealProgress < lockThreshold) {
80 indicators.state = "reveal";
81 } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
82 indicators.state = "locked";
86 if (enableRelease && revealProgress === 0) {
87 menuContent.releaseContent();
91 function calculateCurrentItem(xValue, useBuffer) {
95 var distanceFromRightEdge;
96 var bufferExceeded = false;
98 if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
101 If user drags the indicator handle bar down a distance hintValue or less, this is 0.
102 If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
103 Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
105 var verticalProgress =
106 MathUtils.clamp((indicators.height - handle.height - hintValue) /
107 (lockThreshold - hintValue), 0, 1);
110 Vertical velocity check. Don't change the indicator if we're moving too quickly.
112 var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
113 if (verticalSpeed >= 0.05 && !initalizeItem) {
118 Percentage of an indicator icon's width the user's press can stray horizontally from the
119 focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
120 go right a distance of half an icon's width before focus moves to the icon on the right
122 var maxBufferThreshold = 0.5;
125 To help users find the indicator of their choice while opening the indicators, we add logic to add a
126 left/right buffer to each icon so it is harder for the focus to be moved accidentally to another icon,
127 as the user moves their finger down, but yet allows them to switch indicator if they want.
128 This buffer is wider the further the user's finger is from the top of the screen.
130 var effectiveBufferThreshold = maxBufferThreshold * verticalProgress;
132 rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
133 // get the current delegate
134 currentItem = indicatorRow.row.itemAt(rowCoordinates.x, 0);
136 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
137 distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
138 if (currentItem != indicatorRow.currentItem) {
139 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
140 bufferExceeded = true;
142 if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
143 bufferExceeded = true;
144 } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
145 bufferExceeded = true;
148 if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItemIndex < 0 || indicatorRow.currentItem == null) {
149 indicatorRow.setCurrentItem(currentItem);
152 // need to re-init the distanceFromRightEdge for offset calculation
153 itemCoordinates = indicatorRow.row.mapToItem(indicatorRow.currentItem, rowCoordinates.x, 0);
154 distanceFromRightEdge = (indicatorRow.currentItem.width - itemCoordinates.x) / (indicatorRow.currentItem.width);
156 indicatorRow.currentItemOffset = 1 - (distanceFromRightEdge * 2);
157 } else if (initalizeItem) {
158 indicatorRow.setDefaultItem();
159 indicatorRow.currentItemOffset = 0;
161 initalizeItem = indicatorRow.currentItem == null;
168 bottom: handle.bottom
174 VerticalThinDivider {
177 topMargin: panelHeight
178 bottom: handle.bottom
179 right: indicators.left
182 source: "graphics/VerticalDivider.png"
186 id: visibleIndicators
191 objectName: "menuContent"
196 top: indicatorRow.bottom
199 indicatorsModel: visibleIndicators.model
200 clip: !indicators.fullyOpened
201 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
202 enabled: contentEnabled
204 //small shadow gradient at bottom of menu
209 bottom: parent.bottom
211 height: units.gu(0.5)
213 GradientStop { position: 0.0; color: "transparent" }
214 GradientStop { position: 1.0; color: "black" }
223 color: menuContent.backgroundColor
228 bottom: parent.bottom
230 height: Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
231 clip: height < handleImage.height
235 source: "graphics/handle.sci"
240 bottom: parent.bottom
243 MouseArea { //prevent clicks passing through
249 anchors.fill: indicatorRow
254 objectName: "indicatorRow"
259 height: indicators.panelHeight
260 indicatorsModel: visibleIndicators.model
261 state: indicators.state
262 unitProgress: indicators.unitProgress
266 anchors.fill: indicatorRow
267 direction: Direction.Downwards
274 initalizeItem = true;
275 updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
276 indicators.calculateCurrentItem(touchX, false);
278 indicators.state = "commit";
283 indicators.calculateCurrentItem(touchX, true);
285 onTouchSceneYChanged: {
286 updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
287 yVelocityCalculator.trackedPosition = touchSceneY;
293 target: showAnimation
295 if (showAnimation.running) {
296 indicators.state = "commit";
297 indicatorRow.currentItemOffset = 0;
303 target: hideAnimation
305 if (hideAnimation.running) {
306 indicators.state = "initial";
307 initalizeItem = true;
308 indicatorRow.currentItemOffset = 0;
315 property bool enableIndexChangeSignal: true
316 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
321 onCurrentMenuIndexChanged: {
322 var oldActive = d.enableIndexChangeSignal;
323 if (!oldActive) return;
324 d.enableIndexChangeSignal = false;
326 indicatorRow.setCurrentItemIndex(menuContent.currentMenuIndex);
328 d.enableIndexChangeSignal = oldActive;
334 onCurrentItemIndexChanged: {
335 var oldActive = d.enableIndexChangeSignal;
336 if (!oldActive) return;
337 d.enableIndexChangeSignal = false;
339 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex, fullyOpened || partiallyOpened);
341 d.enableIndexChangeSignal = oldActive;
344 // connections to the active drag handle
346 target: d.activeDragHandle
348 indicators.calculateCurrentItem(d.activeDragHandle.touchX, true);
350 onTouchSceneYChanged: {
351 yVelocityCalculator.trackedPosition = d.activeDragHandle.touchSceneY;
357 anchors.bottom: parent.bottom
358 // go beyond parent so that it stays reachable, at the top of the screen.
359 anchors.bottomMargin: pinnedMode ? 0 : -panelHeight
360 anchors.left: parent.left
361 anchors.right: parent.right
363 direction: Direction.Downwards
364 enabled: !indicators.shown && indicators.available
365 hintDisplacement: pinnedMode ? indicators.hintValue : 0
366 autoCompleteDragThreshold: maxTotalDragDistance / 2
368 maxTotalDragDistance: openedHeight - panelHeight
369 distanceThreshold: pinnedMode ? 0 : units.gu(3)
372 if (status === DirectionalDragArea.Recognized) {
373 menuContent.activateContent();
380 direction: Direction.Upwards
381 enabled: indicators.shown && indicators.available
382 hintDisplacement: indicators.hintValue
383 autoCompleteDragThreshold: maxTotalDragDistance / 6
385 maxTotalDragDistance: openedHeight - panelHeight
389 AxisVelocityCalculator {
390 id: yVelocityCalculator
400 target: indicatorRow;
401 y: pinnedMode ? 0 : panelHeight
405 if (d.activeDragHandle) {
406 calculateCurrentItem(d.activeDragHandle.touchX, false);
428 NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
432 Component.onCompleted: initialise();
433 function initialise() {
434 visibleIndicators.load(profile);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list