From d779ac1a59dbcc840fb59140f0f28275017cb7c8 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 31 Jul 2026 15:15:55 +0200 Subject: [PATCH] Cleaner scroll handling --- pulse-ui/src/render.rs | 95 +++++++++++++++++++++-------------- pulse-ui/src/widget/scroll.rs | 6 +-- 2 files changed, 58 insertions(+), 43 deletions(-) diff --git a/pulse-ui/src/render.rs b/pulse-ui/src/render.rs index dea001d..019abc9 100644 --- a/pulse-ui/src/render.rs +++ b/pulse-ui/src/render.rs @@ -15,58 +15,75 @@ pub struct RenderScope { draw_instructions: Vec, } +struct RenderTextResult { + text: String, + line_len: u16, + lines_len: u16, +} + +impl RenderTextResult { + fn insert_newline(&mut self, height: u16) -> bool { + if self.lines_len >= height { + return true; + } + + self.text.push('\n'); + self.line_len = 0; + self.lines_len += 1; + + false + } + + fn insert(&mut self, c: char) { + self.text.push(c); + self.line_len += 1; + } +} + impl RenderScope { pub fn draw_text, T: Display>(&mut self, at: P, text: T) -> u16 { let point: Point = at.into(); - let lines = text - .to_string() - .lines() - .map(|line| { - let mut chars = line.chars().peekable(); - let mut new_line = String::new(); - let mut len = 0; + let text = text.to_string(); + + let mut chars = text.chars().peekable(); + + let mut result = RenderTextResult { + text: String::new(), + line_len: 0, + lines_len: 1, + }; + + while let Some(c) = chars.next() { + if c == '\x1b' && chars.peek() == Some(&'[') { + result.text.push(c); while let Some(c) = chars.next() { - if c == '\x1b' && chars.peek() == Some(&'[') { - new_line.push(c); + result.text.push(c); - while let Some(c) = chars.next() { - new_line.push(c); - - if c.is_ascii_alphabetic() { - break; - } - } - - continue; - } - - new_line.push(c); - len += 1; - - if len >= self.rect.width as usize { - new_line.push('\n'); - len = 0; + if c.is_ascii_alphabetic() { + break; } } + } else if c == '\n' { + if result.insert_newline(self.rect.height) { + break; + } + } else { + result.insert(c); - new_line - }) - .collect::>() - .join("\n"); - - let lines = lines - .lines() - .take((self.rect.height - point.y) as usize) - .collect::>(); - - let lines_len = lines.len(); + if result.line_len >= self.rect.width { + if result.insert_newline(self.rect.height) { + break; + } + } + } + } self.draw_instructions - .push(Instr::DrawText(point, lines.join("\n"))); + .push(Instr::DrawText(point, result.text)); - lines_len as u16 + result.lines_len } } diff --git a/pulse-ui/src/widget/scroll.rs b/pulse-ui/src/widget/scroll.rs index 2a12586..9f80ac7 100644 --- a/pulse-ui/src/widget/scroll.rs +++ b/pulse-ui/src/widget/scroll.rs @@ -10,9 +10,7 @@ pub struct ScrollText { impl Widget for ScrollText { fn render(&self, scope: &mut crate::render::RenderScope) { - scope.draw_text(0, &self.title); - - let title_lines = self.title.lines().count(); + let title_lines = scope.draw_text(0, &self.title); let mut y = title_lines as u16; @@ -20,7 +18,7 @@ impl Widget for ScrollText { .text .lines() .skip(self.scroll) - .take(scope.rect.height as usize - title_lines) + .take((scope.rect.height - title_lines) as usize) { y += scope.draw_text((0, y), line); }