bevy_yoleck/
editor_window.rs

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