diff options
author | 2023-11-29 22:28:31 +0100 | |
---|---|---|
committer | 2023-11-29 22:28:31 +0100 | |
commit | e09b4e24dda51b8212d8ece52431dacaa3922a7b (patch) | |
tree | 7005e181528134ebdde5bbbe5909273db9f30174 /runtime | |
parent | 83c7870c569a2976923ee6243a19813094d44673 (diff) | |
parent | 7f8b17604a31e00becc43130ec516c1a53552c88 (diff) | |
download | iced-e09b4e24dda51b8212d8ece52431dacaa3922a7b.tar.gz iced-e09b4e24dda51b8212d8ece52431dacaa3922a7b.tar.bz2 iced-e09b4e24dda51b8212d8ece52431dacaa3922a7b.zip |
Merge branch 'master' into feat/multi-window-support
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Cargo.toml | 28 | ||||
-rw-r--r-- | runtime/README.md | 10 | ||||
-rw-r--r-- | runtime/src/command.rs | 41 | ||||
-rw-r--r-- | runtime/src/command/action.rs | 9 | ||||
-rw-r--r-- | runtime/src/debug/basic.rs | 20 | ||||
-rw-r--r-- | runtime/src/lib.rs | 35 | ||||
-rw-r--r-- | runtime/src/overlay/nested.rs | 21 | ||||
-rw-r--r-- | runtime/src/program/state.rs | 4 | ||||
-rw-r--r-- | runtime/src/user_interface.rs | 76 | ||||
-rw-r--r-- | runtime/src/window.rs | 7 | ||||
-rw-r--r-- | runtime/src/window/screenshot.rs | 2 |
11 files changed, 141 insertions, 112 deletions
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 3d2976a7..8089d545 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -1,24 +1,22 @@ [package] name = "iced_runtime" -version = "0.1.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "A renderer-agnostic library for native GUIs" -license = "MIT" -repository = "https://github.com/iced-rs/iced" +description = "A renderer-agnostic runtime for iced" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true [features] debug = [] multi-window = [] [dependencies] -thiserror = "1" +iced_core.workspace = true +iced_futures.workspace = true +iced_futures.features = ["thread-pool"] -[dependencies.iced_core] -version = "0.9" -path = "../core" - -[dependencies.iced_futures] -version = "0.6" -path = "../futures" -features = ["thread-pool"] +thiserror.workspace = true diff --git a/runtime/README.md b/runtime/README.md index 1b0fa857..35c7eb5e 100644 --- a/runtime/README.md +++ b/runtime/README.md @@ -1,12 +1,12 @@ # `iced_runtime` -[][documentation] -[](https://crates.io/crates/iced_native) -[](https://github.com/iced-rs/iced/blob/master/LICENSE) +[][documentation] +[](https://crates.io/crates/iced_runtime) +[](https://github.com/iced-rs/iced/blob/master/LICENSE) [](https://discord.gg/3xZJ65GAhd) -`iced_runtime` takes [`iced_core`] and builds a native runtime on top of it. +`iced_runtime` takes [`iced_core`] and builds a runtime on top of it. -[documentation]: https://docs.rs/iced_native +[documentation]: https://docs.rs/iced_runtime [`iced_core`]: ../core [`iced_winit`]: ../winit [`druid`]: https://github.com/xi-editor/druid diff --git a/runtime/src/command.rs b/runtime/src/command.rs index cd4c51ff..f70da915 100644 --- a/runtime/src/command.rs +++ b/runtime/src/command.rs @@ -4,8 +4,11 @@ mod action; pub use action::Action; use crate::core::widget; +use crate::futures::futures; use crate::futures::MaybeSend; +use futures::channel::mpsc; +use futures::Stream; use std::fmt; use std::future::Future; @@ -40,14 +43,24 @@ impl<T> Command<T> { /// Creates a [`Command`] that performs the action of the given future. pub fn perform<A>( - future: impl Future<Output = T> + 'static + MaybeSend, - f: impl FnOnce(T) -> A + 'static + MaybeSend, - ) -> Command<A> { - use iced_futures::futures::FutureExt; + future: impl Future<Output = A> + 'static + MaybeSend, + f: impl FnOnce(A) -> T + 'static + MaybeSend, + ) -> Command<T> { + use futures::FutureExt; Command::single(Action::Future(Box::pin(future.map(f)))) } + /// Creates a [`Command`] that runs the given stream to completion. + pub fn run<A>( + stream: impl Stream<Item = A> + 'static + MaybeSend, + f: impl Fn(A) -> T + 'static + MaybeSend, + ) -> Command<T> { + use futures::StreamExt; + + Command::single(Action::Stream(Box::pin(stream.map(f)))) + } + /// Creates a [`Command`] that performs the actions of all the given /// commands. /// @@ -106,3 +119,23 @@ impl<T> fmt::Debug for Command<T> { command.fmt(f) } } + +/// Creates a [`Command`] that produces the `Message`s published from a [`Future`] +/// to an [`mpsc::Sender`] with the given bounds. +pub fn channel<Fut, Message>( + size: usize, + f: impl FnOnce(mpsc::Sender<Message>) -> Fut + MaybeSend + 'static, +) -> Command<Message> +where + Fut: Future<Output = ()> + MaybeSend + 'static, + Message: 'static + MaybeSend, +{ + use futures::future; + use futures::stream::{self, StreamExt}; + + let (sender, receiver) = mpsc::channel(size); + + let runner = stream::once(f(sender)).filter_map(|_| future::ready(None)); + + Command::single(Action::Stream(Box::pin(stream::select(receiver, runner)))) +} diff --git a/runtime/src/command/action.rs b/runtime/src/command/action.rs index b2594379..7a70920e 100644 --- a/runtime/src/command/action.rs +++ b/runtime/src/command/action.rs @@ -18,6 +18,11 @@ pub enum Action<T> { /// [`Future`]: iced_futures::BoxFuture Future(iced_futures::BoxFuture<T>), + /// Run a [`Stream`] to completion. + /// + /// [`Stream`]: iced_futures::BoxStream + Stream(iced_futures::BoxStream<T>), + /// Run a clipboard action. Clipboard(clipboard::Action<T>), @@ -52,10 +57,11 @@ impl<T> Action<T> { A: 'static, T: 'static, { - use iced_futures::futures::FutureExt; + use iced_futures::futures::{FutureExt, StreamExt}; match self { Self::Future(future) => Action::Future(Box::pin(future.map(f))), + Self::Stream(stream) => Action::Stream(Box::pin(stream.map(f))), Self::Clipboard(action) => Action::Clipboard(action.map(f)), Self::Window(id, window) => Action::Window(id, window.map(f)), Self::System(system) => Action::System(system.map(f)), @@ -74,6 +80,7 @@ impl<T> fmt::Debug for Action<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Future(_) => write!(f, "Action::Future"), + Self::Stream(_) => write!(f, "Action::Stream"), Self::Clipboard(action) => { write!(f, "Action::Clipboard({action:?})") } diff --git a/runtime/src/debug/basic.rs b/runtime/src/debug/basic.rs index 32f725a1..4c994a2f 100644 --- a/runtime/src/debug/basic.rs +++ b/runtime/src/debug/basic.rs @@ -75,7 +75,7 @@ impl Debug { } pub fn startup_finished(&mut self) { - self.startup_duration = time::Instant::now() - self.startup_start; + self.startup_duration = self.startup_start.elapsed(); } pub fn update_started(&mut self) { @@ -83,8 +83,7 @@ impl Debug { } pub fn update_finished(&mut self) { - self.update_durations - .push(time::Instant::now() - self.update_start); + self.update_durations.push(self.update_start.elapsed()); } pub fn view_started(&mut self) { @@ -92,8 +91,7 @@ impl Debug { } pub fn view_finished(&mut self) { - self.view_durations - .push(time::Instant::now() - self.view_start); + self.view_durations.push(self.view_start.elapsed()); } pub fn layout_started(&mut self) { @@ -101,8 +99,7 @@ impl Debug { } pub fn layout_finished(&mut self) { - self.layout_durations - .push(time::Instant::now() - self.layout_start); + self.layout_durations.push(self.layout_start.elapsed()); } pub fn event_processing_started(&mut self) { @@ -110,8 +107,7 @@ impl Debug { } pub fn event_processing_finished(&mut self) { - self.event_durations - .push(time::Instant::now() - self.event_start); + self.event_durations.push(self.event_start.elapsed()); } pub fn draw_started(&mut self) { @@ -119,8 +115,7 @@ impl Debug { } pub fn draw_finished(&mut self) { - self.draw_durations - .push(time::Instant::now() - self.draw_start); + self.draw_durations.push(self.draw_start.elapsed()); } pub fn render_started(&mut self) { @@ -128,8 +123,7 @@ impl Debug { } pub fn render_finished(&mut self) { - self.render_durations - .push(time::Instant::now() - self.render_start); + self.render_durations.push(self.render_start.elapsed()); } pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4c39f80f..03906f45 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -2,46 +2,19 @@ //! //!  //! -//! `iced_native` takes [`iced_core`] and builds a native runtime on top of it, -//! featuring: +//! `iced_runtime` takes [`iced_core`] and builds a native runtime on top of it. //! -//! - A custom layout engine, greatly inspired by [`druid`] -//! - Event handling for all the built-in widgets -//! - A renderer-agnostic API -//! -//! To achieve this, it introduces a couple of reusable interfaces: -//! -//! - A [`Widget`] trait, which is used to implement new widgets: from layout -//! requirements to event and drawing logic. -//! - A bunch of `Renderer` traits, meant to keep the crate renderer-agnostic. -//! -//! # Usage -//! The strategy to use this crate depends on your particular use case. If you -//! want to: -//! - Implement a custom shell or integrate it in your own system, check out the -//! [`UserInterface`] type. -//! - Build a new renderer, see the [renderer] module. -//! - Build a custom widget, start at the [`Widget`] trait. -//! -//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.9/core -//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.9/winit -//! [`druid`]: https://github.com/xi-editor/druid -//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle -//! [renderer]: crate::renderer +//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.10/core #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(unsafe_code, rust_2018_idioms)] #![deny( missing_debug_implementations, missing_docs, unused_results, - clippy::extra_unused_lifetimes, - clippy::from_over_into, - clippy::needless_borrow, - clippy::new_without_default, - clippy::useless_conversion + rustdoc::broken_intra_doc_links )] -#![forbid(unsafe_code, rust_2018_idioms)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod clipboard; pub mod command; diff --git a/runtime/src/overlay/nested.rs b/runtime/src/overlay/nested.rs index b729f769..4256efb7 100644 --- a/runtime/src/overlay/nested.rs +++ b/runtime/src/overlay/nested.rs @@ -4,9 +4,11 @@ use crate::core::mouse; use crate::core::overlay; use crate::core::renderer; use crate::core::widget; -use crate::core::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size}; +use crate::core::{ + Clipboard, Event, Layout, Point, Rectangle, Shell, Size, Vector, +}; -/// An [`Overlay`] container that displays nested overlays +/// An overlay container that displays nested overlays #[allow(missing_debug_implementations)] pub struct Nested<'a, Message, Renderer> { overlay: overlay::Element<'a, Message, Renderer>, @@ -27,23 +29,24 @@ where } /// Returns the layout [`Node`] of the [`Nested`] overlay. + /// + /// [`Node`]: layout::Node pub fn layout( &mut self, renderer: &Renderer, bounds: Size, - position: Point, + _position: Point, + translation: Vector, ) -> layout::Node { fn recurse<Message, Renderer>( element: &mut overlay::Element<'_, Message, Renderer>, renderer: &Renderer, bounds: Size, - position: Point, + translation: Vector, ) -> layout::Node where Renderer: renderer::Renderer, { - let translation = position - Point::ORIGIN; - let node = element.layout(renderer, bounds, translation); if let Some(mut nested) = @@ -53,7 +56,7 @@ where node.size(), vec![ node, - recurse(&mut nested, renderer, bounds, position), + recurse(&mut nested, renderer, bounds, translation), ], ) } else { @@ -61,7 +64,7 @@ where } } - recurse(&mut self.overlay, renderer, bounds, position) + recurse(&mut self.overlay, renderer, bounds, translation) } /// Draws the [`Nested`] overlay using the associated `Renderer`. @@ -162,7 +165,7 @@ where } } - recurse(&mut self.overlay, layout, renderer, operation) + recurse(&mut self.overlay, layout, renderer, operation); } /// Processes a runtime [`Event`]. diff --git a/runtime/src/program/state.rs b/runtime/src/program/state.rs index 35df6078..6f8f4063 100644 --- a/runtime/src/program/state.rs +++ b/runtime/src/program/state.rs @@ -175,7 +175,7 @@ where (uncaptured_events, command) } - /// Applies [`widget::Operation`]s to the [`State`] + /// Applies [`Operation`]s to the [`State`] pub fn operate( &mut self, renderer: &mut P::Renderer, @@ -200,7 +200,7 @@ where match operation.finish() { operation::Outcome::None => {} operation::Outcome::Some(message) => { - self.queued_messages.push(message) + self.queued_messages.push(message); } operation::Outcome::Chain(next) => { current_operation = Some(next); diff --git a/runtime/src/user_interface.rs b/runtime/src/user_interface.rs index 619423fd..3594ac18 100644 --- a/runtime/src/user_interface.rs +++ b/runtime/src/user_interface.rs @@ -5,7 +5,9 @@ use crate::core::mouse; use crate::core::renderer; use crate::core::widget; use crate::core::window; -use crate::core::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size}; +use crate::core::{ + Clipboard, Element, Layout, Point, Rectangle, Shell, Size, Vector, +}; use crate::overlay; /// A set of interactive graphical elements with a specific [`Layout`]. @@ -19,7 +21,7 @@ use crate::overlay; /// The [`integration`] example uses a [`UserInterface`] to integrate Iced in an /// existing graphical application. /// -/// [`integration`]: https://github.com/iced-rs/iced/tree/0.9/examples/integration +/// [`integration`]: https://github.com/iced-rs/iced/tree/0.10/examples/integration #[allow(missing_debug_implementations)] pub struct UserInterface<'a, Message, Renderer> { root: Element<'a, Message, Renderer>, @@ -95,8 +97,11 @@ where let Cache { mut state } = cache; state.diff(root.as_widget()); - let base = - renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds)); + let base = root.as_widget().layout( + &mut state, + renderer, + &layout::Limits::new(Size::ZERO, bounds), + ); UserInterface { root, @@ -196,7 +201,8 @@ where let bounds = self.bounds; let mut overlay = manual_overlay.as_mut().unwrap(); - let mut layout = overlay.layout(renderer, bounds, Point::ORIGIN); + let mut layout = + overlay.layout(renderer, bounds, Point::ORIGIN, Vector::ZERO); let mut event_statuses = Vec::new(); for event in events.iter().cloned() { @@ -226,8 +232,9 @@ where if shell.is_layout_invalid() { let _ = ManuallyDrop::into_inner(manual_overlay); - self.base = renderer.layout( - &self.root, + self.base = self.root.as_widget().layout( + &mut self.state, + renderer, &layout::Limits::new(Size::ZERO, self.bounds), ); @@ -249,8 +256,12 @@ where overlay = manual_overlay.as_mut().unwrap(); shell.revalidate_layout(|| { - layout = - overlay.layout(renderer, bounds, Point::ORIGIN); + layout = overlay.layout( + renderer, + bounds, + Point::ORIGIN, + Vector::ZERO, + ); }); } @@ -284,12 +295,14 @@ where (cursor, vec![event::Status::Ignored; events.len()]) }; + let viewport = Rectangle::with_size(self.bounds); + let _ = ManuallyDrop::into_inner(manual_overlay); let event_statuses = events .iter() .cloned() - .zip(overlay_statuses.into_iter()) + .zip(overlay_statuses) .map(|(event, overlay_status)| { if matches!(overlay_status, event::Status::Captured) { return overlay_status; @@ -305,6 +318,7 @@ where renderer, clipboard, &mut shell, + &viewport, ); if matches!(event_status, event::Status::Captured) { @@ -322,8 +336,9 @@ where } shell.revalidate_layout(|| { - self.base = renderer.layout( - &self.root, + self.base = self.root.as_widget().layout( + &mut self.state, + renderer, &layout::Limits::new(Size::ZERO, self.bounds), ); @@ -353,7 +368,7 @@ where /// It returns the current [`mouse::Interaction`]. You should update the /// icon of the mouse cursor accordingly in your system. /// - /// [`Renderer`]: crate::Renderer + /// [`Renderer`]: crate::core::Renderer /// /// # Example /// We can finally draw our [counter](index.html#usage) by @@ -440,7 +455,12 @@ where .map(overlay::Nested::new) { let overlay_layout = self.overlay.take().unwrap_or_else(|| { - overlay.layout(renderer, self.bounds, Point::ORIGIN) + overlay.layout( + renderer, + self.bounds, + Point::ORIGIN, + Vector::ZERO, + ) }); let cursor = if cursor @@ -510,17 +530,13 @@ where renderer, ); - let overlay_bounds = layout.bounds(); - - renderer.with_layer(overlay_bounds, |renderer| { - overlay.draw( - renderer, - theme, - style, - Layout::new(layout), - cursor, - ); - }); + overlay.draw( + renderer, + theme, + style, + Layout::new(layout), + cursor, + ); if cursor .position() @@ -562,8 +578,12 @@ where .map(overlay::Nested::new) { if self.overlay.is_none() { - self.overlay = - Some(overlay.layout(renderer, self.bounds, Point::ORIGIN)); + self.overlay = Some(overlay.layout( + renderer, + self.bounds, + Point::ORIGIN, + Vector::ZERO, + )); } overlay.operate( @@ -620,7 +640,7 @@ pub enum State { /// The [`UserInterface`] is up-to-date and can be reused without /// rebuilding. Updated { - /// The [`Instant`] when a redraw should be performed. + /// The [`window::RedrawRequest`] when a redraw should be performed. redraw_request: Option<window::RedrawRequest>, }, } diff --git a/runtime/src/window.rs b/runtime/src/window.rs index 4737dcdd..375ce889 100644 --- a/runtime/src/window.rs +++ b/runtime/src/window.rs @@ -11,7 +11,8 @@ use crate::command::{self, Command}; use crate::core::time::Instant; use crate::core::window::{self, Event, Icon, Level, Mode, UserAttention}; use crate::core::Size; -use crate::futures::subscription::{self, Subscription}; +use crate::futures::event; +use crate::futures::Subscription; /// Subscribes to the frames of the window of the running application. /// @@ -22,8 +23,8 @@ use crate::futures::subscription::{self, Subscription}; /// In any case, this [`Subscription`] is useful to smoothly draw application-driven /// animations without missing any frames. pub fn frames() -> Subscription<Instant> { - subscription::raw_events(|event, _status| match event { - iced_core::Event::Window(_, Event::RedrawRequested(at)) => Some(at), + event::listen_raw(|event, _status| match event { + crate::core::Event::Window(_, Event::RedrawRequested(at)) => Some(at), _ => None, }) } diff --git a/runtime/src/window/screenshot.rs b/runtime/src/window/screenshot.rs index c84286b6..21e04718 100644 --- a/runtime/src/window/screenshot.rs +++ b/runtime/src/window/screenshot.rs @@ -6,7 +6,7 @@ use std::sync::Arc; /// Data of a screenshot, captured with `window::screenshot()`. /// -/// The `bytes` of this screenshot will always be ordered as `RGBA` in the sRGB color space. +/// The `bytes` of this screenshot will always be ordered as `RGBA` in the `sRGB` color space. #[derive(Clone)] pub struct Screenshot { /// The bytes of the [`Screenshot`]. |