From ff46311c341e4487fd1aa043e913607c785cb929 Mon Sep 17 00:00:00 2001 From: Lily Lyons Date: Thu, 19 Oct 2023 00:49:43 -0700 Subject: [PATCH] refactor: :recycle: it compiles (with a LOT of unfinished things) --- Cargo.lock | 16 +- .../src/data_cache.rs | 10 +- crates/luminol-core/src/lib.rs | 15 +- crates/luminol-core/src/tab.rs | 4 +- crates/luminol-core/src/toasts.rs | 29 +- crates/luminol-core/src/window.rs | 4 +- crates/luminol-data/src/lib.rs | 2 - crates/luminol-ui/Cargo.toml | 2 - crates/luminol-ui/src/lib.rs | 159 ++++++++++- crates/luminol-ui/src/windows/console.rs | 6 +- crates/luminol-ui/src/windows/event_edit.rs | 255 +----------------- crates/luminol-ui/src/windows/items.rs | 2 +- crates/luminol-ui/src/windows/map_picker.rs | 13 +- crates/luminol-ui/src/windows/new_project.rs | 4 +- crates/luminol/Cargo.toml | 4 + crates/luminol/src/app/mod.rs | 62 ++++- crates/luminol/src/app/top_bar.rs | 171 +++++++----- 17 files changed, 366 insertions(+), 392 deletions(-) rename crates/{luminol-data => luminol-core}/src/data_cache.rs (94%) diff --git a/Cargo.lock b/Cargo.lock index 663bd7f6..be179eec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,18 +1427,6 @@ dependencies = [ "syn 2.0.29", ] -[[package]] -name = "enum_dispatch" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" -dependencies = [ - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.29", -] - [[package]] name = "enumflags2" version = "0.7.7" @@ -2543,11 +2531,14 @@ dependencies = [ "luminol-data", "luminol-filesystem", "luminol-graphics", + "luminol-term", + "luminol-ui", "once_cell", "parking_lot", "poll-promise", "rfd", "steamworks", + "strum", "tracing-subscriber", "winres", ] @@ -2713,7 +2704,6 @@ dependencies = [ "catppuccin-egui", "egui", "egui_extras", - "enum_dispatch", "futures", "git-version", "itertools", diff --git a/crates/luminol-data/src/data_cache.rs b/crates/luminol-core/src/data_cache.rs similarity index 94% rename from crates/luminol-data/src/data_cache.rs rename to crates/luminol-core/src/data_cache.rs index e252c0bb..1e13946d 100644 --- a/crates/luminol-data/src/data_cache.rs +++ b/crates/luminol-core/src/data_cache.rs @@ -22,12 +22,12 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. -use crate::rpg; +use luminol_data::rpg; #[derive(Default, Debug)] -pub struct Cache {} +pub struct Data {} -impl Cache { +impl Data { /// Load all data required when opening a project. /// Does not load config. That is expected to have been loaded beforehand. pub fn load(&mut self) -> Result<(), String> { @@ -35,7 +35,7 @@ impl Cache { } // TODO dependcy cycle - pub fn defaults_from_config(config: ()) -> Self { + pub fn defaults_from_config(config: &luminol_config::project::Config) -> Self { todo!() } @@ -70,7 +70,7 @@ macro_rules! nested_ref_getter { } -impl Cache { +impl Data { nested_ref_getter! { rpg::Actors, actors, State::Loaded; rpg::Animations, animations, State::Loaded; diff --git a/crates/luminol-core/src/lib.rs b/crates/luminol-core/src/lib.rs index c0b733da..7c61587e 100644 --- a/crates/luminol-core/src/lib.rs +++ b/crates/luminol-core/src/lib.rs @@ -25,14 +25,17 @@ use std::sync::Arc; mod tab; -pub use tab::{Tab, Tabs}; +pub use tab::{EditTabs, Tab, Tabs}; mod window; -pub use window::{Window, Windows}; +pub use window::{EditWindows, Window, Windows}; pub mod modal; pub use modal::Modal; +mod data_cache; +pub use data_cache::Data; + /// Toasts to be displayed for errors, information, etc. mod toasts; pub use toasts::Toasts; @@ -42,14 +45,14 @@ pub struct UpdateState<'res, W, T> { pub graphics: Arc, pub filesystem: &'res mut luminol_filesystem::project::FileSystem, // FIXME: this is probably wrong - pub data: &'res mut luminol_data::data_cache::Cache, // FIXME: this is also probably wrong + pub data: &'res mut Data, // FIXME: this is also probably wrong // TODO: look into std::any? // we're using generics here to allow specialization on the type of window // this is fucntionality not really used atm but maybe in the future..? - pub edit_windows: &'res mut window::EditWindows, - pub edit_tabs: &'res mut tab::EditTabs, - pub toasts: &'res mut toasts::Toasts, + pub edit_windows: &'res mut EditWindows, + pub edit_tabs: &'res mut EditTabs, + pub toasts: &'res mut Toasts, pub project_config: &'res mut Option, pub global_config: &'res mut luminol_config::global::Config, diff --git a/crates/luminol-core/src/tab.rs b/crates/luminol-core/src/tab.rs index 1bfa5e58..c27f185c 100644 --- a/crates/luminol-core/src/tab.rs +++ b/crates/luminol-core/src/tab.rs @@ -139,8 +139,8 @@ where self.clean_fn = Some(Box::new(f)); } - pub fn add_tab(&mut self, tabs: T) { - self.added.push(tabs) + pub fn add_tab(&mut self, tab: impl Into) { + self.added.push(tab.into()) } pub fn remove_tab(&mut self, tab: &T) -> bool { diff --git a/crates/luminol-core/src/toasts.rs b/crates/luminol-core/src/toasts.rs index 182587a6..8af6d31c 100644 --- a/crates/luminol-core/src/toasts.rs +++ b/crates/luminol-core/src/toasts.rs @@ -22,45 +22,42 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. -use egui_notify::{Toast, Toasts as ToastsInner}; -use parking_lot::RwLock; - /// A toasts management struct. #[derive(Default)] pub struct Toasts { - inner: RwLock, + inner: egui_notify::Toasts, } // We wrap the toasts structs in a RefCell to maintain interior mutability. #[allow(dead_code)] impl Toasts { /// Add a custom toast. - pub fn add(&self, toast: Toast) { - self.inner.write().add(toast); + pub fn add(&mut self, toast: egui_notify::Toast) { + self.inner.add(toast); } /// Display an info toast. - pub fn info(&self, caption: impl Into) { - self.inner.write().info(caption); + pub fn info(&mut self, caption: impl Into) { + self.inner.info(caption); } /// Display a warning toast. - pub fn warning(&self, caption: impl Into) { - self.inner.write().warning(caption); + pub fn warning(&mut self, caption: impl Into) { + self.inner.warning(caption); } /// Display an error toast. - pub fn error(&self, caption: impl Into) { - self.inner.write().error(caption); + pub fn error(&mut self, caption: impl Into) { + self.inner.error(caption); } /// Display a generic toast. - pub fn basic(&self, caption: impl Into) { - self.inner.write().basic(caption); + pub fn basic(&mut self, caption: impl Into) { + self.inner.basic(caption); } /// Display all toasts. - pub fn show(&self, ctx: &egui::Context) { - self.inner.write().show(ctx); + pub fn show(&mut self, ctx: &egui::Context) { + self.inner.show(ctx); } } diff --git a/crates/luminol-core/src/window.rs b/crates/luminol-core/src/window.rs index 4a440f63..520c67d6 100644 --- a/crates/luminol-core/src/window.rs +++ b/crates/luminol-core/src/window.rs @@ -117,8 +117,8 @@ where self.clean_fn = Some(Box::new(f)); } - pub fn add_window(&mut self, window: T) { - self.added.push(window) + pub fn add_window(&mut self, window: impl Into) { + self.added.push(window.into()) } pub fn remove_window(&mut self, window: &T) -> bool { diff --git a/crates/luminol-data/src/lib.rs b/crates/luminol-data/src/lib.rs index 12efc199..c58ac265 100644 --- a/crates/luminol-data/src/lib.rs +++ b/crates/luminol-data/src/lib.rs @@ -13,8 +13,6 @@ mod rgss_structs; mod helpers; -pub mod data_cache; - pub mod commands; pub use helpers::*; diff --git a/crates/luminol-ui/Cargo.toml b/crates/luminol-ui/Cargo.toml index 5d2601da..dceb882a 100644 --- a/crates/luminol-ui/Cargo.toml +++ b/crates/luminol-ui/Cargo.toml @@ -32,5 +32,3 @@ reqwest = "0.11.22" zip = { version = "0.6.6", default-features = false, features = ["deflate"] } itertools.workspace = true - -enum_dispatch = "0.3.12" diff --git a/crates/luminol-ui/src/lib.rs b/crates/luminol-ui/src/lib.rs index 10959595..37c446da 100644 --- a/crates/luminol-ui/src/lib.rs +++ b/crates/luminol-ui/src/lib.rs @@ -22,6 +22,161 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. -mod tabs; +pub mod tabs; -mod windows; +pub mod windows; + +macro_rules! tab_enum { + ($visibility:vis enum $name:ident { + $( $variant:ident($variant_type:ty) ),* $(,)? + }) => { + $visibility enum $name { + $( + $variant($variant_type), + )* + } + + impl luminol_core::Tab for $name { + fn name(&self) -> String { + match self { + $( + Self::$variant(v) => v.name(), + )* + } + } + + fn id(&self) -> egui::Id { + match self { + $( + Self::$variant(v) => v.id(), + )* + } + } + + fn show(&mut self, ui: &mut egui::Ui, update_state: &mut luminol_core::UpdateState<'_, W, T>) + where + W: luminol_core::Window, + T: luminol_core::Tab + { + match self { + $( + Self::$variant(v) => v.show(ui, update_state), + )* + } + } + + fn requires_filesystem(&self) -> bool { + match self { + $( + Self::$variant(v) => v.requires_filesystem(), + )* + } + } + + fn force_close(&mut self) -> bool { + match self { + $( + Self::$variant(v) => v.force_close(), + )* + } + } + } + + $( + impl From<$variant_type> for $name { + fn from(value: $variant_type) -> Self { + Self::$variant(value) + } + } + )* + }; +} + +macro_rules! window_enum { + ($visibility:vis enum $name:ident { + $( $variant:ident($variant_type:ty) ),* $(,)? + }) => { + $visibility enum $name { + $( + $variant($variant_type), + )* + } + + impl luminol_core::Window for $name { + fn show( + &mut self, + ctx: &egui::Context, + open: &mut bool, + update_state: &mut luminol_core::UpdateState<'_, W, T>, + ) where + W: luminol_core::Window, + T: luminol_core::Tab + { + match self { + $( + Self::$variant(v) => v.show(ctx, open, update_state), + )* + } + } + + fn name(&self) -> String { + match self { + $( + Self::$variant(v) => v.name(), + )* + } + } + + fn id(&self) -> egui::Id { + match self { + $( + Self::$variant(v) => v.id(), + )* + } + } + + fn requires_filesystem(&self) -> bool { + match self { + $( + Self::$variant(v) => v.requires_filesystem(), + )* + } + } + } + + $( + impl From<$variant_type> for $name { + fn from(value: $variant_type) -> Self { + Self::$variant(value) + } + } + )* + }; +} + +tab_enum! { + pub enum Tab { + Map(tabs::map::Tab), + Started(tabs::started::Tab) + } +} + +window_enum! { + pub enum Window { + About(windows::about::Window), + Appearance(windows::appearance::Window), + CommonEvent(windows::common_event_edit::Window), + ProjectConfig(windows::config_window::Window), + Console(windows::console::Window), + EventEdit(windows::event_edit::Window), + GlobalConfig(windows::global_config_window::Window), + Items(windows::items::Window), + MapPicker(windows::map_picker::Window), + EguiInspection(windows::misc::EguiInspection), + EguiMemory(windows::misc::EguiMemory), + FilesystemDebug(windows::misc::FilesystemDebug), + NewProject(windows::new_project::Window), + ScriptEdit(windows::script_edit::Window), + SoundTest(windows::sound_test::Window) + } +} diff --git a/crates/luminol-ui/src/windows/console.rs b/crates/luminol-ui/src/windows/console.rs index f6a906ea..b38f5e21 100644 --- a/crates/luminol-ui/src/windows/console.rs +++ b/crates/luminol-ui/src/windows/console.rs @@ -22,11 +22,11 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. -pub struct Console { +pub struct Window { term: luminol_term::Terminal, } -impl Console { +impl Window { pub fn new(command: luminol_term::CommandBuilder) -> Result { Ok(Self { term: luminol_term::Terminal::new(command)?, @@ -34,7 +34,7 @@ impl Console { } } -impl luminol_core::Window for Console { +impl luminol_core::Window for Window { fn name(&self) -> String { self.term.title() } diff --git a/crates/luminol-ui/src/windows/event_edit.rs b/crates/luminol-ui/src/windows/event_edit.rs index 42bee910..825171aa 100644 --- a/crates/luminol-ui/src/windows/event_edit.rs +++ b/crates/luminol-ui/src/windows/event_edit.rs @@ -65,265 +65,14 @@ impl luminol_core::Window for Window { .with(self.id) } + // This needs an overhaul fn show( &mut self, ctx: &egui::Context, open: &mut bool, update_state: &mut luminol_core::UpdateState<'_, W, T>, ) { - let mut map = update_state.data.map(self.map_id); - let event = match map.events.get_mut(self.id) { - Some(e) => e, - None => { - *open = false; - return; - } - }; - event.extra_data.is_editor_open = true; - self.name.clone_from(&event.name); - - let mut win_open = true; - - egui::Window::new(self.name()) - .id(egui::Id::new(format!("event_{}_{}", self.id, self.map_id))) - .open(&mut win_open) - .show(ctx, |ui| { - ui.horizontal(|ui| { - ui.text_edit_singleline(&mut event.name); - - ui.button("New page").clicked(); - ui.button("Copy page").clicked(); - ui.button("Paste page").clicked(); - ui.button("Clear page").clicked(); - }); - - ui.separator(); - - ui.horizontal(|ui| { - for (page, _) in event.pages.iter().enumerate() { - if ui - .selectable_value(&mut self.selected_page, page, page.to_string()) - .clicked() - { - self.switch_modal_1 = None; - self.switch_modal_2 = None; - self.variable_modal = None; - } - } - }); - - ui.separator(); - - ui.horizontal(|ui| { - ui.selectable_value(&mut self.viewed_tab, 0, "Configuration"); - ui.selectable_value(&mut self.viewed_tab, 1, "Graphic"); - ui.selectable_value(&mut self.viewed_tab, 2, "Commands"); - }); - - ui.separator(); - - let page = event.pages.get_mut(self.selected_page).unwrap(); - - match self.viewed_tab { - 0 => { - ui.horizontal(|ui| { - ui.vertical(|ui| { - ui.label("Condition"); - ui.group(|ui| { - ui.horizontal(|ui| { - ui.checkbox(&mut page.condition.switch1_valid, "Switch"); - - ui.add_enabled_ui(page.condition.switch1_valid, |ui| { - luminol_modals::switch::Modal::button( - &mut self.switch_modal_1, - ui, - &mut page.condition.switch1_id, - update_state, - ); - }); - }); - - ui.horizontal(|ui| { - ui.checkbox(&mut page.condition.switch2_valid, "Switch"); - - ui.add_enabled_ui(page.condition.switch2_valid, |ui| { - luminol_modals::switch::Modal::button( - &mut self.switch_modal_2, - ui, - &mut page.condition.switch1_id, - update_state, - ); - }); - }); - - ui.horizontal(|ui| { - ui.checkbox(&mut page.condition.variable_valid, "Variable"); - - ui.add_enabled_ui(page.condition.variable_valid, |ui| { - luminol_modals::variable::Modal::button( - &mut self.variable_modal, - ui, - &mut page.condition.variable_id, - update_state, - ); - }); - - ui.add_enabled( - page.condition.variable_valid, - egui::DragValue::new( - &mut page.condition.variable_value, - ), - ); - ui.label("or above"); - }); - - ui.horizontal(|ui| { - ui.checkbox( - &mut page.condition.self_switch_valid, - "Self Switch", - ); - ui.add_enabled_ui(page.condition.self_switch_valid, |ui| { - egui::ComboBox::new( - format!( - "event_{}_{}_self_switch_combo", - self.id, self.map_id - ), - "is on", - ) - .selected_text(page.condition.self_switch_ch.clone()) - .show_ui( - ui, - |ui| { - for ch in ["A", "B", "C", "D"] { - ui.selectable_value( - &mut page.condition.self_switch_ch, - ch.to_string(), - ch, - ); - } - }, - ) - }); - }); - }); - - /* - ui.label("Autonomous Movement"); - ui.group(|ui| { - egui::ComboBox::new( - format!("event_{}_{}_move_type", self.id, self.map_id), - "Type", - ) - .selected_text(MOVE_TYPES[page.move_type]) - .show_ui(ui, |ui| { - for (id, name) in MOVE_TYPES.iter().enumerate() { - ui.selectable_value(&mut page.move_type, id, *name); - } - }); - - ui.add_enabled_ui(page.move_type == 3, |ui| { - if ui.button("Move route").clicked() {} - }); - - egui::ComboBox::new( - format!("event_{}_{}_move_speed", self.id, self.map_id), - "Speed", - ) - .selected_text(MOVE_SPEEDS[page.move_speed - 1]) - .show_ui(ui, |ui| { - for (id, name) in MOVE_SPEEDS.iter().enumerate() { - ui.selectable_value( - &mut page.move_speed, - id + 1, - *name, - ); - } - }); - - egui::ComboBox::new( - format!("event_{}_{}_move_freq", self.id, self.map_id), - "Frequency", - ) - .selected_text(MOVE_FREQS[page.move_frequency - 1]) - .show_ui(ui, |ui| { - for (id, name) in MOVE_FREQS.iter().enumerate() { - ui.selectable_value( - &mut page.move_frequency, - id + 1, - *name, - ); - } - }); - }); - */ - - ui.horizontal(|ui| { - ui.vertical(|ui| { - ui.label("Options"); - ui.group(|ui| { - ui.checkbox(&mut page.step_anime, "Move Animation"); - ui.checkbox(&mut page.walk_anime, "Stop Animation"); - ui.checkbox(&mut page.direction_fix, "Direction Fix"); - ui.checkbox(&mut page.through, "Through"); - ui.checkbox(&mut page.always_on_top, "Always on Top"); - }); - }); - - ui.vertical(|ui| { - ui.label("Trigger"); - ui.group(|ui| { - ui.radio_value(&mut page.trigger, 0, "Action Button"); - ui.radio_value(&mut page.trigger, 1, "Player Touch"); - ui.radio_value(&mut page.trigger, 2, "Event Touch"); - ui.radio_value(&mut page.trigger, 3, "Autorun"); - ui.radio_value( - &mut page.trigger, - 4, - "Parallel Process", - ); - }); - }) - }); - }); - }); - } - - 1 => {} - - 2 => { - ui.vertical(|ui| { - ui.group(|ui| { - egui::ScrollArea::both() - .max_height(500.) - .auto_shrink([false; 2]) - .show(ui, |_ui| { - // CommandView::new(&mut page.list) - // .ui(ui, &info.data_cache.commanddb()); - }); - }); - }); - } - _ => unreachable!(), - } - - ui.separator(); - - ui.horizontal(|ui| { - let ok_clicked = ui.button("Ok").clicked(); - let apply_clicked = ui.button("Apply").clicked(); - let cancel_clicked = ui.button("Cancel").clicked(); - - if apply_clicked || ok_clicked { - //let mut map = state!().data_cache.map(self.map_id); - //map.events[self.id] = event.clone(); - } - - if cancel_clicked || ok_clicked { - *open = false; - } - }); - }); - *open = *open && win_open; + todo!() } fn requires_filesystem(&self) -> bool { diff --git a/crates/luminol-ui/src/windows/items.rs b/crates/luminol-ui/src/windows/items.rs index bb4d60b2..4f332078 100644 --- a/crates/luminol-ui/src/windows/items.rs +++ b/crates/luminol-ui/src/windows/items.rs @@ -38,7 +38,7 @@ pub struct Window { } impl Window { - pub fn new(data_cache: &luminol_data::data_cache::Cache) -> Self { + pub fn new(data_cache: &luminol_core::Data) -> Self { let items = data_cache.items().clone(); Self { diff --git a/crates/luminol-ui/src/windows/map_picker.rs b/crates/luminol-ui/src/windows/map_picker.rs index 4f5b815f..64cbe911 100644 --- a/crates/luminol-ui/src/windows/map_picker.rs +++ b/crates/luminol-ui/src/windows/map_picker.rs @@ -31,12 +31,11 @@ use std::collections::{BTreeMap, BTreeSet}; pub struct Window {} impl Window { - fn render_submap( + fn render_submap( id: usize, children_data: &BTreeMap>, mapinfos: &mut luminol_data::rpg::MapInfos, ui: &mut egui::Ui, - update_state: &mut luminol_core::UpdateState<'_, W, T>, ) { // We get the map name. It's assumed that there is in fact a map with this ID in mapinfos. let map_info = mapinfos.get_mut(&id).unwrap(); @@ -67,7 +66,7 @@ impl Window { .body(|ui| { for id in children_data.get(&id).unwrap() { // Render children. - Self::render_submap(*id, children_data, mapinfos, ui, update_state); + Self::render_submap(*id, children_data, mapinfos, ui); } }); } else { @@ -125,13 +124,7 @@ impl luminol_core::Window for Window { // There will always be a map `0`. // `0` is assumed to be the root map. for &id in children_data.get(&0).unwrap() { - Self::render_submap( - id, - &children_data, - &mut mapinfos, - ui, - update_state, - ); + Self::render_submap(id, &children_data, &mut mapinfos, ui); } }); }) diff --git a/crates/luminol-ui/src/windows/new_project.rs b/crates/luminol-ui/src/windows/new_project.rs index 57cf23f3..f9e2e7b9 100644 --- a/crates/luminol-ui/src/windows/new_project.rs +++ b/crates/luminol-ui/src/windows/new_project.rs @@ -42,7 +42,7 @@ pub struct Window { } struct CreateProjectResult { - data_cache: luminol_data::data_cache::Cache, + data_cache: luminol_core::Data, config: luminol_config::project::Config, host_fs: luminol_filesystem::host::FileSystem, } @@ -204,7 +204,7 @@ impl Window { .map_err(|e| e.to_string())?; // TODO - let data_cache = luminol_data::data_cache::Cache::defaults_from_config(()); + let data_cache = luminol_core::Data::defaults_from_config(&config); data_cache.save()?; if download_executable { diff --git a/crates/luminol/Cargo.toml b/crates/luminol/Cargo.toml index 59ead957..d19465c1 100644 --- a/crates/luminol/Cargo.toml +++ b/crates/luminol/Cargo.toml @@ -44,6 +44,8 @@ luminol-config = { version = "0.1.0", path = "../luminol-config/" } luminol-data = { version = "0.1.0", path = "../luminol-data/" } luminol-filesystem = { version = "0.1.0", path = "../luminol-filesystem/" } luminol-graphics = { version = "0.1.0", path = "../luminol-graphics/" } +luminol-ui = { version = "0.1.0", path = "../luminol-ui/" } +luminol-term = { version = "0.1.0", path = "../luminol-term/" } # luminol-windows = { version = "0.1.0", path = "../luminol-windows/" } # luminol-tabs = { version = "0.1.0", path = "../luminol-tabs/" } @@ -51,6 +53,8 @@ poll-promise.workspace = true camino.workspace = true +strum.workspace = true + [features] steamworks = ["dep:steamworks", "crc"] diff --git a/crates/luminol/src/app/mod.rs b/crates/luminol/src/app/mod.rs index aa7acb9f..ee59b2c6 100644 --- a/crates/luminol/src/app/mod.rs +++ b/crates/luminol/src/app/mod.rs @@ -75,12 +75,21 @@ pub struct App { top_bar: top_bar::TopBar, lumi: Lumi, + audio: luminol_audio::Audio, + + graphics: std::sync::Arc, + filesystem: luminol_filesystem::project::FileSystem, + data: luminol_core::Data, + toasts: luminol_core::Toasts, + windows: luminol_core::Windows, + tabs: luminol_core::Tabs, + global_config: luminol_config::global::Config, project_config: Option, - filesystem: luminol_filesystem::project::FileSystem, + toolbar: luminol_core::ToolbarState, steamworks: Steamworks, } @@ -94,12 +103,19 @@ impl App { #[cfg(target_arch = "wasm32")] audio_wrapper: crate::audio::AudioWrapper, #[cfg(feature = "steamworks")] steamworks: Steamworks, ) -> Self { + let render_state = cc + .wgpu_render_state + .clone() + .expect("wgpu backend not enabled"); + let graphics = std::sync::Arc::new(luminol_graphics::GraphicsState::new(render_state)); + let storage = cc.storage.unwrap(); let mut global_config = eframe::get_value(storage, "SavedState").unwrap_or_default(); let mut project_config = None; let mut filesystem = luminol_filesystem::project::FileSystem::new(); + let data = luminol_core::Data::default(); let mut toasts = luminol_core::Toasts::default(); @@ -109,7 +125,7 @@ impl App { .expect("project path not utf-8"); match filesystem.load_project_from_path(&mut project_config, &mut global_config, path) { - Ok(o) => {} // FIXME load data + Ok(_) => {} // FIXME load data Err(e) => toasts.error(e.to_string()), } } @@ -167,12 +183,19 @@ impl App { top_bar: top_bar::TopBar::default(), lumi, + audio: luminol_audio::Audio::default(), + graphics, + filesystem, + data, toasts, - - project_config, + windows: luminol_core::Windows::default(), + tabs: luminol_core::Tabs::new( + "luminol_main_tabs", + vec![luminol_ui::tabs::started::Tab::default().into()], + ), global_config, - - filesystem, + project_config, + toolbar: luminol_core::ToolbarState::default(), steamworks, } @@ -185,9 +208,10 @@ impl CustomApp for App { ctx.input(|i| { if let Some(f) = i.raw.dropped_files.first() { let path = f.path.clone().expect("dropped file has no path"); + let path = camino::Utf8PathBuf::from_path_buf(path).expect("path was not utf8"); #[cfg(not(target_arch = "wasm32"))] - if let Err(e) = self.filesystem.load_project( + if let Err(e) = self.filesystem.load_project_from_path( &mut self.project_config, &mut self.global_config, path, @@ -203,13 +227,29 @@ impl CustomApp for App { } }); + // dummy values because of the chicken and the egg + let mut edit_windows = luminol_core::EditWindows::default(); + let mut edit_tabs = luminol_core::EditTabs::default(); + let mut update_state = luminol_core::UpdateState { + audio: &mut self.audio, + graphics: self.graphics.clone(), + filesystem: &mut self.filesystem, + data: &mut self.data, + edit_windows: &mut edit_windows, + edit_tabs: &mut edit_tabs, + toasts: &mut self.toasts, + project_config: &mut self.project_config, + global_config: &mut self.global_config, + toolbar: &mut self.toolbar, + }; + egui::TopBottomPanel::top("top_toolbar").show(ctx, |ui| { // We want the top menubar to be horizontal. Without this it would fill up vertically. ui.horizontal_wrapped(|ui| { // Turn off button frame. ui.visuals_mut().button_frame = false; // Show the bar - self.top_bar.ui(ui, frame); + self.top_bar.ui(ui, frame, &mut update_state); }); }); @@ -217,11 +257,11 @@ impl CustomApp for App { egui::CentralPanel::default() .frame(egui::Frame::central_panel(&ctx.style()).inner_margin(0.)) .show(ctx, |ui| { - ui.group(|ui| state!().tabs.ui(ui)); + ui.group(|ui| self.tabs.ui(ui, &mut update_state)); }); // Update all windows. - state!().windows.update(ctx); + self.windows.display(ctx, &mut update_state); // Show toasts. self.toasts.show(ctx); @@ -241,7 +281,7 @@ impl eframe::App for App { /// Called by the frame work to save state before shutdown. fn save(&mut self, storage: &mut dyn eframe::Storage) { - eframe::set_value(storage, "SavedState", &*global_config!()); + eframe::set_value(storage, "SavedState", &self.global_config); } fn persist_egui_memory(&self) -> bool { diff --git a/crates/luminol/src/app/top_bar.rs b/crates/luminol/src/app/top_bar.rs index 7bedfdd4..ca4169dd 100644 --- a/crates/luminol/src/app/top_bar.rs +++ b/crates/luminol/src/app/top_bar.rs @@ -22,14 +22,15 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. -use crate::prelude::*; +use luminol_core::Tab; +use luminol_core::Window; -use crate::Pencil; +use strum::IntoEnumIterator; /// The top bar for managing the project. #[derive(Default)] pub struct TopBar { - open_project_promise: Option>>, + open_project_promise: Option>>, fullscreen: bool, } @@ -37,8 +38,12 @@ pub struct TopBar { impl TopBar { /// Display the top bar. #[allow(unused_variables)] - pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut crate::luminol::CustomFrame<'_>) { - let state = state!(); + pub fn ui( + &mut self, + ui: &mut egui::Ui, + frame: &mut super::CustomFrame<'_>, + update_state: &mut luminol_core::UpdateState<'_, luminol_ui::Window, luminol_ui::Tab>, + ) { egui::widgets::global_dark_light_mode_switch(ui); #[cfg(not(target_arch = "wasm32"))] @@ -48,40 +53,48 @@ impl TopBar { } let mut open_project = ui.input(|i| i.modifiers.command && i.key_pressed(egui::Key::O)) - && state.filesystem.project_loaded(); + && update_state.filesystem.project_loaded(); let mut save_project = ui.input(|i| i.modifiers.command && i.key_pressed(egui::Key::S)) - && state.filesystem.project_loaded(); + && update_state.filesystem.project_loaded(); if ui.input(|i| i.modifiers.command && i.key_pressed(egui::Key::N)) { - state.windows.add_window(new_project::Window::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::new_project::Window::default()); } ui.separator(); ui.menu_button("File", |ui| { - ui.label(if let Some(path) = state.filesystem.project_path() { + ui.label(if let Some(path) = update_state.filesystem.project_path() { format!("Current project:\n{}", path) } else { "No project open".to_string() }); if ui.button("New Project").clicked() { - state.windows.add_window(new_project::Window::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::new_project::Window::default()); } open_project |= ui.button("Open Project").clicked(); ui.separator(); - ui.add_enabled_ui(state.filesystem.project_loaded(), |ui| { + ui.add_enabled_ui(update_state.filesystem.project_loaded(), |ui| { if ui.button("Project Config").clicked() { - state.windows.add_window(config_window::Window {}); + update_state + .edit_windows + .add_window(luminol_ui::windows::config_window::Window {}); } if ui.button("Close Project").clicked() { - state.windows.clean_windows(); - state.tabs.clean_tabs(|t| !t.requires_filesystem()); - state.audio.clear_sinks(); // audio loads files borrows from the filesystem. unloading while they are playing is a crash - state.filesystem.unload_project(); + update_state + .edit_windows + .clean(|w| !w.requires_filesystem()); + update_state.edit_tabs.clean(|t| !t.requires_filesystem()); + update_state.audio.clear_sinks(); // audio loads files borrows from the filesystem. unloading while they are playing is a crash + update_state.filesystem.unload_project(); } save_project |= ui.button("Save Project").clicked(); @@ -89,11 +102,11 @@ impl TopBar { ui.separator(); - ui.add_enabled_ui(state.filesystem.project_loaded(), |ui| { + ui.add_enabled_ui(update_state.filesystem.project_loaded(), |ui| { if ui.button("Command Maker").clicked() { - state - .windows - .add_window(crate::command_gen::CommandGeneratorWindow::default()); + // update_state.windows.add_window( + // luminol_ui::windows::command_gen::CommandGeneratorWindow::default(), + // ); } }); @@ -112,40 +125,50 @@ impl TopBar { ui.menu_button("Edit", |ui| { // if ui.button("Preferences").clicked() { - state - .windows - .add_window(global_config_window::Window::default()) + update_state + .edit_windows + .add_window(luminol_ui::windows::global_config_window::Window::default()) } if ui.button("Appearance").clicked() { - state.windows.add_window(appearance::Window::default()) + update_state + .edit_windows + .add_window(luminol_ui::windows::appearance::Window::default()) } }); ui.separator(); ui.menu_button("Data", |ui| { - ui.add_enabled_ui(state.filesystem.project_loaded(), |ui| { + ui.add_enabled_ui(update_state.filesystem.project_loaded(), |ui| { if ui.button("Maps").clicked() { - state.windows.add_window(map_picker::Window::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::map_picker::Window::default()); } if ui.button("Items").clicked() { - state.windows.add_window(items::Window::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::items::Window::new(update_state.data)); } if ui.button("Common Events").clicked() { - state - .windows - .add_window(common_event_edit::Window::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::common_event_edit::Window::default()); } if ui.button("Scripts").clicked() { - state.windows.add_window(script_edit::Window::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::script_edit::Window::default()); } if ui.button("Sound Test").clicked() { - state.windows.add_window(sound_test::Window::default()); + update_state.edit_windows.add_window( + luminol_ui::windows::sound_test::Window::new(update_state.filesystem), + ); } }); }); @@ -156,17 +179,23 @@ impl TopBar { ui.button("Contents").clicked(); if ui.button("About...").clicked() { - state.windows.add_window(about::Window::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::about::Window::default()); }; }); ui.menu_button("Debug", |ui| { if ui.button("Egui Inspection").clicked() { - state.windows.add_window(misc::EguiInspection::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::misc::EguiInspection::default()); } if ui.button("Egui Memory").clicked() { - state.windows.add_window(misc::EguiMemory::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::misc::EguiMemory::default()); } let mut debug_on_hover = ui.ctx().debug_on_hover(); @@ -176,7 +205,9 @@ impl TopBar { ui.separator(); if ui.button("Filesystem Debug").clicked() { - state.windows.add_window(misc::FilesystemDebug::default()); + update_state + .edit_windows + .add_window(luminol_ui::windows::misc::FilesystemDebug::default()); } }); @@ -184,21 +215,31 @@ impl TopBar { { ui.separator(); - ui.add_enabled_ui(state.filesystem.project_loaded(), |ui| { + ui.add_enabled_ui(update_state.filesystem.project_loaded(), |ui| { if ui.button("Playtest").clicked() { let mut cmd = luminol_term::CommandBuilder::new("steamshim"); - cmd.cwd(state.filesystem.project_path().expect("project not loaded")); - - let result = crate::windows::console::Console::new(cmd).or_else(|_| { + cmd.cwd( + update_state + .filesystem + .project_path() + .expect("project not loaded"), + ); + + let result = luminol_ui::windows::console::Window::new(cmd).or_else(|_| { let mut cmd = luminol_term::CommandBuilder::new("game"); - cmd.cwd(state.filesystem.project_path().expect("project not loaded")); - - crate::windows::console::Console::new(cmd) + cmd.cwd( + update_state + .filesystem + .project_path() + .expect("project not loaded"), + ); + + luminol_ui::windows::console::Window::new(cmd) }); match result { - Ok(w) => state.windows.add_window(w), - Err(e) => state.toasts.error(format!( + Ok(w) => update_state.edit_windows.add_window(w), + Err(e) => update_state.toasts.error(format!( "error starting game (tried steamshim.exe and then game.exe): {e}" )), } @@ -210,11 +251,18 @@ impl TopBar { #[cfg(unix)] let shell = std::env::var("SHELL").unwrap_or_else(|_| "bash".to_string()); let mut cmd = luminol_term::CommandBuilder::new(shell); - cmd.cwd(state.filesystem.project_path().expect("project not loaded")); - - match crate::windows::console::Console::new(cmd) { - Ok(w) => state.windows.add_window(w), - Err(e) => state.toasts.error(format!("error starting shell: {e}")), + cmd.cwd( + update_state + .filesystem + .project_path() + .expect("project not loaded"), + ); + + match luminol_ui::windows::console::Window::new(cmd) { + Ok(w) => update_state.edit_windows.add_window(w), + Err(e) => update_state + .toasts + .error(format!("error starting shell: {e}")), } } }); @@ -224,30 +272,29 @@ impl TopBar { ui.label("Brush:"); - let mut toolbar = state.toolbar.borrow_mut(); - for brush in Pencil::iter() { - ui.selectable_value(&mut toolbar.pencil, brush, brush.to_string()); + for brush in luminol_core::Pencil::iter() { + ui.selectable_value(&mut update_state.toolbar.pencil, brush, brush.to_string()); } if open_project { - self.open_project_promise = Some(Promise::spawn_local( - state.filesystem.spawn_project_file_picker(), - )); + // self.open_project_promise = Some(poll_promise::Promise::spawn_local( + // update_state.filesystem.spawn_project_file_picker(), + // )); } if save_project { - state.toasts.info("Saving project..."); - match state.data_cache.save() { - Ok(_) => state.toasts.info("Saved project sucessfully!"), - Err(e) => state.toasts.error(e), + update_state.toasts.info("Saving project..."); + match update_state.data.save() { + Ok(_) => update_state.toasts.info("Saved project sucessfully!"), + Err(e) => update_state.toasts.error(e), } } if self.open_project_promise.is_some() { if let Some(r) = self.open_project_promise.as_ref().unwrap().ready() { match r { - Ok(_) => state.toasts.info("Opened project successfully!"), - Err(e) => state.toasts.error(e), + Ok(_) => update_state.toasts.info("Opened project successfully!"), + Err(e) => update_state.toasts.error(e), } self.open_project_promise = None; }