pushrod/widgets/
text_widget.rs1use crate::render::callbacks::CallbackRegistry;
17use crate::render::layout_cache::LayoutContainer;
18use crate::render::widget::*;
19use crate::render::widget_cache::WidgetContainer;
20use crate::render::widget_config::*;
21use crate::render::{Points, Size};
22
23use sdl2::render::{Canvas, Texture, TextureQuery};
24use sdl2::ttf::FontStyle;
25use sdl2::video::Window;
26
27use crate::render::texture_cache::TextureCache;
28use crate::render::texture_store::TextureStore;
29use sdl2::rect::Rect;
30use std::any::Any;
31use std::collections::HashMap;
32use std::path::Path;
33
34pub enum TextJustify {
37 Left,
39
40 Center,
42
43 Right,
45}
46
47pub struct TextWidget {
50 config: WidgetConfig,
51 system_properties: HashMap<i32, String>,
52 callback_registry: CallbackRegistry,
53 texture_store: TextureStore,
54 font_name: String,
55 font_style: FontStyle,
56 font_size: i32,
57 justification: TextJustify,
58 msg: String,
59}
60
61impl TextWidget {
64 pub fn new(
68 font_name: String,
69 font_style: FontStyle,
70 font_size: i32,
71 justification: TextJustify,
72 msg: String,
73 points: Points,
74 size: Size,
75 ) -> Self {
76 Self {
77 config: WidgetConfig::new(points, size),
78 system_properties: HashMap::new(),
79 callback_registry: CallbackRegistry::new(),
80 texture_store: TextureStore::default(),
81 font_name,
82 font_style,
83 font_size,
84 justification,
85 msg,
86 }
87 }
88
89 pub fn set_text(&mut self, msg: String) {
91 self.msg = msg;
92 self.get_config().set_invalidated(true);
93 }
94
95 pub fn get_text(&self) -> String {
97 self.msg.clone()
98 }
99}
100
101impl Widget for TextWidget {
105 fn draw(&mut self, c: &mut Canvas<Window>, t: &mut TextureCache) -> Option<&Texture> {
106 if self.get_config().invalidated() {
107 let bounds = self.get_config().get_size(CONFIG_SIZE);
108
109 self.texture_store
110 .create_or_resize_texture(c, bounds[0] as u32, bounds[1] as u32);
111
112 let base_color = self.get_color(CONFIG_COLOR_BASE);
113 let text_max_width = self.get_size(CONFIG_SIZE)[0]
114 - ((self.get_numeric(CONFIG_BORDER_WIDTH) * 2) as u32);
115
116 let ttf_context = t.get_ttf_context();
117 let texture_creator = c.texture_creator();
118 let mut font = ttf_context
119 .load_font(Path::new(&self.font_name), self.font_size as u16)
120 .unwrap();
121 let font_color = self.get_color(CONFIG_COLOR_TEXT);
122
123 font.set_style(self.font_style);
124
125 let surface = font
126 .render(&self.msg)
127 .blended_wrapped(font_color, text_max_width)
128 .map_err(|e| e.to_string())
129 .unwrap();
130 let font_texture = texture_creator
131 .create_texture_from_surface(&surface)
132 .map_err(|e| e.to_string())
133 .unwrap();
134
135 let TextureQuery { width, height, .. } = font_texture.query();
136 let texture_y = 0;
137 let widget_w = self.get_size(CONFIG_SIZE)[0] as i32;
138 let texture_x = match self.justification {
139 TextJustify::Left => 0,
140 TextJustify::Right => widget_w - width as i32,
141 TextJustify::Center => (widget_w - width as i32) / 2,
142 };
143
144 c.with_texture_canvas(self.texture_store.get_mut_ref(), |texture| {
145 texture.set_draw_color(base_color);
146 texture.clear();
147
148 texture
149 .copy(
150 &font_texture,
151 None,
152 Rect::new(texture_x, texture_y, width, height),
153 )
154 .unwrap();
155 })
156 .unwrap();
157 }
158
159 self.texture_store.get_optional_ref()
160 }
161
162 fn on_config_changed(&mut self, _k: u8, _v: Config) {
164 match _k {
165 CONFIG_COLOR_TEXT => self.get_config().set_invalidated(true),
166 CONFIG_COLOR_BASE => self.get_config().set_invalidated(true),
167 CONFIG_FONT_SIZE => {
168 if let Config::Numeric(size) = _v {
169 self.font_size = size;
170 self.get_config().set_invalidated(true);
171 }
172 }
173 CONFIG_TEXT => {
174 if let Config::Text(text) = _v {
175 self.msg = text;
176 self.get_config().set_invalidated(true);
177 }
178 }
179
180 _ => (),
181 };
182 }
183
184 default_widget_functions!();
185 default_widget_properties!();
186 default_widget_callbacks!();
187}