diff --git a/wlx-overlay-s/src/gui/README.md b/wlx-overlay-s/src/gui/README.md
index d7b0cda5..be091422 100644
--- a/wlx-overlay-s/src/gui/README.md
+++ b/wlx-overlay-s/src/gui/README.md
@@ -18,6 +18,16 @@ See the Custom Timezones section for more info on timezones. Skip `_timezone` to
```
+#### Timer label
+
+Instead of a clock, this label shows the amount of time since program start, (aka time in VR).
+
+Use `_format` to arrange `%h` hours, `%m` minutes, and `%s` seconds.
+
+```xml
+
+```
+
#### Battery label
This is a label type that's used internally to display battery states.
diff --git a/wlx-overlay-s/src/gui/panel/label.rs b/wlx-overlay-s/src/gui/panel/label.rs
index ea4b6888..72bce9db 100644
--- a/wlx-overlay-s/src/gui/panel/label.rs
+++ b/wlx-overlay-s/src/gui/panel/label.rs
@@ -1,5 +1,6 @@
use std::rc::Rc;
+use chrono::DateTime;
use chrono::Local;
use chrono_tz::Tz;
use wgui::{
@@ -121,6 +122,19 @@ pub(super) fn setup_custom_label(
Ok(EventResult::Pass)
})
}
+ "timer" => {
+ let format = attribs.get_value("_format").unwrap_or("%h:%m");
+
+ let state = TimerLabelState {
+ start: Local::now(),
+ format: format.into(),
+ };
+
+ Box::new(move |common, data, _, _| {
+ timer_on_tick(&state, common, data);
+ Ok(EventResult::Pass)
+ })
+ }
"ipd" => Box::new(|common, data, app, _| {
ipd_on_tick(common, data, app);
Ok(EventResult::Pass)
@@ -198,6 +212,30 @@ fn clock_on_tick(
label.set_text(common, Translation::from_raw_text(&date_time));
}
+struct TimerLabelState {
+ start: DateTime,
+ format: Rc,
+}
+
+fn timer_on_tick(
+ state: &TimerLabelState,
+ common: &mut event::CallbackDataCommon,
+ data: &mut event::CallbackData,
+) {
+ let duration = Local::now()
+ .signed_duration_since(&state.start)
+ .num_seconds();
+
+ let time = &state
+ .format
+ .replace("%s", &format!("{:02}", (duration % 60)))
+ .replace("%m", &format!("{:02}", ((duration / 60) % 60)))
+ .replace("%h", &format!("{:02}", ((duration / 60) / 60)));
+
+ let label = data.obj.get_as_mut::().unwrap();
+ label.set_text(common, Translation::from_raw_text(&time));
+}
+
fn ipd_on_tick(
common: &mut event::CallbackDataCommon,
data: &mut event::CallbackData,