Lomiri
Loading...
Searching...
No Matches
ScreensAndWorkspaces.qml
1/*
2 * Copyright (C) 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 Lomiri.Components 1.3
19import Lomiri.Components.Popups 1.3
20import WindowManager 1.0
21import QtMir.Application 0.1
22import QtQuick.Layouts 1.12
23import ".."
24import "../.."
25
26Item {
27 id: root
28
29 property string background
30
31 property var screensProxy: Screens.createProxy();
32
33 property QtObject activeWorkspace: null
34
35 property string mode : "staged"
36 property Item availableDesktopArea
37
38 signal closeSpread();
39
40 DeviceConfiguration {
41 id: deviceConfiguration
42 }
43
44 Row {
45 id: row
46 anchors.bottom: parent.bottom
47 anchors.horizontalCenter: parent.horizontalCenter
48 Behavior on anchors.horizontalCenterOffset { NumberAnimation { duration: LomiriAnimation.SlowDuration } }
49 spacing: units.gu(1)
50
51 property var selectedIndex: undefined
52
53 Repeater {
54 model: screensProxy
55
56 delegate: Item {
57 height: root.height - units.gu(6)
58 width: workspaces.width
59 visible: (deviceConfiguration.category == "phone" && index !== 0) || deviceConfiguration.category != "phone"
60
61 Item {
62 id: header
63 anchors { left: parent.left; top: parent.top; right: parent.right }
64 height: units.gu(7)
65 z: 1
66
67 property bool isCurrent: {
68 // another screen is selected.
69 if (row.selectedIndex != undefined && row.selectedIndex != index) return false;
70
71 // this screen is active.
72 if (WMScreen.active && WMScreen.isSameAs(model.screen) && WMScreen.currentWorkspace.isSameAs(activeWorkspace)) return true;
73 if (model.screen.workspaces.indexOf(activeWorkspace) >= 0) return true;
74
75 // not active.
76 return false;
77 }
78
79 property bool isSelected: screenMA.containsMouse
80 onIsSelectedChanged: {
81 if (isSelected) {
82 row.selectedIndex = Qt.binding(function() { return index; });
83 } else if (row.selectedIndex === index) {
84 row.selectedIndex = undefined;
85 }
86 }
87
88 LomiriShape {
89 anchors.fill: parent
90 backgroundColor: "white"
91 opacity: header.isCurrent || header.isSelected ? 1.0 : 0.5
92 }
93
94 DropArea {
95 anchors.fill: parent
96 keys: ["workspace"]
97
98 onEntered: {
99 workspaces.workspaceModel.insert(workspaces.workspaceModel.count, {text: drag.source.text})
100 drag.source.inDropArea = true;
101 }
102
103 onExited: {
104 workspaces.workspaceModel.remove(workspaces.workspaceModel.count - 1, 1)
105 drag.source.inDropArea = false;
106 }
107
108 onDropped: {
109 drag.source.inDropArea = false;
110 }
111 }
112
113 ColumnLayout {
114 spacing: 0
115 anchors.fill: parent
116 anchors.margins: units.gu(1)
117
118 Label {
119 Layout.fillHeight: true
120 text: model.screen.name
121 color: header.isCurrent || header.isSelected ? "black" : "white"
122 }
123
124 Label {
125 Layout.fillHeight: true
126 text: model.screen.outputTypeName
127 color: header.isCurrent || header.isSelected ? "black" : "white"
128 fontSize: "x-small"
129 }
130
131 Label {
132 Layout.fillHeight: true
133 text: screen.availableModes[screen.currentModeIndex].size.width + "x" + screen.availableModes[screen.currentModeIndex].size.height
134 color: header.isCurrent || header.isSelected ? "black" : "white"
135 fontSize: "x-small"
136 }
137 }
138
139 Icon {
140 anchors {
141 top: parent.top
142 right: parent.right
143 margins: units.gu(1)
144 }
145 width: units.gu(3)
146 height: width
147 source: "image://theme/select"
148 color: header.isCurrent || header.isSelected ? "black" : "white"
149 visible: model.screen.active
150 }
151
152 MouseArea {
153 id: screenMA
154 hoverEnabled: true
155 anchors.fill: parent
156
157 onClicked: {
158 var obj = screensMenuComponent.createObject(header)
159 obj.open(mouseX, mouseY)
160 }
161 }
162
163 Component {
164 id: screensMenuComponent
165 LomiriShape {
166 id: screensMenu
167 width: units.gu(20)
168 height: contentColumn.childrenRect.height
169 backgroundColor: "white"
170
171 function open(mouseX, mouseY) {
172 x = Math.max(0, Math.min(mouseX - width / 2, parent.width - width))
173 y = mouseY + units.gu(1)
174 }
175
176 InverseMouseArea {
177 anchors.fill: parent
178 onClicked: {
179 screensMenu.destroy()
180 }
181 }
182
183 Column {
184 id: contentColumn
185 width: parent.width
186 ListItem {
187 height: layout.height
188 highlightColor: "transparent"
189 ListItemLayout {
190 id: layout
191 title.text: qsTr("Add workspace")
192 title.color: "black"
193 }
194 onClicked: {
195 screen.workspaces.addWorkspace();
196 Screens.sync(root.screensProxy);
197 screensMenu.destroy();
198 }
199 }
200 }
201 }
202 }
203 }
204
205 Workspaces {
206 id: workspaces
207 height: parent.height - header.height - units.gu(2)
208 width: {
209 var width = 0;
210 if (screensProxy.count == 1) {
211 width = Math.min(implicitWidth, root.width - units.gu(8));
212 } else {
213 width = Math.min(implicitWidth, model.screen.active ? root.width - units.gu(48) : units.gu(40))
214 }
215 return Math.max(workspaces.minimumWidth, width);
216 }
217
218 Behavior on width { LomiriNumberAnimation {} }
219 anchors.bottom: parent.bottom
220 anchors.bottomMargin: units.gu(1)
221 anchors.horizontalCenter: parent.horizontalCenter
222 screen: model.screen
223 background: root.background
224 availableDesktopArea: root.availableDesktopArea
225
226 workspaceModel: model.screen.workspaces
227 activeWorkspace: root.activeWorkspace
228 readOnly: false
229
230 onCommitScreenSetup: Screens.sync(root.screensProxy)
231 onCloseSpread: root.closeSpread();
232
233 onClicked: {
234 root.activeWorkspace = workspace;
235 }
236 }
237 }
238 }
239 }
240
241 Rectangle {
242 anchors { left: parent.left; top: parent.top; bottom: parent.bottom; topMargin: units.gu(6); bottomMargin: units.gu(1) }
243 width: units.gu(5)
244 color: "#33000000"
245 visible: (row.width - root.width + units.gu(10)) / 2 - row.anchors.horizontalCenterOffset > units.gu(5)
246 MouseArea {
247 id: leftScrollArea
248 anchors.fill: parent
249 hoverEnabled: true
250 onPressed: mouse.accepted = false;
251 }
252 DropArea {
253 id: leftFakeDropArea
254 anchors.fill: parent
255 keys: ["application", "workspace"]
256 }
257 }
258 Rectangle {
259 anchors { right: parent.right; top: parent.top; bottom: parent.bottom; topMargin: units.gu(6); bottomMargin: units.gu(1) }
260 width: units.gu(5)
261 color: "#33000000"
262 visible: (row.width - root.width + units.gu(10)) / 2 + row.anchors.horizontalCenterOffset > units.gu(5)
263 MouseArea {
264 id: rightScrollArea
265 anchors.fill: parent
266 hoverEnabled: true
267 onPressed: mouse.accepted = false;
268 }
269 DropArea {
270 id: rightFakeDropArea
271 anchors.fill: parent
272 keys: ["application", "workspace"]
273 }
274 }
275 Timer {
276 repeat: true
277 running: leftScrollArea.containsMouse || rightScrollArea.containsMouse || leftFakeDropArea.containsDrag || rightFakeDropArea.containsDrag
278 interval: LomiriAnimation.SlowDuration
279 triggeredOnStart: true
280 onTriggered: {
281 var newOffset = row.anchors.horizontalCenterOffset;
282 var maxOffset = Math.max((row.width - root.width + units.gu(10)) / 2, 0);
283 if (leftScrollArea.containsMouse || leftFakeDropArea.containsDrag) {
284 newOffset += units.gu(20)
285 } else {
286 newOffset -= units.gu(20)
287 }
288 newOffset = Math.max(-maxOffset, Math.min(maxOffset, newOffset));
289 row.anchors.horizontalCenterOffset = newOffset;
290 }
291 }
292}