Skip to main content

editor/
menu_scene.rs

1use libdqg::input::{InputState, MouseState};
2use libdqg::renderer::{DrawPass, Renderer};
3use libdqg::scene::{Scene, SceneTransition};
4
5use crate::editor_scene::{EditorScene, PendingAction};
6use crate::egui_layer::EguiLayer;
7use crate::recent_projects::RecentProjects;
8
9/// The editor's landing screen: create a new project, open an existing one, or reopen one from
10/// the recent-projects list. Replaces itself with an `EditorScene` once a project is chosen.
11pub struct MenuScene {
12    egui: EguiLayer,
13    recent: RecentProjects,
14}
15
16impl MenuScene {
17    pub fn new() -> Self {
18        Self { egui: EguiLayer::new(), recent: RecentProjects::load() }
19    }
20}
21
22impl Scene for MenuScene {
23    fn update(
24        &mut self,
25        _delta_time: f32,
26        _input_state: &InputState,
27        _mouse_state: &MouseState,
28        renderer: Option<&mut Renderer>,
29    ) -> SceneTransition {
30        let Some(renderer) = renderer else { return SceneTransition::None };
31
32        let recent = &self.recent;
33        let mut action = None;
34        self.egui.run(renderer, |ui| {
35            action = draw(ui, recent);
36        });
37
38        match action {
39            Some(action) => SceneTransition::Replace(Box::new(EditorScene::opening(action))),
40            None => SceneTransition::None,
41        }
42    }
43
44    fn render(&mut self, _pass: &mut DrawPass) {}
45
46    fn on_window_event(&mut self, event: &winit::event::WindowEvent) {
47        self.egui.on_window_event(event);
48    }
49
50    fn render_overlay(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, view: &wgpu::TextureView) {
51        self.egui.render_overlay(device, queue, encoder, view);
52    }
53}
54
55fn draw(ui: &mut egui::Ui, recent: &RecentProjects) -> Option<PendingAction> {
56    let mut action = None;
57
58    egui::CentralPanel::default().show(ui, |ui| {
59        ui.vertical_centered(|ui| {
60            ui.add_space(48.0);
61            ui.heading("libDQG Editor");
62            ui.add_space(24.0);
63
64            ui.horizontal(|ui| {
65                if ui.button("New Project...").clicked() {
66                    if let Some(root) = rfd::FileDialog::new().pick_folder() {
67                        action = Some(PendingAction::New(root));
68                    }
69                }
70                if ui.button("Open Project...").clicked() {
71                    if let Some(root) = rfd::FileDialog::new().pick_folder() {
72                        action = Some(PendingAction::Open(root));
73                    }
74                }
75            });
76
77            ui.add_space(32.0);
78            ui.separator();
79            ui.add_space(8.0);
80            ui.label("Recent Projects");
81
82            if recent.roots.is_empty() {
83                ui.weak("No recent projects.");
84            }
85
86            egui::ScrollArea::vertical().max_height(300.0).show(ui, |ui| {
87                for root in &recent.roots {
88                    let name = root
89                        .file_name()
90                        .map(|n| n.to_string_lossy().into_owned())
91                        .unwrap_or_else(|| root.display().to_string());
92                    ui.group(|ui| {
93                        ui.vertical(|ui| {
94                            if ui.selectable_label(false, name).clicked() {
95                                action = Some(PendingAction::Open(root.clone()));
96                            }
97                            ui.weak(root.display().to_string());
98                        });
99                    });
100                }
101            });
102        });
103    });
104
105    action
106}