summaryrefslogtreecommitdiffstats
path: root/native/src/program/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'native/src/program/state.rs')
-rw-r--r--native/src/program/state.rs154
1 files changed, 154 insertions, 0 deletions
diff --git a/native/src/program/state.rs b/native/src/program/state.rs
new file mode 100644
index 00000000..bcb7212d
--- /dev/null
+++ b/native/src/program/state.rs
@@ -0,0 +1,154 @@
+use crate::{
+ Cache, Clipboard, Command, Debug, Event, Program, Renderer, Size,
+ UserInterface,
+};
+
+#[allow(missing_debug_implementations)]
+pub struct State<P>
+where
+ P: Program + 'static,
+{
+ program: P,
+ cache: Option<Cache>,
+ primitive: <P::Renderer as Renderer>::Output,
+ queued_events: Vec<Event>,
+ queued_messages: Vec<P::Message>,
+}
+
+impl<P> State<P>
+where
+ P: Program + 'static,
+{
+ pub fn new(
+ mut program: P,
+ bounds: Size,
+ renderer: &mut P::Renderer,
+ debug: &mut Debug,
+ ) -> Self {
+ let user_interface = build_user_interface(
+ &mut program,
+ Cache::default(),
+ renderer,
+ bounds,
+ debug,
+ );
+
+ debug.draw_started();
+ let primitive = user_interface.draw(renderer);
+ debug.draw_finished();
+
+ let cache = Some(user_interface.into_cache());
+
+ State {
+ program,
+ cache,
+ primitive,
+ queued_events: Vec::new(),
+ queued_messages: Vec::new(),
+ }
+ }
+
+ pub fn program(&self) -> &P {
+ &self.program
+ }
+
+ pub fn primitive(&self) -> &<P::Renderer as Renderer>::Output {
+ &self.primitive
+ }
+
+ pub fn queue_event(&mut self, event: Event) {
+ self.queued_events.push(event);
+ }
+
+ pub fn queue_message(&mut self, message: P::Message) {
+ self.queued_messages.push(message);
+ }
+
+ pub fn update(
+ &mut self,
+ clipboard: Option<&dyn Clipboard>,
+ bounds: Size,
+ renderer: &mut P::Renderer,
+ debug: &mut Debug,
+ ) -> Option<Command<P::Message>> {
+ if self.queued_events.is_empty() && self.queued_messages.is_empty() {
+ return None;
+ }
+
+ let mut user_interface = build_user_interface(
+ &mut self.program,
+ self.cache.take().unwrap(),
+ renderer,
+ bounds,
+ debug,
+ );
+
+ debug.event_processing_started();
+ let mut messages = user_interface.update(
+ self.queued_events.drain(..),
+ clipboard,
+ renderer,
+ );
+ messages.extend(self.queued_messages.drain(..));
+ debug.event_processing_finished();
+
+ if messages.is_empty() {
+ debug.draw_started();
+ self.primitive = user_interface.draw(renderer);
+ debug.draw_finished();
+
+ self.cache = Some(user_interface.into_cache());
+
+ None
+ } else {
+ // When there are messages, we are forced to rebuild twice
+ // for now :^)
+ let temp_cache = user_interface.into_cache();
+
+ let commands =
+ Command::batch(messages.into_iter().map(|message| {
+ debug.log_message(&message);
+
+ debug.update_started();
+ let command = self.program.update(message);
+ debug.update_finished();
+
+ command
+ }));
+
+ let user_interface = build_user_interface(
+ &mut self.program,
+ temp_cache,
+ renderer,
+ bounds,
+ debug,
+ );
+
+ debug.draw_started();
+ self.primitive = user_interface.draw(renderer);
+ debug.draw_finished();
+
+ self.cache = Some(user_interface.into_cache());
+
+ Some(commands)
+ }
+ }
+}
+
+fn build_user_interface<'a, P: Program>(
+ program: &'a mut P,
+ cache: Cache,
+ renderer: &mut P::Renderer,
+ size: Size,
+ debug: &mut Debug,
+) -> UserInterface<'a, P::Message, P::Renderer> {
+ debug.view_started();
+ let view = program.view();
+ debug.view_finished();
+
+ debug.layout_started();
+ let user_interface = UserInterface::build(view, size, cache, renderer);
+ debug.layout_finished();
+
+ user_interface
+}