1use crate::*;
2use std::collections::{HashMap, HashSet};
3use sdl3::{pixels::Color, render::{Canvas, Texture, TextureCreator, TextureValueError, UpdateTextureError}, video::{Window, WindowContext}, Error};
4use ab_glyph::Font;
5
6
7
8pub struct TextRenderingSettings<'a, 'b, F: ThreadSafeFont> {
12 pub size: f32,
14 #[allow(missing_docs)]
15 pub h_align: HAlign,
16 #[allow(missing_docs)]
17 pub v_align: VAlign,
18 #[allow(missing_docs)]
19 pub foreground: Color,
20 pub background: Color,
22 #[allow(missing_docs)]
23 pub canvas: &'a mut Canvas<Window>,
24 #[allow(missing_docs)]
25 pub texture_creator: &'b TextureCreator<WindowContext>,
26 #[allow(missing_docs)]
27 pub text_cache: &'a mut TextCache<'b, F>,
28}
29
30impl<'a, 'b, F: ThreadSafeFont> TextRenderingSettings<'a, 'b, F> {
31 #[allow(clippy::too_many_arguments)]
33 pub fn new_regular(size: f32, h_align: impl Into<HAlign>, v_align: impl Into<VAlign>, foreground: impl Into<Color>, canvas: &'a mut Canvas<Window>, texture_creator: &'b TextureCreator<WindowContext>, text_cache: &'a mut TextCache<'b, F>) -> Self {
34 Self {
35 size,
36 h_align: h_align.into(),
37 v_align: v_align.into(),
38 foreground: foreground.into(),
39 background: Color::RGB(127, 127, 127),
40 canvas,
41 texture_creator,
42 text_cache,
43 }
44 }
45 #[allow(clippy::too_many_arguments)]
47 pub fn new_subpixel(size: u32, h_align: impl Into<HAlign>, v_align: impl Into<VAlign>, foreground: impl Into<Color>, background: impl Into<Color>, canvas: &'a mut Canvas<Window>, texture_creator: &'b TextureCreator<WindowContext>, text_cache: &'a mut TextCache<'b, F>) -> Self {
48 Self {
49 size: size as f32,
50 h_align: h_align.into(),
51 v_align: v_align.into(),
52 foreground: foreground.into(),
53 background: background.into(),
54 canvas,
55 texture_creator,
56 text_cache,
57 }
58 }
59}
60
61
62
63pub trait ThreadSafeFont: Font + Send + Sync {}
65
66impl<F: Font + Send + Sync> ThreadSafeFont for F {}
67
68
69
70pub struct TextCache<'a, F: ThreadSafeFont> {
72 pub(crate) map_regular: HashMap<(char, Color), (Texture<'a>, u32, u32, f32, f32)>,
74 pub(crate) set_regular: HashSet<(char, Color)>,
75 pub(crate) map_subpixel: HashMap<(char, u32, Color, Color), (Texture<'a>, u32, u32, f32, f32)>,
78 pub(crate) set_subpixel: HashSet<(char, u32, Color, Color)>,
79 pub(crate) font: F,
80}
81
82impl<'a, F: ThreadSafeFont> TextCache<'a, F> {
83 #[inline]
85 pub fn new(font: F) -> Self {
86 Self {
87 map_regular: HashMap::new(),
88 set_regular: HashSet::new(),
89 map_subpixel: HashMap::new(),
90 set_subpixel: HashSet::new(),
91 font,
92 }
93 }
94 pub fn switch_font(&mut self, new_font: F) {
96 self.font = new_font;
97 self.clear();
98 }
99 pub fn clear(&mut self) {
101 self.map_regular.clear();
102 self.set_regular.clear();
103 self.map_subpixel.clear();
104 self.set_subpixel.clear();
105 }
106}
107
108
109
110#[derive(Copy, Clone)]
112pub enum HAlign {
113 Left,
115 Center,
117 Right,
119}
120
121impl HAlign {
122 pub(crate) fn get_offset(&self, width: f32) -> f32 {
123 match self {
124 Self::Left => 0.0,
125 Self::Center => width * -0.5,
126 Self::Right => -width,
127 }
128 }
129}
130
131#[derive(Copy, Clone)]
133pub enum VAlign {
134 Top,
136 Center,
138 Bottom,
140}
141
142impl VAlign {
143 pub(crate) fn get_offset(&self, height: f32) -> f32 {
144 match self {
145 Self::Top => height * TEXT_HEIGHT_MULT,
146 Self::Center => height * TEXT_HEIGHT_MULT * 0.5,
147 Self::Bottom => 0.0,
148 }
149 }
150}
151
152
153
154#[derive(Debug)]
156pub enum RenderTextError {
157 SdlError (Error),
159 SdlTextureValueError (TextureValueError),
161 SdlUpdateTextureError (UpdateTextureError),
163}
164
165impl From<Error> for RenderTextError {
166 fn from(value: Error) -> Self {
167 Self::SdlError (value)
168 }
169}
170
171impl From<TextureValueError> for RenderTextError {
172 fn from(value: TextureValueError) -> Self {
173 Self::SdlTextureValueError (value)
174 }
175}
176
177impl From<UpdateTextureError> for RenderTextError {
178 fn from(value: UpdateTextureError) -> Self {
179 Self::SdlUpdateTextureError (value)
180 }
181}
182
183impl std::fmt::Display for RenderTextError {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 match self {
186 Self::SdlError (err) => write!(f, "Render Text Error: {err}"),
187 Self::SdlTextureValueError (err) => write!(f, "Render Text Error: {err}"),
188 Self::SdlUpdateTextureError (err) => write!(f, "Render Text Error: {err}"),
189 }
190 }
191}
192
193impl std::error::Error for RenderTextError {}