nightshade 0.8.0

A cross-platform data-oriented game engine.
Documentation
use super::{ComponentInspector, InspectorContext};
use crate::prelude::*;

#[derive(Default)]
pub struct TextInspector;

fn alignment_section(ui: &mut egui::Ui, text: &mut Text) -> bool {
    let mut changed = false;

    ui.horizontal(|ui| {
        ui.label("Alignment:");
        egui::ComboBox::from_label("")
            .selected_text(format!("{:?}", text.properties.alignment))
            .show_ui(ui, |ui| {
                if ui
                    .selectable_value(&mut text.properties.alignment, TextAlignment::Left, "Left")
                    .changed()
                {
                    changed = true;
                }
                if ui
                    .selectable_value(
                        &mut text.properties.alignment,
                        TextAlignment::Center,
                        "Center",
                    )
                    .changed()
                {
                    changed = true;
                }
                if ui
                    .selectable_value(
                        &mut text.properties.alignment,
                        TextAlignment::Right,
                        "Right",
                    )
                    .changed()
                {
                    changed = true;
                }
            });
    });

    ui.horizontal(|ui| {
        ui.label("V-Align:");
        egui::ComboBox::from_label("v_align")
            .selected_text(format!("{:?}", text.properties.vertical_alignment))
            .show_ui(ui, |ui| {
                if ui
                    .selectable_value(
                        &mut text.properties.vertical_alignment,
                        VerticalAlignment::Top,
                        "Top",
                    )
                    .changed()
                {
                    changed = true;
                }
                if ui
                    .selectable_value(
                        &mut text.properties.vertical_alignment,
                        VerticalAlignment::Middle,
                        "Middle",
                    )
                    .changed()
                {
                    changed = true;
                }
                if ui
                    .selectable_value(
                        &mut text.properties.vertical_alignment,
                        VerticalAlignment::Bottom,
                        "Bottom",
                    )
                    .changed()
                {
                    changed = true;
                }
                if ui
                    .selectable_value(
                        &mut text.properties.vertical_alignment,
                        VerticalAlignment::Baseline,
                        "Baseline",
                    )
                    .changed()
                {
                    changed = true;
                }
            });
    });

    changed
}

fn outline_section(ui: &mut egui::Ui, text: &mut Text) -> bool {
    let mut changed = false;

    ui.separator();
    ui.label("Outline");

    ui.horizontal(|ui| {
        ui.label("Width:");
        if ui
            .add(
                egui::DragValue::new(&mut text.properties.outline_width)
                    .speed(0.001)
                    .range(0.0..=0.5),
            )
            .changed()
        {
            changed = true;
        }
    });

    ui.horizontal(|ui| {
        ui.label("Color:");
        let mut outline_color = [
            text.properties.outline_color.x,
            text.properties.outline_color.y,
            text.properties.outline_color.z,
            text.properties.outline_color.w,
        ];
        if ui
            .color_edit_button_rgba_unmultiplied(&mut outline_color)
            .changed()
        {
            text.properties.outline_color = nalgebra_glm::vec4(
                outline_color[0],
                outline_color[1],
                outline_color[2],
                outline_color[3],
            );
            changed = true;
        }
    });

    ui.horizontal(|ui| {
        ui.label("Smoothing:");
        if ui
            .add(
                egui::DragValue::new(&mut text.properties.smoothing)
                    .speed(0.001)
                    .range(0.001..=0.1),
            )
            .changed()
        {
            changed = true;
        }
    });

    changed
}

fn font_section(ui: &mut egui::Ui, text: &mut Text, number_of_fonts: usize) -> bool {
    let mut changed = false;

    ui.separator();

    ui.horizontal(|ui| {
        ui.label("Font:");
        egui::ComboBox::from_label("font_select")
            .selected_text(format!("Font {}", text.font_index))
            .show_ui(ui, |ui| {
                for index in 0..number_of_fonts {
                    if ui
                        .selectable_value(&mut text.font_index, index, format!("Font {}", index))
                        .changed()
                    {
                        changed = true;
                    }
                }
            });
    });

    changed
}

impl ComponentInspector for TextInspector {
    fn name(&self) -> &str {
        "Text"
    }

    fn has_component(&self, world: &World, entity: Entity) -> bool {
        world.get_text(entity).is_some()
    }

    fn add_component(&self, world: &mut World, entity: Entity) {
        let text_index = world.resources.text_cache.add_text("New Text");
        world.set_text(entity, Text::new(text_index));

        if !world.entity_has_local_transform(entity) {
            world.set_local_transform(entity, LocalTransform::default());
        }
        if !world.entity_has_global_transform(entity) {
            world.set_global_transform(entity, GlobalTransform::default());
        }
        if !world.entity_has_local_transform_dirty(entity) {
            world.set_local_transform_dirty(entity, LocalTransformDirty);
        }
        if world.get_visibility(entity).is_none() {
            world.set_visibility(entity, Visibility { visible: true });
        }
    }

    fn remove_component(&self, world: &mut World, entity: Entity) {
        if let Some(text) = world.get_text(entity) {
            world.resources.text_cache.remove_text(text.text_index);
        }
        world.remove_text(entity);
    }

    fn ui(
        &mut self,
        world: &mut World,
        entity: Entity,
        ui: &mut egui::Ui,
        _context: &mut InspectorContext,
    ) {
        ui.label("Text");

        let (text_index, current_content) = if let Some(text) = world.get_text(entity) {
            let content = world
                .resources
                .text_cache
                .get_text(text.text_index)
                .map(|s| s.to_string())
                .unwrap_or_default();
            (text.text_index, content)
        } else {
            return;
        };

        let mut text_content = current_content.clone();
        ui.horizontal(|ui| {
            ui.label("Content:");
            ui.text_edit_multiline(&mut text_content)
        });

        if text_content != current_content {
            world
                .resources
                .text_cache
                .set_text(text_index, text_content);
            if let Some(text) = world.get_text_mut(entity) {
                text.dirty = true;
            }
        }

        let number_of_fonts = world.resources.text_cache.font_manager.fonts.len();
        if let Some(text) = world.get_text_mut(entity) {
            let mut changed = false;

            ui.separator();

            ui.horizontal(|ui| {
                ui.label("Font Size:");
                if ui
                    .add(
                        egui::DragValue::new(&mut text.properties.font_size)
                            .speed(0.5)
                            .range(1.0..=200.0),
                    )
                    .changed()
                {
                    changed = true;
                }
            });

            ui.horizontal(|ui| {
                ui.label("Color:");
                let mut color = [
                    text.properties.color.x,
                    text.properties.color.y,
                    text.properties.color.z,
                    text.properties.color.w,
                ];
                if ui.color_edit_button_rgba_unmultiplied(&mut color).changed() {
                    text.properties.color =
                        nalgebra_glm::vec4(color[0], color[1], color[2], color[3]);
                    changed = true;
                }
            });

            changed |= alignment_section(ui, text);

            ui.horizontal(|ui| {
                ui.label("Line Height:");
                if ui
                    .add(
                        egui::DragValue::new(&mut text.properties.line_height)
                            .speed(0.01)
                            .range(0.5..=3.0),
                    )
                    .changed()
                {
                    changed = true;
                }
            });

            ui.horizontal(|ui| {
                ui.label("Letter Spacing:");
                if ui
                    .add(
                        egui::DragValue::new(&mut text.properties.letter_spacing)
                            .speed(0.1)
                            .range(-10.0..=50.0),
                    )
                    .changed()
                {
                    changed = true;
                }
            });

            changed |= outline_section(ui, text);
            changed |= font_section(ui, text, number_of_fonts);

            if changed {
                text.dirty = true;
            }
        }
    }
}