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
35 readonly property real hintValue: panelHeight + menuContent.headerHeight
36 readonly property int lockThreshold: openedHeight / 2
37 property bool fullyOpened: height == openedHeight
38 property bool partiallyOpened: height > panelHeight && !fullyOpened
39 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
40 property bool contentEnabled: true
41 property bool initalizeItem: true
42 readonly property alias content: menuContent
43 property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
45 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
46 // use its own values. Need to ask design about this.
47 showAnimation: StandardAnimation {
51 easing.type: Easing.OutCubic
53 // Re-size if we've changed the openHeight while shown.
55 if (indicators.shown) {
61 hideAnimation: StandardAnimation {
65 easing.type: Easing.OutCubic
69 onHeightChanged: updateRevealProgressState(indicators.height - panelHeight, true)
71 function updateRevealProgressState(revealProgress, enableRelease) {
72 if (!showAnimation.running && !hideAnimation.running) {
73 if (revealProgress === 0) {
74 indicators.state = "initial";
75 } else if (revealProgress > 0 && revealProgress <= hintValue) {
76 indicators.state = "hint";
77 } else if (revealProgress > hintValue && revealProgress < lockThreshold) {
78 indicators.state = "reveal";
79 } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
80 indicators.state = "locked";
84 if (enableRelease && revealProgress === 0) {
85 menuContent.releaseContent();
89 function calculateCurrentItem(xValue, useBuffer) {
93 var distanceFromRightEdge;
94 var bufferExceeded = false;
96 if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
99 If user drags the indicator handle bar down a distance hintValue or less, this is 0.
100 If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
101 Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
103 var verticalProgress =
104 MathUtils.clamp((indicators.height - handle.height - hintValue) /
105 (lockThreshold - hintValue), 0, 1);
108 Vertical velocity check. Don't change the indicator if we're moving too quickly.
110 var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
111 if (verticalSpeed >= 0.05 && !initalizeItem) {
116 Percentage of an indicator icon's width the user's press can stray horizontally from the
117 focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
118 go right a distance of half an icon's width before focus moves to the icon on the right
120 var maxBufferThreshold = 0.5;
123 To help users find the indicator of their choice while opening the indicators, we add logic to add a
124 left/right buffer to each icon so it is harder for the focus to be moved accidentally to another icon,
125 as the user moves their finger down, but yet allows them to switch indicator if they want.
126 This buffer is wider the further the user's finger is from the top of the screen.
128 var effectiveBufferThreshold = maxBufferThreshold * verticalProgress;
130 rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
131 // get the current delegate
132 currentItem = indicatorRow.row.itemAt(rowCoordinates.x, 0);
134 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
135 distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
136 if (currentItem != indicatorRow.currentItem) {
137 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
138 bufferExceeded = true;
140 if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
141 bufferExceeded = true;
142 } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
143 bufferExceeded = true;
146 if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItemIndex < 0 || indicatorRow.currentItem == null) {
147 indicatorRow.setCurrentItem(currentItem);
150 // need to re-init the distanceFromRightEdge for offset calculation
151 itemCoordinates = indicatorRow.row.mapToItem(indicatorRow.currentItem, rowCoordinates.x, 0);
152 distanceFromRightEdge = (indicatorRow.currentItem.width - itemCoordinates.x) / (indicatorRow.currentItem.width);
154 indicatorRow.currentItemOffset = 1 - (distanceFromRightEdge * 2);
155 } else if (initalizeItem) {
156 indicatorRow.setDefaultItem();
157 indicatorRow.currentItemOffset = 0;
159 initalizeItem = indicatorRow.currentItem == null;
166 bottom: handle.bottom
172 VerticalThinDivider {
175 topMargin: panelHeight
176 bottom: handle.bottom
177 right: indicators.left
180 source: "graphics/VerticalDivider.png"
184 id: visibleIndicators
189 objectName: "menuContent"
194 top: indicatorRow.bottom
197 indicatorsModel: visibleIndicators.model
198 clip: !indicators.fullyOpened
199 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
200 enabled: contentEnabled
202 //small shadow gradient at bottom of menu
207 bottom: parent.bottom
209 height: units.gu(0.5)
211 GradientStop { position: 0.0; color: "transparent" }
212 GradientStop { position: 1.0; color: "black" }
221 color: menuContent.backgroundColor
226 bottom: parent.bottom
228 height: Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
229 clip: height < handleImage.height
233 source: "graphics/handle.sci"
238 bottom: parent.bottom
241 MouseArea { //prevent clicks passing through
247 anchors.fill: indicatorRow
252 objectName: "indicatorRow"
257 height: indicators.panelHeight
258 indicatorsModel: visibleIndicators.model
259 state: indicators.state
260 unitProgress: indicators.unitProgress
264 anchors.fill: indicatorRow
265 direction: Direction.Downwards
272 initalizeItem = true;
273 updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
274 indicators.calculateCurrentItem(touchX, false);
276 indicators.state = "commit";
281 indicators.calculateCurrentItem(touchX, true);
283 onTouchSceneYChanged: {
284 updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
285 yVelocityCalculator.trackedPosition = touchSceneY;
291 target: showAnimation
293 if (showAnimation.running) {
294 indicators.state = "commit";
295 indicatorRow.currentItemOffset = 0;
301 target: hideAnimation
303 if (hideAnimation.running) {
304 indicators.state = "initial";
305 initalizeItem = true;
306 indicatorRow.currentItemOffset = 0;
313 property bool enableIndexChangeSignal: true
314 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
319 onCurrentMenuIndexChanged: {
320 var oldActive = d.enableIndexChangeSignal;
321 if (!oldActive) return;
322 d.enableIndexChangeSignal = false;
324 indicatorRow.setCurrentItemIndex(menuContent.currentMenuIndex);
326 d.enableIndexChangeSignal = oldActive;
332 onCurrentItemIndexChanged: {
333 var oldActive = d.enableIndexChangeSignal;
334 if (!oldActive) return;
335 d.enableIndexChangeSignal = false;
337 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex, fullyOpened || partiallyOpened);
339 d.enableIndexChangeSignal = oldActive;
342 // connections to the active drag handle
344 target: d.activeDragHandle
346 indicators.calculateCurrentItem(d.activeDragHandle.touchX, true);
348 onTouchSceneYChanged: {
349 yVelocityCalculator.trackedPosition = d.activeDragHandle.touchSceneY;
355 anchors.bottom: parent.bottom
356 // go beyond parent so that it stays reachable, at the top of the screen.
357 anchors.bottomMargin: pinnedMode ? 0 : -panelHeight
358 anchors.left: parent.left
359 anchors.right: parent.right
361 direction: Direction.Downwards
362 enabled: !indicators.shown && indicators.available
363 hintDisplacement: pinnedMode ? indicators.hintValue : 0
364 autoCompleteDragThreshold: maxTotalDragDistance / 2
366 maxTotalDragDistance: openedHeight - panelHeight
367 distanceThreshold: pinnedMode ? 0 : units.gu(3)
370 if (status === DirectionalDragArea.Recognized) {
371 menuContent.activateContent();
378 direction: Direction.Upwards
379 enabled: indicators.shown && indicators.available
380 hintDisplacement: indicators.hintValue
381 autoCompleteDragThreshold: maxTotalDragDistance / 6
383 maxTotalDragDistance: openedHeight - panelHeight
387 AxisVelocityCalculator {
388 id: yVelocityCalculator
398 target: indicatorRow;
399 y: pinnedMode ? 0 : panelHeight
403 if (d.activeDragHandle) {
404 calculateCurrentItem(d.activeDragHandle.touchX, false);
426 NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
430 Component.onCompleted: initialise();
431 function initialise() {
432 visibleIndicators.load();
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