From 6900dadd9e89e7be6a4b9596e7b28a71267025cd Mon Sep 17 00:00:00 2001 From: CrispyPin Date: Sat, 21 Dec 2024 18:44:49 +0100 Subject: [PATCH] better line wrap for level descriptions --- src/main.rs | 11 ++++--- src/util.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index e0f22b8..8697c43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ struct Game { selected_level: usize, selected_solution: usize, editing_solution_name: bool, + level_desc_text: ShapedText, } fn main() { @@ -71,6 +72,7 @@ impl Game { selected_level: 0, selected_solution, editing_solution_name: false, + level_desc_text: ShapedText::new(20), } } @@ -181,10 +183,11 @@ impl Game { d.draw_text(level.id(), level_list_width + 10, 50, 10, Color::GRAY); let mut y = 70; - for line in level.description().lines() { - d.draw_text(line, level_list_width + 10, y, 20, Color::WHITE); - y += 30; - } + self.level_desc_text.set_text(level.description()); + self.level_desc_text + .update_width(d, d.get_render_width() - level_list_width - 30); + self.level_desc_text.draw(d, level_list_width + 10, y); + y += self.level_desc_text.height() + 10; if let Some(solutions) = self.solutions.get_mut(level.id()) { let solution_entry_height = 40; diff --git a/src/util.rs b/src/util.rs index 08f2ea7..0e727b2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fs::read_dir, path::PathBuf}; +use std::{collections::HashMap, fs::read_dir, ops::Range, path::PathBuf}; use raylib::prelude::*; @@ -44,6 +44,92 @@ pub fn simple_button(d: &mut RaylibDrawHandle, x: i32, y: i32, width: i32, heigh pressed } +#[derive(Debug)] +pub struct ShapedText { + text: String, + max_width: i32, + font_size: i32, + lines: Vec>, +} + +impl ShapedText { + pub fn new(font_size: i32) -> Self { + Self { + text: String::new(), + font_size, + max_width: 500, + lines: Vec::new(), + } + } + + pub fn set_text(&mut self, text: &str) { + if text != self.text { + self.text = text.to_owned(); + self.lines.clear(); + } + } + + pub fn height(&self) -> i32 { + self.font_size * self.lines.len() as i32 + } + + pub fn update_width(&mut self, d: &RaylibHandle, width: i32) { + if self.max_width == width && !self.lines.is_empty() { + return; + } + self.max_width = width; + self.lines.clear(); + // todo remove leading space on broken lines + // todo fix splitting very long words + let mut line_start = 0; + let mut line_end = 0; + for (i, c) in self.text.char_indices() { + if c == ' ' { + let line = &self.text[line_start..i]; + let new_line_length = d.measure_text(line, self.font_size); + if new_line_length <= self.max_width { + line_end = i; + } else { + self.lines.push(line_start..line_end); + line_start = line_end; + } + } + if c == '\n' { + let line = &self.text[line_start..i]; + let new_line_length = d.measure_text(line, self.font_size); + if new_line_length <= self.max_width { + self.lines.push(line_start..i); + line_end = i + 1; + line_start = i + 1; + } else { + self.lines.push(line_start..line_end); + self.lines.push(line_end..(i + 1)); + line_start = i + 1; + line_end = i + 1; + } + } + } + let i = self.text.len(); + let line = &self.text[line_start..i]; + let new_line_length = d.measure_text(line, self.font_size); + if new_line_length <= self.max_width { + self.lines.push(line_start..i); + } else { + self.lines.push(line_start..line_end); + self.lines.push(line_end..i); + } + } + + pub fn draw(&self, d: &mut RaylibDrawHandle, x: i32, y: i32) { + // d.draw_rectangle(x, y, self.max_width, 4, Color::RED); + for (i, line) in self.lines.iter().enumerate() { + let line = &self.text[line.clone()]; + let line_y = y + self.font_size * i as i32; + d.draw_text(line, x, line_y, self.font_size, Color::WHITE); + } + } +} + #[derive(Debug, Default)] pub struct Tooltip { text: Option<&'static str>,