bevy_yoleck/
editor_window.rs

1use bevy::prelude::*;
2use bevy_egui::{egui, EguiContext, PrimaryEguiContext};
3
4use crate::util::EditSpecificResources;
5use crate::YoleckEditorSections;
6
7pub(crate) fn yoleck_editor_window(
8    world: &mut World,
9    mut egui_query: Local<Option<QueryState<&mut EguiContext, With<PrimaryEguiContext>>>>,
10) {
11    let egui_query = egui_query.get_or_insert_with(|| world.query_filtered());
12    let mut borrowed_egui = if let Ok(mut egui_context) = egui_query.single_mut(world) {
13        core::mem::take(egui_context.as_mut())
14    } else {
15        return;
16    };
17    egui::Window::new("Level Editor")
18        .vscroll(true)
19        .show(borrowed_egui.get_mut(), |ui| {
20            world.resource_scope(
21                |world, mut yoleck_editor_sections: Mut<YoleckEditorSections>| {
22                    world.resource_scope(|world, mut edit_specific: Mut<EditSpecificResources>| {
23                        edit_specific.inject_to_world(world);
24                        for section in yoleck_editor_sections.0.iter_mut() {
25                            section.0.invoke(world, ui).unwrap();
26                        }
27                        edit_specific.take_from_world(world);
28                    });
29                },
30            );
31        });
32    if let Ok(mut egui_context) = egui_query.single_mut(world) {
33        *egui_context = borrowed_egui;
34    }
35}
36
37#[allow(clippy::type_complexity)]
38enum YoleckEditorSectionInner {
39    Uninitialized(
40        Box<
41            dyn 'static
42                + Send
43                + Sync
44                + FnOnce(
45                    &mut World,
46                ) -> Box<
47                    dyn 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui) -> Result,
48                >,
49        >,
50    ),
51    Middle,
52    Initialized(Box<dyn 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui) -> Result>),
53}
54
55impl YoleckEditorSectionInner {
56    fn invoke(&mut self, world: &mut World, ui: &mut egui::Ui) -> Result {
57        match self {
58            Self::Uninitialized(_) => {
59                if let Self::Uninitialized(system_constructor) =
60                    core::mem::replace(self, Self::Middle)
61                {
62                    let mut system = system_constructor(world);
63                    system(world, ui)?;
64                    *self = Self::Initialized(system);
65                } else {
66                    panic!("It was just Uninitialized...");
67                }
68            }
69            Self::Middle => panic!("Cannot start in the middle state when being invoked"),
70            Self::Initialized(system) => {
71                system(world, ui)?;
72            }
73        }
74        Ok(())
75    }
76}
77
78/// A single section of the UI. See [`YoleckEditorSections`](crate::YoleckEditorSections).
79pub struct YoleckEditorSection(YoleckEditorSectionInner);
80
81impl<C, S> From<C> for YoleckEditorSection
82where
83    C: 'static + Send + Sync + FnOnce(&mut World) -> S,
84    S: 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui) -> Result,
85{
86    fn from(system_constructor: C) -> Self {
87        Self(YoleckEditorSectionInner::Uninitialized(Box::new(
88            move |world| Box::new(system_constructor(world)),
89        )))
90    }
91}