Fixed widget animations implementation

This commit is contained in:
Bingus 2023-02-17 11:42:49 -08:00
parent 3c095aa3f0
commit 8da098330b
No known key found for this signature in database
GPG key ID: 5F84D2AA40A9F170
4 changed files with 95 additions and 39 deletions

View file

@ -499,18 +499,17 @@ fn view_content<'a>(
.spacing(10) .spacing(10)
.align_items(Alignment::Center); .align_items(Alignment::Center);
Element::from( container(
container( scrollable(content)
scrollable(content) .height(Length::Fill)
.vertical_scroll(Properties::new()) .vertical_scroll(Properties::new())
.id(scrollable_id), .id(scrollable_id),
)
.width(Length::Fill)
.height(Length::Fill)
.padding(5)
.center_y(),
) )
.explain(Color::default()) .width(Length::Fill)
.height(Length::Fill)
.padding(5)
.center_y()
.into()
} }
fn view_controls<'a>( fn view_controls<'a>(

View file

@ -67,7 +67,7 @@ impl Tree {
} }
} }
/// Reconciliates the children of the tree with the provided list of widgets. /// Reconciles the children of the tree with the provided list of widgets.
pub fn diff_children<'a, Message, Renderer>( pub fn diff_children<'a, Message, Renderer>(
&mut self, &mut self,
new_children: &[impl Borrow<dyn Widget<Message, Renderer> + 'a>], new_children: &[impl Borrow<dyn Widget<Message, Renderer> + 'a>],

View file

@ -21,7 +21,6 @@ pub use user_attention::UserAttention;
use crate::subscription::{self, Subscription}; use crate::subscription::{self, Subscription};
use crate::time::Instant; use crate::time::Instant;
use crate::window;
/// Subscribes to the frames of the window of the running application. /// Subscribes to the frames of the window of the running application.
/// ///

View file

@ -9,7 +9,7 @@ use crate::renderer;
use crate::settings; use crate::settings;
use crate::widget::operation; use crate::widget::operation;
use crate::window; use crate::window;
use crate::{conversion, multi_window}; use crate::conversion;
use crate::{ use crate::{
Command, Debug, Element, Error, Executor, Proxy, Renderer, Runtime, Command, Debug, Element, Error, Executor, Proxy, Renderer, Runtime,
Settings, Size, Subscription, Settings, Size, Subscription,
@ -237,7 +237,8 @@ where
let (compositor, renderer) = C::new(compositor_settings, Some(&window))?; let (compositor, renderer) = C::new(compositor_settings, Some(&window))?;
let (mut sender, receiver) = mpsc::unbounded(); let (mut event_sender, event_receiver) = mpsc::unbounded();
let (control_sender, mut control_receiver) = mpsc::unbounded();
let mut instance = Box::pin({ let mut instance = Box::pin({
let run_instance = run_instance::<A, E, C>( let run_instance = run_instance::<A, E, C>(
@ -247,7 +248,8 @@ where
runtime, runtime,
proxy, proxy,
debug, debug,
receiver, event_receiver,
control_sender,
init_command, init_command,
windows, windows,
settings.exit_on_close_request, settings.exit_on_close_request,
@ -299,13 +301,19 @@ where
}; };
if let Some(event) = event { if let Some(event) = event {
sender.start_send(event).expect("Send event"); event_sender.start_send(event).expect("Send event");
let poll = instance.as_mut().poll(&mut context); let poll = instance.as_mut().poll(&mut context);
*control_flow = match poll { match poll {
task::Poll::Pending => ControlFlow::Wait, task::Poll::Pending => {
task::Poll::Ready(_) => ControlFlow::Exit, if let Ok(Some(flow)) = control_receiver.try_next() {
*control_flow = flow;
}
}
task::Poll::Ready(_) => {
*control_flow = ControlFlow::Exit;
}
}; };
} }
}) })
@ -318,9 +326,10 @@ async fn run_instance<A, E, C>(
mut runtime: Runtime<E, Proxy<Event<A::Message>>, Event<A::Message>>, mut runtime: Runtime<E, Proxy<Event<A::Message>>, Event<A::Message>>,
mut proxy: winit::event_loop::EventLoopProxy<Event<A::Message>>, mut proxy: winit::event_loop::EventLoopProxy<Event<A::Message>>,
mut debug: Debug, mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver< mut event_receiver: mpsc::UnboundedReceiver<
winit::event::Event<'_, Event<A::Message>>, winit::event::Event<'_, Event<A::Message>>,
>, >,
mut control_sender: mpsc::UnboundedSender<winit::event_loop::ControlFlow>,
init_command: Command<A::Message>, init_command: Command<A::Message>,
mut windows: HashMap<window::Id, winit::window::Window>, mut windows: HashMap<window::Id, winit::window::Window>,
_exit_on_close_request: bool, _exit_on_close_request: bool,
@ -332,6 +341,7 @@ async fn run_instance<A, E, C>(
{ {
use iced_futures::futures::stream::StreamExt; use iced_futures::futures::stream::StreamExt;
use winit::event; use winit::event;
use winit::event_loop::ControlFlow;
let mut clipboard = let mut clipboard =
Clipboard::connect(windows.values().next().expect("No window found")); Clipboard::connect(windows.values().next().expect("No window found"));
@ -390,11 +400,20 @@ async fn run_instance<A, E, C>(
let mut mouse_interaction = mouse::Interaction::default(); let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new(); let mut events = Vec::new();
let mut messages = Vec::new(); let mut messages = Vec::new();
let mut redraw_pending = false;
debug.startup_finished(); debug.startup_finished();
'main: while let Some(event) = receiver.next().await { 'main: while let Some(event) = event_receiver.next().await {
match event { match event {
event::Event::NewEvents(start_cause) => {
redraw_pending = matches!(
start_cause,
event::StartCause::Init
| event::StartCause::Poll
| event::StartCause::ResumeTimeReached { .. }
);
}
event::Event::MainEventsCleared => { event::Event::MainEventsCleared => {
for id in states.keys().copied().collect::<Vec<_>>() { for id in states.keys().copied().collect::<Vec<_>>() {
let (filtered, remaining): (Vec<_>, Vec<_>) = let (filtered, remaining): (Vec<_>, Vec<_>) =
@ -408,29 +427,27 @@ async fn run_instance<A, E, C>(
); );
events.retain(|el| remaining.contains(el)); events.retain(|el| remaining.contains(el));
let mut filtered: Vec<_> = filtered let window_events: Vec<_> = filtered
.into_iter() .into_iter()
.map(|(_id, event)| event) .map(|(_id, event)| event)
.collect(); .collect();
filtered.push(iced_native::Event::Window(
id,
window::Event::RedrawRequested(Instant::now()),
));
let cursor_position = if !redraw_pending
states.get(&id).unwrap().cursor_position(); && window_events.is_empty()
let window = windows.get(&id).unwrap(); && messages.is_empty()
{
if filtered.is_empty() && messages.is_empty() {
continue; continue;
} }
debug.event_processing_started(); debug.event_processing_started();
let cursor_position =
states.get(&id).unwrap().cursor_position();
let (interface_state, statuses) = { let (interface_state, statuses) = {
let user_interface = interfaces.get_mut(&id).unwrap(); let user_interface = interfaces.get_mut(&id).unwrap();
user_interface.update( user_interface.update(
&filtered, &window_events,
cursor_position, cursor_position,
&mut renderer, &mut renderer,
&mut clipboard, &mut clipboard,
@ -440,7 +457,8 @@ async fn run_instance<A, E, C>(
debug.event_processing_finished(); debug.event_processing_finished();
for event in filtered.into_iter().zip(statuses.into_iter()) for event in
window_events.into_iter().zip(statuses.into_iter())
{ {
runtime.broadcast(event); runtime.broadcast(event);
} }
@ -487,8 +505,6 @@ async fn run_instance<A, E, C>(
windows.get(&id).expect("No window found with ID."), windows.get(&id).expect("No window found with ID."),
); );
let should_exit = application.should_exit();
interfaces = ManuallyDrop::new(build_user_interfaces( interfaces = ManuallyDrop::new(build_user_interfaces(
&application, &application,
&mut renderer, &mut renderer,
@ -497,17 +513,35 @@ async fn run_instance<A, E, C>(
user_interfaces, user_interfaces,
)); ));
if should_exit { if application.should_exit() {
break 'main; break 'main;
} }
} }
// TODO: Avoid redrawing all the time by forcing widgets to
// request redraws on state changes
//
// Then, we can use the `interface_state` here to decide if a redraw
// is needed right away, or simply wait until a specific time.
let redraw_event = iced_native::Event::Window(
id,
window::Event::RedrawRequested(Instant::now()),
);
let (interface_state, _) =
interfaces.get_mut(&id).unwrap().update(
&[redraw_event.clone()],
cursor_position,
&mut renderer,
&mut clipboard,
&mut messages,
);
debug.draw_started(); debug.draw_started();
let new_mouse_interaction = { let new_mouse_interaction = {
let user_interface = interfaces.get_mut(&id).unwrap();
let state = states.get(&id).unwrap(); let state = states.get(&id).unwrap();
user_interface.draw( interfaces.get_mut(&id).unwrap().draw(
&mut renderer, &mut renderer,
state.theme(), state.theme(),
&renderer::Style { &renderer::Style {
@ -518,6 +552,8 @@ async fn run_instance<A, E, C>(
}; };
debug.draw_finished(); debug.draw_finished();
let window = windows.get(&id).unwrap();
if new_mouse_interaction != mouse_interaction { if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction( window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction, new_mouse_interaction,
@ -528,6 +564,28 @@ async fn run_instance<A, E, C>(
for window in windows.values() { for window in windows.values() {
window.request_redraw(); window.request_redraw();
runtime.broadcast((
redraw_event.clone(),
crate::event::Status::Ignored,
));
let _ =
control_sender.start_send(match interface_state {
user_interface::State::Updated {
redraw_request: Some(redraw_request),
} => match redraw_request {
window::RedrawRequest::NextFrame => {
ControlFlow::Poll
}
window::RedrawRequest::At(at) => {
ControlFlow::WaitUntil(at)
}
},
_ => ControlFlow::Wait,
});
redraw_pending = false;
} }
} }
} }