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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use bevy::prelude::{App, World};
use bevy::utils::HashMap;
use bevy_inspector_egui::egui;
use std::any::{Any, TypeId};

use crate::editor::EditorWindowState;

/// An editor window type
pub trait EditorWindow: 'static {
    type State: Default + Any + Send + Sync;

    const NAME: &'static str;
    const DEFAULT_SIZE: (f32, f32) = (0.0, 0.0);

    fn ui(world: &mut World, cx: EditorWindowContext, ui: &mut egui::Ui);
    /// Ui shown in the `Open Window` menu item. By default opens the window as a floating window.
    fn menu_ui(world: &mut World, mut cx: EditorWindowContext, ui: &mut egui::Ui) {
        let _ = world;

        if ui.button(Self::NAME).clicked() {
            cx.open_floating_window::<Self>();
            ui.close_menu();
        }
    }
    /// Ui shown in the viewport toolbar.
    fn viewport_toolbar_ui(world: &mut World, cx: EditorWindowContext, ui: &mut egui::Ui) {
        let _ = (world, cx, ui);
    }
    /// Ui shown on top of the game viewport.
    fn viewport_ui(world: &mut World, cx: EditorWindowContext, ui: &mut egui::Ui) {
        let _ = (world, cx, ui);
    }

    /// Necessary setup (resources, systems) for the window.
    fn app_setup(app: &mut App) {
        let _ = app;
    }

    fn app_finish(app: &mut App) {
        let _ = app;
    }
}

pub struct EditorWindowContext<'a> {
    pub(crate) window_states: &'a mut HashMap<TypeId, EditorWindowState>,
    pub(crate) internal_state: &'a mut crate::editor::EditorInternalState,
}
impl EditorWindowContext<'_> {
    pub fn state_mut<W: EditorWindow>(&mut self) -> Option<&mut W::State> {
        self.window_states
            .get_mut(&TypeId::of::<W>())
            .and_then(|s| s.downcast_mut::<W::State>())
    }
    pub fn state<W: EditorWindow>(&self) -> Option<&W::State> {
        self.window_states
            .get(&TypeId::of::<W>())
            .and_then(|s| s.downcast_ref::<W::State>())
    }

    pub fn state_mut_many<const N: usize>(
        &mut self,
        ids: [&TypeId; N],
    ) -> [&mut (dyn Any + Send + Sync + 'static); N] {
        self.window_states
            .get_many_mut(ids)
            .unwrap()
            .map(|val| &mut **val)
    }
    pub fn state_mut_triplet<W1: EditorWindow, W2: EditorWindow, W3: EditorWindow>(
        &mut self,
    ) -> Option<(&mut W1::State, &mut W2::State, &mut W3::State)> {
        let [a, b, c] = self.window_states.get_many_mut([
            &TypeId::of::<W1>(),
            &TypeId::of::<W2>(),
            &TypeId::of::<W3>(),
        ])?;

        let a = a.downcast_mut::<W1::State>()?;
        let b = b.downcast_mut::<W2::State>()?;
        let c = c.downcast_mut::<W3::State>()?;
        Some((a, b, c))
    }

    pub fn state_mut_pair<W1: EditorWindow, W2: EditorWindow>(
        &mut self,
    ) -> Option<(&mut W1::State, &mut W2::State)> {
        assert_ne!(TypeId::of::<W1>(), TypeId::of::<W2>());

        let [a, b] = self
            .window_states
            .get_many_mut([&TypeId::of::<W1>(), &TypeId::of::<W2>()])?;

        let a = a.downcast_mut::<W1::State>()?;
        let b = b.downcast_mut::<W2::State>()?;
        Some((a, b))
    }

    pub fn open_floating_window<W: ?Sized + EditorWindow>(&mut self) {
        let floating_window_id = self.internal_state.next_floating_window_id();
        let window_id = std::any::TypeId::of::<W>();
        self.internal_state
            .floating_windows
            .push(crate::editor::FloatingWindow {
                window: window_id,
                id: floating_window_id,
                initial_position: None,
            });
    }
}