2 * Copyright (C) 2014-2016 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 Unity.Application 0.1 // For Mir singleton
19import Ubuntu.Components 1.3
22import "../Components/PanelState"
27 property Item target // appDelegate
28 property int stageWidth
29 property int stageHeight
30 property real buttonsWidth: 0
31 property PanelState panelState
33 readonly property bool dragging: priv.dragging
35 signal fakeMaximizeAnimationRequested(real amount)
36 signal fakeMaximizeLeftAnimationRequested(real amount)
37 signal fakeMaximizeRightAnimationRequested(real amount)
38 signal fakeMaximizeTopLeftAnimationRequested(real amount)
39 signal fakeMaximizeTopRightAnimationRequested(real amount)
40 signal fakeMaximizeBottomLeftAnimationRequested(real amount)
41 signal fakeMaximizeBottomRightAnimationRequested(real amount)
42 signal stopFakeAnimation()
44 property QtObject priv: QtObject {
45 property real distanceX
46 property real distanceY
47 property bool dragging
49 readonly property int triggerArea: units.gu(8)
50 property bool nearLeftEdge: target.maximizedLeft
51 property bool nearTopEdge: target.maximized
52 property bool nearRightEdge: target.maximizedRight
53 property bool nearTopLeftCorner: target.maximizedTopLeft
54 property bool nearTopRightCorner: target.maximizedTopRight
55 property bool nearBottomLeftCorner: target.maximizedBottomLeft
56 property bool nearBottomRightCorner: target.maximizedBottomRight
58 property Timer mouseDownTimer: Timer {
60 onTriggered: Mir.cursorName = "grabbing"
63 function resetEdges() {
65 nearRightEdge = false;
67 nearTopLeftCorner = false;
68 nearTopRightCorner = false;
69 nearBottomLeftCorner = false;
70 nearBottomRightCorner = false;
73 // return the progress of mouse pointer movement from 0 to 1 within a corner square of the screen
74 // 0 -> before the mouse enters the square
75 // 1 -> mouse is in the outer corner
76 // a is the corner, b is the mouse pos
77 function progressInCorner(ax, ay, bx, by) {
78 // distance of two points, a and b, in pixels
79 var distance = Math.sqrt(Math.pow(bx-ax, 2) + Math.pow(by-ay, 2));
80 // length of the triggerArea square diagonal
81 var diagLength = Math.sqrt(2 * priv.triggerArea * priv.triggerArea);
82 var ratio = 1 - (distance / diagLength);
83 return bx > 0 && bx <= stageWidth && by > 0 && by <= stageHeight ? ratio : 1; // everything "outside" of our square from the center is 1
85 property real progress: 0
88 function handlePressedChanged(pressed, pressedButtons, mouseX, mouseY) {
89 if (pressed && pressedButtons === Qt.LeftButton) {
90 var pos = mapToItem(target, mouseX, mouseY);
91 if (target.anyMaximized) {
92 // keep distanceX relative to the normal window width minus the window control buttons (+spacing)
93 // so that dragging it back doesn't make the window jump around to weird positions, away from the mouse pointer
94 priv.distanceX = MathUtils.clampAndProject(pos.x, 0, target.width, buttonsWidth, target.normalWidth);
95 priv.distanceY = MathUtils.clampAndProject(pos.y, 0, target.height, 0, target.normalHeight);
97 priv.distanceX = pos.x;
98 priv.distanceY = pos.y;
101 priv.dragging = true;
102 priv.mouseDownTimer.start();
104 priv.dragging = false;
105 priv.mouseDownTimer.stop();
110 function handlePositionChanged(mouse, sensingPoints) {
112 priv.mouseDownTimer.stop();
113 Mir.cursorName = "grabbing";
115 // restore from maximized when dragging away from edges/corners; guard against inadvertent changes when going into maximized state
116 if (target.anyMaximized && !target.windowedTransitionRunning) {
118 target.requestRestore();
121 var pos = mapToItem(target.parent, mouse.x, mouse.y);
122 // Use integer coordinate values to ensure that target is left in a pixel-aligned
123 // position. Mouse movement could have subpixel precision, yielding a fractional
125 target.windowedX = Math.round(pos.x - priv.distanceX);
126 target.windowedY = Math.round(Math.max(pos.y - priv.distanceY, panelState.panelHeight));
128 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
129 if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < panelState.panelHeight + priv.triggerArea
130 && target.canBeCornerMaximized) { // top left
131 priv.progress = priv.progressInCorner(0, panelState.panelHeight, sensingPoints.topLeft.x, sensingPoints.topLeft.y);
133 priv.nearTopLeftCorner = true;
134 root.fakeMaximizeTopLeftAnimationRequested(priv.progress);
135 } else if (sensingPoints.topRight.x > stageWidth - priv.triggerArea && sensingPoints.topRight.y < panelState.panelHeight + priv.triggerArea
136 && target.canBeCornerMaximized) { // top right
137 priv.progress = priv.progressInCorner(stageWidth, panelState.panelHeight, sensingPoints.topRight.x, sensingPoints.topRight.y);
139 priv.nearTopRightCorner = true;
140 root.fakeMaximizeTopRightAnimationRequested(priv.progress);
141 } else if (sensingPoints.bottomLeft.x < priv.triggerArea && sensingPoints.bottomLeft.y > stageHeight - priv.triggerArea
142 && target.canBeCornerMaximized) { // bottom left
143 priv.progress = priv.progressInCorner(0, stageHeight, sensingPoints.bottomLeft.x, sensingPoints.bottomLeft.y);
145 priv.nearBottomLeftCorner = true;
146 root.fakeMaximizeBottomLeftAnimationRequested(priv.progress);
147 } else if (sensingPoints.bottomRight.x > stageWidth - priv.triggerArea && sensingPoints.bottomRight.y > stageHeight - priv.triggerArea
148 && target.canBeCornerMaximized) { // bottom right
149 priv.progress = priv.progressInCorner(stageWidth, stageHeight, sensingPoints.bottomRight.x, sensingPoints.bottomRight.y);
151 priv.nearBottomRightCorner = true;
152 root.fakeMaximizeBottomRightAnimationRequested(priv.progress);
153 } else if (sensingPoints.left.x < priv.triggerArea && target.canBeMaximizedLeftRight) { // left
154 priv.progress = MathUtils.clampAndProject(sensingPoints.left.x, priv.triggerArea, 0, 0, 1);
156 priv.nearLeftEdge = true;
157 root.fakeMaximizeLeftAnimationRequested(priv.progress);
158 } else if (sensingPoints.right.x > stageWidth - priv.triggerArea && target.canBeMaximizedLeftRight) { // right
159 priv.progress = MathUtils.clampAndProject(sensingPoints.right.x, stageWidth - priv.triggerArea, stageWidth, 0, 1);
161 priv.nearRightEdge = true;
162 root.fakeMaximizeRightAnimationRequested(priv.progress);
163 } else if (sensingPoints.top.y < panelState.panelHeight + priv.triggerArea && target.canBeMaximized) { // top
164 priv.progress = MathUtils.clampAndProject(sensingPoints.top.y, panelState.panelHeight + priv.triggerArea, 0, 0, 1);
166 priv.nearTopEdge = true;
167 root.fakeMaximizeAnimationRequested(priv.progress);
168 } else if (priv.nearLeftEdge || priv.nearRightEdge || priv.nearTopEdge || priv.nearTopLeftCorner || priv.nearTopRightCorner ||
169 priv.nearBottomLeftCorner || priv.nearBottomRightCorner) {
172 root.stopFakeAnimation();
178 function handleReleased(touchMode) {
183 if ((target.state == "normal" || target.state == "restored") && priv.progress == 0) {
184 // save the x/y to restore to
185 target.restoredX = target.x;
186 target.restoredY = target.y;
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