Skip to content

Commit 4b30520

Browse files
committed
refactor: size usage-cell column to measured text width
1 parent 38c4132 commit 4b30520

1 file changed

Lines changed: 72 additions & 4 deletions

File tree

‎src/window.rs‎

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::path::PathBuf;
2-
use std::sync::atomic::{AtomicU32, Ordering};
2+
use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
33
use std::sync::{Mutex, MutexGuard};
44
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
55

@@ -491,6 +491,8 @@ fn refresh_usage_texts(state: &mut AppState) {
491491
state.codex_session_text = "!".to_string();
492492
state.codex_weekly_text = "!".to_string();
493493
}
494+
495+
update_measured_text_width(state);
494496
}
495497

496498
fn set_window_title(hwnd: HWND, strings: Strings) {
@@ -883,6 +885,72 @@ fn active_model_count(show_claude_code: bool, show_codex: bool) -> i32 {
883885
(show_claude_code as i32 + show_codex as i32).max(1)
884886
}
885887

888+
/// Small trailing padding (device px, unscaled) added after measured text.
889+
const TEXT_MEASURE_PAD: i32 = 6;
890+
891+
/// Width (device px, already DPI-scaled) of the widest usage-cell text actually
892+
/// shown, recomputed whenever the texts change. The cell column sizes to real
893+
/// content (detailed time / ETD suffix only when present) instead of a fixed
894+
/// worst-case reservation. Falls back to the base column before first measure.
895+
static MEASURED_TEXT_WIDTH: AtomicI32 = AtomicI32::new(0);
896+
897+
fn current_text_width() -> i32 {
898+
MEASURED_TEXT_WIDTH.load(Ordering::Relaxed).max(sc(TEXT_WIDTH))
899+
}
900+
901+
/// Measure a string's pixel width in the same font the widget renders with.
902+
fn measure_text_px(text: &str) -> i32 {
903+
if text.is_empty() {
904+
return 0;
905+
}
906+
unsafe {
907+
let hdc = GetDC(HWND::default());
908+
let mem = CreateCompatibleDC(hdc);
909+
let font_name = native_interop::wide_str("Segoe UI");
910+
let font = CreateFontW(
911+
sc(-12),
912+
0,
913+
0,
914+
0,
915+
FW_MEDIUM.0 as i32,
916+
0,
917+
0,
918+
0,
919+
DEFAULT_CHARSET.0 as u32,
920+
OUT_TT_PRECIS.0 as u32,
921+
CLIP_DEFAULT_PRECIS.0 as u32,
922+
CLEARTYPE_QUALITY.0 as u32,
923+
(DEFAULT_PITCH.0 | FF_DONTCARE.0) as u32,
924+
PCWSTR::from_raw(font_name.as_ptr()),
925+
);
926+
let old = SelectObject(mem, font);
927+
let wide: Vec<u16> = text.encode_utf16().collect();
928+
let mut size = SIZE::default();
929+
let _ = GetTextExtentPoint32W(mem, &wide, &mut size);
930+
SelectObject(mem, old);
931+
let _ = DeleteObject(font);
932+
let _ = DeleteDC(mem);
933+
ReleaseDC(HWND::default(), hdc);
934+
size.cx
935+
}
936+
}
937+
938+
/// Recompute the measured cell-text width from the currently-visible texts.
939+
fn update_measured_text_width(state: &AppState) {
940+
let mut max_w = 0;
941+
if state.show_claude_code {
942+
max_w = max_w.max(measure_text_px(&state.session_text));
943+
max_w = max_w.max(measure_text_px(&state.weekly_text));
944+
}
945+
if state.show_codex {
946+
max_w = max_w.max(measure_text_px(&state.codex_session_text));
947+
max_w = max_w.max(measure_text_px(&state.codex_weekly_text));
948+
}
949+
if max_w > 0 {
950+
MEASURED_TEXT_WIDTH.store(max_w + sc(TEXT_MEASURE_PAD), Ordering::Relaxed);
951+
}
952+
}
953+
886954
fn row_bar_segment_count(active_models: i32) -> i32 {
887955
if active_models > 1 {
888956
5
@@ -895,7 +963,7 @@ fn total_widget_width_for(active_models: i32) -> i32 {
895963
let bar_segments = row_bar_segment_count(active_models);
896964
let model_width = (sc(SEGMENT_W) + sc(SEGMENT_GAP)) * bar_segments - sc(SEGMENT_GAP)
897965
+ sc(BAR_RIGHT_MARGIN)
898-
+ sc(TEXT_WIDTH);
966+
+ current_text_width();
899967

900968
sc(LEFT_DIVIDER_W)
901969
+ sc(DIVIDER_RIGHT_MARGIN)
@@ -2946,7 +3014,7 @@ fn draw_row(
29463014
fn model_usage_width(segment_count: i32) -> i32 {
29473015
(sc(SEGMENT_W) + sc(SEGMENT_GAP)) * segment_count - sc(SEGMENT_GAP)
29483016
+ sc(BAR_RIGHT_MARGIN)
2949-
+ sc(TEXT_WIDTH)
3017+
+ current_text_width()
29503018
}
29513019

29523020
fn draw_usage_bar(
@@ -3112,7 +3180,7 @@ fn draw_usage_bar(
31123180
let mut text_rect = RECT {
31133181
left: text_x,
31143182
top: y,
3115-
right: text_x + sc(TEXT_WIDTH),
3183+
right: text_x + current_text_width(),
31163184
bottom: y + seg_h,
31173185
};
31183186
let _ = SetTextColor(hdc, COLORREF(text_color.to_colorref()));

0 commit comments

Comments
 (0)