11use std:: path:: PathBuf ;
2- use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
2+ use std:: sync:: atomic:: { AtomicI32 , AtomicU32 , Ordering } ;
33use std:: sync:: { Mutex , MutexGuard } ;
44use 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
496498fn 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+
886954fn 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(
29463014fn 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
29523020fn 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