2 * Copyright (C) 2014-2017 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 Lomiri.Components 1.3
19import QtMir.Application 0.1
20import "Spread/MathUtils.js" as MathUtils
21import Lomiri.ApplicationMenu 0.1
22import Lomiri.Indicators 0.1 as Indicators
23import "../Components/PanelState"
28 // The DecoratedWindow takes requestedWidth/requestedHeight and asks its surface to be resized to that
29 // (minus the window decoration size in case hasDecoration and showDecoration are true)
30 // The surface might not be able to resize to the requested values. It will return its actual size
31 // in implicitWidth/implicitHeight.
33 property alias application: applicationWindow.application
34 property alias surface: applicationWindow.surface
35 readonly property alias focusedSurface: applicationWindow.focusedSurface
36 readonly property alias supportsResize: applicationWindow.supportsResize
37 property alias active: decoration.active
38 readonly property alias title: applicationWindow.title
39 property alias maximizeButtonShown: decoration.maximizeButtonShown
40 property alias interactive: applicationWindow.interactive
41 readonly property alias orientationChangesEnabled: applicationWindow.orientationChangesEnabled
42 property alias windowControlButtonsVisible: decoration.windowControlButtonsVisible
43 property PanelState panelState
45 // Changing this will actually add/remove a decoration, meaning, requestedHeight will take the decoration into account.
46 property bool hasDecoration: true
47 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
48 property real showDecoration: 1
49 property alias decorationHeight: decoration.height
50 property bool animateDecoration: false
51 property bool showHighlight: false
52 property int highlightSize: units.gu(1)
53 property real shadowOpacity: 0
54 property bool darkening: false
56 property real requestedWidth
57 property real requestedHeight
58 property real scaleToPreviewProgress: 0
59 property int scaleToPreviewSize: units.gu(30)
61 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
63 // Height of the decoration that's actually being displayed at this moment. Will match decorationHeight
64 // when the decoration is being fully displayed
65 readonly property real actualDecorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
67 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
69 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
70 readonly property int minimumHeight: actualDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
71 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
72 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
73 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
74 readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
75 readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
77 property alias overlayShown: decoration.overlayShown
78 property alias boundsItem: moveHandler.boundsItem
79 readonly property alias dragging: moveHandler.dragging
81 readonly property Item clientAreaItem: applicationWindow
83 property alias altDragEnabled: altDragHandler.enabled
85 property Item windowMargins
88 signal maximizeClicked()
89 signal maximizeHorizontallyClicked()
90 signal maximizeVerticallyClicked()
91 signal minimizeClicked()
92 signal decorationPressed()
93 signal decorationReleased()
94 signal dragResizePressed(point mouse)
95 signal dragResizeReleased(point mouse)
96 signal dragResizePositionChanged(point mouse)
98 function cancelDrag() {
99 moveHandler.cancelDrag();
104 property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
105 Behavior on requestedDecorationHeight { enabled: root.animateDecoration; LomiriNumberAnimation { } }
107 property int visibleDecorationHeight: root.hasDecoration ? root.showDecoration * decoration.height : 0
108 Behavior on visibleDecorationHeight { enabled: root.animateDecoration; LomiriNumberAnimation { } }
114 name: "normal"; when: root.scaleToPreviewProgress <= 0 && root.application.state === ApplicationInfoInterface.Running
117 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
118 implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
122 name: "normalSuspended"; when: root.scaleToPreviewProgress <= 0 && root.application.state !== ApplicationInfoInterface.Running
126 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
127 implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
131 name: "preview"; when: root.scaleToPreviewProgress > 0
134 implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.requestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
135 implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.requestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
138 target: applicationWindow;
139// requestedWidth: applicationWindow.oldRequestedWidth
140// requestedHeight: applicationWindow.oldRequestedHeight
141 width: MathUtils.linearAnimation(0, 1, applicationWindow.requestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
142 height: MathUtils.linearAnimation(0, 1, applicationWindow.requestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
143 itemScale: root.implicitWidth / width
150 id: selectionHighlight
151 objectName: "selectionHighlight"
153 anchors.margins: -root.highlightSize
154 color: LomiriColors.porcelain
155 opacity: showHighlight ? 0.3 : 0
163 left: parent.left; top: parent.top; right: parent.right
164 margins: active ? -units.gu(2) : -units.gu(1.5)
166 height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
167 + root.actualDecorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
168 source: "../graphics/dropshadow2gu.sci"
169 opacity: root.shadowOpacity
173 id: applicationWindow
174 objectName: "appWindow"
175 anchors.top: parent.top
176 anchors.topMargin: root.actualDecorationHeight * Math.min(1, root.showDecoration)
177 anchors.left: parent.left
179 height: implicitHeight
180 requestedHeight: !counterRotate ? root.requestedHeight - d.requestedDecorationHeight : root.requestedWidth
181 requestedWidth: !counterRotate ? root.requestedWidth : root.requestedHeight - d.requestedDecorationHeight
182// property int oldRequestedWidth: requestedWidth
183// property int oldRequestedHeight: requestedHeight
184// onRequestedWidthChanged: oldRequestedWidth = requestedWidth
185// onRequestedHeightChanged: oldRequestedHeight = requestedHeight
188 property real itemScale: 1
189 property real minSize: Math.min(root.scaleToPreviewSize, Math.min(requestedHeight, Math.min(requestedWidth, Math.min(implicitHeight, implicitWidth))))
193 id: rotationTransform
194 readonly property int rotationAngle: applicationWindow.application &&
195 applicationWindow.application.rotatesWindowContents
196 ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
198 if (rotationAngle == 90) return applicationWindow.height / 2;
199 else if (rotationAngle == 270) return applicationWindow.width / 2;
200 else if (rotationAngle == 180) return applicationWindow.width / 2;
204 if (rotationAngle == 90) return applicationWindow.height / 2;
205 else if (rotationAngle == 270) return applicationWindow.width / 2;
206 else if (rotationAngle == 180) return applicationWindow.height / 2;
212 xScale: applicationWindow.itemScale
213 yScale: applicationWindow.itemScale
220 closeButtonVisible: true
221 objectName: "appWindowDecoration"
223 property bool wasDoubleClicked: false
225 anchors { left: parent.left; top: parent.top; right: parent.right }
226 height: units.gu(3) // a default value. overwritten by root.decorationHeight
228 title: applicationWindow.title
229 windowMoving: moveHandler.moving && !altDragHandler.dragging
230 panelState: root.panelState
232 opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
233 Behavior on opacity { LomiriNumberAnimation { } }
234 visible: opacity > 0 // don't eat input when decoration is fully translucent
236 onPressed: root.decorationPressed();
237 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
238 onPressedChangedEx: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
239 onPositionChanged: moveHandler.handlePositionChanged(mouse)
241 if (!wasDoubleClicked) {
242 root.decorationReleased();
243 moveHandler.handleReleased();
245 wasDoubleClicked = false;
247 onDoubleClicked: wasDoubleClicked = true;
249 onCloseClicked: root.closeClicked();
250 onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
251 onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
252 onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
253 onMinimizeClicked: root.minimizeClicked();
258 (panelState.focusedPersistentSurfaceId === surface.persistentId && !panelState.decorationsVisible)
260 menu: sharedAppModel.model
262 Indicators.SharedLomiriMenuModel {
264 property var menus: surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : []
265 property var menuService: menus.length > 0 ? menus[0] : undefined
267 busName: menuService ? menuService.service : ""
268 menuObjectPath: menuService && menuService.menuPath ? menuService.menuPath : ""
269 actions: menuService && menuService.actionPath ? { "lomiri": menuService.actionPath } : {}
273 target: ApplicationMenuRegistry
274 function onSurfaceMenuRegistered(surfaceId) {
275 if (surface && surfaceId === surface.persistentId) {
276 sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
279 function onSurfaceMenuUnregistered(surfaceId) {
280 if (surface && surfaceId === surface.persistentId) {
281 sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
289 anchors.fill: applicationWindow
290 acceptedButtons: Qt.LeftButton | Qt.RightButton
291 property bool dragging: false
292 property bool draggingForResize: false
293 cursorShape: undefined // don't interfere with the cursor shape set by the underlying MirSurfaceItem
296 if (mouse.button == Qt.LeftButton && mouse.modifiers == Qt.AltModifier) {
297 root.decorationPressed(); // to raise it
298 moveHandler.handlePressedChanged(true, Qt.LeftButton, mouse.x, mouse.y);
300 mouse.accepted = true;
301 } else if (mouse.button == Qt.RightButton && mouse.modifiers & Qt.AltModifier) {
302 root.dragResizePressed(Qt.point(mouse.x, mouse.y))
303 draggingForResize = true;
304 mouse.accepted = true;
306 mouse.accepted = false;
311 moveHandler.handlePositionChanged(mouse);
312 } else if (draggingForResize) {
313 root.dragResizePositionChanged(Qt.point(mouse.x, mouse.y))
318 moveHandler.handlePressedChanged(false, Qt.LeftButton);
319 root.decorationReleased(); // commits the fake preview max rectangle
320 moveHandler.handleReleased();
322 } else if (draggingForResize) {
323 root.dragResizeReleased(Qt.point(mouse.x, mouse.y))
324 draggingForResize = false;
331 objectName: "moveHandler"
333 buttonsWidth: decoration.buttonsWidth
338 color: LomiriColors.jet
340 opacity: root.darkening && !root.showHighlight ? 0.5 : 0
341 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }