From 39a9166109bb017c39da46f871cffa450f7e8412 Mon Sep 17 00:00:00 2001 From: "Carlos Miguel C. Resurreccion" Date: Fri, 19 Jun 2026 20:10:20 +0800 Subject: [PATCH] refactor: read display flags from state for merge compatibility Revert shared window.rs/poller.rs signatures to base. Detailed-remaining is read from a lock-free poller atomic (countdown formatting) and a shared window-level text-width slot (layout). The slot mechanism block is identical to the ETD branch's so any merge subset stays conflict-free; each branch wires only its own slot. Relocate the localization field to a distinct anchor (after exit). --- README.md | 2 +- src/localization/dutch.rs | 2 +- src/localization/english.rs | 2 +- src/localization/french.rs | 2 +- src/localization/german.rs | 2 +- src/localization/japanese.rs | 2 +- src/localization/korean.rs | 2 +- src/localization/mod.rs | 2 +- src/localization/portuguese_brazil.rs | 2 +- src/localization/russian.rs | 2 +- src/localization/spanish.rs | 2 +- src/localization/traditional_chinese.rs | 2 +- src/poller.rs | 40 +++++--- src/window.rs | 131 +++++++++++++----------- 14 files changed, 111 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index eb20097..be1cc27 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,8 @@ Once running, it will appear in your taskbar and as one or more tray icons in th - Drag the left divider to move the taskbar widget - Right-click the taskbar widget or tray icon for refresh, displayed models, update frequency, Start with Windows, reset position, language, updates, and exit - Left-click the tray icon to toggle the taskbar widget on or off -- Enable `Start with Windows` from the right-click menu if you want it to launch automatically when you sign in - Enable `Show detailed remaining time` under right-click `Settings` to add minutes alongside hours (5h window) and hours alongside days (7d window) +- Enable `Start with Windows` from the right-click menu if you want it to launch automatically when you sign in ### Models diff --git a/src/localization/dutch.rs b/src/localization/dutch.rs index be4f3bd..bbdc849 100644 --- a/src/localization/dutch.rs +++ b/src/localization/dutch.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "Instellingen", start_with_windows: "Opstarten met Windows", reset_position: "Positie herstellen", - show_detailed_remaining: "Gedetailleerde resterende tijd tonen", language: "Taal", system_default: "Systeemstandaard", check_for_updates: "Controleren op updates", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "Update beschikbaar", update_prompt_now: "Versie {version} is beschikbaar. Wil je nu bijwerken?", exit: "Afsluiten", + show_detailed_remaining: "Gedetailleerde resterende tijd tonen", show_widget: "Widget tonen", session_window: "5u", weekly_window: "7d", diff --git a/src/localization/english.rs b/src/localization/english.rs index 32c81a9..848dd7e 100644 --- a/src/localization/english.rs +++ b/src/localization/english.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "Settings", start_with_windows: "Start with Windows", reset_position: "Reset Position", - show_detailed_remaining: "Show detailed remaining time", language: "Language", system_default: "System Default", check_for_updates: "Check for Updates", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "Update available", update_prompt_now: "Version {version} is available. Do you want to update now?", exit: "Exit", + show_detailed_remaining: "Show detailed remaining time", show_widget: "Show Widget", session_window: "5h", weekly_window: "7d", diff --git a/src/localization/french.rs b/src/localization/french.rs index 195b1a3..988067f 100644 --- a/src/localization/french.rs +++ b/src/localization/french.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "Paramètres", start_with_windows: "Démarrer avec Windows", reset_position: "Réinitialiser la position", - show_detailed_remaining: "Afficher le temps restant détaillé", language: "Langue", system_default: "Par défaut du système", check_for_updates: "Vérifier les mises à jour", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "Mise à jour disponible", update_prompt_now: "La version {version} est disponible. Voulez-vous mettre à jour maintenant ?", exit: "Quitter", + show_detailed_remaining: "Afficher le temps restant détaillé", show_widget: "Afficher le widget", session_window: "5h", weekly_window: "7d", diff --git a/src/localization/german.rs b/src/localization/german.rs index d86dc2c..f714d83 100644 --- a/src/localization/german.rs +++ b/src/localization/german.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "Einstellungen", start_with_windows: "Mit Windows starten", reset_position: "Position zurücksetzen", - show_detailed_remaining: "Detaillierte Restzeit anzeigen", language: "Sprache", system_default: "Systemstandard", check_for_updates: "Nach Updates suchen", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "Update verfügbar", update_prompt_now: "Version {version} ist verfügbar. Möchten Sie jetzt aktualisieren?", exit: "Beenden", + show_detailed_remaining: "Detaillierte Restzeit anzeigen", show_widget: "Widget anzeigen", session_window: "5h", weekly_window: "7d", diff --git a/src/localization/japanese.rs b/src/localization/japanese.rs index 3b7b269..e40cd57 100644 --- a/src/localization/japanese.rs +++ b/src/localization/japanese.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "設定", start_with_windows: "Windows と同時に開始", reset_position: "位置をリセット", - show_detailed_remaining: "残り時間を詳細表示", language: "言語", system_default: "システム既定", check_for_updates: "更新を確認", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "更新が利用可能です", update_prompt_now: "バージョン {version} が利用可能です。今すぐ更新しますか?", exit: "終了", + show_detailed_remaining: "残り時間を詳細表示", show_widget: "ウィジェットを表示", session_window: "5h", weekly_window: "7d", diff --git a/src/localization/korean.rs b/src/localization/korean.rs index 0fc9bb0..61a5ace 100644 --- a/src/localization/korean.rs +++ b/src/localization/korean.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "설정", start_with_windows: "Windows 시작 시 자동 실행", reset_position: "위치 초기화", - show_detailed_remaining: "남은 시간 상세 표시", language: "언어", system_default: "시스템 기본값", check_for_updates: "업데이트 확인", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "업데이트 사용 가능", update_prompt_now: "버전 {version}을 사용할 수 있습니다. 지금 업데이트하시겠습니까?", exit: "종료", + show_detailed_remaining: "남은 시간 상세 표시", show_widget: "위젯 표시", session_window: "5시간", weekly_window: "7일", diff --git a/src/localization/mod.rs b/src/localization/mod.rs index 89a77b0..b660917 100644 --- a/src/localization/mod.rs +++ b/src/localization/mod.rs @@ -150,7 +150,6 @@ pub struct Strings { pub settings: &'static str, pub start_with_windows: &'static str, pub reset_position: &'static str, - pub show_detailed_remaining: &'static str, pub language: &'static str, pub system_default: &'static str, pub check_for_updates: &'static str, @@ -165,6 +164,7 @@ pub struct Strings { pub update_available: &'static str, pub update_prompt_now: &'static str, pub exit: &'static str, + pub show_detailed_remaining: &'static str, pub show_widget: &'static str, pub session_window: &'static str, pub weekly_window: &'static str, diff --git a/src/localization/portuguese_brazil.rs b/src/localization/portuguese_brazil.rs index 631c6b5..9df7f3e 100644 --- a/src/localization/portuguese_brazil.rs +++ b/src/localization/portuguese_brazil.rs @@ -30,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "Atualização disponível", update_prompt_now: "Versão {version} está disponível. Deseja atualizar agora?", exit: "Sair", + show_detailed_remaining: "Mostrar tempo restante detalhado", show_widget: "Exibir Widget", session_window: "5h", weekly_window: "7d", @@ -43,5 +44,4 @@ pub(super) const STRINGS: Strings = Strings { codex_token_expired_title: "Erro de Autenticação do Codex", codex_token_expired_body: "Execute 'codex' em um terminal e siga as instruções de login. Depois disso, atualize ou reinicie este aplicativo.", codex_window_title: "Monitor de uso do Codex", - show_detailed_remaining: "Mostrar tempo restante detalhado", }; diff --git a/src/localization/russian.rs b/src/localization/russian.rs index 7cfa3df..816d53d 100644 --- a/src/localization/russian.rs +++ b/src/localization/russian.rs @@ -30,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "Доступно обновление", update_prompt_now: "Доступна версия {version}. Обновить сейчас?", exit: "Выход", + show_detailed_remaining: "Показывать подробное оставшееся время", show_widget: "Показать виджет", session_window: "5ч", weekly_window: "7д", @@ -43,5 +44,4 @@ pub(super) const STRINGS: Strings = Strings { codex_token_expired_title: "Ошибка авторизации Codex", codex_token_expired_body: "Запустите 'codex' в терминале и следуйте инструкциям для входа. После этого обновите или перезапустите приложение.", codex_window_title: "Монитор использования Codex", - show_detailed_remaining: "Показывать подробное оставшееся время", }; \ No newline at end of file diff --git a/src/localization/spanish.rs b/src/localization/spanish.rs index 0538516..f43d49a 100644 --- a/src/localization/spanish.rs +++ b/src/localization/spanish.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "Configuración", start_with_windows: "Iniciar con Windows", reset_position: "Restablecer posición", - show_detailed_remaining: "Mostrar tiempo restante detallado", language: "Idioma", system_default: "Predeterminado del sistema", check_for_updates: "Buscar actualizaciones", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "Actualización disponible", update_prompt_now: "La versión {version} está disponible. ¿Quieres actualizar ahora?", exit: "Salir", + show_detailed_remaining: "Mostrar tiempo restante detallado", show_widget: "Mostrar widget", session_window: "5h", weekly_window: "7d", diff --git a/src/localization/traditional_chinese.rs b/src/localization/traditional_chinese.rs index 4f74537..fd94ddd 100644 --- a/src/localization/traditional_chinese.rs +++ b/src/localization/traditional_chinese.rs @@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings { settings: "設定", start_with_windows: "開機時啟動", reset_position: "重置位置", - show_detailed_remaining: "顯示詳細剩餘時間", language: "語言", system_default: "系統預設", check_for_updates: "檢查更新", @@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings { update_available: "有可用更新", update_prompt_now: "版本 {version} 已可用。是否立即更新?", exit: "結束", + show_detailed_remaining: "顯示詳細剩餘時間", show_widget: "顯示小工具", session_window: "5h", weekly_window: "7d", diff --git a/src/poller.rs b/src/poller.rs index d379722..75e32af 100644 --- a/src/poller.rs +++ b/src/poller.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; use std::process::Command; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use serde::Deserialize; @@ -1020,10 +1021,25 @@ fn is_leap(y: u64) -> bool { (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 } +/// Detailed remaining-time flag, mirrored from window state. Read lock-free +/// here so the countdown formatters (which run while the window state lock is +/// held) never re-lock shared state. Kept at base signatures so other features +/// that call these formatters stay source-compatible. +static DETAILED_REMAINING: AtomicBool = AtomicBool::new(false); + +/// Update the detailed remaining-time flag the formatters read. +pub fn set_detailed_remaining(enabled: bool) { + DETAILED_REMAINING.store(enabled, Ordering::Relaxed); +} + +fn detailed_remaining_enabled() -> bool { + DETAILED_REMAINING.load(Ordering::Relaxed) +} + /// Format a usage section as "X% · Yh" style text -pub fn format_line(section: &UsageSection, strings: Strings, detailed: bool) -> String { +pub fn format_line(section: &UsageSection, strings: Strings) -> String { let pct = format!("{:.0}%", section.percentage); - let cd = format_countdown(section.resets_at, strings, detailed); + let cd = format_countdown(section.resets_at, strings); if cd.is_empty() { pct } else { @@ -1031,7 +1047,7 @@ pub fn format_line(section: &UsageSection, strings: Strings, detailed: bool) -> } } -fn format_countdown(resets_at: Option, strings: Strings, detailed: bool) -> String { +fn format_countdown(resets_at: Option, strings: Strings) -> String { let reset = match resets_at { Some(t) => t, None => return String::new(), @@ -1042,23 +1058,18 @@ fn format_countdown(resets_at: Option, strings: Strings, detailed: b Err(_) => return strings.now.to_string(), }; - format_countdown_from_secs(remaining.as_secs(), strings, detailed) + format_countdown_from_secs(remaining.as_secs(), strings) } /// Calculate how long until the display text would change -pub fn time_until_display_change( - resets_at: Option, - detailed: bool, -) -> Option { +pub fn time_until_display_change(resets_at: Option) -> Option { let reset = resets_at?; let remaining = reset.duration_since(SystemTime::now()).ok()?; - Some(time_until_display_change_from_secs( - remaining.as_secs(), - detailed, - )) + Some(time_until_display_change_from_secs(remaining.as_secs())) } -fn format_countdown_from_secs(total_secs: u64, strings: Strings, detailed: bool) -> String { +fn format_countdown_from_secs(total_secs: u64, strings: Strings) -> String { + let detailed = detailed_remaining_enabled(); let total_mins = total_secs / 60; let total_hours = total_secs / 3600; let total_days = total_secs / 86400; @@ -1090,7 +1101,8 @@ fn format_countdown_from_secs(total_secs: u64, strings: Strings, detailed: bool) } } -fn time_until_display_change_from_secs(total_secs: u64, detailed: bool) -> Duration { +fn time_until_display_change_from_secs(total_secs: u64) -> Duration { + let detailed = detailed_remaining_enabled(); let total_mins = total_secs / 60; let total_hours = total_secs / 3600; let total_days = total_secs / 86400; diff --git a/src/window.rs b/src/window.rs index d122fd8..30eec8e 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,5 +1,5 @@ use std::path::PathBuf; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use std::sync::{Mutex, MutexGuard}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -421,22 +421,21 @@ fn refresh_usage_texts(state: &mut AppState) { } let strings = state.language.strings(); - let detailed = state.show_detailed_remaining; let Some(data) = state.data.as_ref() else { return; }; if let Some(claude_code) = data.claude_code.as_ref() { - state.session_text = poller::format_line(&claude_code.session, strings, detailed); - state.weekly_text = poller::format_line(&claude_code.weekly, strings, detailed); + state.session_text = poller::format_line(&claude_code.session, strings); + state.weekly_text = poller::format_line(&claude_code.weekly, strings); } else if state.show_claude_code { state.session_text = "!".to_string(); state.weekly_text = "!".to_string(); } if let Some(codex) = data.codex.as_ref() { - state.codex_session_text = poller::format_line(&codex.session, strings, detailed); - state.codex_weekly_text = poller::format_line(&codex.weekly, strings, detailed); + state.codex_session_text = poller::format_line(&codex.session, strings); + state.codex_weekly_text = poller::format_line(&codex.weekly, strings); } else if state.show_codex { state.codex_session_text = "!".to_string(); state.codex_weekly_text = "!".to_string(); @@ -834,12 +833,31 @@ fn active_model_count(show_claude_code: bool, show_codex: bool) -> i32 { (show_claude_code as i32 + show_codex as i32).max(1) } -fn text_width_for(detailed: bool) -> i32 { - if detailed { - TEXT_WIDTH_DETAILED - } else { - TEXT_WIDTH - } +// Optional display features may widen the usage text column. Each feature +// stores its own extra width (in base 96-DPI px) in a dedicated slot, read +// lock-free by the width/layout helpers below. Slots are summed so multiple +// features stack. This block is identical across the display-feature branches +// so they merge without conflict; a branch only wires up its own slot. +#[allow(dead_code)] +static EXTRA_TEXT_WIDTH_DETAILED: AtomicI32 = AtomicI32::new(0); +#[allow(dead_code)] +static EXTRA_TEXT_WIDTH_ETD: AtomicI32 = AtomicI32::new(0); + +#[allow(dead_code)] +fn set_extra_text_width_detailed(px: i32) { + EXTRA_TEXT_WIDTH_DETAILED.store(px, Ordering::Relaxed); +} + +#[allow(dead_code)] +fn set_extra_text_width_etd(px: i32) { + EXTRA_TEXT_WIDTH_ETD.store(px, Ordering::Relaxed); +} + +/// Usage text-column width including any enabled display-feature widening. +fn effective_text_width() -> i32 { + TEXT_WIDTH + + EXTRA_TEXT_WIDTH_DETAILED.load(Ordering::Relaxed) + + EXTRA_TEXT_WIDTH_ETD.load(Ordering::Relaxed) } fn row_bar_segment_count(active_models: i32) -> i32 { @@ -850,11 +868,20 @@ fn row_bar_segment_count(active_models: i32) -> i32 { } } -fn total_widget_width_for(active_models: i32, detailed: bool) -> i32 { +/// Whether the detailed remaining-time display is enabled, read from shared +/// state. Returns false when state is not yet populated (startup) or the lock +/// cannot be acquired. Callers must not hold the state lock. +fn show_detailed_remaining_enabled() -> bool { + lock_state() + .as_ref() + .map_or(false, |s| s.show_detailed_remaining) +} + +fn total_widget_width_for(active_models: i32) -> i32 { let bar_segments = row_bar_segment_count(active_models); let model_width = (sc(SEGMENT_W) + sc(SEGMENT_GAP)) * bar_segments - sc(SEGMENT_GAP) + sc(BAR_RIGHT_MARGIN) - + sc(text_width_for(detailed)); + + sc(effective_text_width()); sc(LEFT_DIVIDER_W) + sc(DIVIDER_RIGHT_MARGIN) @@ -865,27 +892,15 @@ fn total_widget_width_for(active_models: i32, detailed: bool) -> i32 { + sc(RIGHT_MARGIN) } -fn total_widget_width_for_state(state: &AppState) -> i32 { - total_widget_width_for( - active_model_count(state.show_claude_code, state.show_codex), - state.show_detailed_remaining, - ) -} - fn total_widget_width() -> i32 { - let (active_models, detailed) = { + let active_models = { let state = lock_state(); state .as_ref() - .map(|s| { - ( - active_model_count(s.show_claude_code, s.show_codex), - s.show_detailed_remaining, - ) - }) - .unwrap_or((1, false)) + .map(|s| active_model_count(s.show_claude_code, s.show_codex)) + .unwrap_or(1) }; - total_widget_width_for(active_models, detailed) + total_widget_width_for(active_models) } fn claude_accent_color() -> Color { @@ -986,7 +1001,7 @@ pub fn run() { WS_POPUP, 0, 0, - total_widget_width_for(initial_model_count, settings.show_detailed_remaining), + total_widget_width_for(initial_model_count), sc(WIDGET_HEIGHT), HWND::default(), HMENU::default(), @@ -1058,6 +1073,15 @@ pub fn run() { }); } + // Mirror the detailed-remaining flag into the poller, which reads it + // lock-free while formatting countdowns (avoids re-locking shared state). + poller::set_detailed_remaining(settings.show_detailed_remaining); + set_extra_text_width_detailed(if settings.show_detailed_remaining { + TEXT_WIDTH_DETAILED - TEXT_WIDTH + } else { + 0 + }); + // Try to embed in taskbar if let Some(taskbar_hwnd) = native_interop::find_taskbar() { diagnose::log(format!("taskbar found hwnd={:?}", taskbar_hwnd)); @@ -1179,7 +1203,6 @@ fn render_layered() { codex_weekly_text, show_claude_code, show_codex, - show_detailed_remaining, ) = { let state = lock_state(); match state.as_ref() { @@ -1198,7 +1221,6 @@ fn render_layered() { s.codex_weekly_text.clone(), s.show_claude_code, s.show_codex, - s.show_detailed_remaining, ), None => return, } @@ -1289,7 +1311,6 @@ fn render_layered() { show_claude_code, show_codex, &codex_accent, - show_detailed_remaining, ); // Background pixels → alpha 1 (nearly invisible but still hittable for right-click). @@ -1360,7 +1381,6 @@ fn paint_content( show_claude_code: bool, show_codex: bool, codex_accent: &Color, - detailed: bool, ) { unsafe { let client_rect = RECT { @@ -1453,7 +1473,6 @@ fn paint_content( accent, codex_accent, track, - detailed, ); draw_row( hdc, @@ -1471,7 +1490,6 @@ fn paint_content( accent, codex_accent, track, - detailed, ); SelectObject(hdc, old_font); @@ -1662,20 +1680,19 @@ fn schedule_countdown_timer() { } } - let detailed = s.show_detailed_remaining; let delays = [ data.claude_code .as_ref() - .and_then(|usage| poller::time_until_display_change(usage.session.resets_at, detailed)), + .and_then(|usage| poller::time_until_display_change(usage.session.resets_at)), data.claude_code .as_ref() - .and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at, detailed)), + .and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at)), data.codex .as_ref() - .and_then(|usage| poller::time_until_display_change(usage.session.resets_at, detailed)), + .and_then(|usage| poller::time_until_display_change(usage.session.resets_at)), data.codex .as_ref() - .and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at, detailed)), + .and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at)), ]; let min_delay = delays.into_iter().flatten().min(); @@ -2046,6 +2063,9 @@ unsafe extern "system" fn wnd_proc( if is_dragging { let mut pt = POINT::default(); let _ = GetCursorPos(&mut pt); + // Compute the widget width before locking; the width helpers read + // shared state themselves and must not run while the lock is held. + let widget_width = total_widget_width(); let move_target = { let mut state = lock_state(); let s = match state.as_mut() { @@ -2079,7 +2099,6 @@ unsafe extern "system" fn wnd_proc( tray_left = tray_rect.left; } } - let widget_width = total_widget_width_for_state(s); let max_offset = (tray_left - taskbar_rect.left - widget_width).max(0); if new_offset > max_offset { new_offset = max_offset; @@ -2257,6 +2276,12 @@ unsafe extern "system" fn wnd_proc( let mut state = lock_state(); if let Some(s) = state.as_mut() { s.show_detailed_remaining = !s.show_detailed_remaining; + poller::set_detailed_remaining(s.show_detailed_remaining); + set_extra_text_width_detailed(if s.show_detailed_remaining { + TEXT_WIDTH_DETAILED - TEXT_WIDTH + } else { + 0 + }); refresh_usage_texts(s); } } @@ -2378,7 +2403,6 @@ fn show_context_menu(hwnd: HWND) { widget_visible, show_claude_code, show_codex, - show_detailed_remaining, ) = { let state = lock_state(); match state.as_ref() { @@ -2392,7 +2416,6 @@ fn show_context_menu(hwnd: HWND) { s.widget_visible, s.show_claude_code, s.show_codex, - s.show_detailed_remaining, ), None => ( POLL_15_MIN, @@ -2404,7 +2427,6 @@ fn show_context_menu(hwnd: HWND) { true, true, false, - false, ), } }; @@ -2511,7 +2533,7 @@ fn show_context_menu(hwnd: HWND) { ); let detailed_str = native_interop::wide_str(strings.show_detailed_remaining); - let detailed_flags = if show_detailed_remaining { + let detailed_flags = if show_detailed_remaining_enabled() { MF_CHECKED } else { MENU_ITEM_FLAGS(0) @@ -2646,7 +2668,6 @@ fn paint(hdc: HDC, hwnd: HWND) { codex_weekly_text, show_claude_code, show_codex, - show_detailed_remaining, ) = { let state = lock_state(); match state.as_ref() { @@ -2663,7 +2684,6 @@ fn paint(hdc: HDC, hwnd: HWND) { s.codex_weekly_text.clone(), s.show_claude_code, s.show_codex, - s.show_detailed_remaining, ), None => return, } @@ -2722,7 +2742,6 @@ fn paint(hdc: HDC, hwnd: HWND) { show_claude_code, show_codex, &codex_accent, - show_detailed_remaining, ); let _ = BitBlt(hdc, 0, 0, width, height, mem_dc, 0, 0, SRCCOPY); @@ -2749,7 +2768,6 @@ fn draw_row( claude_accent: &Color, codex_accent: &Color, track: &Color, - detailed: bool, ) { let seg_h = sc(SEGMENT_H); let active_models = active_model_count(show_claude_code, show_codex); @@ -2794,9 +2812,8 @@ fn draw_row( claude_accent, track, &claude_value_color, - detailed, ); - model_x += model_usage_width(segment_count, detailed) + sc(MODEL_RIGHT_MARGIN); + model_x += model_usage_width(segment_count) + sc(MODEL_RIGHT_MARGIN); } if show_codex { draw_usage_bar( @@ -2809,16 +2826,15 @@ fn draw_row( codex_accent, track, &codex_value_color, - detailed, ); } } } -fn model_usage_width(segment_count: i32, detailed: bool) -> i32 { +fn model_usage_width(segment_count: i32) -> i32 { (sc(SEGMENT_W) + sc(SEGMENT_GAP)) * segment_count - sc(SEGMENT_GAP) + sc(BAR_RIGHT_MARGIN) - + sc(text_width_for(detailed)) + + sc(effective_text_width()) } fn draw_usage_bar( @@ -2831,7 +2847,6 @@ fn draw_usage_bar( accent: &Color, track: &Color, text_color: &Color, - detailed: bool, ) { let seg_w = sc(SEGMENT_W); let seg_h = sc(SEGMENT_H); @@ -2892,7 +2907,7 @@ fn draw_usage_bar( let mut text_rect = RECT { left: text_x, top: y, - right: text_x + sc(text_width_for(detailed)), + right: text_x + sc(effective_text_width()), bottom: y + seg_h, }; let _ = SetTextColor(hdc, COLORREF(text_color.to_colorref()));