nightshade-editor 0.14.2

Interactive map editor for the Nightshade game engine
use crate::ecs::EditorWorld;
use crate::systems::retained_ui::UiHandles;
use nightshade::prelude::*;

const PANEL_RECT: Rect = Rect {
    min: Vec2::new(80.0, 80.0),
    max: Vec2::new(380.0, 360.0),
};

const MIN_LENGTH: f32 = 0.01;
const MAX_LENGTH: f32 = 1.0;

#[derive(Default, Clone, Copy)]
pub struct NormalsSettingsHandles {
    pub panel: Entity,
    pub length_drag: Entity,
    pub color_picker: Entity,
}

pub fn build(tree: &mut UiTreeBuilder) -> NormalsSettingsHandles {
    let panel = tree.add_floating_panel("normals_settings", "Normals settings", PANEL_RECT);
    ui_set_visible(tree.world_mut(), panel, false);
    let content = super::panel_content(tree, panel);

    let mut length_drag = Entity::default();
    let mut color_picker = Entity::default();

    tree.in_parent(content, |tree| {
        let grid = tree.add_property_grid(120.0);
        let section = tree.add_property_section(grid, "Appearance");

        let length_row = tree.add_property_row(grid, section, "Length");
        tree.in_parent(length_row, |tree| {
            length_drag = tree.add_drag_value_configured(
                DragValueConfig::new(MIN_LENGTH, MAX_LENGTH, 0.1)
                    .speed(0.01)
                    .precision(2),
            );
        });

        let color_row = tree.add_property_row(grid, section, "Color");
        tree.in_parent(color_row, |tree| {
            color_picker = tree.add_color_picker(vec4(1.0, 1.0, 0.0, 1.0));
        });
    });

    NormalsSettingsHandles {
        panel,
        length_drag,
        color_picker,
    }
}

pub fn poll(_editor_world: &mut EditorWorld, world: &mut World, handles: &UiHandles) {
    let normals = handles.normals_settings;
    let mut new_length: Option<f32> = None;
    let mut new_color: Option<[f32; 4]> = None;
    for event in ui_events(world) {
        match event {
            UiEvent::DragValueChanged { entity, value } if *entity == normals.length_drag => {
                new_length = Some(value.clamp(MIN_LENGTH, MAX_LENGTH));
            }
            UiEvent::ColorPickerChanged { entity, color } if *entity == normals.color_picker => {
                new_color = Some([color.x, color.y, color.z, color.w]);
            }
            _ => {}
        }
    }
    if let Some(length) = new_length {
        world.resources.graphics.normal_line_length = length;
    }
    if let Some(color) = new_color {
        world.resources.graphics.normal_line_color = color;
    }
}

pub fn sync(editor_world: &EditorWorld, world: &mut World) {
    let handles = editor_world.resources.ui_handles.normals_settings;
    let length = world.resources.graphics.normal_line_length;
    sync_drag_value(world, handles.length_drag, length);
    let color = world.resources.graphics.normal_line_color;
    sync_color_picker(world, handles.color_picker, color);
}

fn sync_drag_value(world: &mut World, entity: Entity, value: f32) {
    if let Some(data) = world.ui.get_ui_drag_value_mut(entity)
        && !data.editing
        && (data.value - value).abs() > f32::EPSILON
    {
        data.value = value;
    }
}

fn sync_color_picker(world: &mut World, entity: Entity, color: [f32; 4]) {
    if let Some(data) = world.ui.get_ui_color_picker_mut(entity) {
        let current = data.color;
        if (current.x - color[0]).abs() > f32::EPSILON
            || (current.y - color[1]).abs() > f32::EPSILON
            || (current.z - color[2]).abs() > f32::EPSILON
            || (current.w - color[3]).abs() > f32::EPSILON
        {
            data.color = vec4(color[0], color[1], color[2], color[3]);
        }
    }
}