1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
import Quickshell
import Quickshell.Widgets
import QtQuick
import ".."
import "../modules/vm"
import "Logic.js" as Logic
// Date and time at rest, with one dot per VM that is not plainly shut off.
// During a flick: the workspace's desktop icon, the app's icon and its name.
Capsule {
id: pill
property bool flicking: false
property string flickWs: ""
property string flickApp: ""
readonly property var entry: flickApp ? DesktopEntries.heuristicLookup(flickApp) : null
readonly property string wsIcon: Workspaces.icon(flickWs)
// Resolved paths, not names, decide what shows: a name the icon theme
// lacks resolves to "", and testing the name left a blank slot where the
// workspace number should have been.
readonly property string wsPath: wsIcon ? Quickshell.iconPath(wsIcon, true) : ""
readonly property string appPath:
flickApp ? Quickshell.iconPath(entry?.icon || flickApp, true) : ""
restWidth: (flicking ? flickRow.implicitWidth : restRow.implicitWidth) + 28
SystemClock { id: clock; precision: SystemClock.Minutes }
Row {
id: restRow
anchors.centerIn: parent
spacing: 10
opacity: pill.flicking ? 0 : 1
Behavior on opacity { NumberAnimation { duration: 150 } }
Text {
anchors.verticalCenter: parent.verticalCenter
text: Qt.formatDateTime(clock.date, "ddd dd/MM")
font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
color: Theme.subtext
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: Qt.formatDateTime(clock.date, "HH:mm")
font { family: Theme.fontFamily; pixelSize: Theme.fontSize; weight: Font.DemiBold }
color: Theme.text
}
Repeater {
model: Virsh.names.filter(n => Logic.vmRole(Virsh.vms[n]) !== "")
delegate: Rectangle {
required property string modelData
anchors.verticalCenter: parent.verticalCenter
width: 8
height: 8
radius: 4
color: Theme[Logic.vmRole(Virsh.vms[modelData])]
}
}
}
Row {
id: flickRow
anchors.centerIn: parent
spacing: 8
opacity: pill.flicking ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 150 } }
// The desktop sits in a badge so it does not read as a second app
// icon next to the real one.
Rectangle {
anchors.verticalCenter: parent.verticalCenter
implicitWidth: Math.max(26, wsContent.implicitWidth + 10)
implicitHeight: 24
radius: 6
color: Qt.alpha(Theme.surface, 0.9)
border.width: 1
border.color: Qt.alpha(Theme.accent, 0.6)
Item {
id: wsContent
anchors.centerIn: parent
implicitWidth: pill.wsPath !== "" ? wsIconImage.implicitWidth : wsNumber.implicitWidth
implicitHeight: 18
IconImage {
id: wsIconImage
anchors.centerIn: parent
visible: pill.wsPath !== ""
implicitSize: 16
source: pill.wsPath
}
// A named workspace, or one past eight, has no icon: its number.
Text {
id: wsNumber
anchors.centerIn: parent
visible: pill.wsPath === ""
text: pill.flickWs
font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2; weight: Font.DemiBold }
color: Theme.accent
}
}
}
IconImage {
anchors.verticalCenter: parent.verticalCenter
visible: pill.appPath !== ""
implicitSize: 18
source: pill.appPath
}
Text {
anchors.verticalCenter: parent.verticalCenter
visible: pill.flickApp !== ""
text: pill.entry?.name || pill.flickApp
font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1 }
color: Theme.text
}
}
}
|