diff --git a/crates/render/src/gpustate.rs b/crates/render/src/gpustate.rs index fd6964f..f7b30d0 100644 --- a/crates/render/src/gpustate.rs +++ b/crates/render/src/gpustate.rs @@ -443,6 +443,7 @@ impl GPUState { } } +// Render utilities impl GPUState { fn push_ships( &mut self, diff --git a/crates/render/src/ui/manager.rs b/crates/render/src/ui/manager.rs index 6343c4a..0ed2e6c 100644 --- a/crates/render/src/ui/manager.rs +++ b/crates/render/src/ui/manager.rs @@ -182,8 +182,8 @@ impl UiManager { /// Draw all ui elements pub fn draw(&mut self, input: Rc, state: &mut RenderState) -> Result<()> { + // Initialize start scene if we haven't yet if self.current_scene.is_none() { - // Initialize start scene if we haven't yet self.set_scene( state, input.clone(), @@ -191,13 +191,16 @@ impl UiManager { )?; } + // Update timings if they're being displayed if self.show_timings { self.fps_indicator.step(&input, state); } - // Check for player ship state changes - let player = input.player.ship; - let send_event = { + let mut keep_doing_actions = true; + + // Send player state change events + if { + let player = input.player.ship; if let Some(player) = player { let ship = input.phys_img.get_ship(&PhysSimShipHandle(player)).unwrap(); if self.last_player_state == 0 @@ -213,10 +216,7 @@ impl UiManager { self.last_player_state = 0; true } - }; - - let mut actions = Vec::new(); - if send_event { + } { let action: Dynamic = self .engine .call_fn( @@ -236,156 +236,108 @@ impl UiManager { })?; if let Some(action) = action.try_cast::() { - match action { - SceneAction::None => {} - _ => { - actions.push(action); - } - } + keep_doing_actions = self.handle_action(state, input.clone(), action)?; } } - for e in &self.elements { - let action: Dynamic = { - if let Some(e) = e.sprite() { - let mut x = (*e).borrow_mut(); - let event = x.check_mouse(&input, state); - x.step(&input, state); - x.push_to_buffer(&input, state); - drop(x); + for i in 0..self.elements.len() { + match &self.elements[i] { + UiElement::Sprite(e) => { + // Draw and update sprites + let mut sprite = (*e).borrow_mut(); + sprite.step(&input, state); + sprite.push_to_buffer(&input, state); + + if !keep_doing_actions { + continue; + } + + let event = sprite.check_events(&input, state); // we MUST drop here, since script calls mutate the sprite RefCell + drop(sprite); match event { - Event::None => Dynamic::from(SceneAction::None), - - Event::MouseClick => self - .engine - .call_fn( - &mut self.scope, - &self - .ct - .get_config() - .ui_scenes - .get(self.current_scene.as_ref().unwrap()) - .unwrap(), - "event", - ( - State::new(input.clone()), - MouseClickEvent { - down: true, - element: SpriteElement::new(self.ct.clone(), e.clone()), - }, - ), - ) - .with_context(|| format!("while handling click event")) - .with_context(|| { - format!("in ui scene `{}`", self.current_scene.as_ref().unwrap()) - })?, - - Event::MouseRelease => self - .engine - .call_fn( - &mut self.scope, - &self - .ct - .get_config() - .ui_scenes - .get(self.current_scene.as_ref().unwrap()) - .unwrap(), - "event", - ( - State::new(input.clone()), - MouseClickEvent { - down: false, - element: SpriteElement::new(self.ct.clone(), e.clone()), - }, - ), - ) - .with_context(|| format!("while handling release event")) - .with_context(|| { - format!("in ui scene `{}`", self.current_scene.as_ref().unwrap()) - })?, - - Event::MouseHover => self - .engine - .call_fn( - &mut self.scope, - &self - .ct - .get_config() - .ui_scenes - .get(self.current_scene.as_ref().unwrap()) - .unwrap(), - "event", - ( - State::new(input.clone()), - MouseHoverEvent { - enter: true, - element: SpriteElement::new(self.ct.clone(), e.clone()), - }, - ), - ) - .with_context(|| format!("while handling hover event")) - .with_context(|| { - format!("in ui scene `{}`", self.current_scene.as_ref().unwrap()) - })?, - - Event::MouseUnhover => self - .engine - .call_fn( - &mut self.scope, - &self - .ct - .get_config() - .ui_scenes - .get(self.current_scene.as_ref().unwrap()) - .unwrap(), - "event", - ( - State::new(input.clone()), - MouseHoverEvent { - enter: false, - element: SpriteElement::new(self.ct.clone(), e.clone()), - }, - ), - ) - .with_context(|| format!("while handling unhover event")) - .with_context(|| { - format!("in ui scene `{}`", self.current_scene.as_ref().unwrap()) - })?, + Event::None => continue, + _ => {} } - } else if let Some(e) = e.radialbar() { + + let event_arg = match event { + Event::None => unreachable!("this shouldn't happen"), + + Event::MouseClick => Dynamic::from(MouseClickEvent { + down: true, + element: SpriteElement::new(self.ct.clone(), e.clone()), + }), + + Event::MouseRelease => Dynamic::from(MouseClickEvent { + down: false, + element: SpriteElement::new(self.ct.clone(), e.clone()), + }), + + Event::MouseHover => Dynamic::from(MouseHoverEvent { + enter: true, + element: SpriteElement::new(self.ct.clone(), e.clone()), + }), + + Event::MouseUnhover => Dynamic::from(MouseHoverEvent { + enter: false, + element: SpriteElement::new(self.ct.clone(), e.clone()), + }), + }; + + let action: Dynamic = self + .engine + .call_fn( + &mut self.scope, + &self + .ct + .get_config() + .ui_scenes + .get(self.current_scene.as_ref().unwrap()) + .unwrap(), + "event", + (State::new(input.clone()), event_arg), + ) + .with_context(|| format!("while handling event `{:?}`", event)) + .with_context(|| { + format!("in ui scene `{}`", self.current_scene.as_ref().unwrap()) + })?; + + if let Some(action) = action.try_cast::() { + keep_doing_actions = self.handle_action(state, input.clone(), action)?; + } + } + + UiElement::RadialBar(e) => { + // Draw and update radialbar let mut x = (*e).borrow_mut(); x.step(&input, state); x.push_to_buffer(&input, state); - Dynamic::from(SceneAction::None) - } else { - Dynamic::from(SceneAction::None) } - }; - if let Some(action) = action.try_cast::() { - match action { - SceneAction::None => {} - _ => { - actions.push(action); - } - } - } - } - - for a in actions { - match a { - SceneAction::None => {} - SceneAction::GoTo(s) => { - self.set_scene(state, input.clone(), s.clone())?; - break; - } + UiElement::Text(..) => {} } } return Ok(()); } + + /// Do a SceneAction. + /// Returns true if we should execute the action that is next, and false otherwise. + fn handle_action( + &mut self, + state: &mut RenderState, + input: Rc, + action: SceneAction, + ) -> Result { + Ok(match action { + SceneAction::None => true, + SceneAction::GoTo(s) => { + self.set_scene(state, input.clone(), s.clone())?; + false + } + }) + } } impl<'a> UiManager { diff --git a/crates/render/src/ui/uielement.rs b/crates/render/src/ui/uielement.rs index 1e054db..9df8931 100644 --- a/crates/render/src/ui/uielement.rs +++ b/crates/render/src/ui/uielement.rs @@ -22,24 +22,10 @@ impl UiElement { Self::Text(text) } - pub fn sprite(&self) -> Option>> { - match self { - Self::Sprite(s) => Some(s.clone()), - _ => None, - } - } - pub fn text(&self) -> Option<&TextBox> { match self { Self::Text(t) => Some(t), _ => None, } } - - pub fn radialbar(&self) -> Option>> { - match self { - Self::RadialBar(r) => Some(r.clone()), - _ => None, - } - } } diff --git a/crates/render/src/ui/util/sprite.rs b/crates/render/src/ui/util/sprite.rs index b999641..eee0eb2 100644 --- a/crates/render/src/ui/util/sprite.rs +++ b/crates/render/src/ui/util/sprite.rs @@ -71,7 +71,7 @@ impl Sprite { }); } - pub fn check_mouse(&mut self, input: &RenderInput, state: &mut RenderState) -> Event { + pub fn check_events(&mut self, input: &RenderInput, state: &mut RenderState) -> Event { let r = self.rect.to_centered(state, input.ct.get_config().ui_scale); if self.waiting_for_release && self.has_mouse && !input.player.input.pressed_leftclick() {