on e1659ca help sign in
unity8/qml/Stage/WindowResizeArea.qml
287 lines 10 kB history raw
1/*
2 * Copyright (C) 2014-2016 Canonical, Ltd.
3 *
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.
7 *
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.
12 *
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/>.
15 */
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import Utils 0.1
20import Unity.Application 0.1 // for Mir.cursorName
22MouseArea {
23 id: root
25 anchors.margins: -borderThickness
27 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
29 readonly property alias dragging: d.dragging
31 // The target item managed by this. Must be a parent or a sibling
32 // The area will anchor to it and manage resize events
33 property Item target: null
34 property int borderThickness: 0
35 property real minimumY: -100000000 // By default, impose no limit
36 property int minWidth: 0
37 property int minHeight: 0
39 QtObject {
40 id: d
42 readonly property int maxSafeInt: 2147483647
43 readonly property int maxSizeIncrement: units.gu(40)
45 readonly property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
46 onMinimumWidthChanged: {
47 if (target.windowedWidth < minimumWidth) {
48 target.windowedWidth = minimumWidth;
49 }
50 }
51 readonly property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
52 onMinimumHeightChanged: {
53 if (target.windowedHeight < minimumHeight) {
54 target.windowedHeight = minimumHeight;
55 }
56 }
57 readonly property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
58 ? root.target.maximumWidth : maxSafeInt
59 onMaximumWidthChanged: {
60 if (target.windowedWidth > maximumWidth) {
61 target.windowedWidth = maximumWidth;
62 }
63 }
64 readonly property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
65 ? root.target.maximumHeight : maxSafeInt
66 onMaximumHeightChanged: {
67 if (target.windowedHeight > maximumHeight) {
68 target.windowedHeight = maximumHeight;
69 }
70 }
71 readonly property int widthIncrement: {
72 if (!root.target) {
73 return 1;
74 }
75 if (root.target.widthIncrement > 0) {
76 if (root.target.widthIncrement < maxSizeIncrement) {
77 return root.target.widthIncrement;
78 } else {
79 return maxSizeIncrement;
80 }
81 } else {
82 return 1;
83 }
84 }
85 readonly property int heightIncrement: {
86 if (!root.target) {
87 return 1;
88 }
89 if (root.target.heightIncrement > 0) {
90 if (root.target.heightIncrement < maxSizeIncrement) {
91 return root.target.heightIncrement;
92 } else {
93 return maxSizeIncrement;
94 }
95 } else {
96 return 1;
97 }
98 }
100 property bool leftBorder: false
101 property bool rightBorder: false
102 property bool topBorder: false
103 property bool bottomBorder: false
105 // true - A change in surface size will cause the left border of the window to move accordingly.
106 // The window's right border will stay in the same position.
107 // false - a change in surface size will cause the right border of the window to move accordingly.
108 // The window's left border will stay in the same position.
109 property bool moveLeftBorder: false
111 // true - A change in surface size will cause the top border of the window to move accordingly.
112 // The window's bottom border will stay in the same position.
113 // false - a change in surface size will cause the bottom border of the window to move accordingly.
114 // The window's top border will stay in the same position.
115 property bool moveTopBorder: false
117 property bool dragging: false
118 property real startMousePosX
119 property real startMousePosY
120 property real startX
121 property real startY
122 property real startWidth
123 property real startHeight
124 property real currentWidth
125 property real currentHeight
127 readonly property string cursorName: {
128 if (root.containsMouse || root.pressed) {
129 if (leftBorder && !topBorder && !bottomBorder) {
130 return "left_side";
131 } else if (rightBorder && !topBorder && !bottomBorder) {
132 return "right_side";
133 } else if (topBorder && !leftBorder && !rightBorder) {
134 return "top_side";
135 } else if (bottomBorder && !leftBorder && !rightBorder) {
136 return "bottom_side";
137 } else if (leftBorder && topBorder) {
138 return "top_left_corner";
139 } else if (leftBorder && bottomBorder) {
140 return "bottom_left_corner";
141 } else if (rightBorder && topBorder) {
142 return "top_right_corner";
143 } else if (rightBorder && bottomBorder) {
144 return "bottom_right_corner";
145 } else {
146 return "";
147 }
148 } else {
149 return "";
150 }
151 }
152 onCursorNameChanged: {
153 Mir.cursorName = cursorName;
154 }
156 function updateBorders() {
157 leftBorder = mouseX <= borderThickness;
158 rightBorder = mouseX >= width - borderThickness;
159 topBorder = mouseY <= borderThickness;
160 bottomBorder = mouseY >= height - borderThickness;
161 }
162 }
164 Timer {
165 id: resetBordersToMoveTimer
166 interval: 2000
167 onTriggered: {
168 d.moveLeftBorder = false;
169 d.moveTopBorder = false;
170 }
171 }
173 onPressedChanged: {
174 if (pressed) {
175 d.updateBorders();
176 resetBordersToMoveTimer.stop();
177 d.moveLeftBorder = d.leftBorder;
178 d.moveTopBorder = d.topBorder;
180 var pos = mapToItem(root.target.parent, mouseX, mouseY);
181 d.startMousePosX = pos.x;
182 d.startMousePosY = pos.y;
183 d.startX = target.windowedX;
184 d.startY = target.windowedY;
185 d.startWidth = target.width;
186 d.startHeight = target.height;
187 d.currentWidth = target.width;
188 d.currentHeight = target.height;
189 d.dragging = true;
190 } else {
191 resetBordersToMoveTimer.start();
192 d.dragging = false;
193 if (containsMouse) {
194 d.updateBorders();
195 }
196 }
197 }
199 onEntered: {
200 if (!pressed) {
201 d.updateBorders();
202 }
203 }
205 onPositionChanged: {
206 if (!pressed) {
207 d.updateBorders();
208 }
210 if (!d.dragging) {
211 return;
212 }
214 var pos = mapToItem(target.parent, mouse.x, mouse.y);
216 var deltaX = Math.floor((pos.x - d.startMousePosX) / d.widthIncrement) * d.widthIncrement;
217 var deltaY = Math.floor((pos.y - d.startMousePosY) / d.heightIncrement) * d.heightIncrement;
219 if (d.leftBorder) {
220 var newTargetX = d.startX + deltaX;
221 var rightBorderX = target.windowedX + target.width;
222 if (rightBorderX > newTargetX + d.minimumWidth) {
223 if (rightBorderX < newTargetX + d.maximumWidth) {
224 target.windowedWidth = rightBorderX - newTargetX;
225 } else {
226 target.windowedWidth = d.maximumWidth;
227 }
228 } else {
229 target.windowedWidth = d.minimumWidth;
230 }
232 } else if (d.rightBorder) {
233 var newWidth = d.startWidth + deltaX;
234 if (newWidth > d.minimumWidth) {
235 if (newWidth < d.maximumWidth) {
236 target.windowedWidth = newWidth;
237 } else {
238 target.windowedWidth = d.maximumWidth;
239 }
240 } else {
241 target.windowedWidth = d.minimumWidth;
242 }
243 }
245 if (d.topBorder) {
246 var newTargetY = Math.max(d.startY + deltaY, root.minimumY);
247 var bottomBorderY = target.windowedY + target.height;
248 if (bottomBorderY > newTargetY + d.minimumHeight) {
249 if (bottomBorderY < newTargetY + d.maximumHeight) {
250 target.windowedHeight = bottomBorderY - newTargetY;
251 } else {
252 target.windowedHeight = d.maximumHeight;
253 }
254 } else {
255 target.windowedHeight = d.minimumHeight;
256 }
258 } else if (d.bottomBorder) {
259 var newHeight = d.startHeight + deltaY;
260 if (newHeight > d.minimumHeight) {
261 if (newHeight < d.maximumHeight) {
262 target.windowedHeight = newHeight;
263 } else {
264 target.windowedHeight = d.maximumHeight;
265 }
266 } else {
267 target.windowedHeight = d.minimumHeight;
268 }
269 }
270 }
272 Connections {
273 target: root.target
274 onWidthChanged: {
275 if (d.moveLeftBorder) {
276 target.windowedX += d.currentWidth - target.width;
277 }
278 d.currentWidth = target.width;
279 }
280 onHeightChanged: {
281 if (d.moveTopBorder) {
282 target.windowedY += d.currentHeight - target.height;
283 }
284 d.currentHeight = target.height;
285 }
286 }