1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy_egui::{egui, EguiContext};

use crate::util::EditSpecificResources;
use crate::YoleckEditorSections;

pub(crate) fn yoleck_editor_window(
    world: &mut World,
    mut egui_query: Local<Option<QueryState<&mut EguiContext, With<PrimaryWindow>>>>,
) {
    let egui_query = egui_query.get_or_insert_with(|| world.query_filtered());
    let mut borrowed_egui = if let Ok(mut egui_context) = egui_query.get_single_mut(world) {
        core::mem::take(egui_context.as_mut())
    } else {
        return;
    };
    egui::Window::new("Level Editor")
        .vscroll(true)
        .show(borrowed_egui.get_mut(), |ui| {
            world.resource_scope(
                |world, mut yoleck_editor_sections: Mut<YoleckEditorSections>| {
                    world.resource_scope(|world, mut edit_specific: Mut<EditSpecificResources>| {
                        edit_specific.inject_to_world(world);
                        for section in yoleck_editor_sections.0.iter_mut() {
                            section.0.invoke(world, ui);
                        }
                        edit_specific.take_from_world(world);
                    });
                },
            );
        });
    if let Ok(mut egui_context) = egui_query.get_single_mut(world) {
        *egui_context = borrowed_egui;
    }
}

#[allow(clippy::type_complexity)]
enum YoleckEditorSectionInner {
    Uninitialized(
        Box<
            dyn 'static
                + Send
                + Sync
                + FnOnce(
                    &mut World,
                )
                    -> Box<dyn 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui)>,
        >,
    ),
    Middle,
    Initialized(Box<dyn 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui)>),
}

impl YoleckEditorSectionInner {
    fn invoke(&mut self, world: &mut World, ui: &mut egui::Ui) {
        match self {
            Self::Uninitialized(_) => {
                if let Self::Uninitialized(system_constructor) =
                    core::mem::replace(self, Self::Middle)
                {
                    let mut system = system_constructor(world);
                    system(world, ui);
                    *self = Self::Initialized(system);
                } else {
                    panic!("It was just Uninitialized...");
                }
            }
            Self::Middle => panic!("Cannot start in the middle state when being invoked"),
            Self::Initialized(system) => {
                system(world, ui);
            }
        }
    }
}

/// A single section of the UI. See [`YoleckEditorSections`](crate::YoleckEditorSections).
pub struct YoleckEditorSection(YoleckEditorSectionInner);

impl<C, S> From<C> for YoleckEditorSection
where
    C: 'static + Send + Sync + FnOnce(&mut World) -> S,
    S: 'static + Send + Sync + FnMut(&mut World, &mut egui::Ui),
{
    fn from(system_constructor: C) -> Self {
        Self(YoleckEditorSectionInner::Uninitialized(Box::new(
            move |world| Box::new(system_constructor(world)),
        )))
    }
}