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