use iced_core::widget::operation::{OperationWrapper, Outcome};
use iced_core::widget::OperationOutputWrapper;
use crate::core::event::{self, Event};
use crate::core::mouse;
use crate::core::renderer;
use crate::core::widget::operation::{self, Operation};
use crate::core::{Clipboard, Size};
use crate::user_interface::{self, UserInterface};
use crate::{command::Action, Command, Debug, Program};
#[allow(missing_debug_implementations)]
pub struct State<P>
where
P: Program + 'static,
{
program: P,
cache: Option<user_interface::Cache>,
queued_events: Vec<Event>,
queued_messages: Vec<P::Message>,
mouse_interaction: mouse::Interaction,
}
impl<P> State<P>
where
P: Program + 'static,
{
pub fn new(
id: crate::window::Id,
mut program: P,
bounds: Size,
renderer: &mut P::Renderer,
debug: &mut Debug,
) -> Self {
let user_interface = build_user_interface(
id,
&mut program,
user_interface::Cache::default(),
renderer,
bounds,
debug,
);
let cache = Some(user_interface.into_cache());
State {
program,
cache,
queued_events: Vec::new(),
queued_messages: Vec::new(),
mouse_interaction: mouse::Interaction::Idle,
}
}
pub fn program(&self) -> &P {
&self.program
}
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 is_queue_empty(&self) -> bool {
self.queued_events.is_empty() && self.queued_messages.is_empty()
}
pub fn mouse_interaction(&self) -> mouse::Interaction {
self.mouse_interaction
}
pub fn update(
&mut self,
id: crate::window::Id,
bounds: Size,
cursor: mouse::Cursor,
renderer: &mut P::Renderer,
theme: &P::Theme,
style: &renderer::Style,
clipboard: &mut dyn Clipboard,
debug: &mut Debug,
) -> (Vec<Event>, Vec<Action<P::Message>>) {
let mut user_interface = build_user_interface(
id,
&mut self.program,
self.cache.take().unwrap(),
renderer,
bounds,
debug,
);
debug.event_processing_started();
let mut messages = Vec::new();
let (_, event_statuses) = user_interface.update(
&self.queued_events,
cursor,
renderer,
clipboard,
&mut messages,
);
let uncaptured_events = self
.queued_events
.iter()
.zip(event_statuses)
.filter_map(|(event, status)| {
matches!(status, event::Status::Ignored).then_some(event)
})
.cloned()
.collect();
self.queued_events.clear();
messages.append(&mut self.queued_messages);
debug.event_processing_finished();
let actions = if messages.is_empty() {
debug.draw_started();
self.mouse_interaction =
user_interface.draw(renderer, theme, style, cursor);
debug.draw_finished();
self.cache = Some(user_interface.into_cache());
Vec::new()
} else {
let temp_cache = user_interface.into_cache();
let (actions, widget_actions) =
Command::batch(messages.into_iter().map(|message| {
debug.log_message(&message);
debug.update_started();
let command = self.program.update(message);
debug.update_finished();
command
}))
.actions()
.into_iter()
.partition::<Vec<_>, _>(|action| {
!matches!(action, Action::Widget(_))
});
let mut user_interface = build_user_interface(
id,
&mut self.program,
temp_cache,
renderer,
bounds,
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!(),
})
.map(OperationWrapper::Message)
{
let mut current_operation = Some(operation);
while let Some(mut operation) = current_operation.take() {
user_interface.operate(renderer, &mut operation);
match operation.finish() {
Outcome::Some(OperationOutputWrapper::Message(
message,
)) => self.queued_messages.push(message),
Outcome::Chain(op) => {
current_operation =
Some(OperationWrapper::Wrapper(op));
}
_ => {}
};
}
}
let mut user_interface = if had_operations {
let temp_cache = user_interface.into_cache();
build_user_interface(
id,
&mut self.program,
temp_cache,
renderer,
bounds,
debug,
)
} else {
user_interface
};
debug.draw_started();
self.mouse_interaction =
user_interface.draw(renderer, theme, style, cursor);
debug.draw_finished();
self.cache = Some(user_interface.into_cache());
actions
};
(uncaptured_events, actions)
}
pub fn operate(
&mut self,
id: crate::window::Id,
renderer: &mut P::Renderer,
operations: impl Iterator<
Item = Box<dyn Operation<OperationOutputWrapper<P::Message>>>,
>,
bounds: Size,
debug: &mut Debug,
) {
let mut user_interface = build_user_interface(
id,
&mut self.program,
self.cache.take().unwrap(),
renderer,
bounds,
debug,
);
for operation in operations {
let mut current_operation = Some(operation);
while let Some(mut operation) = current_operation.take() {
user_interface.operate(renderer, operation.as_mut());
match operation.finish() {
operation::Outcome::None => {}
operation::Outcome::Some(
OperationOutputWrapper::Message(message),
) => {
self.queued_messages.push(message);
}
operation::Outcome::Chain(next) => {
current_operation = Some(next);
}
_ => {}
};
}
}
self.cache = Some(user_interface.into_cache());
}
}
fn build_user_interface<'a, P: Program>(
_id: crate::window::Id,
program: &'a mut P,
cache: user_interface::Cache,
renderer: &mut P::Renderer,
size: Size,
debug: &mut Debug,
) -> UserInterface<'a, P::Message, P::Theme, 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
}