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);
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                )
47                    -> Box<dyn 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui)>,
48        >,
49    ),
50    Middle,
51    Initialized(Box<dyn 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui)>),
52}
53
54impl YoleckEditorSectionInner {
55    fn invoke(&mut self, world: &mut World, ui: &mut egui::Ui) {
56        match self {
57            Self::Uninitialized(_) => {
58                if let Self::Uninitialized(system_constructor) =
59                    core::mem::replace(self, Self::Middle)
60                {
61                    let mut system = system_constructor(world);
62                    system(world, ui);
63                    *self = Self::Initialized(system);
64                } else {
65                    panic!("It was just Uninitialized...");
66                }
67            }
68            Self::Middle => panic!("Cannot start in the middle state when being invoked"),
69            Self::Initialized(system) => {
70                system(world, ui);
71            }
72        }
73    }
74}
75
76/// A single section of the UI. See [`YoleckEditorSections`](crate::YoleckEditorSections).
77pub struct YoleckEditorSection(YoleckEditorSectionInner);
78
79impl<C, S> From<C> for YoleckEditorSection
80where
81    C: 'static + Send + Sync + FnOnce(&mut World) -> S,
82    S: 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui),
83{
84    fn from(system_constructor: C) -> Self {
85        Self(YoleckEditorSectionInner::Uninitialized(Box::new(
86            move |world| Box::new(system_constructor(world)),
87        )))
88    }
89}