Skip to content

Commit

Permalink
Merge pull request #1647 from iced-rs/feature/widget-request-redraw
Browse files Browse the repository at this point in the history
Widget-driven animations
  • Loading branch information
hecrj authored Jan 13, 2023
2 parents d2b6680 + 507820a commit 597af31
Show file tree
Hide file tree
Showing 20 changed files with 431 additions and 126 deletions.
2 changes: 1 addition & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ version = "0.6"
optional = true

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-timer = { version = "0.2" }
instant = "0.1"
6 changes: 5 additions & 1 deletion core/src/time.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
//! Keep track of time, both in native and web platforms!

#[cfg(target_arch = "wasm32")]
pub use wasm_timer::Instant;
pub use instant::Instant;

#[cfg(target_arch = "wasm32")]
pub use instant::Duration;

#[cfg(not(target_arch = "wasm32"))]
pub use std::time::Instant;

#[cfg(not(target_arch = "wasm32"))]
pub use std::time::Duration;
2 changes: 1 addition & 1 deletion examples/events/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ edition = "2021"
publish = false

[dependencies]
iced = { path = "../.." }
iced = { path = "../..", features = ["debug"] }
iced_native = { path = "../../native" }
24 changes: 11 additions & 13 deletions examples/events/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use iced::alignment;
use iced::executor;
use iced::widget::{button, checkbox, container, text, Column};
use iced::window;
use iced::{
Alignment, Application, Command, Element, Length, Settings, Subscription,
Theme,
};
use iced_native::{window, Event};
use iced_native::Event;

pub fn main() -> iced::Result {
Events::run(Settings {
Expand All @@ -18,7 +19,6 @@ pub fn main() -> iced::Result {
struct Events {
last: Vec<iced_native::Event>,
enabled: bool,
should_exit: bool,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -50,31 +50,29 @@ impl Application for Events {
if self.last.len() > 5 {
let _ = self.last.remove(0);
}

Command::none()
}
Message::EventOccurred(event) => {
if let Event::Window(window::Event::CloseRequested) = event {
self.should_exit = true;
window::close()
} else {
Command::none()
}
}
Message::Toggled(enabled) => {
self.enabled = enabled;
}
Message::Exit => {
self.should_exit = true;
}
};

Command::none()
Command::none()
}
Message::Exit => window::close(),
}
}

fn subscription(&self) -> Subscription<Message> {
iced_native::subscription::events().map(Message::EventOccurred)
}

fn should_exit(&self) -> bool {
self.should_exit
}

fn view(&self) -> Element<Message> {
let events = Column::with_children(
self.last
Expand Down
26 changes: 13 additions & 13 deletions examples/exit/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use iced::executor;
use iced::widget::{button, column, container};
use iced::{Alignment, Element, Length, Sandbox, Settings};
use iced::window;
use iced::{Alignment, Application, Command, Element, Length, Settings, Theme};

pub fn main() -> iced::Result {
Exit::run(Settings::default())
Expand All @@ -8,7 +10,6 @@ pub fn main() -> iced::Result {
#[derive(Default)]
struct Exit {
show_confirm: bool,
exit: bool,
}

#[derive(Debug, Clone, Copy)]
Expand All @@ -17,28 +18,27 @@ enum Message {
Exit,
}

impl Sandbox for Exit {
impl Application for Exit {
type Executor = executor::Default;
type Message = Message;
type Theme = Theme;
type Flags = ();

fn new() -> Self {
Self::default()
fn new(_flags: ()) -> (Self, Command<Message>) {
(Self::default(), Command::none())
}

fn title(&self) -> String {
String::from("Exit - Iced")
}

fn should_exit(&self) -> bool {
self.exit
}

fn update(&mut self, message: Message) {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Confirm => {
self.exit = true;
}
Message::Confirm => window::close(),
Message::Exit => {
self.show_confirm = true;

Command::none()
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions examples/solar_system/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use iced::application;
use iced::executor;
use iced::theme::{self, Theme};
use iced::time;
use iced::widget::canvas;
use iced::widget::canvas::gradient::{self, Gradient};
use iced::widget::canvas::stroke::{self, Stroke};
Expand Down Expand Up @@ -90,7 +89,7 @@ impl Application for SolarSystem {
}

fn subscription(&self) -> Subscription<Message> {
time::every(time::Duration::from_millis(10)).map(Message::Tick)
window::frames().map(Message::Tick)
}
}

Expand Down
6 changes: 3 additions & 3 deletions glutin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ trace = ["iced_winit/trace"]
debug = ["iced_winit/debug"]
system = ["iced_winit/system"]

[dependencies.log]
version = "0.4"
[dependencies]
log = "0.4"

[dependencies.glutin]
version = "0.29"
Expand All @@ -39,4 +39,4 @@ features = ["opengl"]

[dependencies.tracing]
version = "0.1.6"
optional = true
optional = true
79 changes: 68 additions & 11 deletions glutin/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use iced_winit::conversion;
use iced_winit::futures;
use iced_winit::futures::channel::mpsc;
use iced_winit::renderer;
use iced_winit::time::Instant;
use iced_winit::user_interface;
use iced_winit::{Clipboard, Command, Debug, Proxy, Settings};
use iced_winit::{Clipboard, Command, Debug, Event, Proxy, Settings};

use glutin::window::Window;
use std::mem::ManuallyDrop;
Expand Down Expand Up @@ -131,7 +132,8 @@ where
})?
};

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 run_instance = run_instance::<A, E, C>(
Expand All @@ -141,7 +143,8 @@ where
runtime,
proxy,
debug,
receiver,
event_receiver,
control_sender,
context,
init_command,
settings.exit_on_close_request,
Expand Down Expand Up @@ -179,14 +182,20 @@ where
};

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);

*control_flow = match poll {
task::Poll::Pending => ControlFlow::Wait,
task::Poll::Ready(_) => ControlFlow::Exit,
};
match poll {
task::Poll::Pending => {
if let Ok(Some(flow)) = control_receiver.try_next() {
*control_flow = flow;
}
}
task::Poll::Ready(_) => {
*control_flow = ControlFlow::Exit;
}
}
}
});

Expand All @@ -200,7 +209,10 @@ async fn run_instance<A, E, C>(
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut proxy: glutin::event_loop::EventLoopProxy<A::Message>,
mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>,
mut event_receiver: mpsc::UnboundedReceiver<
glutin::event::Event<'_, A::Message>,
>,
mut control_sender: mpsc::UnboundedSender<glutin::event_loop::ControlFlow>,
mut context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>,
init_command: Command<A::Message>,
exit_on_close_request: bool,
Expand All @@ -211,6 +223,7 @@ async fn run_instance<A, E, C>(
<A::Renderer as iced_native::Renderer>::Theme: StyleSheet,
{
use glutin::event;
use glutin::event_loop::ControlFlow;
use iced_winit::futures::stream::StreamExt;

let mut clipboard = Clipboard::connect(context.window());
Expand Down Expand Up @@ -247,13 +260,22 @@ async fn run_instance<A, E, C>(
let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new();
let mut messages = Vec::new();
let mut redraw_pending = false;

debug.startup_finished();

while let Some(event) = receiver.next().await {
while let Some(event) = event_receiver.next().await {
match event {
event::Event::NewEvents(start_cause) => {
redraw_pending = matches!(
start_cause,
event::StartCause::Init
| event::StartCause::Poll
| event::StartCause::ResumeTimeReached { .. }
);
}
event::Event::MainEventsCleared => {
if events.is_empty() && messages.is_empty() {
if !redraw_pending && events.is_empty() && messages.is_empty() {
continue;
}

Expand Down Expand Up @@ -315,6 +337,23 @@ async fn run_instance<A, E, C>(
}
}

// 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 = Event::Window(
crate::window::Event::RedrawRequested(Instant::now()),
);

let (interface_state, _) = user_interface.update(
&[redraw_event.clone()],
state.cursor_position(),
&mut renderer,
&mut clipboard,
&mut messages,
);

debug.draw_started();
let new_mouse_interaction = user_interface.draw(
&mut renderer,
Expand All @@ -335,6 +374,24 @@ async fn run_instance<A, E, C>(
}

context.window().request_redraw();
runtime
.broadcast((redraw_event, crate::event::Status::Ignored));

let _ = control_sender.start_send(match interface_state {
user_interface::State::Updated {
redraw_request: Some(redraw_request),
} => match redraw_request {
crate::window::RedrawRequest::NextFrame => {
ControlFlow::Poll
}
crate::window::RedrawRequest::At(at) => {
ControlFlow::WaitUntil(at)
}
},
_ => ControlFlow::Wait,
});

redraw_pending = false;
}
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url),
Expand Down
6 changes: 3 additions & 3 deletions native/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ pub trait Renderer: Sized {
f: impl FnOnce(&mut Self),
);

/// Clears all of the recorded primitives in the [`Renderer`].
fn clear(&mut self);

/// Fills a [`Quad`] with the provided [`Background`].
fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>);

/// Clears all of the recorded primitives in the [`Renderer`].
fn clear(&mut self);
}

/// A polygon with four sides.
Expand Down
Loading

0 comments on commit 597af31

Please sign in to comment.