diff options
Diffstat (limited to 'accounts/gkleen@sif/shell/quickshell/Clock.qml')
-rw-r--r-- | accounts/gkleen@sif/shell/quickshell/Clock.qml | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/accounts/gkleen@sif/shell/quickshell/Clock.qml b/accounts/gkleen@sif/shell/quickshell/Clock.qml new file mode 100644 index 00000000..382af168 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Clock.qml | |||
@@ -0,0 +1,283 @@ | |||
1 | import QtQml | ||
2 | import QtQuick | ||
3 | import Quickshell | ||
4 | import Custom as Custom | ||
5 | import QtQuick.Controls | ||
6 | import QtQuick.Layouts | ||
7 | import Quickshell.Widgets | ||
8 | |||
9 | Item { | ||
10 | id: clockItem | ||
11 | |||
12 | property bool calendarPopup: true | ||
13 | |||
14 | width: clock.contentWidth | ||
15 | height: parent.height | ||
16 | anchors.verticalCenter: parent.verticalCenter | ||
17 | |||
18 | WrapperMouseArea { | ||
19 | id: clockMouseArea | ||
20 | |||
21 | anchors.fill: parent | ||
22 | hoverEnabled: true | ||
23 | enabled: clockItem.calendarPopup | ||
24 | |||
25 | Item { | ||
26 | anchors.fill: parent | ||
27 | |||
28 | Text { | ||
29 | id: clock | ||
30 | color: "white" | ||
31 | |||
32 | anchors.verticalCenter: parent.verticalCenter | ||
33 | |||
34 | Custom.Chrono { | ||
35 | id: chrono | ||
36 | |||
37 | onDateChanged: clock.text = format("W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}") | ||
38 | } | ||
39 | |||
40 | font.pointSize: 10 | ||
41 | font.family: "Fira Sans" | ||
42 | font.features: { "tnum": 1 } | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | |||
47 | Loader { | ||
48 | id: tooltipLoader | ||
49 | |||
50 | active: false | ||
51 | |||
52 | Connections { | ||
53 | target: clockMouseArea | ||
54 | function onContainsMouseChanged() { | ||
55 | if (clockMouseArea.containsMouse) | ||
56 | tooltipLoader.active = true; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | sourceComponent: PopupWindow { | ||
61 | id: tooltip | ||
62 | |||
63 | property bool nextVisible: clockMouseArea.containsMouse || tooltipMouseArea.containsMouse | ||
64 | |||
65 | anchor { | ||
66 | item: clockMouseArea | ||
67 | edges: Edges.Bottom | Edges.Left | ||
68 | } | ||
69 | visible: false | ||
70 | |||
71 | onNextVisibleChanged: hangTimer.restart() | ||
72 | |||
73 | Timer { | ||
74 | id: hangTimer | ||
75 | interval: 100 | ||
76 | onTriggered: tooltip.visible = tooltip.nextVisible | ||
77 | } | ||
78 | |||
79 | implicitWidth: clockTooltipContent.width | ||
80 | implicitHeight: clockTooltipContent.height | ||
81 | color: "black" | ||
82 | |||
83 | onVisibleChanged: { | ||
84 | yearCalendar.year = chrono.date.getFullYear(); | ||
85 | yearCalendar.angleRem = 0; | ||
86 | } | ||
87 | |||
88 | WrapperMouseArea { | ||
89 | id: tooltipMouseArea | ||
90 | |||
91 | hoverEnabled: true | ||
92 | enabled: true | ||
93 | |||
94 | onWheel: event => yearCalendar.scrollYear(event) | ||
95 | |||
96 | anchors.fill: parent | ||
97 | |||
98 | WrapperItem { | ||
99 | id: clockTooltipContent | ||
100 | |||
101 | margin: 8 | ||
102 | leftMargin: 0 | ||
103 | |||
104 | ColumnLayout { | ||
105 | Text { | ||
106 | id: yearLabel | ||
107 | |||
108 | horizontalAlignment: Text.AlignHCenter | ||
109 | |||
110 | font.pointSize: 14 | ||
111 | font.family: "Fira Sans" | ||
112 | font.features: { "tnum": 1 } | ||
113 | color: "white" | ||
114 | |||
115 | text: yearCalendar.year | ||
116 | |||
117 | Layout.fillWidth: true | ||
118 | Layout.bottomMargin: 8 | ||
119 | } | ||
120 | |||
121 | GridLayout { | ||
122 | property int year: chrono.date.getFullYear() | ||
123 | |||
124 | id: yearCalendar | ||
125 | |||
126 | columns: 3 | ||
127 | columnSpacing: 16 | ||
128 | rowSpacing: 16 | ||
129 | |||
130 | Layout.alignment: Qt.AlignHCenter | ||
131 | Layout.fillWidth: false | ||
132 | |||
133 | property real angleRem: 0 | ||
134 | property real sensitivity: 1 / 120 | ||
135 | |||
136 | function scrollYear(event) { | ||
137 | angleRem += event.angleDelta.y; | ||
138 | const d = Math.round(angleRem * sensitivity); | ||
139 | yearCalendar.year += d; | ||
140 | angleRem -= d / sensitivity; | ||
141 | } | ||
142 | |||
143 | Connections { | ||
144 | target: clockMouseArea | ||
145 | function onWheel(event) { yearCalendar.scrollYear(event); } | ||
146 | } | ||
147 | |||
148 | Repeater { | ||
149 | model: 12 | ||
150 | |||
151 | GridLayout { | ||
152 | columns: 2 | ||
153 | |||
154 | required property int index | ||
155 | property int month: index | ||
156 | |||
157 | id: monthCalendar | ||
158 | |||
159 | Layout.alignment: Qt.AlignTop | Qt.AlignRight | ||
160 | Layout.fillWidth: false | ||
161 | |||
162 | Text { | ||
163 | Layout.column: 1 | ||
164 | Layout.fillWidth: true | ||
165 | |||
166 | horizontalAlignment: Text.AlignHCenter | ||
167 | |||
168 | font.pointSize: 10 | ||
169 | font.family: "Fira Sans" | ||
170 | |||
171 | text: new Date(yearCalendar.year, monthCalendar.month, 1).toLocaleString(Qt.locale("en_DK"), "MMMM") | ||
172 | |||
173 | color: "#ffead3" | ||
174 | } | ||
175 | |||
176 | DayOfWeekRow { | ||
177 | locale: grid.locale | ||
178 | |||
179 | Layout.row: 1 | ||
180 | Layout.column: 1 | ||
181 | Layout.fillWidth: true | ||
182 | |||
183 | delegate: WrapperItem { | ||
184 | required property string shortName | ||
185 | |||
186 | width: dowLabel.contentWidth + 6 | ||
187 | |||
188 | Text { | ||
189 | id: dowLabel | ||
190 | |||
191 | anchors.fill: parent | ||
192 | |||
193 | font.pointSize: 10 | ||
194 | font.family: "Fira Sans" | ||
195 | |||
196 | text: parent.shortName | ||
197 | color: "#ffcc66" | ||
198 | |||
199 | horizontalAlignment: Text.AlignHCenter | ||
200 | verticalAlignment: Text.AlignVCenter | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | |||
205 | WeekNumberColumn { | ||
206 | month: grid.month | ||
207 | year: grid.year | ||
208 | locale: grid.locale | ||
209 | |||
210 | Layout.fillHeight: true | ||
211 | |||
212 | delegate: Text { | ||
213 | required property int weekNumber | ||
214 | |||
215 | opacity: { | ||
216 | const simple = new Date(weekNumber == 1 && monthCalendar.month == 12 ? yearCalendar.year + 1 : yearCalendar.year, 0, 1 + (weekNumber - 1) * 7); | ||
217 | const dayOfWeek = simple.getDay(); | ||
218 | const isoWeekStart = simple; | ||
219 | |||
220 | isoWeekStart.setDate(simple.getDate() - dayOfWeek + 1); | ||
221 | if (dayOfWeek > 4) { | ||
222 | isoWeekStart.setDate(isoWeekStart.getDate() + 7); | ||
223 | } | ||
224 | |||
225 | for (let i = 0; i < 7; i++) { | ||
226 | const dayInWeek = new Date(isoWeekStart); | ||
227 | dayInWeek.setDate(dayInWeek.getDate() + i); | ||
228 | if (dayInWeek.getMonth() == monthCalendar.month) | ||
229 | return 1; | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | font.pointSize: 10 | ||
236 | font.family: "Fira Sans" | ||
237 | font.features: { "tnum": 1 } | ||
238 | |||
239 | text: weekNumber | ||
240 | color: "#99ffdd" | ||
241 | |||
242 | horizontalAlignment: Text.AlignRight | ||
243 | verticalAlignment: Text.AlignVCenter | ||
244 | } | ||
245 | } | ||
246 | |||
247 | MonthGrid { | ||
248 | id: grid | ||
249 | |||
250 | year: yearCalendar.year | ||
251 | month: monthCalendar.month | ||
252 | locale: Qt.locale("en_DK") | ||
253 | |||
254 | Layout.fillWidth: true | ||
255 | Layout.fillHeight: true | ||
256 | |||
257 | delegate: Text { | ||
258 | required property var model | ||
259 | |||
260 | opacity: model.month === monthCalendar.month ? 1 : 0 | ||
261 | |||
262 | font.pointSize: 10 | ||
263 | font.family: "Fira Sans" | ||
264 | font.features: { "tnum": 1 } | ||
265 | |||
266 | property bool today: chrono.date.getFullYear() == model.year && chrono.date.getMonth() == model.month && chrono.date.getDate() == model.day | ||
267 | |||
268 | text: model.day | ||
269 | color: today ? "#ff6699" : "white" | ||
270 | |||
271 | horizontalAlignment: Text.AlignRight | ||
272 | verticalAlignment: Text.AlignVCenter | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | } | ||