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
22import "../Components/ListItems"
23import "../Components/Math.js" as MathLocal
28 property real openedHeight: units.gu(71)
29 property int panelHeight: units.gu(3)
30 property bool pinnedMode: true //should be set true if indicators menu can cover whole screen
32 property int hintValue
33 readonly property int lockThreshold: openedHeight / 2
34 property bool fullyOpened: height == openedHeight
35 property bool partiallyOpened: height > panelHeight && !fullyOpened
36 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
37 property bool contentEnabled: true
38 readonly property alias content: menuContent
40 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
41 // use its own values. Need to ask design about this.
42 showAnimation: StandardAnimation {
46 easing.type: Easing.OutCubic
48 // Re-size if we've changed the openHeight while shown.
50 if (indicators.shown) {
56 hideAnimation: StandardAnimation {
60 easing.type: Easing.OutCubic
66 // need to use handle.get_height(). As the handle height depends on indicators.height changes (but this is called first!)
67 var revealProgress = indicators.height - panelHeight
68 if (!showAnimation.running && !hideAnimation.running) {
69 if (revealProgress == 0) {
70 indicators.state = "initial";
71 } else if (revealProgress <= hintValue) {
72 indicators.state = "hint";
73 } else if (revealProgress > hintValue && revealProgress < lockThreshold) {
74 indicators.state = "reveal";
75 } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
76 indicators.state = "locked";
80 if (revealProgress == 0) {
81 menuContent.releaseContent();
85 function calculateCurrentItem(xValue, useBuffer) {
89 var distanceFromRightEdge;
90 var bufferExceeded = false;
92 if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
95 If user drags the indicator handle bar down a distance hintValue or less, this is 0.
96 If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
97 Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
99 var verticalProgress =
100 MathLocal.clamp((indicators.height - handle.height - hintValue) /
101 (lockThreshold - hintValue), 0, 1);
104 Vertical velocity check. Don't change the indicator if we're moving too quickly.
106 var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
107 if (verticalSpeed >= 0.05 && indicatorRow.currentItem!=null) {
112 Percentage of an indicator icon's width the user's press can stray horizontally from the
113 focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
114 go right a distance of half an icon's width before focus moves to the icon on the right
116 var maxBufferThreshold = 0.5;
119 To help users find the indicator of their choice while opening the indicators, we add logic to add a
120 left/right buffer to each icon so it is harder for the focus to be moved accidentally to another icon,
121 as the user moves their finger down, but yet allows them to switch indicator if they want.
122 This buffer is wider the further the user's finger is from the top of the screen.
124 var effectiveBufferThreshold = maxBufferThreshold * verticalProgress;
126 rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
127 // get the current delegate
128 currentItem = indicatorRow.row.childAt(rowCoordinates.x, 0);
129 if (currentItem && currentItem != indicatorRow.currentItem ) {
130 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
131 distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
132 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
133 bufferExceeded = true;
135 if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
136 bufferExceeded = true;
137 } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
138 bufferExceeded = true;
141 if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItem < 0 || indicatorRow.currentItem == null) {
142 indicatorRow.currentItem = currentItem;
144 } else if (!currentItem) {
145 indicatorRow.setDefaultItem();
153 bottom: handle.bottom
159 VerticalThinDivider {
162 topMargin: panelHeight
163 bottom: handle.bottom
164 right: indicators.left
167 source: "graphics/VerticalDivider.png"
172 objectName: "menuContent"
177 top: indicatorRow.bottom
180 indicatorsModel: indicatorsModel
181 clip: !indicators.fullyOpened
182 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
183 enabled: contentEnabled
184 visibleIndicators: indicatorRow.visibleIndicators
187 property bool enableIndexChangeSignal: true
189 target: enableIndexChangeSignal ? indicatorRow : null
190 onCurrentItemIndexChanged: {
191 var oldActive = enableIndexChangeSignal;
192 enableIndexChangeSignal = false;
194 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
196 enableIndexChangeSignal = oldActive;
200 //small shadow gradient at bottom of menu
205 bottom: parent.bottom
207 height: units.gu(0.5)
209 GradientStop { position: 0.0; color: "transparent" }
210 GradientStop { position: 1.0; color: "black" }
219 color: menuContent.backgroundColor
224 bottom: parent.bottom
227 clip: height < handleImage.height
229 function get_height() {
230 return Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0);
235 source: "graphics/handle.sci"
240 bottom: parent.bottom
243 MouseArea { //prevent clicks passing through
249 anchors.fill: indicatorRow
252 IndicatorsDataModel {
258 objectName: "indicatorRow"
263 height: indicators.panelHeight
264 indicatorsModel: indicatorsModel
265 state: indicators.state
268 property bool enableIndexChangeSignal: true
270 target: enableIndexChangeSignal ? menuContent : null
271 onCurrentMenuIndexChanged: {
272 var oldActive = enableIndexChangeSignal;
273 enableIndexChangeSignal = false;
275 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
277 enableIndexChangeSignal = oldActive;
283 target: showAnimation
285 if (showAnimation.running) {
286 indicators.state = "commit";
292 target: hideAnimation
294 if (hideAnimation.running) {
295 indicators.state = "initial";
296 indicatorRow.currentItem = null;
301 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
302 // connections to the active drag handle
304 target: activeDragHandle
306 indicators.calculateCurrentItem(activeDragHandle.touchX, true);
308 onTouchSceneYChanged: {
309 yVelocityCalculator.trackedPosition = activeDragHandle.touchSceneY;
315 anchors.bottom: parent.bottom
316 // go beyond parent so that it stays reachable, at the top of the screen.
317 anchors.bottomMargin: pinnedMode ? 0 : -panelHeight
318 anchors.left: parent.left
319 anchors.right: parent.right
321 direction: Direction.Downwards
322 enabled: !indicators.shown && indicators.available
323 hintDisplacement: pinnedMode ? indicators.hintValue : 0
324 autoCompleteDragThreshold: maxTotalDragDistance / 2
326 maxTotalDragDistance: openedHeight - panelHeight
327 distanceThreshold: pinnedMode ? 0 : units.gu(3)
330 if (status === DirectionalDragArea.Recognized) {
331 menuContent.activateContent();
338 direction: Direction.Upwards
339 enabled: indicators.shown && indicators.available
340 hintDisplacement: indicators.hintValue
341 autoCompleteDragThreshold: maxTotalDragDistance / 6
343 maxTotalDragDistance: openedHeight - panelHeight
347 AxisVelocityCalculator {
348 id: yVelocityCalculator
358 target: indicatorRow;
359 y: pinnedMode ? 0 : panelHeight
363 if (activeDragHandle) {
364 calculateCurrentItem(activeDragHandle.touchX, false);
386 NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
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