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 alias stage: applicationWindow.stage
44 property PanelState panelState
46 // Changing this will actually add/remove a decoration, meaning, requestedHeight will take the decoration into account.
47 property bool hasDecoration: true
48 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
49 property real showDecoration: 1
50 property alias decorationHeight: decoration.height
51 property bool animateDecoration: false
52 property bool showHighlight: false
53 property int highlightSize: units.gu(1)
54 property real shadowOpacity: 0
55 property bool darkening: false
56 property bool lightMode: false
58 property real requestedWidth
59 property real requestedHeight
60 property real scaleToPreviewProgress: 0
61 property int scaleToPreviewSize: units.gu(30)
63 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
65 // Height of the decoration that's actually being displayed at this moment. Will match decorationHeight
66 // when the decoration is being fully displayed
67 readonly property real actualDecorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
69 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
71 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
72 readonly property int minimumHeight: actualDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
73 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
74 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
75 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
76 readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
77 readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
79 property alias overlayShown: decoration.overlayShown
80 property alias boundsItem: moveHandler.boundsItem
81 readonly property alias dragging: moveHandler.dragging
83 readonly property Item clientAreaItem: applicationWindow
85 property alias altDragEnabled: altDragHandler.enabled
87 property alias clipSurface: applicationWindow.clip
89 property Item windowMargins
92 signal maximizeClicked()
93 signal maximizeHorizontallyClicked()
94 signal maximizeVerticallyClicked()
95 signal minimizeClicked()
96 signal decorationPressed()
97 signal decorationReleased()
99 function cancelDrag() {
100 moveHandler.cancelDrag();
105 property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
106 Behavior on requestedDecorationHeight { enabled: root.animateDecoration; LomiriNumberAnimation { } }
108 property int visibleDecorationHeight: root.hasDecoration ? root.showDecoration * decoration.height : 0
109 Behavior on visibleDecorationHeight { enabled: root.animateDecoration; LomiriNumberAnimation { } }
115 name: "normal"; when: root.scaleToPreviewProgress <= 0 && root.application.state === ApplicationInfoInterface.Running
118 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
119 implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
123 name: "normalSuspended"; when: root.scaleToPreviewProgress <= 0 && root.application.state !== ApplicationInfoInterface.Running
127 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
128 implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
132 name: "preview"; when: root.scaleToPreviewProgress > 0
135 implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.requestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
136 implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.requestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
139 target: applicationWindow;
140// requestedWidth: applicationWindow.oldRequestedWidth
141// requestedHeight: applicationWindow.oldRequestedHeight
142 width: MathUtils.linearAnimation(0, 1, applicationWindow.requestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
143 height: MathUtils.linearAnimation(0, 1, applicationWindow.requestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
144 itemScale: root.implicitWidth / width
151 id: selectionHighlight
152 objectName: "selectionHighlight"
154 anchors.margins: -root.highlightSize
156 opacity: showHighlight ? 0.55 : 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 anchors { left: parent.left; top: parent.top; right: parent.right }
224 height: units.gu(3) // a default value. overwritten by root.decorationHeight
226 title: applicationWindow.title
227 windowMoving: moveHandler.moving && !altDragHandler.dragging
228 panelState: root.panelState
229 lightMode: root.lightMode
231 opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
232 Behavior on opacity { LomiriNumberAnimation { } }
233 visible: opacity > 0 // don't eat input when decoration is fully translucent
235 onPressed: root.decorationPressed();
236 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
237 onPressedChangedEx: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
238 onPositionChanged: moveHandler.handlePositionChanged(mouse)
240 root.decorationReleased();
241 moveHandler.handleReleased();
244 onCloseClicked: root.closeClicked();
245 onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
246 onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
247 onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
248 onMinimizeClicked: root.minimizeClicked();
253 (panelState.focusedPersistentSurfaceId === surface.persistentId && !panelState.decorationsVisible)
255 menu: sharedAppModel.model
257 Indicators.SharedLomiriMenuModel {
259 property var menus: surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : []
260 property var menuService: menus.length > 0 ? menus[0] : undefined
262 busName: menuService ? menuService.service : ""
263 menuObjectPath: menuService && menuService.menuPath ? menuService.menuPath : ""
264 actions: menuService && menuService.actionPath ? { "lomiri": menuService.actionPath } : {}
268 target: ApplicationMenuRegistry
269 function onSurfaceMenuRegistered(surfaceId) {
270 if (surface && surfaceId === surface.persistentId) {
271 sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
274 function onSurfaceMenuUnregistered(surfaceId) {
275 if (surface && surfaceId === surface.persistentId) {
276 sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
284 anchors.fill: applicationWindow
285 acceptedButtons: Qt.LeftButton
286 property bool dragging: false
287 cursorShape: undefined // don't interfere with the cursor shape set by the underlying MirSurfaceItem
290 if (mouse.button == Qt.LeftButton && mouse.modifiers == Qt.AltModifier) {
291 root.decorationPressed(); // to raise it
292 moveHandler.handlePressedChanged(true, Qt.LeftButton, mouse.x, mouse.y);
294 mouse.accepted = true;
296 mouse.accepted = false;
301 moveHandler.handlePositionChanged(mouse);
306 moveHandler.handlePressedChanged(false, Qt.LeftButton);
307 root.decorationReleased(); // commits the fake preview max rectangle
308 moveHandler.handleReleased();
316 objectName: "moveHandler"
318 buttonsWidth: decoration.buttonsWidth
324 opacity: root.darkening && !root.showHighlight ? 0.05 : 0
325 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }