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"
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
31 property alias overFlowWidth: indicatorRow.overFlowWidth
32 property alias showAll: indicatorRow.showAll
34 property int hintValue
35 readonly property int lockThreshold: openedHeight / 2
36 property bool fullyOpened: height == openedHeight
37 property bool partiallyOpened: height > panelHeight && !fullyOpened
38 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
39 property bool contentEnabled: true
40 property bool initalizeItem: true
41 readonly property alias content: menuContent
43 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
44 // use its own values. Need to ask design about this.
45 showAnimation: StandardAnimation {
49 easing.type: Easing.OutCubic
51 // Re-size if we've changed the openHeight while shown.
53 if (indicators.shown) {
59 hideAnimation: StandardAnimation {
63 easing.type: Easing.OutCubic
67 onHeightChanged: updateRevealProgressState(indicators.height - panelHeight, true)
69 function updateRevealProgressState(revealProgress, enableRelease) {
70 if (!showAnimation.running && !hideAnimation.running) {
71 if (revealProgress === 0) {
72 indicators.state = "initial";
73 } else if (revealProgress > 0 && revealProgress <= hintValue) {
74 indicators.state = "hint";
75 } else if (revealProgress > hintValue && revealProgress < lockThreshold) {
76 indicators.state = "reveal";
77 } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
78 indicators.state = "locked";
82 if (enableRelease && revealProgress === 0) {
83 menuContent.releaseContent();
87 function calculateCurrentItem(xValue, useBuffer) {
91 var distanceFromRightEdge;
92 var bufferExceeded = false;
94 if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
97 If user drags the indicator handle bar down a distance hintValue or less, this is 0.
98 If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
99 Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
101 var verticalProgress =
102 MathUtils.clamp((indicators.height - handle.height - hintValue) /
103 (lockThreshold - hintValue), 0, 1);
106 Vertical velocity check. Don't change the indicator if we're moving too quickly.
108 var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
109 if (verticalSpeed >= 0.05 && !initalizeItem) {
114 Percentage of an indicator icon's width the user's press can stray horizontally from the
115 focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
116 go right a distance of half an icon's width before focus moves to the icon on the right
118 var maxBufferThreshold = 0.5;
121 To help users find the indicator of their choice while opening the indicators, we add logic to add a
122 left/right buffer to each icon so it is harder for the focus to be moved accidentally to another icon,
123 as the user moves their finger down, but yet allows them to switch indicator if they want.
124 This buffer is wider the further the user's finger is from the top of the screen.
126 var effectiveBufferThreshold = maxBufferThreshold * verticalProgress;
128 rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
129 // get the current delegate
130 currentItem = indicatorRow.row.childAt(rowCoordinates.x, 0);
131 if (currentItem && currentItem != indicatorRow.currentItem ) {
132 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
133 distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
134 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
135 bufferExceeded = true;
137 if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
138 bufferExceeded = true;
139 } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
140 bufferExceeded = true;
143 if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItem < 0 || indicatorRow.currentItem == null) {
144 indicatorRow.currentItem = currentItem;
146 } else if (!currentItem) {
147 indicatorRow.setDefaultItem();
149 initalizeItem = indicatorRow.currentItem == null;
156 bottom: handle.bottom
162 VerticalThinDivider {
165 topMargin: panelHeight
166 bottom: handle.bottom
167 right: indicators.left
170 source: "graphics/VerticalDivider.png"
175 objectName: "menuContent"
180 top: indicatorRow.bottom
183 indicatorsModel: indicatorsModel
184 clip: !indicators.fullyOpened
185 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
186 enabled: contentEnabled
187 visibleIndicators: indicatorRow.visibleIndicators
190 property bool enableIndexChangeSignal: true
192 target: enableIndexChangeSignal ? indicatorRow : null
193 onCurrentItemIndexChanged: {
194 var oldActive = enableIndexChangeSignal;
195 enableIndexChangeSignal = false;
197 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
199 enableIndexChangeSignal = oldActive;
203 //small shadow gradient at bottom of menu
208 bottom: parent.bottom
210 height: units.gu(0.5)
212 GradientStop { position: 0.0; color: "transparent" }
213 GradientStop { position: 1.0; color: "black" }
222 color: menuContent.backgroundColor
227 bottom: parent.bottom
230 clip: height < handleImage.height
232 function get_height() {
233 return Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0);
238 source: "graphics/handle.sci"
243 bottom: parent.bottom
246 MouseArea { //prevent clicks passing through
252 anchors.fill: indicatorRow
255 Indicators.IndicatorsModel {
258 Component.onCompleted: load()
263 objectName: "indicatorRow"
268 height: indicators.panelHeight
269 indicatorsModel: indicatorsModel
270 state: indicators.state
273 property bool enableIndexChangeSignal: true
275 target: enableIndexChangeSignal ? menuContent : null
276 onCurrentMenuIndexChanged: {
277 var oldActive = enableIndexChangeSignal;
278 enableIndexChangeSignal = false;
280 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
282 enableIndexChangeSignal = oldActive;
288 anchors.fill: indicatorRow
289 direction: Direction.Downwards
296 initalizeItem = true;
297 updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
298 indicators.calculateCurrentItem(touchX, false);
300 indicators.state = "commit";
305 indicators.calculateCurrentItem(touchX, true);
307 onTouchSceneYChanged: {
308 updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
309 yVelocityCalculator.trackedPosition = touchSceneY;
315 target: showAnimation
317 if (showAnimation.running) {
318 indicators.state = "commit";
324 target: hideAnimation
326 if (hideAnimation.running) {
327 indicators.state = "initial";
328 initalizeItem = true;
333 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
334 // connections to the active drag handle
336 target: activeDragHandle
338 indicators.calculateCurrentItem(activeDragHandle.touchX, true);
340 onTouchSceneYChanged: {
341 yVelocityCalculator.trackedPosition = activeDragHandle.touchSceneY;
347 anchors.bottom: parent.bottom
348 // go beyond parent so that it stays reachable, at the top of the screen.
349 anchors.bottomMargin: pinnedMode ? 0 : -panelHeight
350 anchors.left: parent.left
351 anchors.right: parent.right
353 direction: Direction.Downwards
354 enabled: !indicators.shown && indicators.available
355 hintDisplacement: pinnedMode ? indicators.hintValue : 0
356 autoCompleteDragThreshold: maxTotalDragDistance / 2
358 maxTotalDragDistance: openedHeight - panelHeight
359 distanceThreshold: pinnedMode ? 0 : units.gu(3)
362 if (status === DirectionalDragArea.Recognized) {
363 menuContent.activateContent();
370 direction: Direction.Upwards
371 enabled: indicators.shown && indicators.available
372 hintDisplacement: indicators.hintValue
373 autoCompleteDragThreshold: maxTotalDragDistance / 6
375 maxTotalDragDistance: openedHeight - panelHeight
379 AxisVelocityCalculator {
380 id: yVelocityCalculator
390 target: indicatorRow;
391 y: pinnedMode ? 0 : panelHeight
395 if (activeDragHandle) {
396 calculateCurrentItem(activeDragHandle.touchX, false);
418 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