diff --git a/runtime/src/program/state.rs b/runtime/src/program/state.rs index d83e3f5467..0c4fa85eef 100644 --- a/runtime/src/program/state.rs +++ b/runtime/src/program/state.rs @@ -1,9 +1,10 @@ use crate::core::event::{self, Event}; use crate::core::mouse; use crate::core::renderer; +use crate::core::widget::operation::Outcome; use crate::core::{Clipboard, Size}; use crate::user_interface::{self, UserInterface}; -use crate::{Command, Debug, Program}; +use crate::{command::Action, Command, Debug, Program}; /// The execution state of a [`Program`]. It leverages caching, event /// processing, and rendering primitive storage. @@ -94,7 +95,7 @@ where style: &renderer::Style, clipboard: &mut dyn Clipboard, debug: &mut Debug, - ) -> (Vec, Option>) { + ) -> (Vec, Vec>) { let mut user_interface = build_user_interface( &mut self.program, self.cache.take().unwrap(), @@ -128,7 +129,7 @@ where messages.append(&mut self.queued_messages); debug.event_processing_finished(); - let command = if messages.is_empty() { + let actions = if messages.is_empty() { debug.draw_started(); self.mouse_interaction = user_interface.draw(renderer, theme, style, cursor); @@ -136,13 +137,13 @@ where self.cache = Some(user_interface.into_cache()); - None + Vec::new() } else { // When there are messages, we are forced to rebuild twice // for now :^) let temp_cache = user_interface.into_cache(); - let commands = + let (actions, widget_actions) = Command::batch(messages.into_iter().map(|message| { debug.log_message(&message); @@ -151,7 +152,12 @@ where debug.update_finished(); command - })); + })) + .actions() + .into_iter() + .partition::, _>(|action| { + !matches!(action, Action::Widget(_)) + }); let mut user_interface = build_user_interface( &mut self.program, @@ -161,6 +167,42 @@ where debug, ); + let had_operations = !widget_actions.is_empty(); + for operation in widget_actions + .into_iter() + .map(|action| match action { + Action::Widget(widget_action) => widget_action, + _ => unreachable!(), + }) + { + let mut current_operation = Some(operation); + while let Some(mut operation) = current_operation.take() { + user_interface.operate(renderer, operation.as_mut()); + match operation.finish() { + Outcome::None => {}, + Outcome::Some(message) => self.queued_messages.push(message), + Outcome::Chain(op) => { + current_operation = Some(op); + } + }; + } + } + + let mut user_interface = if had_operations { + // When there were operations, we are forced to rebuild thrice ... + let temp_cache = user_interface.into_cache(); + + build_user_interface( + &mut self.program, + temp_cache, + renderer, + bounds, + debug, + ) + } else { + user_interface + }; + debug.draw_started(); self.mouse_interaction = user_interface.draw(renderer, theme, style, cursor); @@ -168,10 +210,10 @@ where self.cache = Some(user_interface.into_cache()); - Some(commands) + actions }; - (uncaptured_events, command) + (uncaptured_events, actions) } }