2 * Copyright (C) 2014-2015 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
21 import "../Components/PanelState"
26 anchors.margins: -borderThickness
28 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
30 property var windowStateStorage: WindowStateStorage
32 // The target item managed by this. Must be a parent or a sibling
33 // The area will anchor to it and manage move and resize events
34 property Item target: null
35 property string windowId: ""
36 property int borderThickness: 0
37 property int minWidth: 0
38 property int minHeight: 0
39 property int defaultWidth: units.gu(60)
40 property int defaultHeight: units.gu(50)
41 property int screenWidth: 0
42 property int screenHeight: 0
48 property int normalX: 0
49 property int normalY: 0
50 property int normalWidth: 0
51 property int normalHeight: 0
53 function updateNormalGeometry() {
54 if (root.target.state == "normal") {
55 normalX = root.target.x
56 normalY = root.target.y
57 normalWidth = root.target.width
58 normalHeight = root.target.height
65 onXChanged: priv.updateNormalGeometry();
66 onYChanged: priv.updateNormalGeometry();
67 onWidthChanged: priv.updateNormalGeometry();
68 onHeightChanged: priv.updateNormalGeometry();
71 Component.onCompleted: {
72 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
73 Qt.rect(target.x, target.y, defaultWidth, defaultHeight));
75 target.requestedWidth = Math.min(Math.max(windowGeometry.width, minWidth), screenWidth);
76 target.requestedHeight = Math.min(Math.max(windowGeometry.height, minHeight), root.screenHeight - PanelState.panelHeight);
77 target.x = Math.max(Math.min(windowGeometry.x, root.screenWidth - target.requestedWidth), 0)
78 target.y = Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight)
80 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
81 if (windowState === WindowStateStorage.WindowStateMaximized) {
82 target.maximize(false)
84 priv.updateNormalGeometry();
87 Component.onDestruction: {
88 windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
89 windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
94 property bool leftBorder: false
95 property bool rightBorder: false
96 property bool topBorder: false
97 property bool bottomBorder: false
99 // true - A change in surface size will cause the left border of the window to move accordingly.
100 // The window's right border will stay in the same position.
101 // false - a change in surface size will cause the right border of the window to move accordingly.
102 // The window's left border will stay in the same position.
103 property bool moveLeftBorder: false
105 // true - A change in surface size will cause the top border of the window to move accordingly.
106 // The window's bottom border will stay in the same position.
107 // false - a change in surface size will cause the bottom border of the window to move accordingly.
108 // The window's top border will stay in the same position.
109 property bool moveTopBorder: false
111 property bool dragging: false
112 property real startMousePosX
113 property real startMousePosY
116 property real startWidth
117 property real startHeight
118 property real currentWidth
119 property real currentHeight
121 property string cursorName: {
122 if (root.containsMouse || root.pressed) {
123 if (leftBorder && !topBorder && !bottomBorder) {
125 } else if (rightBorder && !topBorder && !bottomBorder) {
127 } else if (topBorder && !leftBorder && !rightBorder) {
129 } else if (bottomBorder && !leftBorder && !rightBorder) {
130 return "bottom_side";
131 } else if (leftBorder && topBorder) {
132 return "top_left_corner";
133 } else if (leftBorder && bottomBorder) {
134 return "bottom_left_corner";
135 } else if (rightBorder && topBorder) {
136 return "top_right_corner";
137 } else if (rightBorder && bottomBorder) {
138 return "bottom_right_corner";
146 onCursorNameChanged: {
147 Mir.cursorName = cursorName;
150 function updateBorders() {
151 leftBorder = mouseX <= borderThickness;
152 rightBorder = mouseX >= width - borderThickness;
153 topBorder = mouseY <= borderThickness;
154 bottomBorder = mouseY >= height - borderThickness;
159 id: resetBordersToMoveTimer
162 d.moveLeftBorder = false;
163 d.moveTopBorder = false;
168 var pos = mapToItem(target.parent, mouseX, mouseY);
172 resetBordersToMoveTimer.stop();
173 d.moveLeftBorder = d.leftBorder;
174 d.moveTopBorder = d.topBorder;
176 var pos = mapToItem(root.target.parent, mouseX, mouseY);
177 d.startMousePosX = pos.x;
178 d.startMousePosY = pos.y;
181 d.startWidth = target.width;
182 d.startHeight = target.height;
183 d.currentWidth = target.width;
184 d.currentHeight = target.height;
187 resetBordersToMoveTimer.start();
210 var pos = mapToItem(target.parent, mouse.x, mouse.y);
212 var deltaX = pos.x - d.startMousePosX;
213 var deltaY = pos.y - d.startMousePosY;
216 var newTargetX = d.startX + deltaX;
217 if (target.x + target.width > newTargetX + minWidth) {
218 target.requestedWidth = target.x + target.width - newTargetX;
220 target.requestedWidth = minWidth;
223 } else if (d.rightBorder) {
224 if (d.startWidth + deltaX >= minWidth) {
225 target.requestedWidth = d.startWidth + deltaX;
227 target.requestedWidth = minWidth;
232 var newTargetY = d.startY + deltaY;
233 if (target.y + target.height > newTargetY + minHeight) {
234 target.requestedHeight = target.y + target.height - newTargetY;
236 target.requestedHeight = minHeight;
239 } else if (d.bottomBorder) {
240 if (d.startHeight + deltaY >= minHeight) {
241 target.requestedHeight = d.startHeight + deltaY;
243 target.requestedHeight = minHeight;
251 if (d.moveLeftBorder) {
252 target.x += d.currentWidth - target.width;
254 d.currentWidth = target.width;
257 if (d.moveTopBorder) {
258 target.y += d.currentHeight - target.height;
260 d.currentHeight = target.height;