nightshade-editor 0.14.2

Interactive map editor for the Nightshade game engine
mod browsers;
pub(crate) mod camera_grid;
mod command_palette;
mod entity_context_menu;
mod inspector;
pub(crate) mod interaction;
mod materials;
mod normals_settings;
mod overlays;
pub(crate) mod prefab_browser;
mod snap_settings;
mod status;
mod tag_manager;
mod top_bar;
mod tree;
pub(crate) mod viewport;
pub(crate) mod viewport_controls;

use crate::ecs::EditorWorld;
pub use browsers::BrowsersHandles;
pub use command_palette::CommandPaletteHandles;
pub use entity_context_menu::EntityContextMenuHandles;
pub use inspector::InspectorHandles;
pub use interaction::{Action, UiInteraction};
pub use materials::MaterialsHandles;
use nightshade::prelude::*;
pub use normals_settings::NormalsSettingsHandles;
pub use overlays::OverlayHandles;
pub use prefab_browser::PrefabBrowserHandles;
pub use snap_settings::SnapSettingsHandles;
pub use status::StatusHandles;
pub use tag_manager::TagManagerHandles;
pub use top_bar::TopBarHandles;
pub use tree::TreePanelHandles;
pub use viewport::ViewportHandles;

pub(crate) fn panel_content(tree: &mut UiTreeBuilder, panel: Entity) -> Entity {
    widget::<UiPanelData>(tree.world_mut(), panel)
        .map(|d| d.content_entity)
        .expect("panel content missing")
}

pub fn init(editor_world: &mut EditorWorld, world: &mut World) {
    let (
        top_bar,
        status,
        tree,
        inspector,
        overlays,
        browsers,
        materials,
        viewport,
        snap_settings,
        normals_settings,
        command_palette,
        tag_manager,
        prefab_browser,
        entity_context_menu,
    ) = {
        let mut tree_builder = UiTreeBuilder::new(world);
        let top_bar = top_bar::build(&mut tree_builder);
        let status = status::build(&mut tree_builder);
        let tree = tree::build(&mut tree_builder);
        let inspector = inspector::build(&mut tree_builder);
        let overlays = overlays::build(&mut tree_builder);
        let browsers = browsers::build(&mut tree_builder);
        let materials = materials::build(&mut tree_builder);
        let viewport = viewport::build(&mut tree_builder);
        let snap_settings = snap_settings::build(&mut tree_builder);
        let normals_settings = normals_settings::build(&mut tree_builder);
        let command_palette = command_palette::build(&mut tree_builder);
        let tag_manager = tag_manager::build(&mut tree_builder);
        let prefab_browser = prefab_browser::build(&mut tree_builder);
        let entity_context_menu = entity_context_menu::build(&mut tree_builder);
        tree_builder.finish();
        (
            top_bar,
            status,
            tree,
            inspector,
            overlays,
            browsers,
            materials,
            viewport,
            snap_settings,
            normals_settings,
            command_palette,
            tag_manager,
            prefab_browser,
            entity_context_menu,
        )
    };

    editor_world.resources.ui_handles = UiHandles {
        top_bar,
        status,
        tree,
        inspector,
        overlays,
        browsers,
        materials,
        viewport,
        snap_settings,
        normals_settings,
        command_palette,
        tag_manager,
        prefab_browser,
        entity_context_menu,
    };

    let tree_panel = editor_world.resources.ui_handles.tree.panel;
    let inspector_panel = editor_world.resources.ui_handles.inspector.panel;
    ui_set_visible(world, tree_panel, editor_world.resources.ui.show_tree);
    ui_set_visible(
        world,
        inspector_panel,
        editor_world.resources.ui.show_inspector,
    );
}

pub fn update(editor_world: &mut EditorWorld, world: &mut World) {
    let snapshot = editor_world.resources.ui_handles.clone();
    top_bar::poll(editor_world, world, &snapshot);
    inspector::poll(editor_world, world, &snapshot);
    browsers::poll(editor_world, world, &snapshot);
    tree::poll(editor_world, world, &snapshot);
    snap_settings::poll(editor_world, world, &snapshot);
    normals_settings::poll(editor_world, world, &snapshot);
    command_palette::poll(editor_world, world, &snapshot);
    entity_context_menu::poll(editor_world, world, &snapshot);
    if let Some(controls) = snapshot.viewport.controls {
        viewport_controls::poll(editor_world, world, &controls);
    }
    for tile in &snapshot.viewport.extra_camera_tiles {
        viewport_controls::poll(editor_world, world, &tile.controls);
    }
    interaction::drain(editor_world, world);
    top_bar::sync(world, &snapshot);
    status::update(editor_world, world);
    tree::update(editor_world, world);
    inspector::update(editor_world, world);
    overlays::update(editor_world, world);
    browsers::update(editor_world, world);
    tag_manager::poll(editor_world, world, &snapshot);
    prefab_browser::poll(editor_world, world, &snapshot);
    materials::update(editor_world, world);
    tag_manager::update(editor_world, world);
    prefab_browser::update(editor_world, world);
    snap_settings::sync(editor_world, world);
    normals_settings::sync(editor_world, world);

    let container = editor_world.resources.ui_handles.viewport.tile_container;
    let orphan_panes: Vec<nightshade::ecs::ui::components::TileId> = editor_world
        .resources
        .ui_handles
        .viewport
        .extra_camera_tiles
        .iter()
        .filter(|tile| {
            !world
                .core
                .entity_has_components(tile.camera_entity, nightshade::ecs::world::CAMERA)
        })
        .map(|tile| tile.pane_id)
        .collect();
    for pane_id in orphan_panes {
        nightshade::ecs::ui::widgets::world_tiles::ui_tile_remove(world, container, pane_id);
    }
    editor_world
        .resources
        .ui_handles
        .viewport
        .extra_camera_tiles
        .retain(|tile| {
            world
                .ui
                .get_ui_tile_container(container)
                .and_then(|data| data.get(tile.pane_id))
                .is_some_and(|node| match node {
                    nightshade::ecs::ui::components::TileNode::Pane {
                        content_entity: stored,
                        ..
                    } => *stored == tile.content_entity,
                    _ => false,
                })
        });

    viewport::update(
        world,
        &snapshot,
        &editor_world
            .resources
            .ui_handles
            .viewport
            .extra_camera_tiles,
    );
}

pub type IconLookupFn = fn(&IconLookup) -> IconGlyph;
pub type IconBinding = (Entity, IconLookupFn);

#[derive(Default, Clone, Copy)]
pub struct ThumbnailCard {
    pub card: Entity,
    pub image: Entity,
}

#[derive(Default, Clone)]
pub struct UiHandles {
    pub top_bar: TopBarHandles,
    pub status: StatusHandles,
    pub tree: TreePanelHandles,
    pub inspector: InspectorHandles,
    pub overlays: OverlayHandles,
    pub browsers: BrowsersHandles,
    pub materials: MaterialsHandles,
    pub viewport: ViewportHandles,
    pub snap_settings: SnapSettingsHandles,
    pub normals_settings: NormalsSettingsHandles,
    pub command_palette: CommandPaletteHandles,
    pub tag_manager: TagManagerHandles,
    pub prefab_browser: PrefabBrowserHandles,
    pub entity_context_menu: EntityContextMenuHandles,
}