diff --git a/local/recipes/tui/tlc/source/src/widget/button.rs b/local/recipes/tui/tlc/source/src/widget/button.rs index 4261a2ffa4..46426c1d60 100644 --- a/local/recipes/tui/tlc/source/src/widget/button.rs +++ b/local/recipes/tui/tlc/source/src/widget/button.rs @@ -35,6 +35,9 @@ pub enum ButtonKind { /// MC `DEFPUSH_BUTTON` — `[< X >]`. Enter triggers this when /// focused. Default, + /// MC `NARROW_BUTTON` — `[X]` (no inner padding). Used for + /// compact dialogs and toolbar items. + Narrow, } /// Per-button render spec. @@ -85,6 +88,7 @@ pub fn render_button( let (left, right) = match spec.kind { ButtonKind::Normal => ("[ ", " ]"), ButtonKind::Default => ("[< ", " >]"), + ButtonKind::Narrow => ("[", "]"), }; let mut spans = vec![Span::styled( left.to_string(), @@ -133,14 +137,16 @@ pub fn render_button_row( } } -/// MC button width formula: `label_chars + 4` (Normal) or -/// `label_chars + 6` (Default). +/// MC button width formula: `label_chars + 4` (Normal), `+ 6` +/// (Default), or `+ 2` (Narrow). All variants use unicode-safe +/// `chars().count()` so CJK labels compute correctly. #[must_use] pub fn button_width(spec: ButtonSpec<'_>) -> u16 { let label_chars = spec.label.chars().count() as u16; let padding = match spec.kind { ButtonKind::Normal => 4, ButtonKind::Default => 6, + ButtonKind::Narrow => 2, }; label_chars + padding } @@ -321,4 +327,37 @@ mod tests { assert!(s.starts_with("[ "), "want `[ ...`, got {s:?}"); assert!(s.trim_end().ends_with(" ]"), "want `... ]`, got {s:?}"); } + + #[test] + fn narrow_button_fused_brackets_no_padding() { + // MC NARROW_BUTTON: "[X]" — label + 2, no inner space. + let s = render_test( + ButtonSpec { + label: "OK", + hotkey: Some('O'), + kind: ButtonKind::Narrow, + }, + false, + ); + assert!(s.starts_with("[OK"), "want `[OK...`, got {s:?}"); + assert!(s.trim_end().ends_with("K]"), "want `...K]`, got {s:?}"); + } + + #[test] + fn button_width_unicode_safe() { + // 3 CJK characters + Normal = 3 + 4 = 7 cells (not bytes). + let spec = ButtonSpec { + label: "日本語", + hotkey: Some('本'), + kind: ButtonKind::Normal, + }; + assert_eq!(button_width(spec), 7); + // Same with Default variant. + let spec_d = ButtonSpec { + label: "日本語", + hotkey: Some('本'), + kind: ButtonKind::Default, + }; + assert_eq!(button_width(spec_d), 9); + } } \ No newline at end of file