From de2dbab592a0c2c51e27cb4ab13e62535aaec2f6 Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Fri, 6 Nov 2026 08:34:08 +0100 Subject: [PATCH] Tooltips wrap every line and grow with their text Co-Authored-By: Claude Opus 5.5 --- src/ui.rs | 51 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 1622057..b521762 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -515,25 +515,49 @@ pub struct Ui { hud_h: f32, } +// word wrap to `cols` characters: keeps line breaks, splits words longer than a line pub fn wrap(s: &str, cols: usize) -> Vec { + let cols = cols.max(1); let mut out = Vec::new(); - let mut line = String::new(); - for word in s.split(' ') { - let len = line.chars().count(); - if len > 0 && len + 1 + word.chars().count() > cols { - out.push(std::mem::take(&mut line)); + for para in s.split('\n') { + let mut line = String::new(); + for word in para.split(' ') { + let mut word: Vec = word.chars().collect(); + while word.len() > cols { + if !line.is_empty() { + out.push(std::mem::take(&mut line)); + } + out.push(word.drain(..cols).collect()); + } + let word: String = word.into_iter().collect(); + let len = line.chars().count(); + if len > 0 && len + 1 + word.chars().count() > cols { + out.push(std::mem::take(&mut line)); + } + if !line.is_empty() { + line.push(' '); + } + line.push_str(&word); } - if !line.is_empty() { - line.push(' '); - } - line.push_str(word); - } - if !line.is_empty() { out.push(line); } + while out.last().map_or(false, |l| l.is_empty()) { + out.pop(); + } out } +#[cfg(test)] +mod wrap_tests { + #[test] + fn wrap_keeps_every_line_inside() { + let l = super::wrap("Cost: 30 gold + 2 wood/tile over water, 60 gold over lava", 20); + assert!(l.len() >= 3 && l.iter().all(|x| x.chars().count() <= 20), "{:?}", l); + let l = super::wrap("a\nsuperlongwordwithoutanyspaces", 8); + assert_eq!(l[0], "a"); + assert!(l.iter().all(|x| x.chars().count() <= 8), "{:?}", l); + } +} fn mmss(t: f32) -> String { let t = t.max(0.0) as i32; @@ -1149,12 +1173,13 @@ impl Ui { let ti = tool_info(t); let tcols = 34.min(cols as usize); let mut lines: Vec<(String, Color)> = wrap(&ti.desc, tcols - 4).into_iter().map(|l| (l, TXT)).collect(); + // every line wraps; the window grows with the lines let cost = tool_cost(t, g); if !cost.is_empty() { - lines.push((trf("ui.cost", &[cost]), GOLD)); + lines.extend(wrap(&trf("ui.cost", &[cost]), tcols - 4).into_iter().map(|l| (l, GOLD))); } if !touch_ui() { - lines.push((trf("ui.key", &[keys[i].clone()]), DIM)); + lines.extend(wrap(&trf("ui.key", &[keys[i].clone()]), tcols - 4).into_iter().map(|l| (l, DIM))); } let rows = lines.len() as i32 + 2; let anchor = if touch_ui() { sw * 0.5 } else { mx };