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