Skip to main content

fantasy_craft/gui/
text_display.rs

1use 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    // This system correctly uses Transform.position, which is set by the
58    // gui_resolve_layout_system. No changes are needed.
59    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        // --- Alignment Logic (Correct) ---
70        let mut draw_x = transform.position.x;
71        if let Some(h_align) = h_align {
72            match h_align.0 {
73                HorizontalAlignmentType::Left => { /* Default */ }
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 => { /* Default */ }
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        // --- End Alignment Logic ---
89
90        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}