summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/shell/quickshell/Bar.qml
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif/shell/quickshell/Bar.qml')
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Bar.qml307
1 files changed, 296 insertions, 11 deletions
diff --git a/accounts/gkleen@sif/shell/quickshell/Bar.qml b/accounts/gkleen@sif/shell/quickshell/Bar.qml
index b7235a61..e19c0b32 100644
--- a/accounts/gkleen@sif/shell/quickshell/Bar.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Bar.qml
@@ -1,14 +1,19 @@
1import Quickshell 1import Quickshell
2import Quickshell.Io 2import Quickshell.Io
3import Quickshell.Services.SystemTray
4import Quickshell.Widgets
3import Custom as Custom 5import Custom as Custom
4import QtQuick 6import QtQuick
7import qs.Services
5 8
6 9
7PanelWindow { 10PanelWindow {
11 id: bar
12
8 property var modelData 13 property var modelData
9 14
10 anchors { 15 anchors {
11 bottom: true 16 top: true
12 left: true 17 left: true
13 right: true 18 right: true
14 } 19 }
@@ -25,15 +30,79 @@ PanelWindow {
25 id: left 30 id: left
26 31
27 height: parent.height 32 height: parent.height
33 width: childrenRect.width
28 anchors.left: parent.left 34 anchors.left: parent.left
29 anchors.leftMargin: 8 35 anchors.leftMargin: 8
30 anchors.verticalCenter: parent.verticalCenter 36 anchors.verticalCenter: parent.verticalCenter
31 spacing: 5 37 spacing: 8
32 38
33 Text { 39 Row {
34 color: "white" 40 id: workspaces
41
42 property var ignoreWorkspaces: @ignore_workspaces@
43
44 height: parent.height
35 anchors.verticalCenter: parent.verticalCenter 45 anchors.verticalCenter: parent.verticalCenter
36 text: "left" 46 spacing: 0
47
48 Repeater {
49 model: {
50 let currWorkspaces = NiriService.workspaces;
51 const ignoreWorkspaces = Array.from(workspaces.ignoreWorkspaces);
52 currWorkspaces = currWorkspaces.filter(ws => ws.is_active || ignoreWorkspaces.every(iws => iws !== ws.name));
53 currWorkspaces.sort((a, b) => {
54 if (NiriService.outputs?.[a.output]?.logical?.x !== NiriService.outputs?.[b.output]?.logical?.x)
55 return NiriService.outputs?.[a.output]?.logical?.x - NiriService.outputs?.[b.output]?.logical?.x
56 if (NiriService.outputs?.[a.output]?.logical?.y !== NiriService.outputs?.[b.output]?.logical?.y)
57 return NiriService.outputs?.[a.output]?.logical?.y - NiriService.outputs?.[b.output]?.logical?.y
58 return a.idx - b.idx;
59 });
60 return currWorkspaces;
61 }
62
63 Rectangle {
64 property var workspaceData: modelData
65
66 width: wsLabel.contentWidth + 8
67 color: {
68 if (mouseArea.containsMouse) {
69 return "#33808080";
70 }
71 return "transparent";
72 }
73 height: parent.height
74 anchors.verticalCenter: parent.verticalCenter
75
76 MouseArea {
77 id: mouseArea
78
79 anchors.fill: parent
80 hoverEnabled: true
81 cursorShape: Qt.PointingHandCursor
82 enabled: true
83 onClicked: {
84 NiriService.sendCommand({ "Action": { "FocusWorkspace": { "reference": { "Id": workspaceData.id } } } }, _ => {})
85 }
86 }
87
88 Text {
89 id: wsLabel
90
91 font.pointSize: 10
92 font.family: "Fira Sans"
93 color: {
94 if (workspaceData.active_window_id === null)
95 return "#555";
96 if (workspaceData.is_active)
97 return "#23fd00";
98 return "white";
99 }
100 anchors.centerIn: parent
101
102 text: workspaceData.name ? workspaceData.name : workspaceData.idx
103 }
104 }
105 }
37 } 106 }
38 } 107 }
39 108
@@ -41,13 +110,92 @@ PanelWindow {
41 id: center 110 id: center
42 111
43 height: parent.height 112 height: parent.height
113 width: childrenRect.width
44 anchors.centerIn: parent 114 anchors.centerIn: parent
45 spacing: 5 115 spacing: 5
46 116
47 Text { 117 Item {
48 color: "white" 118 id: activeWindowDisplay
119
120 property var activeWindow: {
121 let currWindowId = Array.from(NiriService.workspaces).find(ws => {
122 return ws.output === bar.screen.name && ws.is_active;
123 })?.active_window_id;
124
125 return currWindowId ? Array.from(NiriService.windows).find(win => win.id == currWindowId) : null;
126 }
127 property var windowEntry: activeWindow ? DesktopEntries.heuristicLookup(activeWindow.app_id) : null
128
49 anchors.verticalCenter: parent.verticalCenter 129 anchors.verticalCenter: parent.verticalCenter
50 text: "center" 130 width: activeWindowDisplayContent.width
131 height: parent.height
132
133 Row {
134 id: activeWindowDisplayContent
135
136 width: childrenRect.width
137 height: parent.height
138 anchors.verticalCenter: parent.verticalCenter
139 spacing: 8
140
141 IconImage {
142 id: activeWindowIcon
143
144 height: 14
145 width: 14
146
147 anchors.verticalCenter: parent.verticalCenter
148
149 source: {
150 let icon = activeWindowDisplay.windowEntry?.icon
151 if (typeof icon === 'string' || icon instanceof String) {
152 if (icon.includes("?path=")) {
153 const split = icon.split("?path=")
154 if (split.length !== 2)
155 return icon
156 const name = split[0]
157 const path = split[1]
158 const fileName = name.substring(
159 name.lastIndexOf("/") + 1)
160 return `file://${path}/${fileName}`
161 } else
162 icon = Quickshell.iconPath(icon);
163 return icon
164 }
165 return ""
166 }
167 asynchronous: true
168 smooth: true
169 mipmap: true
170 }
171
172 Text {
173 id: windowTitle
174
175 width: Math.min(implicitWidth, bar.width - 2*Math.max(left.width, right.width) - 2*8 - activeWindowIcon.width - activeWindowDisplayContent.spacing)
176
177 property var appAliases: { "Firefox": "Mozilla Firefox", "mpv Media Player": "mpv", "Thunderbird": "Mozilla Thunderbird", "Thunderbird (LMU)": "Mozilla Thunderbird" }
178
179 elide: Text.ElideRight
180 maximumLineCount: 1
181 color: "white"
182 anchors.verticalCenter: parent.verticalCenter
183 text: {
184 if (!activeWindowDisplay.activeWindow)
185 return "";
186
187 var title = activeWindowDisplay.activeWindow.title;
188 var appName = activeWindowDisplay.windowEntry?.name;
189 if (appAliases[appName])
190 appName = appAliases[appName];
191 if (appName && title.endsWith(appName)) {
192 title = title.substring(0, title.length - appName.length);
193 title = title.replace(/\s*(—|-)\s*$/, "");
194 }
195 return title;
196 }
197 }
198 }
51 } 199 }
52 } 200 }
53 201
@@ -55,10 +203,147 @@ PanelWindow {
55 id: right 203 id: right
56 204
57 height: parent.height 205 height: parent.height
206 width: childrenRect.width
58 anchors.right: parent.right 207 anchors.right: parent.right
59 anchors.rightMargin: 8 208 anchors.rightMargin: 8
60 anchors.verticalCenter: parent.verticalCenter 209 anchors.verticalCenter: parent.verticalCenter
61 spacing: 5 210 spacing: 8
211
212 Rectangle {
213 id: kbdWidget
214
215 property var keyboardAbbrev: { "English (programmer Dvorak)": "dvp", "English (US)": "us" }
216
217 width: kbdLabel.contentWidth
218 color: {
219 /* if (kbdMouseArea.containsMouse) {
220 return "#33808080";
221 } */
222 return "transparent";
223 }
224 height: parent.height
225 anchors.verticalCenter: parent.verticalCenter
226
227 MouseArea {
228 id: kbdMouseArea
229
230 anchors.fill: parent
231 hoverEnabled: true
232 cursorShape: Qt.PointingHandCursor
233 enabled: true
234 onClicked: {
235 NiriService.sendCommand({ "Action": { "SwitchLayout": { "layout": "Next" } } }, _ => {})
236 }
237 }
238
239 Text {
240 id: kbdLabel
241
242 font.pointSize: 10
243 font.family: "Fira Sans"
244 color: {
245 if (NiriService.keyboardLayouts?.current_idx === 0)
246 return "#555";
247 return "white";
248 }
249 anchors.centerIn: parent
250
251 text: {
252 const currentLayout = NiriService.keyboardLayouts?.names?.[NiriService.keyboardLayouts.current_idx];
253 return kbdWidget.keyboardAbbrev[currentLayout] ? kbdWidget.keyboardAbbrev[currentLayout] : currentLayout;
254 }
255 }
256 }
257
258 Item {
259 anchors.verticalCenter: parent.verticalCenter
260 width: systemTrayRow.childrenRect.width
261 height: parent.height
262 clip: true
263
264 Row {
265 id: systemTrayRow
266 anchors.centerIn: parent
267 width: childrenRect.width
268 height: parent.height
269 spacing: 0
270
271 Repeater {
272 model: SystemTray.items.values
273
274 delegate: Item {
275 property var trayItem: modelData
276 property string iconSource: {
277 let icon = trayItem && trayItem.icon
278 if (typeof icon === 'string' || icon instanceof String) {
279 if (icon.includes("?path=")) {
280 const split = icon.split("?path=")
281 if (split.length !== 2)
282 return icon
283 const name = split[0]
284 const path = split[1]
285 const fileName = name.substring(
286 name.lastIndexOf("/") + 1)
287 return `file://${path}/${fileName}`
288 }
289 return icon
290 }
291 return ""
292 }
293
294 width: 16
295 height: parent.height
296 anchors.verticalCenter: parent.verticalCenter
297
298 IconImage {
299 anchors.centerIn: parent
300 width: parent.width
301 height: parent.width
302 source: parent.iconSource
303 asynchronous: true
304 smooth: true
305 mipmap: true
306 }
307
308 MouseArea {
309 id: trayItemArea
310
311 anchors.fill: parent
312 acceptedButtons: Qt.LeftButton | Qt.RightButton
313 hoverEnabled: true
314 cursorShape: Qt.PointingHandCursor
315 onClicked: mouse => {
316 if (!trayItem)
317 return
318
319 if (mouse.button === Qt.LeftButton
320 && !trayItem.onlyMenu) {
321 trayItem.activate()
322 return
323 }
324
325 if (trayItem.hasMenu) {
326 var globalPos = mapToGlobal(0, 0)
327 var currentScreen = screen || Screen
328 var screenX = currentScreen.x || 0
329 var relativeX = globalPos.x - screenX
330 menuAnchor.menu = trayItem.menu
331 menuAnchor.anchor.window = bar
332 menuAnchor.anchor.rect = Qt.rect(
333 relativeX,
334 21,
335 parent.width, 1)
336 menuAnchor.open()
337 }
338 }
339 }
340 }
341 }
342 }
343 QsMenuAnchor {
344 id: menuAnchor
345 }
346 }
62 347
63 Text { 348 Text {
64 id: clock 349 id: clock
@@ -67,8 +352,8 @@ PanelWindow {
67 anchors.verticalCenter: parent.verticalCenter 352 anchors.verticalCenter: parent.verticalCenter
68 353
69 Custom.Chrono { 354 Custom.Chrono {
70 id: chrono 355 id: chrono
71 format: "W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}" 356 format: "W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}"
72 } 357 }
73 358
74 text: chrono.date 359 text: chrono.date