From 1174a5cce1d4fe83aa34a00504c709c66fd484d5 Mon Sep 17 00:00:00 2001 From: Luca Della Vedova Date: Fri, 2 Aug 2024 17:44:07 +0800 Subject: [PATCH] Remove events and add workflow based API Signed-off-by: Luca Della Vedova --- rmf_site_editor/src/keyboard.rs | 7 +-- rmf_site_editor/src/main_menu.rs | 20 ++++---- rmf_site_editor/src/site/sdf_exporter.rs | 6 +-- rmf_site_editor/src/widgets/menu_bar.rs | 9 ++-- rmf_site_editor/src/workspace.rs | 63 +++++++++--------------- 5 files changed, 48 insertions(+), 57 deletions(-) diff --git a/rmf_site_editor/src/keyboard.rs b/rmf_site_editor/src/keyboard.rs index 27ea2034..fffb7eee 100644 --- a/rmf_site_editor/src/keyboard.rs +++ b/rmf_site_editor/src/keyboard.rs @@ -18,7 +18,7 @@ use crate::{ interaction::{ChangeMode, ChangeProjectionMode, InteractionMode, Selection}, site::{AlignSiteDrawings, Delete}, - CreateNewWorkspace, CurrentWorkspace, LoadWorkspace, SaveWorkspace, + CreateNewWorkspace, CurrentWorkspace, SaveWorkspace, WorkspaceLoadingServices, }; use bevy::{prelude::*, window::PrimaryWindow}; use bevy_egui::EguiContexts; @@ -42,6 +42,7 @@ impl Plugin for KeyboardInputPlugin { } fn handle_keyboard_input( + mut commands: Commands, keyboard_input: Res>, selection: Res, current_mode: Res, @@ -50,12 +51,12 @@ fn handle_keyboard_input( mut delete: EventWriter, mut save_workspace: EventWriter, mut new_workspace: EventWriter, - mut load_workspace: EventWriter, mut change_camera_mode: EventWriter, mut debug_mode: ResMut, mut align_site: EventWriter, current_workspace: Res, primary_windows: Query>, + load_workspace: Res, ) { let Some(egui_context) = primary_windows .get_single() @@ -122,7 +123,7 @@ fn handle_keyboard_input( } if keyboard_input.just_pressed(KeyCode::O) { - load_workspace.send(LoadWorkspace::Dialog); + load_workspace.load_from_dialog(&mut commands); } } } diff --git a/rmf_site_editor/src/main_menu.rs b/rmf_site_editor/src/main_menu.rs index d6822509..7f08a5ab 100644 --- a/rmf_site_editor/src/main_menu.rs +++ b/rmf_site_editor/src/main_menu.rs @@ -16,14 +16,15 @@ */ use super::demo_world::*; -use crate::{AppState, Autoload, LoadWorkspace, WorkspaceData}; +use crate::{AppState, Autoload, WorkspaceData, WorkspaceLoadingServices}; use bevy::{app::AppExit, prelude::*, window::PrimaryWindow}; use bevy_egui::{egui, EguiContexts}; fn egui_ui( + mut commands: Commands, mut egui_context: EguiContexts, mut _exit: EventWriter, - mut _load_workspace: EventWriter, + load_workspace: Res, mut _app_state: ResMut>, autoload: Option>, primary_windows: Query>, @@ -32,7 +33,7 @@ fn egui_ui( #[cfg(not(target_arch = "wasm32"))] { if let Some(filename) = autoload.filename.take() { - _load_workspace.send(LoadWorkspace::Path(filename)); + load_workspace.load_from_path(&mut commands, filename); } } return; @@ -57,23 +58,24 @@ fn egui_ui( ui.horizontal(|ui| { if ui.button("View demo map").clicked() { - _load_workspace.send(LoadWorkspace::Data(WorkspaceData::LegacyBuilding( - demo_office(), - ))); + load_workspace.load_from_data( + &mut commands, + WorkspaceData::LegacyBuilding(demo_office()), + ); } if ui.button("Open a file").clicked() { - _load_workspace.send(LoadWorkspace::Dialog); + load_workspace.load_from_dialog(&mut commands); } if ui.button("Create new file").clicked() { - _load_workspace.send(LoadWorkspace::BlankFromDialog); + load_workspace.create_empty_from_dialog(&mut commands); } // TODO(@mxgrey): Bring this back when we have finished developing // the key features for workcell editing. // if ui.button("Workcell Editor").clicked() { - // _load_workspace.send(LoadWorkspace::Data(WorkspaceData::Workcell( + // load_workspace.send(LoadWorkspace::Data(WorkspaceData::Workcell( // demo_workcell(), // ))); // } diff --git a/rmf_site_editor/src/site/sdf_exporter.rs b/rmf_site_editor/src/site/sdf_exporter.rs index acf43b31..966fcfdb 100644 --- a/rmf_site_editor/src/site/sdf_exporter.rs +++ b/rmf_site_editor/src/site/sdf_exporter.rs @@ -11,7 +11,7 @@ use crate::{ ChildLiftCabinGroup, CollisionMeshMarker, DoorSegments, DrawingMarker, FloorSegments, LiftDoormat, ModelSceneRoot, TentativeModelFormat, VisualMeshMarker, }, - Autoload, LoadWorkspace, + Autoload, WorkspaceLoadingServices, }; use rmf_site_format::{ IsStatic, LevelElevation, LiftCabin, ModelMarker, NameInSite, NameOfSite, SiteID, WallMarker, @@ -51,11 +51,11 @@ pub fn headless_sdf_export( sites: Query<(Entity, &NameOfSite)>, drawings: Query>, autoload: Option>, - mut load_workspace: EventWriter, + load_workspace: Res, ) { if let Some(mut autoload) = autoload { if let Some(filename) = autoload.filename.take() { - load_workspace.send(LoadWorkspace::Path(filename)); + load_workspace.load_from_path(&mut commands, filename); } } else { error!("Cannot perform a headless export since no site file was specified for loading"); diff --git a/rmf_site_editor/src/widgets/menu_bar.rs b/rmf_site_editor/src/widgets/menu_bar.rs index 98d2bc4f..13c4f667 100644 --- a/rmf_site_editor/src/widgets/menu_bar.rs +++ b/rmf_site_editor/src/widgets/menu_bar.rs @@ -15,7 +15,9 @@ * */ -use crate::{widgets::prelude::*, AppState, CreateNewWorkspace, LoadWorkspace, SaveWorkspace}; +use crate::{ + widgets::prelude::*, AppState, CreateNewWorkspace, SaveWorkspace, WorkspaceLoadingServices, +}; use bevy::ecs::query::Has; use bevy::prelude::*; @@ -275,9 +277,10 @@ struct MenuParams<'w, 's> { fn top_menu_bar( In(input): In, + mut commands: Commands, mut new_workspace: EventWriter, mut save: EventWriter, - mut load_workspace: EventWriter, + load_workspace: Res, file_menu: Res, top_level_components: Query<(), Without>, children: Query<&Children>, @@ -308,7 +311,7 @@ fn top_menu_bar( .add(Button::new("Open").shortcut_text("Ctrl+O")) .clicked() { - load_workspace.send(LoadWorkspace::Dialog); + load_workspace.load_from_dialog(&mut commands); } render_sub_menu( diff --git a/rmf_site_editor/src/workspace.rs b/rmf_site_editor/src/workspace.rs index 27175bfa..6bf42a85 100644 --- a/rmf_site_editor/src/workspace.rs +++ b/rmf_site_editor/src/workspace.rs @@ -45,20 +45,6 @@ pub struct CreateNewWorkspace; #[derive(Component)] pub struct WorkspaceMarker; -/// Used as an event to command that a workspace should be loaded. This will spawn a file open -/// dialog (in non-wasm) with allowed extensions depending on the app state -// TODO(luca) Encapsulate a list of optional filters, for example to allow users to only load -// workcells or sites -// Dialog will spawn a RFD dialog, Path will open a specific path, the others will parse embedded -// data -#[derive(Event)] -pub enum LoadWorkspace { - Dialog, - BlankFromDialog, - Path(PathBuf), - Data(WorkspaceData), -} - #[derive(Clone)] pub enum WorkspaceData { LegacyBuilding(Vec), @@ -198,7 +184,6 @@ impl Plugin for WorkspacePlugin { fn build(&self, app: &mut App) { app.add_event::() .add_event::() - .add_event::() .add_event::() .add_event::() .add_event::() @@ -211,7 +196,6 @@ impl Plugin for WorkspacePlugin { ( dispatch_new_workspace_events, sync_workspace_visibility, - dispatch_load_workspace_workflows, workspace_file_save_complete, ), ); @@ -485,31 +469,32 @@ impl FromWorld for WorkspaceLoadingServices { } impl WorkspaceLoadingServices { - /// Given a `LoadWorkspace` event, dispatches the corresponding workflow to process it - pub fn dispatch_workflow_for_request(&self, commands: &mut Commands, request: &LoadWorkspace) { - match request { - LoadWorkspace::Dialog => commands.request((), self.load_workspace_from_dialog), - LoadWorkspace::BlankFromDialog => { - commands.request((), self.create_empty_workspace_from_dialog) - } - LoadWorkspace::Path(path) => { - commands.request(path.clone(), self.load_workspace_from_path) - } - LoadWorkspace::Data(data) => { - commands.request(data.clone(), self.load_workspace_from_data) - } - } - .detach(); + /// Request to spawn a dialog and load a workspace + pub fn load_from_dialog(&self, commands: &mut Commands) { + commands + .request((), self.load_workspace_from_dialog) + .detach(); } -} -pub fn dispatch_load_workspace_workflows( - mut commands: Commands, - mut load_workspace: EventReader, - workspace_service: Res, -) { - if let Some(cmd) = load_workspace.read().last() { - workspace_service.dispatch_workflow_for_request(&mut commands, cmd); + /// Request to spawn a dialog to select a file and create a new site with a blank level + pub fn create_empty_from_dialog(&self, commands: &mut Commands) { + commands + .request((), self.create_empty_workspace_from_dialog) + .detach(); + } + + /// Request to load a workspace from a path + pub fn load_from_path(&self, commands: &mut Commands, path: PathBuf) { + commands + .request(path, self.load_workspace_from_path) + .detach(); + } + + /// Request to load a workspace from data + pub fn load_from_data(&self, commands: &mut Commands, data: WorkspaceData) { + commands + .request(data, self.load_workspace_from_data) + .detach(); } }