fantasy_craft/gui/
text_display.rs1use macroquad::prelude::*;
2use serde::Deserialize;
3
4use crate::{gui::{alignment::{HorizontalAlignment, HorizontalAlignmentType, VerticalAlignment, VerticalAlignmentType}, font_component::FontComponent}, prelude::{ColorData, ComponentLoader, Context, Transform, Visible}};
5
6#[derive(Debug, Clone)]
7pub struct TextDisplay {
8 pub text: String,
9 pub font_size: f32,
10 pub color: Color,
11 pub screen_space: bool
12}
13
14impl Default for TextDisplay {
15 fn default() -> Self {
16 Self {
17 text: String::new(),
18 font_size: 30.0,
19 color: BLACK,
20 screen_space: true
21 }
22 }
23}
24
25#[derive(Deserialize, Debug, Default)]
26pub struct TextDisplayLoaderData {
27 pub text: String,
28 pub font_size: f32,
29 pub color: ColorData,
30 pub screen_space: bool
31}
32
33pub struct TextDisplayLoader;
34
35impl ComponentLoader for TextDisplayLoader {
36 fn load(&self, ctx: &mut crate::prelude::Context, entity: hecs::Entity, data: &serde_json::Value) {
37 let loader_data: TextDisplayLoaderData = serde_json::from_value(data.clone())
38 .unwrap_or_default();
39
40 let component = TextDisplay {
41 text: loader_data.text,
42 font_size: loader_data.font_size,
43 color: Color::new(
44 loader_data.color.r,
45 loader_data.color.g,
46 loader_data.color.b,
47 loader_data.color.a
48 ),
49 screen_space: true
50 };
51
52 ctx.world.insert_one(entity, component).expect("Failed to insert TextDisplay");
53 }
54}
55
56pub fn text_render_system(ctx: &mut Context) {
57 for (_, (text_display, transform, visibility, font_opt, h_align, v_align)) in ctx.world.query::<(&TextDisplay, &Transform, Option<&Visible>, Option<&FontComponent>, Option<&HorizontalAlignment>, Option<&VerticalAlignment>)>().iter() {
60 let is_visible = visibility.map_or(true, |v| v.0);
61 if !is_visible || !text_display.screen_space {
62 continue;
63 }
64
65 let font = font_opt.and_then(|f| ctx.asset_server.get_font(&f.0));
66
67 let text_size = measure_text(&text_display.text, font, text_display.font_size as u16, 1.0);
68
69 let mut draw_x = transform.position.x;
71 if let Some(h_align) = h_align {
72 match h_align.0 {
73 HorizontalAlignmentType::Left => { }
74 HorizontalAlignmentType::Center => draw_x = transform.position.x - text_size.width / 2.0,
75 HorizontalAlignmentType::Right => draw_x = transform.position.x - text_size.width,
76 }
77 }
78
79 let mut baseline_y = transform.position.y + text_size.offset_y;
80
81 if let Some(v_align) = v_align {
82 match v_align.0 {
83 VerticalAlignmentType::Top => { }
84 VerticalAlignmentType::Center => baseline_y = transform.position.y - (text_size.height / 2.0) + text_size.offset_y,
85 VerticalAlignmentType::Bottom => baseline_y = transform.position.y - text_size.height + text_size.offset_y,
86 }
87 }
88 if let Some(font) = font {
91 draw_text_ex(
92 &text_display.text,
93 draw_x.round(),
94 baseline_y.round(),
95 TextParams {
96 font: Some(font),
97 font_size: text_display.font_size as u16,
98 color: text_display.color,
99 ..Default::default()
100 }
101 );
102 }
103 else {
104 draw_text(
105 &text_display.text,
106 draw_x.round(),
107 baseline_y.round(),
108 text_display.font_size,
109 text_display.color
110 );
111 }
112 }
113}