bevy_vista 0.17.1

A visual UI editor plugin for Bevy with inspector-driven editing and .vista.ron serialization.
Documentation
use std::sync::Arc;

use bevy::prelude::*;
use bevy::reflect::PartialReflect;

use crate::core::inspector::{
    BlueprintNodeId, InspectorDriverId, InspectorFieldDescriptor, InspectorFieldEditor,
};
use crate::core::theme::Theme;

use super::driver::{self, InspectorDriver};

pub(crate) fn init_inspector_runtime(app: &mut App) {
    app.init_resource::<InspectorControlRegistry>();
    driver::init_inspector_drivers(app);
}

#[derive(Resource, Default)]
pub struct InspectorContext {
    pub selected_node: Option<BlueprintNodeId>,
    pub visible: bool,
}

impl InspectorContext {
    pub fn clear(&mut self) {
        self.selected_node = None;
        self.visible = false;
    }

    pub fn select(&mut self, node_id: BlueprintNodeId) {
        self.selected_node = Some(node_id);
        self.visible = true;
    }
}

pub type InspectorPanelState = InspectorContext;

#[derive(Resource, Default)]
pub struct VistaEditorViewOptions {
    pub show_grid: bool,
    pub snap_to_grid: bool,
    pub show_outlines: bool,
    pub is_preview_mode: bool,
}

#[derive(Resource, Default)]
pub(crate) struct InspectorControlRegistry {
    registrations:
        bevy::platform::collections::HashMap<InspectorDriverId, Arc<dyn InspectorDriver>>,
}

impl InspectorControlRegistry {
    pub(super) fn register(&mut self, driver: Arc<dyn InspectorDriver>) {
        self.registrations.insert(driver.id(), driver);
    }

    pub(super) fn registration_for(
        &self,
        editor: InspectorFieldEditor,
    ) -> Option<&Arc<dyn InspectorDriver>> {
        let driver = self.registrations.get(&editor.driver_id)?;
        driver.supports(editor).then_some(driver)
    }

    pub(crate) fn build(
        &self,
        commands: &mut Commands,
        field: &InspectorFieldDescriptor,
        theme: Option<&Theme>,
        target: InspectorBindingTarget,
    ) -> Entity {
        let Some(driver) = self.registration_for(field.editor) else {
            panic!(
                "missing inspector control builder for {}",
                field.editor.driver_id
            );
        };
        let control = driver.build(commands, field, theme);
        commands.entity(control).insert(InspectorControlBinding {
            field_path: field.field_path.clone(),
            editor: field.editor,
            target,
        });
        control
    }

    pub(super) fn serialize_value(
        &self,
        editor: InspectorFieldEditor,
        field: &dyn PartialReflect,
    ) -> Option<String> {
        let driver = self.registration_for(editor)?;
        driver.serialize(field)
    }

    pub(crate) fn apply_serialized_value(
        &self,
        editor: InspectorFieldEditor,
        field: &mut dyn PartialReflect,
        raw: &str,
    ) -> bool {
        let Some(driver) = self.registration_for(editor) else {
            return false;
        };
        driver.apply_serialized(field, raw)
    }
}

#[derive(Component)]
pub(crate) struct InspectorContentRoot;

#[derive(Component)]
pub(crate) struct InspectorWidgetSectionRoot;

#[derive(Component, Default)]
pub(crate) struct InspectorWidgetSectionState {
    pub(crate) selected_node: Option<BlueprintNodeId>,
    pub(crate) widget_path: Option<String>,
}

#[derive(Component)]
pub(crate) struct InspectorNameField;

#[derive(Component, Clone)]
pub(crate) enum InspectorBindingTarget {
    Style,
    WidgetProp,
}

#[derive(Component, Clone)]
pub(super) struct InspectorControlBinding {
    pub(super) field_path: String,
    pub(super) editor: InspectorFieldEditor,
    pub(super) target: InspectorBindingTarget,
}

#[derive(Component, Copy, Clone)]
pub(super) struct InspectorControlOwner {
    pub(super) owner: Entity,
}

#[derive(Component, Clone)]
pub(crate) struct InspectorFieldDecoration {
    pub(crate) field_path: String,
    pub(crate) target: InspectorBindingTarget,
}

#[derive(Component)]
pub(crate) struct InspectorFieldLabel;

#[derive(Component)]
pub(crate) struct InspectorFieldRow;

#[derive(Component)]
pub(crate) struct InspectorResetButton;