1use std::{fmt::Display, str::FromStr};
2
3use glam::Vec2;
4
5use crate::{Color, Rect};
6
7#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
8pub enum TextAlign {
9 #[default]
10 Start,
11 Center,
12 End,
13}
14
15impl Display for TextAlign {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 TextAlign::Start => write!(f, "start"),
19 TextAlign::Center => write!(f, "center"),
20 TextAlign::End => write!(f, "end"),
21 }
22 }
23}
24
25impl FromStr for TextAlign {
26 type Err = ();
27
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 match s {
30 "left" | "start" => Ok(TextAlign::Start),
31 "center" => Ok(TextAlign::Center),
32 "right" | "end" => Ok(TextAlign::End),
33 _ => Err(()),
34 }
35 }
36}
37
38impl TextAlign {
39 pub fn align(&self, start: f32, end: f32) -> f32 {
40 match self {
41 TextAlign::Start => start,
42 TextAlign::Center => (start + end) / 2.0,
43 TextAlign::End => end,
44 }
45 }
46}
47
48#[derive(Clone, Debug)]
49pub struct TextSection {
50 pub rect: Rect,
51 pub scale: f32,
52 pub h_align: TextAlign,
53 pub v_align: TextAlign,
54 pub wrap: bool,
55 pub text: String,
56 pub font: Option<String>,
57 pub color: Color,
58}
59
60impl Default for TextSection {
61 fn default() -> Self {
62 Self {
63 rect: Rect::new(Vec2::ZERO, Vec2::splat(f32::INFINITY)),
64 scale: 16.0,
65 h_align: TextAlign::Start,
66 v_align: TextAlign::Start,
67 wrap: true,
68 text: String::new(),
69 font: None,
70 color: Color::BLACK,
71 }
72 }
73}
74
75impl TextSection {
76 pub fn aligned_rect(&self) -> Rect {
77 let x = self.h_align.align(self.rect.min.x, self.rect.max.x);
78 let y = self.v_align.align(self.rect.min.y, self.rect.max.y);
79 let position = Vec2::new(x, y);
80
81 Rect::min_size(position, self.rect.size())
82 }
83}
84
85#[derive(Clone, Copy, Debug, PartialEq)]
86pub struct TextHit {
87 pub inside: bool,
88 pub index: usize,
89 pub delta: Vec2,
90}