From ea45a9df79a4e4daf431696cf7a2542ebe7a0c4e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 13:59:17 +0100 Subject: [PATCH 01/19] Move `status` into event loop state struct --- crates/fj-window/src/run.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 17a11530a..ff0ee5a63 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -30,8 +30,6 @@ pub fn run( shape_processor: ShapeProcessor, invert_zoom: bool, ) -> Result<(), Error> { - let mut status = StatusReport::new(); - let event_loop = EventLoop::new(); let window = Window::new(&event_loop)?; let mut viewer = block_on(Viewer::new(&window))?; @@ -48,6 +46,10 @@ pub fn run( // https://github.com/rust-windowing/winit/issues/2094 let mut new_size = None; + let mut state = EventLoopHandler { + status: StatusReport::new(), + }; + event_loop.run(move |event, _, control_flow| { trace!("Handling event: {:?}", event); @@ -70,12 +72,12 @@ pub fn run( match event { ModelEvent::ChangeDetected => { - status.update_status( + state.status.update_status( "Change in model detected. Evaluating model...", ); } ModelEvent::Evaluation(evaluation) => { - status.update_status( + state.status.update_status( "Model evaluated. Processing model...", ); @@ -100,11 +102,11 @@ pub fn run( } } - status.update_status("Model processed."); + state.status.update_status("Model processed."); } ModelEvent::Error(err) => { - status.update_status(&err.to_string()); + state.status.update_status(&err.to_string()); } } } @@ -198,7 +200,7 @@ pub fn run( egui_winit_state.take_egui_input(window.window()); let gui_state = GuiState { - status: &status, + status: &state.status, model_available: host.is_some(), }; let new_model_path = @@ -212,7 +214,7 @@ pub fn run( host = Some(new_host); } Err(err) => { - status.update_status(&format!( + state.status.update_status(&format!( "Error creating host: {err}" )); } @@ -297,6 +299,10 @@ fn input_event( } } +struct EventLoopHandler { + status: StatusReport, +} + /// Error in main loop #[derive(Debug, thiserror::Error)] pub enum Error { From c0386c029fc6d8aae91057ec7fd342d93e6bfb82 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:02:12 +0100 Subject: [PATCH 02/19] Move `window` to `state` --- crates/fj-window/src/run.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index ff0ee5a63..7bb20f55b 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -47,6 +47,7 @@ pub fn run( let mut new_size = None; let mut state = EventLoopHandler { + window, status: StatusReport::new(), }; @@ -184,7 +185,7 @@ pub fn run( .. } => viewer.add_focus_point(), Event::MainEventsCleared => { - window.window().request_redraw(); + state.window.window().request_redraw(); } Event::RedrawRequested(_) => { // Only do a screen resize once per frame. This protects against @@ -193,11 +194,12 @@ pub fn run( viewer.handle_screen_resize(size); } - let pixels_per_point = window.window().scale_factor() as f32; + let pixels_per_point = + state.window.window().scale_factor() as f32; egui_winit_state.set_pixels_per_point(pixels_per_point); let egui_input = - egui_winit_state.take_egui_input(window.window()); + egui_winit_state.take_egui_input(state.window.window()); let gui_state = GuiState { status: &state.status, @@ -226,7 +228,7 @@ pub fn run( let input_event = input_event( &event, - &window, + &state.window, &held_mouse_button, &mut viewer.cursor, invert_zoom, @@ -300,6 +302,7 @@ fn input_event( } struct EventLoopHandler { + window: Window, status: StatusReport, } From 501e9ea0f1a68aadc7062d10c8266f37c579047c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:04:05 +0100 Subject: [PATCH 03/19] Rename variable to prevent naming collision --- crates/fj-window/src/run.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 7bb20f55b..ca912d6cb 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -46,7 +46,7 @@ pub fn run( // https://github.com/rust-windowing/winit/issues/2094 let mut new_size = None; - let mut state = EventLoopHandler { + let mut handler = EventLoopHandler { window, status: StatusReport::new(), }; @@ -73,12 +73,12 @@ pub fn run( match event { ModelEvent::ChangeDetected => { - state.status.update_status( + handler.status.update_status( "Change in model detected. Evaluating model...", ); } ModelEvent::Evaluation(evaluation) => { - state.status.update_status( + handler.status.update_status( "Model evaluated. Processing model...", ); @@ -103,11 +103,11 @@ pub fn run( } } - state.status.update_status("Model processed."); + handler.status.update_status("Model processed."); } ModelEvent::Error(err) => { - state.status.update_status(&err.to_string()); + handler.status.update_status(&err.to_string()); } } } @@ -185,7 +185,7 @@ pub fn run( .. } => viewer.add_focus_point(), Event::MainEventsCleared => { - state.window.window().request_redraw(); + handler.window.window().request_redraw(); } Event::RedrawRequested(_) => { // Only do a screen resize once per frame. This protects against @@ -195,14 +195,14 @@ pub fn run( } let pixels_per_point = - state.window.window().scale_factor() as f32; + handler.window.window().scale_factor() as f32; egui_winit_state.set_pixels_per_point(pixels_per_point); let egui_input = - egui_winit_state.take_egui_input(state.window.window()); + egui_winit_state.take_egui_input(handler.window.window()); let gui_state = GuiState { - status: &state.status, + status: &handler.status, model_available: host.is_some(), }; let new_model_path = @@ -216,7 +216,7 @@ pub fn run( host = Some(new_host); } Err(err) => { - state.status.update_status(&format!( + handler.status.update_status(&format!( "Error creating host: {err}" )); } @@ -228,7 +228,7 @@ pub fn run( let input_event = input_event( &event, - &state.window, + &handler.window, &held_mouse_button, &mut viewer.cursor, invert_zoom, From 34d43b3ae7f1b58d9eb595fd931a2e3e7579a3d8 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:06:02 +0100 Subject: [PATCH 04/19] Move `viewer` to `handler` --- crates/fj-window/src/run.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index ca912d6cb..65ed1b9ce 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -32,7 +32,7 @@ pub fn run( ) -> Result<(), Error> { let event_loop = EventLoop::new(); let window = Window::new(&event_loop)?; - let mut viewer = block_on(Viewer::new(&window))?; + let viewer = block_on(Viewer::new(&window))?; let mut held_mouse_button = None; @@ -48,6 +48,7 @@ pub fn run( let mut handler = EventLoopHandler { window, + viewer, status: StatusReport::new(), }; @@ -84,7 +85,7 @@ pub fn run( match shape_processor.process(&evaluation.shape) { Ok(shape) => { - viewer.handle_shape_update(shape); + handler.viewer.handle_shape_update(shape); } Err(err) => { // Can be cleaned up, once `Report` is stable: @@ -122,7 +123,7 @@ pub fn run( // The primary visible impact of this currently is that if you drag // a title bar that overlaps the model then both the model & window // get moved. - egui_winit_state.on_event(viewer.gui.context(), event); + egui_winit_state.on_event(handler.viewer.gui.context(), event); } // fj-window events @@ -148,13 +149,13 @@ pub fn run( } => match virtual_key_code { VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit, VirtualKeyCode::Key1 => { - viewer.toggle_draw_model(); + handler.viewer.toggle_draw_model(); } VirtualKeyCode::Key2 => { - viewer.toggle_draw_mesh(); + handler.viewer.toggle_draw_mesh(); } VirtualKeyCode::Key3 => { - viewer.toggle_draw_debug(); + handler.viewer.toggle_draw_debug(); } _ => {} }, @@ -173,17 +174,17 @@ pub fn run( } => match state { ElementState::Pressed => { held_mouse_button = Some(button); - viewer.add_focus_point(); + handler.viewer.add_focus_point(); } ElementState::Released => { held_mouse_button = None; - viewer.remove_focus_point(); + handler.viewer.remove_focus_point(); } }, Event::WindowEvent { event: WindowEvent::MouseWheel { .. }, .. - } => viewer.add_focus_point(), + } => handler.viewer.add_focus_point(), Event::MainEventsCleared => { handler.window.window().request_redraw(); } @@ -191,7 +192,7 @@ pub fn run( // Only do a screen resize once per frame. This protects against // spurious resize events that cause issues with the renderer. if let Some(size) = new_size.take() { - viewer.handle_screen_resize(size); + handler.viewer.handle_screen_resize(size); } let pixels_per_point = @@ -205,8 +206,11 @@ pub fn run( status: &handler.status, model_available: host.is_some(), }; - let new_model_path = - viewer.draw(pixels_per_point, egui_input, gui_state); + let new_model_path = handler.viewer.draw( + pixels_per_point, + egui_input, + gui_state, + ); if let Some(model_path) = new_model_path { let model = @@ -230,11 +234,11 @@ pub fn run( &event, &handler.window, &held_mouse_button, - &mut viewer.cursor, + &mut handler.viewer.cursor, invert_zoom, ); if let Some(input_event) = input_event { - viewer.handle_input_event(input_event); + handler.viewer.handle_input_event(input_event); } }); } @@ -303,6 +307,7 @@ fn input_event( struct EventLoopHandler { window: Window, + viewer: Viewer, status: StatusReport, } From 8c28dce0bd76a7ccda8b2e818e6fa9d1eab0e137 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:07:40 +0100 Subject: [PATCH 05/19] Move `held_mouse_button` to `handler` --- crates/fj-window/src/run.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 65ed1b9ce..b8ae5b61f 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -34,8 +34,6 @@ pub fn run( let window = Window::new(&event_loop)?; let viewer = block_on(Viewer::new(&window))?; - let mut held_mouse_button = None; - let mut egui_winit_state = egui_winit::State::new(&event_loop); let mut host = model.map(Host::from_model).transpose()?; @@ -50,6 +48,7 @@ pub fn run( window, viewer, status: StatusReport::new(), + held_mouse_button: None, }; event_loop.run(move |event, _, control_flow| { @@ -173,11 +172,11 @@ pub fn run( .. } => match state { ElementState::Pressed => { - held_mouse_button = Some(button); + handler.held_mouse_button = Some(button); handler.viewer.add_focus_point(); } ElementState::Released => { - held_mouse_button = None; + handler.held_mouse_button = None; handler.viewer.remove_focus_point(); } }, @@ -233,7 +232,7 @@ pub fn run( let input_event = input_event( &event, &handler.window, - &held_mouse_button, + &handler.held_mouse_button, &mut handler.viewer.cursor, invert_zoom, ); @@ -309,6 +308,7 @@ struct EventLoopHandler { window: Window, viewer: Viewer, status: StatusReport, + held_mouse_button: Option, } /// Error in main loop From 9a1f0e10b2bfcd5ba9a5e48438be64a95f6bdc9c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:17:35 +0100 Subject: [PATCH 06/19] Move `egui_winit_state` to `handler` --- crates/fj-window/src/run.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index b8ae5b61f..517c460cb 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -34,7 +34,7 @@ pub fn run( let window = Window::new(&event_loop)?; let viewer = block_on(Viewer::new(&window))?; - let mut egui_winit_state = egui_winit::State::new(&event_loop); + let egui_winit_state = egui_winit::State::new(&event_loop); let mut host = model.map(Host::from_model).transpose()?; @@ -47,6 +47,7 @@ pub fn run( let mut handler = EventLoopHandler { window, viewer, + egui_winit_state, status: StatusReport::new(), held_mouse_button: None, }; @@ -122,7 +123,9 @@ pub fn run( // The primary visible impact of this currently is that if you drag // a title bar that overlaps the model then both the model & window // get moved. - egui_winit_state.on_event(handler.viewer.gui.context(), event); + handler + .egui_winit_state + .on_event(handler.viewer.gui.context(), event); } // fj-window events @@ -197,9 +200,12 @@ pub fn run( let pixels_per_point = handler.window.window().scale_factor() as f32; - egui_winit_state.set_pixels_per_point(pixels_per_point); - let egui_input = - egui_winit_state.take_egui_input(handler.window.window()); + handler + .egui_winit_state + .set_pixels_per_point(pixels_per_point); + let egui_input = handler + .egui_winit_state + .take_egui_input(handler.window.window()); let gui_state = GuiState { status: &handler.status, @@ -307,6 +313,7 @@ fn input_event( struct EventLoopHandler { window: Window, viewer: Viewer, + egui_winit_state: egui_winit::State, status: StatusReport, held_mouse_button: Option, } From 686cfeb7cdf70668bd7da6996c5df29b4947eabb Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:18:19 +0100 Subject: [PATCH 07/19] Move `host` to `handler` --- crates/fj-window/src/run.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 517c460cb..9255f7ab0 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -36,7 +36,7 @@ pub fn run( let egui_winit_state = egui_winit::State::new(&event_loop); - let mut host = model.map(Host::from_model).transpose()?; + let host = model.map(Host::from_model).transpose()?; // Only handle resize events once every frame. This filters out spurious // resize events that can lead to wgpu warnings. See this issue for some @@ -48,6 +48,7 @@ pub fn run( window, viewer, egui_winit_state, + host, status: StatusReport::new(), held_mouse_button: None, }; @@ -55,7 +56,7 @@ pub fn run( event_loop.run(move |event, _, control_flow| { trace!("Handling event: {:?}", event); - if let Some(host) = &host { + if let Some(host) = &handler.host { loop { let events = host.events(); let event = events @@ -209,7 +210,7 @@ pub fn run( let gui_state = GuiState { status: &handler.status, - model_available: host.is_some(), + model_available: handler.host.is_some(), }; let new_model_path = handler.viewer.draw( pixels_per_point, @@ -222,7 +223,7 @@ pub fn run( Model::new(model_path, Parameters::empty()).unwrap(); match Host::from_model(model) { Ok(new_host) => { - host = Some(new_host); + handler.host = Some(new_host); } Err(err) => { handler.status.update_status(&format!( @@ -314,6 +315,7 @@ struct EventLoopHandler { window: Window, viewer: Viewer, egui_winit_state: egui_winit::State, + host: Option, status: StatusReport, held_mouse_button: Option, } From 3167f79f82e215640609d7f02cb31b3c697b171b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:20:08 +0100 Subject: [PATCH 08/19] Update order of code --- crates/fj-window/src/run.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 9255f7ab0..9d62cd2d6 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -249,6 +249,15 @@ pub fn run( }); } +struct EventLoopHandler { + window: Window, + viewer: Viewer, + egui_winit_state: egui_winit::State, + host: Option, + status: StatusReport, + held_mouse_button: Option, +} + fn input_event( event: &Event, window: &Window, @@ -311,15 +320,6 @@ fn input_event( } } -struct EventLoopHandler { - window: Window, - viewer: Viewer, - egui_winit_state: egui_winit::State, - host: Option, - status: StatusReport, - held_mouse_button: Option, -} - /// Error in main loop #[derive(Debug, thiserror::Error)] pub enum Error { From 48d34ad31a1553ba4b3b68f9bd6b3a800a8bc4ab Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:24:09 +0100 Subject: [PATCH 09/19] Add `new_size` to `handler` --- crates/fj-window/src/run.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 9d62cd2d6..3bb9399d9 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -38,12 +38,6 @@ pub fn run( let host = model.map(Host::from_model).transpose()?; - // Only handle resize events once every frame. This filters out spurious - // resize events that can lead to wgpu warnings. See this issue for some - // context: - // https://github.com/rust-windowing/winit/issues/2094 - let mut new_size = None; - let mut handler = EventLoopHandler { window, viewer, @@ -51,6 +45,7 @@ pub fn run( host, status: StatusReport::new(), held_mouse_button: None, + new_size: None, }; event_loop.run(move |event, _, control_flow| { @@ -166,7 +161,7 @@ pub fn run( event: WindowEvent::Resized(size), .. } => { - new_size = Some(ScreenSize { + handler.new_size = Some(ScreenSize { width: size.width, height: size.height, }); @@ -194,7 +189,7 @@ pub fn run( Event::RedrawRequested(_) => { // Only do a screen resize once per frame. This protects against // spurious resize events that cause issues with the renderer. - if let Some(size) = new_size.take() { + if let Some(size) = handler.new_size.take() { handler.viewer.handle_screen_resize(size); } @@ -256,6 +251,12 @@ struct EventLoopHandler { host: Option, status: StatusReport, held_mouse_button: Option, + + /// Only handle resize events once every frame. This filters out spurious + /// resize events that can lead to wgpu warnings. See this issue for some + /// context: + /// + new_size: Option, } fn input_event( From 01d683e4e1245eaa8e1e3237e5189daa976b0380 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:26:21 +0100 Subject: [PATCH 10/19] Add `shape_processor` to `handler` --- crates/fj-window/src/run.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 3bb9399d9..cf301a73e 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -39,6 +39,7 @@ pub fn run( let host = model.map(Host::from_model).transpose()?; let mut handler = EventLoopHandler { + shape_processor, window, viewer, egui_winit_state, @@ -79,7 +80,8 @@ pub fn run( "Model evaluated. Processing model...", ); - match shape_processor.process(&evaluation.shape) { + match handler.shape_processor.process(&evaluation.shape) + { Ok(shape) => { handler.viewer.handle_shape_update(shape); } @@ -245,6 +247,7 @@ pub fn run( } struct EventLoopHandler { + shape_processor: ShapeProcessor, window: Window, viewer: Viewer, egui_winit_state: egui_winit::State, From eb2ec9d7778555953ae9f2f668617b076c4a177b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:28:33 +0100 Subject: [PATCH 11/19] Add `invert_zoom` to `handler` --- crates/fj-window/src/run.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index cf301a73e..713095e49 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -39,6 +39,7 @@ pub fn run( let host = model.map(Host::from_model).transpose()?; let mut handler = EventLoopHandler { + invert_zoom, shape_processor, window, viewer, @@ -238,7 +239,7 @@ pub fn run( &handler.window, &handler.held_mouse_button, &mut handler.viewer.cursor, - invert_zoom, + handler.invert_zoom, ); if let Some(input_event) = input_event { handler.viewer.handle_input_event(input_event); @@ -247,6 +248,7 @@ pub fn run( } struct EventLoopHandler { + invert_zoom: bool, shape_processor: ShapeProcessor, window: Window, viewer: Viewer, From 114b205b031c032fb461c651259300ecc986dc68 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:31:25 +0100 Subject: [PATCH 12/19] Move event loop handling into method --- crates/fj-window/src/run.rs | 125 ++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 713095e49..fccd6b946 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -52,8 +52,34 @@ pub fn run( event_loop.run(move |event, _, control_flow| { trace!("Handling event: {:?}", event); + handler.handle_event(event, control_flow); + }); +} + +struct EventLoopHandler { + invert_zoom: bool, + shape_processor: ShapeProcessor, + window: Window, + viewer: Viewer, + egui_winit_state: egui_winit::State, + host: Option, + status: StatusReport, + held_mouse_button: Option, + + /// Only handle resize events once every frame. This filters out spurious + /// resize events that can lead to wgpu warnings. See this issue for some + /// context: + /// + new_size: Option, +} - if let Some(host) = &handler.host { +impl EventLoopHandler { + fn handle_event( + &mut self, + event: Event<()>, + control_flow: &mut ControlFlow, + ) { + if let Some(host) = &self.host { loop { let events = host.events(); let event = events @@ -72,19 +98,18 @@ pub fn run( match event { ModelEvent::ChangeDetected => { - handler.status.update_status( + self.status.update_status( "Change in model detected. Evaluating model...", ); } ModelEvent::Evaluation(evaluation) => { - handler.status.update_status( + self.status.update_status( "Model evaluated. Processing model...", ); - match handler.shape_processor.process(&evaluation.shape) - { + match self.shape_processor.process(&evaluation.shape) { Ok(shape) => { - handler.viewer.handle_shape_update(shape); + self.viewer.handle_shape_update(shape); } Err(err) => { // Can be cleaned up, once `Report` is stable: @@ -103,11 +128,11 @@ pub fn run( } } - handler.status.update_status("Model processed."); + self.status.update_status("Model processed."); } ModelEvent::Error(err) => { - handler.status.update_status(&err.to_string()); + self.status.update_status(&err.to_string()); } } } @@ -122,9 +147,8 @@ pub fn run( // The primary visible impact of this currently is that if you drag // a title bar that overlaps the model then both the model & window // get moved. - handler - .egui_winit_state - .on_event(handler.viewer.gui.context(), event); + self.egui_winit_state + .on_event(self.viewer.gui.context(), event); } // fj-window events @@ -150,13 +174,13 @@ pub fn run( } => match virtual_key_code { VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit, VirtualKeyCode::Key1 => { - handler.viewer.toggle_draw_model(); + self.viewer.toggle_draw_model(); } VirtualKeyCode::Key2 => { - handler.viewer.toggle_draw_mesh(); + self.viewer.toggle_draw_mesh(); } VirtualKeyCode::Key3 => { - handler.viewer.toggle_draw_debug(); + self.viewer.toggle_draw_debug(); } _ => {} }, @@ -164,7 +188,7 @@ pub fn run( event: WindowEvent::Resized(size), .. } => { - handler.new_size = Some(ScreenSize { + self.new_size = Some(ScreenSize { width: size.width, height: size.height, }); @@ -174,57 +198,51 @@ pub fn run( .. } => match state { ElementState::Pressed => { - handler.held_mouse_button = Some(button); - handler.viewer.add_focus_point(); + self.held_mouse_button = Some(button); + self.viewer.add_focus_point(); } ElementState::Released => { - handler.held_mouse_button = None; - handler.viewer.remove_focus_point(); + self.held_mouse_button = None; + self.viewer.remove_focus_point(); } }, Event::WindowEvent { event: WindowEvent::MouseWheel { .. }, .. - } => handler.viewer.add_focus_point(), + } => self.viewer.add_focus_point(), Event::MainEventsCleared => { - handler.window.window().request_redraw(); + self.window.window().request_redraw(); } Event::RedrawRequested(_) => { // Only do a screen resize once per frame. This protects against // spurious resize events that cause issues with the renderer. - if let Some(size) = handler.new_size.take() { - handler.viewer.handle_screen_resize(size); + if let Some(size) = self.new_size.take() { + self.viewer.handle_screen_resize(size); } let pixels_per_point = - handler.window.window().scale_factor() as f32; + self.window.window().scale_factor() as f32; - handler - .egui_winit_state - .set_pixels_per_point(pixels_per_point); - let egui_input = handler - .egui_winit_state - .take_egui_input(handler.window.window()); + self.egui_winit_state.set_pixels_per_point(pixels_per_point); + let egui_input = + self.egui_winit_state.take_egui_input(self.window.window()); let gui_state = GuiState { - status: &handler.status, - model_available: handler.host.is_some(), + status: &self.status, + model_available: self.host.is_some(), }; - let new_model_path = handler.viewer.draw( - pixels_per_point, - egui_input, - gui_state, - ); + let new_model_path = + self.viewer.draw(pixels_per_point, egui_input, gui_state); if let Some(model_path) = new_model_path { let model = Model::new(model_path, Parameters::empty()).unwrap(); match Host::from_model(model) { Ok(new_host) => { - handler.host = Some(new_host); + self.host = Some(new_host); } Err(err) => { - handler.status.update_status(&format!( + self.status.update_status(&format!( "Error creating host: {err}" )); } @@ -236,32 +254,15 @@ pub fn run( let input_event = input_event( &event, - &handler.window, - &handler.held_mouse_button, - &mut handler.viewer.cursor, - handler.invert_zoom, + &self.window, + &self.held_mouse_button, + &mut self.viewer.cursor, + self.invert_zoom, ); if let Some(input_event) = input_event { - handler.viewer.handle_input_event(input_event); + self.viewer.handle_input_event(input_event); } - }); -} - -struct EventLoopHandler { - invert_zoom: bool, - shape_processor: ShapeProcessor, - window: Window, - viewer: Viewer, - egui_winit_state: egui_winit::State, - host: Option, - status: StatusReport, - held_mouse_button: Option, - - /// Only handle resize events once every frame. This filters out spurious - /// resize events that can lead to wgpu warnings. See this issue for some - /// context: - /// - new_size: Option, + } } fn input_event( From d32e7324a3ff950ffdf11df1b8495274f0b6fb8b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:35:02 +0100 Subject: [PATCH 13/19] Handle shape processing error outside of method --- crates/fj-window/src/run.rs | 45 +++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index fccd6b946..982934c46 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -52,7 +52,22 @@ pub fn run( event_loop.run(move |event, _, control_flow| { trace!("Handling event: {:?}", event); - handler.handle_event(event, control_flow); + + if let Err(err) = handler.handle_event(event, control_flow) { + // Can be cleaned up, once `Report` is stable: + // https://doc.rust-lang.org/std/error/struct.Report.html + + println!("Shape processing error: {}", err); + + let mut current_err = &err as &dyn error::Error; + while let Some(err) = current_err.source() { + println!(); + println!("Caused by:"); + println!(" {}", err); + + current_err = err; + } + } }); } @@ -74,11 +89,12 @@ struct EventLoopHandler { } impl EventLoopHandler { + #[allow(clippy::result_large_err)] fn handle_event( &mut self, event: Event<()>, control_flow: &mut ControlFlow, - ) { + ) -> Result<(), fj_operations::shape_processor::Error> { if let Some(host) = &self.host { loop { let events = host.events(); @@ -107,26 +123,9 @@ impl EventLoopHandler { "Model evaluated. Processing model...", ); - match self.shape_processor.process(&evaluation.shape) { - Ok(shape) => { - self.viewer.handle_shape_update(shape); - } - Err(err) => { - // Can be cleaned up, once `Report` is stable: - // https://doc.rust-lang.org/std/error/struct.Report.html - - println!("Shape processing error: {}", err); - - let mut current_err = &err as &dyn error::Error; - while let Some(err) = current_err.source() { - println!(); - println!("Caused by:"); - println!(" {}", err); - - current_err = err; - } - } - } + let shape = + self.shape_processor.process(&evaluation.shape)?; + self.viewer.handle_shape_update(shape); self.status.update_status("Model processed."); } @@ -262,6 +261,8 @@ impl EventLoopHandler { if let Some(input_event) = input_event { self.viewer.handle_input_event(input_event); } + + Ok(()) } } From 5113097d77109ca2da0ae51f4bf75da5ba7756a7 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:44:50 +0100 Subject: [PATCH 14/19] Move error handling to dedicated function --- crates/fj-window/src/run.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 982934c46..fab55ca4d 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -54,19 +54,7 @@ pub fn run( trace!("Handling event: {:?}", event); if let Err(err) = handler.handle_event(event, control_flow) { - // Can be cleaned up, once `Report` is stable: - // https://doc.rust-lang.org/std/error/struct.Report.html - - println!("Shape processing error: {}", err); - - let mut current_err = &err as &dyn error::Error; - while let Some(err) = current_err.source() { - println!(); - println!("Caused by:"); - println!(" {}", err); - - current_err = err; - } + handle_error(err); } }); } @@ -328,6 +316,22 @@ fn input_event( } } +fn handle_error(err: fj_operations::shape_processor::Error) { + // Can be cleaned up, once `Report` is stable: + // https://doc.rust-lang.org/std/error/struct.Report.html + + println!("Shape processing error: {}", err); + + let mut current_err = &err as &dyn error::Error; + while let Some(err) = current_err.source() { + println!(); + println!("Caused by:"); + println!(" {}", err); + + current_err = err; + } +} + /// Error in main loop #[derive(Debug, thiserror::Error)] pub enum Error { From 6dbbd779f8a52bdc46b9d70a143c9fbec40e9899 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:48:08 +0100 Subject: [PATCH 15/19] Print error message to GUI --- crates/fj-window/src/run.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index fab55ca4d..43a6d9997 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -3,7 +3,10 @@ //! Provides the functionality to create a window and perform basic viewing //! with programmed models. -use std::error; +use std::{ + error, + fmt::{self, Write}, +}; use fj_host::{Host, Model, ModelEvent, Parameters}; use fj_operations::shape_processor::ShapeProcessor; @@ -54,7 +57,8 @@ pub fn run( trace!("Handling event: {:?}", event); if let Err(err) = handler.handle_event(event, control_flow) { - handle_error(err); + handle_error(err, &mut handler.status) + .expect("Expected error handling not to fail"); } }); } @@ -316,20 +320,29 @@ fn input_event( } } -fn handle_error(err: fj_operations::shape_processor::Error) { +fn handle_error( + err: fj_operations::shape_processor::Error, + status: &mut StatusReport, +) -> Result<(), fmt::Error> { // Can be cleaned up, once `Report` is stable: // https://doc.rust-lang.org/std/error/struct.Report.html - println!("Shape processing error: {}", err); + let mut msg = String::new(); + + writeln!(msg, "Shape processing error: {}", err)?; let mut current_err = &err as &dyn error::Error; while let Some(err) = current_err.source() { - println!(); - println!("Caused by:"); - println!(" {}", err); + writeln!(msg)?; + writeln!(msg, "Caused by:")?; + writeln!(msg, " {}", err)?; current_err = err; } + + status.update_status(&msg); + + Ok(()) } /// Error in main loop From 7e0d1f15b41d4803884aa2da2d66e96e58ed7a91 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:53:17 +0100 Subject: [PATCH 16/19] Move `EventLoopHandler` to dedicated module --- crates/fj-window/src/event_loop_handler.rs | 291 ++++++++++++++++++++ crates/fj-window/src/lib.rs | 2 + crates/fj-window/src/run.rs | 296 +-------------------- 3 files changed, 300 insertions(+), 289 deletions(-) create mode 100644 crates/fj-window/src/event_loop_handler.rs diff --git a/crates/fj-window/src/event_loop_handler.rs b/crates/fj-window/src/event_loop_handler.rs new file mode 100644 index 000000000..6a4df9c73 --- /dev/null +++ b/crates/fj-window/src/event_loop_handler.rs @@ -0,0 +1,291 @@ +use fj_host::{Host, Model, ModelEvent, Parameters}; +use fj_operations::shape_processor::ShapeProcessor; +use fj_viewer::{ + GuiState, InputEvent, NormalizedScreenPosition, Screen, ScreenSize, + StatusReport, Viewer, +}; +use winit::{ + dpi::PhysicalPosition, + event::{ + ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, + VirtualKeyCode, WindowEvent, + }, + event_loop::ControlFlow, +}; + +use crate::window::Window; + +pub struct EventLoopHandler { + pub invert_zoom: bool, + pub shape_processor: ShapeProcessor, + pub window: Window, + pub viewer: Viewer, + pub egui_winit_state: egui_winit::State, + pub host: Option, + pub status: StatusReport, + pub held_mouse_button: Option, + + /// Only handle resize events once every frame. This filters out spurious + /// resize events that can lead to wgpu warnings. See this issue for some + /// context: + /// + pub new_size: Option, +} + +impl EventLoopHandler { + #[allow(clippy::result_large_err)] + pub fn handle_event( + &mut self, + event: Event<()>, + control_flow: &mut ControlFlow, + ) -> Result<(), fj_operations::shape_processor::Error> { + if let Some(host) = &self.host { + loop { + let events = host.events(); + let event = events + .try_recv() + .map_err(|err| { + if err.is_disconnected() { + panic!("Expected channel to never disconnect"); + } + }) + .ok(); + + let event = match event { + Some(status_update) => status_update, + None => break, + }; + + match event { + ModelEvent::ChangeDetected => { + self.status.update_status( + "Change in model detected. Evaluating model...", + ); + } + ModelEvent::Evaluation(evaluation) => { + self.status.update_status( + "Model evaluated. Processing model...", + ); + + let shape = + self.shape_processor.process(&evaluation.shape)?; + self.viewer.handle_shape_update(shape); + + self.status.update_status("Model processed."); + } + + ModelEvent::Error(err) => { + self.status.update_status(&err.to_string()); + } + } + } + } + + if let Event::WindowEvent { event, .. } = &event { + // In theory we could/should check if `egui` wants "exclusive" use + // of this event here. But with the current integration with Fornjot + // we're kinda blurring the lines between "app" and "platform", so + // for the moment we pass every event to both `egui` & Fornjot. + // + // The primary visible impact of this currently is that if you drag + // a title bar that overlaps the model then both the model & window + // get moved. + self.egui_winit_state + .on_event(self.viewer.gui.context(), event); + } + + // fj-window events + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + *control_flow = ControlFlow::Exit; + } + Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(virtual_key_code), + .. + }, + .. + }, + .. + } => match virtual_key_code { + VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit, + VirtualKeyCode::Key1 => { + self.viewer.toggle_draw_model(); + } + VirtualKeyCode::Key2 => { + self.viewer.toggle_draw_mesh(); + } + VirtualKeyCode::Key3 => { + self.viewer.toggle_draw_debug(); + } + _ => {} + }, + Event::WindowEvent { + event: WindowEvent::Resized(size), + .. + } => { + self.new_size = Some(ScreenSize { + width: size.width, + height: size.height, + }); + } + Event::WindowEvent { + event: WindowEvent::MouseInput { state, button, .. }, + .. + } => match state { + ElementState::Pressed => { + self.held_mouse_button = Some(button); + self.viewer.add_focus_point(); + } + ElementState::Released => { + self.held_mouse_button = None; + self.viewer.remove_focus_point(); + } + }, + Event::WindowEvent { + event: WindowEvent::MouseWheel { .. }, + .. + } => self.viewer.add_focus_point(), + Event::MainEventsCleared => { + self.window.window().request_redraw(); + } + Event::RedrawRequested(_) => { + // Only do a screen resize once per frame. This protects against + // spurious resize events that cause issues with the renderer. + if let Some(size) = self.new_size.take() { + self.viewer.handle_screen_resize(size); + } + + let pixels_per_point = + self.window.window().scale_factor() as f32; + + self.egui_winit_state.set_pixels_per_point(pixels_per_point); + let egui_input = + self.egui_winit_state.take_egui_input(self.window.window()); + + let gui_state = GuiState { + status: &self.status, + model_available: self.host.is_some(), + }; + let new_model_path = + self.viewer.draw(pixels_per_point, egui_input, gui_state); + + if let Some(model_path) = new_model_path { + let model = + Model::new(model_path, Parameters::empty()).unwrap(); + match Host::from_model(model) { + Ok(new_host) => { + self.host = Some(new_host); + } + Err(err) => { + self.status.update_status(&format!( + "Error creating host: {err}" + )); + } + } + } + } + _ => {} + } + + let input_event = input_event( + &event, + &self.window, + &self.held_mouse_button, + &mut self.viewer.cursor, + self.invert_zoom, + ); + if let Some(input_event) = input_event { + self.viewer.handle_input_event(input_event); + } + + Ok(()) + } +} + +fn input_event( + event: &Event, + window: &Window, + held_mouse_button: &Option, + previous_cursor: &mut Option, + invert_zoom: bool, +) -> Option { + match event { + Event::WindowEvent { + event: WindowEvent::CursorMoved { position, .. }, + .. + } => { + let [width, height] = window.size().as_f64(); + let aspect_ratio = width / height; + + // Cursor position in normalized coordinates (-1 to +1) with + // aspect ratio taken into account. + let current = NormalizedScreenPosition { + x: position.x / width * 2. - 1., + y: -(position.y / height * 2. - 1.) / aspect_ratio, + }; + let event = match (*previous_cursor, held_mouse_button) { + (Some(previous), Some(button)) => match button { + MouseButton::Left => { + let diff_x = current.x - previous.x; + let diff_y = current.y - previous.y; + let angle_x = -diff_y * ROTATION_SENSITIVITY; + let angle_y = diff_x * ROTATION_SENSITIVITY; + + Some(InputEvent::Rotation { angle_x, angle_y }) + } + MouseButton::Right => { + Some(InputEvent::Translation { previous, current }) + } + _ => None, + }, + _ => None, + }; + *previous_cursor = Some(current); + event + } + Event::WindowEvent { + event: WindowEvent::MouseWheel { delta, .. }, + .. + } => { + let delta = match delta { + MouseScrollDelta::LineDelta(_, y) => { + (*y as f64) * ZOOM_FACTOR_LINE + } + MouseScrollDelta::PixelDelta(PhysicalPosition { + y, .. + }) => y * ZOOM_FACTOR_PIXEL, + }; + + let delta = if invert_zoom { -delta } else { delta }; + + Some(InputEvent::Zoom(delta)) + } + _ => None, + } +} + +/// Affects the speed of zoom movement given a scroll wheel input in lines. +/// +/// Smaller values will move the camera less with the same input. +/// Larger values will move the camera more with the same input. +const ZOOM_FACTOR_LINE: f64 = 0.075; + +/// Affects the speed of zoom movement given a scroll wheel input in pixels. +/// +/// Smaller values will move the camera less with the same input. +/// Larger values will move the camera more with the same input. +const ZOOM_FACTOR_PIXEL: f64 = 0.005; + +/// Affects the speed of rotation given a change in normalized screen position [-1, 1] +/// +/// Smaller values will move the camera less with the same input. +/// Larger values will move the camera more with the same input. +const ROTATION_SENSITIVITY: f64 = 5.; diff --git a/crates/fj-window/src/lib.rs b/crates/fj-window/src/lib.rs index b67bc34ac..ccf7450ba 100644 --- a/crates/fj-window/src/lib.rs +++ b/crates/fj-window/src/lib.rs @@ -15,3 +15,5 @@ pub mod run; pub mod window; + +mod event_loop_handler; diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 43a6d9997..86cfee3f8 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -8,24 +8,17 @@ use std::{ fmt::{self, Write}, }; -use fj_host::{Host, Model, ModelEvent, Parameters}; +use fj_host::{Host, Model}; use fj_operations::shape_processor::ShapeProcessor; -use fj_viewer::{ - GuiState, InputEvent, NormalizedScreenPosition, RendererInitError, Screen, - ScreenSize, StatusReport, Viewer, -}; +use fj_viewer::{RendererInitError, StatusReport, Viewer}; use futures::executor::block_on; use tracing::trace; -use winit::{ - dpi::PhysicalPosition, - event::{ - ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, - VirtualKeyCode, WindowEvent, - }, - event_loop::{ControlFlow, EventLoop}, -}; +use winit::event_loop::EventLoop; -use crate::window::{self, Window}; +use crate::{ + event_loop_handler::EventLoopHandler, + window::{self, Window}, +}; /// Initializes a model viewer for a given model and enters its process loop. pub fn run( @@ -63,263 +56,6 @@ pub fn run( }); } -struct EventLoopHandler { - invert_zoom: bool, - shape_processor: ShapeProcessor, - window: Window, - viewer: Viewer, - egui_winit_state: egui_winit::State, - host: Option, - status: StatusReport, - held_mouse_button: Option, - - /// Only handle resize events once every frame. This filters out spurious - /// resize events that can lead to wgpu warnings. See this issue for some - /// context: - /// - new_size: Option, -} - -impl EventLoopHandler { - #[allow(clippy::result_large_err)] - fn handle_event( - &mut self, - event: Event<()>, - control_flow: &mut ControlFlow, - ) -> Result<(), fj_operations::shape_processor::Error> { - if let Some(host) = &self.host { - loop { - let events = host.events(); - let event = events - .try_recv() - .map_err(|err| { - if err.is_disconnected() { - panic!("Expected channel to never disconnect"); - } - }) - .ok(); - - let event = match event { - Some(status_update) => status_update, - None => break, - }; - - match event { - ModelEvent::ChangeDetected => { - self.status.update_status( - "Change in model detected. Evaluating model...", - ); - } - ModelEvent::Evaluation(evaluation) => { - self.status.update_status( - "Model evaluated. Processing model...", - ); - - let shape = - self.shape_processor.process(&evaluation.shape)?; - self.viewer.handle_shape_update(shape); - - self.status.update_status("Model processed."); - } - - ModelEvent::Error(err) => { - self.status.update_status(&err.to_string()); - } - } - } - } - - if let Event::WindowEvent { event, .. } = &event { - // In theory we could/should check if `egui` wants "exclusive" use - // of this event here. But with the current integration with Fornjot - // we're kinda blurring the lines between "app" and "platform", so - // for the moment we pass every event to both `egui` & Fornjot. - // - // The primary visible impact of this currently is that if you drag - // a title bar that overlaps the model then both the model & window - // get moved. - self.egui_winit_state - .on_event(self.viewer.gui.context(), event); - } - - // fj-window events - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => { - *control_flow = ControlFlow::Exit; - } - Event::WindowEvent { - event: - WindowEvent::KeyboardInput { - input: - KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(virtual_key_code), - .. - }, - .. - }, - .. - } => match virtual_key_code { - VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit, - VirtualKeyCode::Key1 => { - self.viewer.toggle_draw_model(); - } - VirtualKeyCode::Key2 => { - self.viewer.toggle_draw_mesh(); - } - VirtualKeyCode::Key3 => { - self.viewer.toggle_draw_debug(); - } - _ => {} - }, - Event::WindowEvent { - event: WindowEvent::Resized(size), - .. - } => { - self.new_size = Some(ScreenSize { - width: size.width, - height: size.height, - }); - } - Event::WindowEvent { - event: WindowEvent::MouseInput { state, button, .. }, - .. - } => match state { - ElementState::Pressed => { - self.held_mouse_button = Some(button); - self.viewer.add_focus_point(); - } - ElementState::Released => { - self.held_mouse_button = None; - self.viewer.remove_focus_point(); - } - }, - Event::WindowEvent { - event: WindowEvent::MouseWheel { .. }, - .. - } => self.viewer.add_focus_point(), - Event::MainEventsCleared => { - self.window.window().request_redraw(); - } - Event::RedrawRequested(_) => { - // Only do a screen resize once per frame. This protects against - // spurious resize events that cause issues with the renderer. - if let Some(size) = self.new_size.take() { - self.viewer.handle_screen_resize(size); - } - - let pixels_per_point = - self.window.window().scale_factor() as f32; - - self.egui_winit_state.set_pixels_per_point(pixels_per_point); - let egui_input = - self.egui_winit_state.take_egui_input(self.window.window()); - - let gui_state = GuiState { - status: &self.status, - model_available: self.host.is_some(), - }; - let new_model_path = - self.viewer.draw(pixels_per_point, egui_input, gui_state); - - if let Some(model_path) = new_model_path { - let model = - Model::new(model_path, Parameters::empty()).unwrap(); - match Host::from_model(model) { - Ok(new_host) => { - self.host = Some(new_host); - } - Err(err) => { - self.status.update_status(&format!( - "Error creating host: {err}" - )); - } - } - } - } - _ => {} - } - - let input_event = input_event( - &event, - &self.window, - &self.held_mouse_button, - &mut self.viewer.cursor, - self.invert_zoom, - ); - if let Some(input_event) = input_event { - self.viewer.handle_input_event(input_event); - } - - Ok(()) - } -} - -fn input_event( - event: &Event, - window: &Window, - held_mouse_button: &Option, - previous_cursor: &mut Option, - invert_zoom: bool, -) -> Option { - match event { - Event::WindowEvent { - event: WindowEvent::CursorMoved { position, .. }, - .. - } => { - let [width, height] = window.size().as_f64(); - let aspect_ratio = width / height; - - // Cursor position in normalized coordinates (-1 to +1) with - // aspect ratio taken into account. - let current = NormalizedScreenPosition { - x: position.x / width * 2. - 1., - y: -(position.y / height * 2. - 1.) / aspect_ratio, - }; - let event = match (*previous_cursor, held_mouse_button) { - (Some(previous), Some(button)) => match button { - MouseButton::Left => { - let diff_x = current.x - previous.x; - let diff_y = current.y - previous.y; - let angle_x = -diff_y * ROTATION_SENSITIVITY; - let angle_y = diff_x * ROTATION_SENSITIVITY; - - Some(InputEvent::Rotation { angle_x, angle_y }) - } - MouseButton::Right => { - Some(InputEvent::Translation { previous, current }) - } - _ => None, - }, - _ => None, - }; - *previous_cursor = Some(current); - event - } - Event::WindowEvent { - event: WindowEvent::MouseWheel { delta, .. }, - .. - } => { - let delta = match delta { - MouseScrollDelta::LineDelta(_, y) => { - (*y as f64) * ZOOM_FACTOR_LINE - } - MouseScrollDelta::PixelDelta(PhysicalPosition { - y, .. - }) => y * ZOOM_FACTOR_PIXEL, - }; - - let delta = if invert_zoom { -delta } else { delta }; - - Some(InputEvent::Zoom(delta)) - } - _ => None, - } -} - fn handle_error( err: fj_operations::shape_processor::Error, status: &mut StatusReport, @@ -360,21 +96,3 @@ pub enum Error { #[error("Error initializing graphics")] GraphicsInit(#[from] RendererInitError), } - -/// Affects the speed of zoom movement given a scroll wheel input in lines. -/// -/// Smaller values will move the camera less with the same input. -/// Larger values will move the camera more with the same input. -const ZOOM_FACTOR_LINE: f64 = 0.075; - -/// Affects the speed of zoom movement given a scroll wheel input in pixels. -/// -/// Smaller values will move the camera less with the same input. -/// Larger values will move the camera more with the same input. -const ZOOM_FACTOR_PIXEL: f64 = 0.005; - -/// Affects the speed of rotation given a change in normalized screen position [-1, 1] -/// -/// Smaller values will move the camera less with the same input. -/// Larger values will move the camera more with the same input. -const ROTATION_SENSITIVITY: f64 = 5.; From 6fdeaf83b1376c39f995597a92c253ae18edaf61 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:55:37 +0100 Subject: [PATCH 17/19] Add `event_loop_handler::Error` --- crates/fj-window/src/event_loop_handler.rs | 10 ++++++++-- crates/fj-window/src/run.rs | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/fj-window/src/event_loop_handler.rs b/crates/fj-window/src/event_loop_handler.rs index 6a4df9c73..a9e8dbeb6 100644 --- a/crates/fj-window/src/event_loop_handler.rs +++ b/crates/fj-window/src/event_loop_handler.rs @@ -1,5 +1,5 @@ use fj_host::{Host, Model, ModelEvent, Parameters}; -use fj_operations::shape_processor::ShapeProcessor; +use fj_operations::shape_processor::{self, ShapeProcessor}; use fj_viewer::{ GuiState, InputEvent, NormalizedScreenPosition, Screen, ScreenSize, StatusReport, Viewer, @@ -38,7 +38,7 @@ impl EventLoopHandler { &mut self, event: Event<()>, control_flow: &mut ControlFlow, - ) -> Result<(), fj_operations::shape_processor::Error> { + ) -> Result<(), Error> { if let Some(host) = &self.host { loop { let events = host.events(); @@ -272,6 +272,12 @@ fn input_event( } } +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Shape processing error")] + ShapeProcessor(#[from] shape_processor::Error), +} + /// Affects the speed of zoom movement given a scroll wheel input in lines. /// /// Smaller values will move the camera less with the same input. diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 86cfee3f8..f58e26565 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -16,7 +16,7 @@ use tracing::trace; use winit::event_loop::EventLoop; use crate::{ - event_loop_handler::EventLoopHandler, + event_loop_handler::{self, EventLoopHandler}, window::{self, Window}, }; @@ -57,7 +57,7 @@ pub fn run( } fn handle_error( - err: fj_operations::shape_processor::Error, + err: event_loop_handler::Error, status: &mut StatusReport, ) -> Result<(), fmt::Error> { // Can be cleaned up, once `Report` is stable: From 8e106eb8c46691a9d61d7a57791f236e33fb82f2 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:56:58 +0100 Subject: [PATCH 18/19] Improve handling of host errors --- crates/fj-window/src/event_loop_handler.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/fj-window/src/event_loop_handler.rs b/crates/fj-window/src/event_loop_handler.rs index a9e8dbeb6..6190461f5 100644 --- a/crates/fj-window/src/event_loop_handler.rs +++ b/crates/fj-window/src/event_loop_handler.rs @@ -75,7 +75,7 @@ impl EventLoopHandler { } ModelEvent::Error(err) => { - self.status.update_status(&err.to_string()); + return Err(err.into()); } } } @@ -274,6 +274,9 @@ fn input_event( #[derive(Debug, thiserror::Error)] pub enum Error { + #[error("Host error")] + Host(#[from] fj_host::Error), + #[error("Shape processing error")] ShapeProcessor(#[from] shape_processor::Error), } From 3e59f5ef5b53af7910bb834b1857b4f8a0c42aeb Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 29 Nov 2022 14:58:34 +0100 Subject: [PATCH 19/19] Improve handling of model loading errors --- crates/fj-window/src/event_loop_handler.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/crates/fj-window/src/event_loop_handler.rs b/crates/fj-window/src/event_loop_handler.rs index 6190461f5..c737b3cf6 100644 --- a/crates/fj-window/src/event_loop_handler.rs +++ b/crates/fj-window/src/event_loop_handler.rs @@ -180,16 +180,8 @@ impl EventLoopHandler { if let Some(model_path) = new_model_path { let model = Model::new(model_path, Parameters::empty()).unwrap(); - match Host::from_model(model) { - Ok(new_host) => { - self.host = Some(new_host); - } - Err(err) => { - self.status.update_status(&format!( - "Error creating host: {err}" - )); - } - } + let new_host = Host::from_model(model)?; + self.host = Some(new_host); } } _ => {}