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 property alias active: decoration.active
37 readonly property alias title: applicationWindow.title
38 property alias maximizeButtonShown: decoration.maximizeButtonShown
39 property alias interactive: applicationWindow.interactive
40 readonly property alias orientationChangesEnabled: applicationWindow.orientationChangesEnabled
41 property alias windowControlButtonsVisible: decoration.windowControlButtonsVisible
42 property PanelState panelState
44 // Changing this will actually add/remove a decoration, meaning, requestedHeight will take the decoration into account.
45 property bool hasDecoration: true
46 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
47 property real showDecoration: 1
48 property alias decorationHeight: decoration.height
49 property bool animateDecoration: false
50 property bool showHighlight: false
51 property int highlightSize: units.gu(1)
52 property real shadowOpacity: 0
53 property bool darkening: false
54 property bool lightMode: 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
231 lightMode: root.lightMode
233 opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
234 Behavior on opacity { LomiriNumberAnimation { } }
235 visible: opacity > 0 // don't eat input when decoration is fully translucent
237 onPressed: root.decorationPressed();
238 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
239 onPressedChangedEx: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
240 onPositionChanged: moveHandler.handlePositionChanged(mouse)
242 if (!wasDoubleClicked) {
243 root.decorationReleased();
244 moveHandler.handleReleased();
246 wasDoubleClicked = false;
248 onDoubleClicked: wasDoubleClicked = true;
250 onCloseClicked: root.closeClicked();
251 onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
252 onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
253 onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
254 onMinimizeClicked: root.minimizeClicked();
259 (panelState.focusedPersistentSurfaceId === surface.persistentId && !panelState.decorationsVisible)
261 menu: sharedAppModel.model
263 Indicators.SharedLomiriMenuModel {
265 property var menus: surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : []
266 property var menuService: menus.length > 0 ? menus[0] : undefined
268 busName: menuService ? menuService.service : ""
269 menuObjectPath: menuService && menuService.menuPath ? menuService.menuPath : ""
270 actions: menuService && menuService.actionPath ? { "lomiri": menuService.actionPath } : {}
274 target: ApplicationMenuRegistry
275 function onSurfaceMenuRegistered(surfaceId) {
276 if (surface && surfaceId === surface.persistentId) {
277 sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
280 function onSurfaceMenuUnregistered(surfaceId) {
281 if (surface && surfaceId === surface.persistentId) {
282 sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
290 anchors.fill: applicationWindow
291 acceptedButtons: Qt.LeftButton | Qt.RightButton
292 property bool dragging: false
293 property bool draggingForResize: false
294 cursorShape: undefined // don't interfere with the cursor shape set by the underlying MirSurfaceItem
297 if (mouse.button == Qt.LeftButton && mouse.modifiers == Qt.AltModifier) {
298 root.decorationPressed(); // to raise it
299 moveHandler.handlePressedChanged(true, Qt.LeftButton, mouse.x, mouse.y);
301 mouse.accepted = true;
302 } else if (mouse.button == Qt.RightButton && mouse.modifiers & Qt.AltModifier) {
303 root.dragResizePressed(Qt.point(mouse.x, mouse.y))
304 draggingForResize = true;
305 mouse.accepted = true;
307 mouse.accepted = false;
312 moveHandler.handlePositionChanged(mouse);
313 } else if (draggingForResize) {
314 root.dragResizePositionChanged(Qt.point(mouse.x, mouse.y))
319 moveHandler.handlePressedChanged(false, Qt.LeftButton);
320 root.decorationReleased(); // commits the fake preview max rectangle
321 moveHandler.handleReleased();
323 } else if (draggingForResize) {
324 root.dragResizeReleased(Qt.point(mouse.x, mouse.y))
325 draggingForResize = false;
332 objectName: "moveHandler"
334 buttonsWidth: decoration.buttonsWidth
339 color: LomiriColors.jet
341 opacity: root.darkening && !root.showHighlight ? 0.5 : 0
342 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }