Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget-driven animations #1647

Merged
merged 11 commits into from
Jan 13, 2023
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