Lomiri
Loading...
Searching...
No Matches
ChildWindow.qml
1/*
2 * Copyright (C) 2016-2017 Canonical Ltd.
3 *
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.
7 *
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.
12 *
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/>.
15 */
16
17import QtQuick 2.12
18import Lomiri.Components 1.3
19import QtMir.Application 0.1
20
21FocusScope {
22 id: root
23 objectName: "childWindow"
24
25 // Set from outside.
26 property var surface
27 property Item boundsItem
28 property Item target
29 property alias requestedWidth: surfaceContainer.requestedWidth
30 property alias requestedHeight: surfaceContainer.requestedHeight
31 property real decorationHeight
32
33 width: surface ? surface.size.width : 0
34 height: surface ? surface.size.height : 0
35
36 // Make it get shown and hidden with a fade in/out effect
37 opacity: surface && surface.state !== Mir.MinimizedState && surface.state !== Mir.HiddenState ? 1.0 : 0.0
38 Behavior on opacity { LomiriNumberAnimation {} }
39 visible: opacity !== 0.0 // make it transparent to input as well
40
41 readonly property bool dragging: windowResizeArea.dragging || d.touchOverlayDragging || d.moveHandlerDragging
42
43 QtObject {
44 id: d
45 readonly property bool decorated: surface ? surface.type === Mir.UtilityType
46 || surface.type === Mir.DialogType
47 || surface.type === Mir.NormalType
48 || surface.type === Mir.SatelliteType
49 : false
50
51 readonly property bool moveable: decorated
52 readonly property bool resizeable: decorated
53
54 property alias decoration: decorationLoader.item
55 property alias moveHandler: moveHandlerLoader.item
56
57 readonly property bool touchOverlayDragging: touchOverlayLoader.item ? touchOverlayLoader.item.dragging : false
58 readonly property bool moveHandlerDragging: moveHandlerLoader.item ? moveHandlerLoader.item.dragging : false
59 }
60
61 WindowResizeArea {
62 id: windowResizeArea
63 anchors {
64 top: decorationLoader.top
65 bottom: parent.bottom
66 left: parent.left; right: parent.right
67 }
68 target: root.target
69 boundsItem: root.boundsItem
70 minWidth: units.gu(10)
71 minHeight: units.gu(10)
72 borderThickness: units.gu(2)
73 enabled: d.resizeable
74 visible: enabled
75 onPressed: root.surface.activate();
76 }
77
78 BorderImage {
79 property real shadowThickness: root.surface && root.surface.focused ? units.gu(2) : units.gu(1.5)
80 anchors {
81 top: decorationLoader.top
82 bottom: parent.bottom
83 left: parent.left; right: parent.right
84 margins: -shadowThickness
85 }
86 source: "../graphics/dropshadow2gu.sci"
87 opacity: .3
88 }
89
90 Loader {
91 id: decorationLoader
92 anchors.bottom: root.top
93 anchors.left: root.left
94 anchors.right: root.right
95
96 visible: active
97 active: d.decorated
98
99 height: item ? item.height : 0
100
101 sourceComponent: Component {
102 WindowDecoration {
103 id: windowDecoration
104 height: root.decorationHeight
105 title: root.surface ? root.surface.name : ""
106 active: root.surface ? root.surface.focused : false
107 minimizeButtonVisible: false
108 maximizeButtonShown: false
109 onPressed: root.surface.activate();
110 onPressedChanged: if (d.moveHandler) { d.moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY); }
111 onPositionChanged: if (d.moveHandler) {
112 d.moveHandler.handlePositionChanged(mouse);
113 }
114 onReleased: if (d.moveHandler) { d.moveHandler.handleReleased(); }
115 onCloseClicked: root.surface.close();
116 Binding {
117 target: root.surface
118 property: "topMargin"
119 value: windowDecoration.height
120 }
121 }
122 }
123 }
124
125 Loader {
126 id: moveHandlerLoader
127 active: d.moveable
128 sourceComponent: Component {
129 MoveHandler {
130 target: root.target
131 buttonsWidth: d.decoration ? d.decoration.buttonsWidth : 0
132 boundsItem: root.boundsItem
133 boundsTopMargin: decorationLoader.height
134 }
135 }
136 }
137
138 SurfaceContainer {
139 id: surfaceContainer
140
141 // Do not hold on to a dead surface so that it can be destroyed.
142 // FIXME It should not be QML's job to release the MirSurface if its backing surface goes away. Instead backing
143 // MirSurface should go away but the MirSurfaceItem should be able to live on with the last drawn frame
144 // and properties.
145 surface: root.surface && root.surface.live ? root.surface : null
146
147 requestedWidth: surface ? surface.size.width : 0
148 requestedHeight: surface ? surface.size.height : 0
149
150 // TODO ChildWindow parent will probably want to control those
151 interactive: true
152 consumesInput: true
153
154 focus: true
155 }
156
157 Loader {
158 active: d.moveable
159 anchors.fill: parent
160 sourceComponent: Component {
161 MouseArea {
162 acceptedButtons: Qt.LeftButton
163 property bool dragging: false
164 cursorShape: undefined // don't interfere with the cursor shape set by the underlying MirSurfaceItem
165 onPressed: {
166 if (mouse.button == Qt.LeftButton && mouse.modifiers == Qt.AltModifier) {
167 d.moveHandler.handlePressedChanged(true, Qt.LeftButton, mouse.x, mouse.y);
168 dragging = true;
169 mouse.accepted = true;
170 } else {
171 mouse.accepted = false;
172 }
173 }
174 onPositionChanged: {
175 if (dragging) {
176 d.moveHandler.handlePositionChanged(mouse);
177 }
178 }
179 onReleased: {
180 if (dragging) {
181 d.moveHandler.handlePressedChanged(false, Qt.LeftButton);
182 d.moveHandler.handleReleased();
183 dragging = false;
184 }
185 }
186 }
187 }
188 }
189
190 Loader {
191 id: touchOverlayLoader
192 active: d.resizeable || d.moveable
193 anchors.top: decorationLoader.top
194 anchors.bottom: parent.bottom
195 anchors.left: parent.left
196 anchors.right: parent.right
197 sourceComponent: Component { WindowControlsOverlay {
198 target: root.target
199 resizeArea: windowResizeArea
200 boundsItem: root.boundsItem
201 } }
202 }
203}