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/>.
18 import Ubuntu.Components 1.3
20 import Unity.Application 0.1 // for Mir.cursorName
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
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;
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;
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;
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;
71 readonly property int widthIncrement: {
75 if (root.target.widthIncrement > 0) {
76 if (root.target.widthIncrement < maxSizeIncrement) {
77 return root.target.widthIncrement;
79 return maxSizeIncrement;
85 readonly property int heightIncrement: {
89 if (root.target.heightIncrement > 0) {
90 if (root.target.heightIncrement < maxSizeIncrement) {
91 return root.target.heightIncrement;
93 return maxSizeIncrement;
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
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) {
131 } else if (rightBorder && !topBorder && !bottomBorder) {
133 } else if (topBorder && !leftBorder && !rightBorder) {
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";
152 onCursorNameChanged: {
153 Mir.cursorName = cursorName;
156 function updateBorders() {
157 leftBorder = mouseX <= borderThickness;
158 rightBorder = mouseX >= width - borderThickness;
159 topBorder = mouseY <= borderThickness;
160 bottomBorder = mouseY >= height - borderThickness;
165 id: resetBordersToMoveTimer
168 d.moveLeftBorder = false;
169 d.moveTopBorder = false;
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;
191 resetBordersToMoveTimer.start();
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;
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;
226 target.windowedWidth = d.maximumWidth;
229 target.windowedWidth = d.minimumWidth;
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;
238 target.windowedWidth = d.maximumWidth;
241 target.windowedWidth = d.minimumWidth;
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;
252 target.windowedHeight = d.maximumHeight;
255 target.windowedHeight = d.minimumHeight;
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;
264 target.windowedHeight = d.maximumHeight;
267 target.windowedHeight = d.minimumHeight;
275 if (d.moveLeftBorder) {
276 target.windowedX += d.currentWidth - target.width;
278 d.currentWidth = target.width;
281 if (d.moveTopBorder) {
282 target.windowedY += d.currentHeight - target.height;
284 d.currentHeight = target.height;