better line wrap for level descriptions

This commit is contained in:
Crispy 2024-12-21 18:44:49 +01:00
parent 1e370201e1
commit 6900dadd9e
2 changed files with 94 additions and 5 deletions

View file

@ -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;

View file

@ -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<Range<usize>>,
}
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>,