diff --git a/.gitignore b/.gitignore index 0475229..80a3a1f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Visual Studio +*.vs/ + # Rust build artifacts /target/ diff --git a/src/localization/english.rs b/src/localization/english.rs index ce80505..4e753cb 100644 --- a/src/localization/english.rs +++ b/src/localization/english.rs @@ -11,6 +11,7 @@ pub(super) const STRINGS: Strings = Strings { fifteen_minutes: "15 Minutes", one_hour: "1 Hour", settings: "Settings", + show_decimals: "Show Decimals", start_with_windows: "Start with Windows", reset_position: "Reset Position", language: "Language", diff --git a/src/localization/french.rs b/src/localization/french.rs index a8ddf7c..af20d13 100644 --- a/src/localization/french.rs +++ b/src/localization/french.rs @@ -11,6 +11,7 @@ pub(super) const STRINGS: Strings = Strings { fifteen_minutes: "15 minutes", one_hour: "1 heure", settings: "Paramètres", + show_decimals: "Afficher les décimales", start_with_windows: "Démarrer avec Windows", reset_position: "Réinitialiser la position", language: "Langue", diff --git a/src/localization/german.rs b/src/localization/german.rs index 7640123..2de54d7 100644 --- a/src/localization/german.rs +++ b/src/localization/german.rs @@ -11,6 +11,7 @@ pub(super) const STRINGS: Strings = Strings { fifteen_minutes: "15 Minuten", one_hour: "1 Stunde", settings: "Einstellungen", + show_decimals: "Dezimalstellen anzeigen", start_with_windows: "Mit Windows starten", reset_position: "Position zurücksetzen", language: "Sprache", diff --git a/src/localization/japanese.rs b/src/localization/japanese.rs index ec55d7e..938c35c 100644 --- a/src/localization/japanese.rs +++ b/src/localization/japanese.rs @@ -11,6 +11,7 @@ pub(super) const STRINGS: Strings = Strings { fifteen_minutes: "15分", one_hour: "1時間", settings: "設定", + show_decimals: "小数点を表示", start_with_windows: "Windows と同時に開始", reset_position: "位置をリセット", language: "言語", diff --git a/src/localization/mod.rs b/src/localization/mod.rs index b5f8097..64d1a86 100644 --- a/src/localization/mod.rs +++ b/src/localization/mod.rs @@ -95,6 +95,7 @@ pub struct Strings { pub fifteen_minutes: &'static str, pub one_hour: &'static str, pub settings: &'static str, + pub show_decimals: &'static str, pub start_with_windows: &'static str, pub reset_position: &'static str, pub language: &'static str, diff --git a/src/localization/spanish.rs b/src/localization/spanish.rs index d525cc3..21d7b1f 100644 --- a/src/localization/spanish.rs +++ b/src/localization/spanish.rs @@ -11,6 +11,7 @@ pub(super) const STRINGS: Strings = Strings { fifteen_minutes: "15 minutos", one_hour: "1 hora", settings: "Configuración", + show_decimals: "Mostrar decimales", start_with_windows: "Iniciar con Windows", reset_position: "Restablecer posición", language: "Idioma", diff --git a/src/poller.rs b/src/poller.rs index 938075c..4441acb 100644 --- a/src/poller.rs +++ b/src/poller.rs @@ -642,9 +642,9 @@ fn is_leap(y: u64) -> bool { } /// Format a usage section as "X% · Yh" style text -pub fn format_line(section: &UsageSection, strings: Strings) -> String { +pub fn format_line(section: &UsageSection, strings: Strings, show_decimals: bool) -> String { let pct = format!("{:.0}%", section.percentage); - let cd = format_countdown(section.resets_at, strings); + let cd = format_countdown(section.resets_at, strings, show_decimals); if cd.is_empty() { pct } else { @@ -652,7 +652,7 @@ pub fn format_line(section: &UsageSection, strings: Strings) -> String { } } -fn format_countdown(resets_at: Option, strings: Strings) -> String { +fn format_countdown(resets_at: Option, strings: Strings, show_decimals: bool) -> String { let reset = match resets_at { Some(t) => t, None => return String::new(), @@ -678,11 +678,21 @@ fn format_countdown_from_secs(total_secs: u64, strings: Strings) -> String { let total_hours = total_secs / 3600; let total_days = total_secs / 86400; - if total_days >= 1 { + let hours_fraction = total_mins / 60; + let days_fraction = total_hours / 24; + let minute_fraction = total_secs / 60; + + if total_days > 0 && show_decimals && days_fraction > 0 { + format!("{total_days}.{days_fraction:01}{}", strings.day_suffix) + } else if total_days > 0 { format!("{total_days}{}", strings.day_suffix) - } else if total_hours >= 1 { + } else if total_hours > 0 && show_decimals && hours_fraction > 0 { + format!("{total_hours}.{hours_fraction:01}{}", strings.hour_suffix) + } else if total_hours > 0 { format!("{total_hours}{}", strings.hour_suffix) - } else if total_mins >= 1 { + } else if total_mins > 0 && show_decimals && minute_fraction > 0 { + format!("{total_mins}.{minute_fraction:01}{}", strings.minute_suffix) + } else if total_mins > 0 { format!("{total_mins}{}", strings.minute_suffix) } else { format!("{total_secs}{}", strings.second_suffix) diff --git a/src/window.rs b/src/window.rs index 2d1b284..61331ae 100644 --- a/src/window.rs +++ b/src/window.rs @@ -72,6 +72,7 @@ struct AppState { dragging: bool, drag_start_mouse_x: i32, drag_start_offset: i32, + show_decimals: bool, widget_visible: bool, } @@ -106,6 +107,7 @@ const IDM_LANG_SPANISH: u16 = 42; const IDM_LANG_FRENCH: u16 = 43; const IDM_LANG_GERMAN: u16 = 44; const IDM_LANG_JAPANESE: u16 = 45; +const IDM_SHOW_DECIMALS: u16 = 50; const DIVIDER_HIT_ZONE: i32 = 13; // LEFT_DIVIDER_W + DIVIDER_RIGHT_MARGIN @@ -189,6 +191,8 @@ struct SettingsFile { language: Option, #[serde(default, skip_serializing_if = "Option::is_none")] last_update_check_unix: Option, + #[serde(default)] + show_decimals: bool, #[serde(default = "default_widget_visible")] widget_visible: bool, } @@ -200,6 +204,7 @@ impl Default for SettingsFile { poll_interval_ms: default_poll_interval(), language: None, last_update_check_unix: None, + show_decimals: true, widget_visible: true, } } @@ -241,6 +246,7 @@ fn save_state_settings() { .language_override .map(|language| language.code().to_string()), last_update_check_unix: s.last_update_check_unix, + show_decimals: s.show_decimals, widget_visible: s.widget_visible, }); } @@ -330,8 +336,8 @@ fn refresh_usage_texts(state: &mut AppState) { let strings = state.language.strings(); let Some((session_text, weekly_text)) = state.data.as_ref().map(|data| { ( - poller::format_line(&data.session, strings), - poller::format_line(&data.weekly, strings), + poller::format_line(&data.session, strings, state.show_decimals), + poller::format_line(&data.weekly, strings, state.show_decimals), ) }) else { return; @@ -722,7 +728,7 @@ const DIVIDER_RIGHT_MARGIN: i32 = 10; const LABEL_WIDTH: i32 = 18; const LABEL_RIGHT_MARGIN: i32 = 10; const BAR_RIGHT_MARGIN: i32 = 4; -const TEXT_WIDTH: i32 = 62; +const TEXT_WIDTH: i32 = 80; const RIGHT_MARGIN: i32 = 1; const WIDGET_HEIGHT: i32 = 46; @@ -860,6 +866,7 @@ pub fn run() { dragging: false, drag_start_mouse_x: 0, drag_start_offset: 0, + show_decimals: settings.show_decimals, widget_visible: settings.widget_visible, }); } @@ -1798,6 +1805,16 @@ unsafe extern "system" fn wnd_proc( IDM_START_WITH_WINDOWS => { set_startup_enabled(!is_startup_enabled()); } + IDM_SHOW_DECIMALS => { + { + let mut state = lock_state(); + if let Some(s) = state.as_mut() { + s.show_decimals = !s.show_decimals; + } + } + save_state_settings(); + render_layered(); + } IDM_FREQ_1MIN | IDM_FREQ_5MIN | IDM_FREQ_15MIN | IDM_FREQ_1HOUR => { let new_interval = match id { IDM_FREQ_1MIN => POLL_1_MIN, @@ -1970,6 +1987,23 @@ fn show_context_menu(hwnd: HWND) { PCWSTR::from_raw(reset_pos_str.as_ptr()), ); + // Show Decimals toggle + let show_decimals_str = native_interop::wide_str(strings.show_decimals); + let show_checked_flags = if { + let state = lock_state(); + state.as_ref().map(|s| s.show_decimals).unwrap_or(true) + } { + MF_CHECKED + } else { + MENU_ITEM_FLAGS(0) + }; + let _ = AppendMenuW( + settings_menu, + show_checked_flags, + IDM_SHOW_DECIMALS as usize, + PCWSTR::from_raw(show_decimals_str.as_ptr()), + ); + let language_menu = CreatePopupMenu().unwrap(); let system_label = native_interop::wide_str(strings.system_default); let system_flags = if language_override.is_none() {