on xenial help sign in
WIP: touch based edge detection and maximizing
commit9eaba2a42f7ae39f841e91fd21edbafe84e1d6bf authorLukáš Tinkl <lukas.tinkl@canonical.com> dateTue 30 Aug 2016, 01:35 (10 years ago) parent3adcd5e
7 files changed+122−110
plugins/Ubuntu/Gestures/TouchGestureArea.h+2−2 qml/Panel/Panel.qml+3−2 qml/Stages/DecoratedWindow.qml+1−10 qml/Stages/DesktopStage.qml+2−1 qml/Stages/FakeMaximizeDelegate.qml+1−1 qml/Stages/MoveHandler.qml+81−89 qml/Stages/WindowControlsOverlay.qml+32−5
plugins/Ubuntu/Gestures/TouchGestureArea.h+2−2
@@ -76,7 +76,7 @@ public:
7676 return *this;
7777 }
7878
79− bool operator=(const GestureTouchPoint& rhs) const {
79+ bool operator==(const GestureTouchPoint& rhs) const {
8080 if (&rhs == this) return true;
8181 return m_id == rhs.m_id &&
8282 m_pressed == rhs.m_pressed &&
@@ -84,7 +84,7 @@ public:
8484 m_y == rhs.m_y &&
8585 m_dragging == rhs.m_dragging;
8686 }
87− bool operator!=(const GestureTouchPoint& rhs) const { return !operator=(rhs); }
87+ bool operator!=(const GestureTouchPoint& rhs) const { return !operator==(rhs); }
8888
8989 void setPos(const QPointF &pos);
9090
qml/Panel/Panel.qml+3−2
@@ -113,6 +113,7 @@ Item {
113113 }
114114 onPositionChanged: {
115115 if (delegate && delegate.moveHandler.dragging) {
116+ delegate.focus = true;
116117 delegate.restoredX = Math.round(mouse.x - delegate.moveHandler.buttonsWidth);
117118 delegate.restoredY = Math.round(Math.max(mouse.y, PanelState.panelHeight));
118119 delegate.restoreFromMaximized(false);
@@ -120,8 +121,8 @@ Item {
120121 }
121122 onReleased: {
122123 if (delegate) {
123− delegate.moveHandler.handlePressedChanged(false, pressedButtons, mouseX, mouseY);
124− delegate.moveHandler.handleReleased(mouse);
124+ delegate.moveHandler.handlePressedChanged(false, pressedButtons);
125+ delegate.moveHandler.handleReleased();
125126 delegate.moveHandler.shouldCommitSnapWindow();
126127 delegate = null;
127128 }
qml/Stages/DecoratedWindow.qml+1−10
@@ -121,7 +121,7 @@ FocusScope {
121121 onReleased: {
122122 print("!!! Mouse released on decoration")
123123 root.shouldCommitSnapWindow();
124− moveHandler.handleReleased(mouse);
124+ moveHandler.handleReleased();
125125 }
126126 }
127127
@@ -131,15 +131,6 @@ FocusScope {
131131 objectName: "moveHandler"
132132 target: root.parent
133133 buttonsWidth: decoration.buttonsWidth
134−
135− onFakeMaximizeAnimationRequested: root.fakeMaximizeAnimationRequested(progress)
136− onFakeMaximizeLeftAnimationRequested: root.fakeMaximizeLeftAnimationRequested(progress)
137− onFakeMaximizeRightAnimationRequested: root.fakeMaximizeRightAnimationRequested(progress)
138− onFakeMaximizeTopLeftAnimationRequested: root.fakeMaximizeTopLeftAnimationRequested(progress)
139− onFakeMaximizeTopRightAnimationRequested: root.fakeMaximizeTopRightAnimationRequested(progress)
140− onFakeMaximizeBottomLeftAnimationRequested: root.fakeMaximizeBottomLeftAnimationRequested(progress)
141− onFakeMaximizeBottomRightAnimationRequested: root.fakeMaximizeBottomRightAnimationRequested(progress)
142− onStopFakeAnimation: root.stopFakeAnimation()
143134 onShouldCommitSnapWindow: root.shouldCommitSnapWindow()
144135 }
145136
qml/Stages/DesktopStage.qml+2−1
@@ -358,7 +358,7 @@ AbstractStage {
358358 readonly property var surface: model.surface
359359 readonly property alias resizeArea: resizeArea
360360 readonly property alias focusedSurface: decoratedWindow.focusedSurface
361− readonly property alias moveHandler: decoratedWindow.moveHandler
361+ readonly property var moveHandler: touchControls.overlayShown ? touchControls.moveHandler : decoratedWindow.moveHandler
362362
363363 readonly property bool isDash: model.application.appId == "unity8-dash"
364364
@@ -773,6 +773,7 @@ AbstractStage {
773773 onFakeMaximizeBottomLeftAnimationRequested: decoratedWindow.fakeMaximizeBottomLeftAnimationRequested(progress)
774774 onFakeMaximizeBottomRightAnimationRequested: decoratedWindow.fakeMaximizeBottomRightAnimationRequested(progress)
775775 onStopFakeAnimation: decoratedWindow.stopFakeAnimation()
776+ onShouldCommitSnapWindow: fakeRectangle.commit();
776777 }
777778
778779 WindowedFullscreenPolicy {
qml/Stages/FakeMaximizeDelegate.qml+1−1
@@ -97,7 +97,7 @@ Rectangle {
9797 function commit() {
9898 if (progress > hintThreshold && edge != -1) {
9999 print("!!! Committing edge", edge, ", progress:", progress);
100− target.moveHandler.handlePressedChanged(false, Qt.LeftButton, 0, 0); // cancel the drag
100+ target.moveHandler.handlePressedChanged(false, Qt.LeftButton); // cancel the drag
101101 if (edge == Item.Top) {
102102 target.maximize();
103103 } else if (edge == Item.Left) {
qml/Stages/MoveHandler.qml+81−89
@@ -48,7 +48,7 @@ Item {
4848 property real distanceY
4949 property bool dragging
5050
51− readonly property int triggerArea: units.gu(3)
51+ readonly property int triggerArea: units.gu(8)
5252 property bool nearLeftEdge: target.maximizedLeft
5353 property bool nearTopEdge: target.maximized
5454 property bool nearRightEdge: target.maximizedRight
@@ -101,7 +101,7 @@ Item {
101101 }
102102 }
103103
104− function handlePositionChanged(mouse) {
104+ function handlePositionChanged(mouse, sensingPoints) {
105105 if (priv.dragging) {
106106 Mir.cursorName = "grabbing";
107107
@@ -118,99 +118,91 @@ Item {
118118 target.requestedX = Math.round(pos.x - priv.distanceX);
119119 target.requestedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
120120
121−// var globalPos = mapToItem(null, mouse.x, mouse.y);
122−// var globalX = globalPos.x;
123−// var globalY = globalPos.y;
124−// if (globalX < priv.triggerArea && globalY < PanelState.panelHeight) { // top left
125−// if (target.canBeCornerMaximized) {
126−// priv.progress = priv.progressInCorner(0, PanelState.panelHeight, globalX, globalY);
127−// priv.resetEdges();
128−// priv.nearTopLeftCorner = true;
129−// root.fakeMaximizeTopLeftAnimationRequested(priv.progress);
130−// }
131−// } else if (globalX > stageWidth - priv.triggerArea && globalY < PanelState.panelHeight) { // top right
132−// if (target.canBeCornerMaximized) {
133−// priv.progress = priv.progressInCorner(stageWidth, PanelState.panelHeight, globalX, globalY);
134−// priv.resetEdges();
135−// priv.nearTopRightCorner = true;
136−// root.fakeMaximizeTopRightAnimationRequested(priv.progress);
137−// }
138−// } else if (globalX < priv.triggerArea && globalY > stageHeight - priv.triggerArea) { // bottom left
139−// if (target.canBeCornerMaximized) {
140−// priv.progress = priv.progressInCorner(0, stageHeight, globalX, globalY);
141−// priv.resetEdges();
142−// priv.nearBottomLeftCorner = true;
143−// root.fakeMaximizeBottomLeftAnimationRequested(priv.progress);
144−// }
145−// } else if (globalX > stageWidth - priv.triggerArea && globalY > stageHeight - priv.triggerArea) { // bottom right
146−// if (target.canBeCornerMaximized) {
147−// priv.progress = priv.progressInCorner(stageWidth, stageHeight, globalX, globalY);
148−// priv.resetEdges();
149−// priv.nearBottomRightCorner = true;
150−// root.fakeMaximizeBottomRightAnimationRequested(priv.progress);
151−// }
152−// } else if (globalX < priv.triggerArea) { // left
153−// if (target.canBeMaximizedLeftRight) {
154−// priv.progress = MathUtils.clampAndProject(globalX, priv.triggerArea, 0, 0, 1);
155−// priv.resetEdges();
156−// priv.nearLeftEdge = true;
157−// root.fakeMaximizeLeftAnimationRequested(priv.progress);
158−// }
159−// } else if (globalX > stageWidth - priv.triggerArea) { // right
160−// if (target.canBeMaximizedLeftRight) {
161−// priv.progress = MathUtils.clampAndProject(globalX, stageWidth - priv.triggerArea, stageWidth, 0, 1);
162−// priv.resetEdges();
163−// priv.nearRightEdge = true;
164−// root.fakeMaximizeRightAnimationRequested(priv.progress);
165−// }
166−// } else if (globalY < PanelState.panelHeight) { // top
167−// if (target.canBeMaximized) {
168−// priv.progress = MathUtils.clampAndProject(globalY, Math.max(PanelState.panelHeight, priv.triggerArea), 0, 0, 1);
169−// priv.resetEdges();
170−// priv.nearTopEdge = true;
171−// root.fakeMaximizeAnimationRequested(priv.progress);
172−// }
173−// } else if (priv.nearLeftEdge || priv.nearRightEdge || priv.nearTopEdge || priv.nearTopLeftCorner || priv.nearTopRightCorner ||
174−// priv.nearBottomLeftCorner || priv.nearBottomRightCorner) {
175−// print("!!! Exited")
176−// priv.progress = 0;
177−// priv.resetEdges();
178−// root.stopFakeAnimation();
179−// }
121+ if (sensingPoints) {
122+ print("!!! Detecting edges/corners in touch mode")
123+ if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < PanelState.panelHeight
124+ && target.canBeCornerMaximized) { // top left
125+ priv.progress = priv.progressInCorner(0, PanelState.panelHeight, sensingPoints.topLeft.x, sensingPoints.topLeft.y);
126+ priv.resetEdges();
127+ priv.nearTopLeftCorner = true;
128+ root.fakeMaximizeTopLeftAnimationRequested(priv.progress);
129+ } else if (sensingPoints.topRight.x > stageWidth - priv.triggerArea && sensingPoints.topRight.y < PanelState.panelHeight
130+ && target.canBeCornerMaximized) { // top right
131+ priv.progress = priv.progressInCorner(stageWidth, PanelState.panelHeight, sensingPoints.topRight.x, sensingPoints.topRight.y);
132+ priv.resetEdges();
133+ priv.nearTopRightCorner = true;
134+ root.fakeMaximizeTopRightAnimationRequested(priv.progress);
135+ } else if (sensingPoints.bottomLeft.x < priv.triggerArea && sensingPoints.bottomLeft.y > stageHeight - priv.triggerArea
136+ && target.canBeCornerMaximized) { // bottom left
137+ priv.progress = priv.progressInCorner(0, stageHeight, sensingPoints.bottomLeft.x, sensingPoints.bottomLeft.y);
138+ priv.resetEdges();
139+ priv.nearBottomLeftCorner = true;
140+ root.fakeMaximizeBottomLeftAnimationRequested(priv.progress);
141+ } else if (sensingPoints.bottomRight.x > stageWidth - priv.triggerArea && sensingPoints.bottomRight.y > stageHeight - priv.triggerArea
142+ && target.canBeCornerMaximized) { // bottom right
143+ priv.progress = priv.progressInCorner(stageWidth, stageHeight, sensingPoints.bottomRight.x, sensingPoints.bottomRight.y);
144+ priv.resetEdges();
145+ priv.nearBottomRightCorner = true;
146+ root.fakeMaximizeBottomRightAnimationRequested(priv.progress);
147+ } else if (sensingPoints.topLeft.x < priv.triggerArea && target.canBeMaximizedLeftRight) { // left
148+ priv.progress = MathUtils.clampAndProject(sensingPoints.topLeft.x, priv.triggerArea, 0, 0, 1);
149+ priv.resetEdges();
150+ priv.nearLeftEdge = true;
151+ root.fakeMaximizeLeftAnimationRequested(priv.progress);
152+ } else if (sensingPoints.topRight.x > stageWidth - priv.triggerArea && target.canBeMaximizedLeftRight) { // right
153+ priv.progress = MathUtils.clampAndProject(sensingPoints.topRight.x, stageWidth - priv.triggerArea, stageWidth, 0, 1);
154+ priv.resetEdges();
155+ priv.nearRightEdge = true;
156+ root.fakeMaximizeRightAnimationRequested(priv.progress);
157+ } else if (sensingPoints.topLeft.y < PanelState.panelHeight && target.canBeMaximized) { // top
158+ priv.progress = MathUtils.clampAndProject(sensingPoints.topLeft.y, Math.max(PanelState.panelHeight, priv.triggerArea), 0, 0, 1);
159+ priv.resetEdges();
160+ priv.nearTopEdge = true;
161+ root.fakeMaximizeAnimationRequested(priv.progress);
162+ } else if (priv.nearLeftEdge || priv.nearRightEdge || priv.nearTopEdge || priv.nearTopLeftCorner || priv.nearTopRightCorner ||
163+ priv.nearBottomLeftCorner || priv.nearBottomRightCorner) {
164+ print("!!! Exited")
165+ priv.progress = 0;
166+ priv.resetEdges();
167+ root.stopFakeAnimation();
168+ }
169+ }
180170 }
181171 }
182172
183− function handleReleased(mouse) {
184− if (mouse.button == Qt.LeftButton && (target.state == "normal" || target.state == "restored") && priv.progress == 0) {
173+ function handleReleased(touchMode) {
174+ if (touchMode) {
175+ if (priv.progress < 0.3) { // cancel the preview shape if under 30%
176+ priv.progress = 0;
177+ priv.resetEdges();
178+ root.stopFakeAnimation();
179+ } else if (priv.nearLeftEdge) {
180+ target.maximizeLeft();
181+ priv.resetEdges();
182+ } else if (priv.nearTopEdge) {
183+ target.maximize();
184+ priv.resetEdges();
185+ } else if (priv.nearRightEdge) {
186+ target.maximizeRight();
187+ priv.resetEdges();
188+ } else if (priv.nearTopLeftCorner) {
189+ target.maximizeTopLeft();
190+ priv.resetEdges();
191+ } else if (priv.nearTopRightCorner) {
192+ target.maximizeTopRight();
193+ priv.resetEdges();
194+ } else if (priv.nearBottomLeftCorner) {
195+ target.maximizeBottomLeft();
196+ priv.resetEdges();
197+ } else if (priv.nearBottomRightCorner) {
198+ target.maximizeBottomRight();
199+ priv.resetEdges();
200+ }
201+ } else if ((target.state == "normal" || target.state == "restored") && priv.progress == 0) {
185202 // save the x/y to restore to
186203 print("!!! Saving restoredX/Y")
187204 target.restoredX = target.x;
188205 target.restoredY = target.y;
189− } /*else if (priv.progress < 0.3) { // cancel the preview shape if under 30%
190− priv.progress = 0;
191− priv.resetEdges();
192− root.stopFakeAnimation();
193− } else if (priv.nearLeftEdge) {
194− target.maximizeLeft();
195− priv.resetEdges();
196− } else if (priv.nearTopEdge) {
197− target.maximize();
198− priv.resetEdges();
199− } else if (priv.nearRightEdge) {
200− target.maximizeRight();
201− priv.resetEdges();
202− } else if (priv.nearTopLeftCorner) {
203− target.maximizeTopLeft();
204− priv.resetEdges();
205− } else if (priv.nearTopRightCorner) {
206− target.maximizeTopRight();
207− priv.resetEdges();
208− } else if (priv.nearBottomLeftCorner) {
209− target.maximizeBottomLeft();
210− priv.resetEdges();
211− } else if (priv.nearBottomRightCorner) {
212− target.maximizeBottomRight();
213− priv.resetEdges();
214− }*/
206+ }
215207 }
216208}
qml/Stages/WindowControlsOverlay.qml+32−5
@@ -32,6 +32,7 @@ Item {
3232
3333 // to be read from outside
3434 readonly property alias overlayShown: overlay.visible
35+ readonly property alias moveHandler: moveHandler
3536
3637 signal fakeMaximizeAnimationRequested(real progress)
3738 signal fakeMaximizeLeftAnimationRequested(real progress)
@@ -41,6 +42,7 @@ Item {
4142 signal fakeMaximizeBottomLeftAnimationRequested(real progress)
4243 signal fakeMaximizeBottomRightAnimationRequested(real progress)
4344 signal stopFakeAnimation()
45+ signal shouldCommitSnapWindow()
4446
4547 TouchGestureArea {
4648 id: gestureArea
@@ -65,15 +67,15 @@ Item {
6567 if (recognizedDrag) {
6668 moveHandler.handlePressedChanged(true, Qt.LeftButton, tp.x, tp.y);
6769 } else if (!mouseArea.containsPress) { // prevent interfering with the central piece drag/move
68− // FIXME!!!
69− moveHandler.handlePressedChanged(false, Qt.LeftButton, tp.x, tp.y);
70+ moveHandler.handlePressedChanged(false, Qt.LeftButton);
71+ moveHandler.handleReleased(true);
7072 }
7173 }
7274
7375 readonly property point tp: recognizedPress ? Qt.point(touchPoints[0].x, touchPoints[0].y) : Qt.point(-1, -1)
7476 onUpdated: {
7577 if (recognizedDrag) {
76− moveHandler.handlePositionChanged(tp);
78+ moveHandler.handlePositionChanged(tp, priv.getSensingPoints());
7779 }
7880 }
7981 }
@@ -89,6 +91,28 @@ Item {
8991 id: priv
9092 readonly property var resizeArea: root.target && root.target.resizeArea ? root.target.resizeArea : null
9193 readonly property bool ensureWindow: root.target.state == "normal" || root.target.state == "restored"
94+
95+ function getSensingPoints() {
96+ var xPoints = [];
97+ var yPoints = [];
98+ for (var i = 0; i < gestureArea.touchPoints.length; i++) {
99+ var pt = gestureArea.touchPoints[i];
100+ xPoints.push(Math.round(pt.x));
101+ yPoints.push(Math.round(pt.y));
102+ }
103+
104+ var leftmost = Math.min.apply(Math, xPoints);
105+ var rightmost = Math.max.apply(Math, xPoints);
106+ var topmost = Math.min.apply(Math, yPoints);
107+ var bottommost = Math.max.apply(Math, yPoints);
108+
109+ return {
110+ topLeft: mapToItem(target.parent, leftmost, topmost),
111+ topRight: mapToItem(target.parent, rightmost, topmost),
112+ bottomLeft: mapToItem(target.parent, leftmost, bottommost),
113+ bottomRight: mapToItem(target.parent, rightmost, bottommost)
114+ }
115+ }
92116 }
93117
94118 // the visual overlay
@@ -123,7 +147,10 @@ Item {
123147
124148 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
125149 onPositionChanged: moveHandler.handlePositionChanged(mouse)
126− onReleased: moveHandler.handleReleased(mouse)
150+ onReleased: {
151+ root.shouldCommitSnapWindow();
152+ moveHandler.handleReleased();
153+ }
127154 }
128155
129156 MoveHandler {
@@ -154,7 +181,7 @@ Item {
154181 }
155182
156183 overlayTimer.stop();
157− mouse.accepted = root.contains(Qt.point(mouse.x, mouse.y));
184+ mouse.accepted = root.contains(mapToItem(root.target, mouse.x, mouse.y));
158185 }
159186 propagateComposedEvents: true
160187 }