space_editor_ui/
ui_registration.rs

1use bevy::{ecs::system::EntityCommands, utils::HashMap};
2
3use space_prefab::{component::*, ext::*};
4use space_shared::PrefabMarker;
5
6pub const MESH_CATEGORY: &str = "mesh";
7
8/// Resource with bundles to spawn
9#[derive(Resource, Default)]
10pub struct BundleReg {
11    pub bundles: HashMap<String, HashMap<String, EditorBundleUntyped>>,
12}
13
14impl BundleReg {
15    pub fn add_bundle<T: Bundle + Clone>(&mut self, bundle: EditorBundle<T>) {
16        let dyn_bundle = EditorBundleUntyped::new(bundle.data.clone(), bundle.name.clone());
17
18        self.bundles
19            .entry(bundle.category)
20            .or_default()
21            .insert(bundle.name, dyn_bundle);
22    }
23}
24
25/// Contains all info to display and spawn editor bundle
26pub struct EditorBundle<T: Bundle + Clone> {
27    pub data: T,
28    pub category: String,
29    pub name: String,
30}
31
32/// Untyped editor bundle
33pub struct EditorBundleUntyped {
34    pub data: Box<dyn Fn(&mut EntityCommands) + Send + Sync>,
35    pub name: String,
36}
37
38impl EditorBundleUntyped {
39    /// Create new untyped editor bundle
40    pub fn new<T: Bundle + Clone>(data: T, name: String) -> Self {
41        Self {
42            data: Box::new(move |cmds| {
43                cmds.insert(data.clone());
44            }),
45            name,
46        }
47    }
48
49    /// Spawn in world untyped editor bundle and mark entity as part of prefab
50    pub fn spawn(&self, commands: &mut Commands) -> Entity {
51        let mut cmds = commands.spawn_empty();
52        (self.data)(&mut cmds);
53        cmds.insert(PrefabMarker);
54        cmds.id()
55    }
56}
57
58/// Trait to add `editor_bundle(..)` to App
59pub trait EditorUiExt {
60    /// Register new bundle in editor ui
61    fn editor_bundle<T: Bundle + Clone>(&mut self, category: &str, name: &str, bundle: T);
62}
63
64impl EditorUiExt for App {
65    fn editor_bundle<T: Bundle + Clone>(&mut self, category: &str, name: &str, bundle: T) {
66        let mut reg = if let Some(reg) = self.world.get_resource_mut::<BundleReg>() {
67            reg
68        } else {
69            self.init_resource::<BundleReg>();
70            self.world.get_resource_mut::<BundleReg>().unwrap()
71        };
72
73        reg.add_bundle(EditorBundle {
74            data: bundle,
75            category: category.to_string(),
76            name: name.to_string(),
77        });
78    }
79}
80
81pub fn register_light_editor_bundles(app: &mut App) {
82    app.editor_bundle(
83        "Light",
84        "Point light",
85        (Name::new("Point light"), PointLight::default()),
86    );
87
88    app.editor_bundle(
89        "Light",
90        "Directional light",
91        (Name::new("Directional light"), DirectionalLight::default()),
92    );
93
94    app.editor_bundle(
95        "Light",
96        "Spot light",
97        (Name::new("Spot light"), SpotLight::default()),
98    );
99}
100
101/// Register meshs
102pub fn register_mesh_editor_bundles(app: &mut App) {
103    app.editor_bundle(
104        "Mesh",
105        "Cube",
106        (
107            MeshPrimitivePrefab::Cube(1.0),
108            Name::new("Cube".to_string()),
109            Transform::default(),
110            Visibility::default(),
111        ),
112    );
113    app.editor_bundle(
114        "Mesh",
115        "Box",
116        (
117            MeshPrimitivePrefab::Box(BoxPrefab::default()),
118            Name::new("Box".to_string()),
119            Transform::default(),
120            Visibility::default(),
121        ),
122    );
123    app.editor_bundle(
124        "Mesh",
125        "Sphere",
126        (
127            MeshPrimitivePrefab::Sphere(SpherePrefab::default()),
128            Name::new("UVSphere".to_string()),
129            Transform::default(),
130            Visibility::default(),
131        ),
132    );
133    app.editor_bundle(
134        "Mesh",
135        "Quad",
136        (
137            MeshPrimitivePrefab::Quad(QuadPrefab::default()),
138            Name::new("Quad".to_string()),
139            Transform::default(),
140            Visibility::default(),
141        ),
142    );
143    app.editor_bundle(
144        "Mesh",
145        "Capsule",
146        (
147            MeshPrimitivePrefab::Capsule(CapsulePrefab::default()),
148            Name::new("Capsule"),
149            Transform::default(),
150            Visibility::default(),
151        ),
152    );
153    app.editor_bundle(
154        "Mesh",
155        "Circle",
156        (
157            MeshPrimitivePrefab::Circle(CirclePrefab::default()),
158            Name::new("Circle".to_string()),
159            Transform::default(),
160            Visibility::default(),
161        ),
162    );
163    app.editor_bundle(
164        "Mesh",
165        "Cylinder",
166        (
167            MeshPrimitivePrefab::Cylinder(CylinderPrefab::default()),
168            Name::new("Cylinder".to_string()),
169            Transform::default(),
170            Visibility::default(),
171        ),
172    );
173    app.editor_bundle(
174        "Mesh",
175        "Icosphere",
176        (
177            MeshPrimitivePrefab::Icosphere(IcospherePrefab::default()),
178            Name::new("Icosphere".to_string()),
179            Transform::default(),
180            Visibility::default(),
181        ),
182    );
183    app.editor_bundle(
184        "Mesh",
185        "Plane",
186        (
187            MeshPrimitivePrefab::Plane(PlanePrefab::default()),
188            Name::new("Plane".to_string()),
189            Transform::default(),
190            Visibility::default(),
191        ),
192    );
193    app.editor_bundle(
194        "Mesh",
195        "RegularPolygon",
196        (
197            MeshPrimitivePrefab::RegularPolygon(RegularPolygonPrefab::default()),
198            Name::new("RegularPolygon".to_string()),
199            Transform::default(),
200            Visibility::default(),
201        ),
202    );
203    app.editor_bundle(
204        "Mesh",
205        "Torus",
206        (
207            MeshPrimitivePrefab::Torus(TorusPrefab::default()),
208            Name::new("Torus".to_string()),
209            Transform::default(),
210            Visibility::default(),
211        ),
212    );
213
214    app.editor_bundle(
215        "Camera",
216        "CameraPlay",
217        (
218            Camera3d::default(),
219            Name::new("Camera3d".to_string()),
220            Transform::default(),
221            Visibility::default(),
222            CameraPlay::default(),
223        ),
224    );
225}