diff options
author | 2023-03-05 06:35:20 +0100 | |
---|---|---|
committer | 2023-03-05 06:35:20 +0100 | |
commit | 99e0a71504456976ba88040f5d1d3bbc347694ea (patch) | |
tree | a228c064fd3847831ff8072aa9375dc59db47f47 /native | |
parent | 8af69be47e88896b3c5f70174db609eee0c67971 (diff) | |
download | iced-99e0a71504456976ba88040f5d1d3bbc347694ea.tar.gz iced-99e0a71504456976ba88040f5d1d3bbc347694ea.tar.bz2 iced-99e0a71504456976ba88040f5d1d3bbc347694ea.zip |
Rename `iced_native` to `iced_runtime`
Diffstat (limited to 'native')
-rw-r--r-- | native/Cargo.toml | 23 | ||||
-rw-r--r-- | native/README.md | 37 | ||||
-rw-r--r-- | native/src/clipboard.rs | 40 | ||||
-rw-r--r-- | native/src/command.rs | 108 | ||||
-rw-r--r-- | native/src/command/action.rs | 86 | ||||
-rw-r--r-- | native/src/debug/basic.rs | 226 | ||||
-rw-r--r-- | native/src/debug/null.rs | 47 | ||||
-rw-r--r-- | native/src/font.rs | 19 | ||||
-rw-r--r-- | native/src/keyboard.rs | 2 | ||||
-rw-r--r-- | native/src/lib.rs | 71 | ||||
-rw-r--r-- | native/src/program.rs | 33 | ||||
-rw-r--r-- | native/src/program/state.rs | 194 | ||||
-rw-r--r-- | native/src/system.rs | 6 | ||||
-rw-r--r-- | native/src/system/action.rs | 39 | ||||
-rw-r--r-- | native/src/system/information.rs | 29 | ||||
-rw-r--r-- | native/src/user_interface.rs | 592 | ||||
-rw-r--r-- | native/src/window.rs | 23 | ||||
-rw-r--r-- | native/src/window/action.rs | 147 |
18 files changed, 0 insertions, 1722 deletions
diff --git a/native/Cargo.toml b/native/Cargo.toml deleted file mode 100644 index bc4e7ca1..00000000 --- a/native/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "iced_native" -version = "0.9.1" -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" - -[features] -debug = [] - -[dependencies] -thiserror = "1" - -[dependencies.iced_core] -version = "0.8" -path = "../core" - -[dependencies.iced_futures] -version = "0.6" -path = "../futures" -features = ["thread-pool"] diff --git a/native/README.md b/native/README.md deleted file mode 100644 index 996daa76..00000000 --- a/native/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# `iced_native` -[][documentation] -[](https://crates.io/crates/iced_native) -[](https://github.com/iced-rs/iced/blob/master/LICENSE) -[](https://discord.gg/3xZJ65GAhd) - -`iced_native` takes [`iced_core`] and builds a native runtime on top of it, featuring: -- 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 bunch 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. -- A `Windowed` trait, leveraging [`raw-window-handle`], which can be implemented by graphical renderers that target _windows_. Window-based shells (like [`iced_winit`]) can use this trait to stay renderer-agnostic. - -<p align="center"> - <img alt="The native target" src="../docs/graphs/native.png" width="80%"> -</p> - -[documentation]: https://docs.rs/iced_native -[`iced_core`]: ../core -[`iced_winit`]: ../winit -[`druid`]: https://github.com/xi-editor/druid -[`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle - -## Installation -Add `iced_native` as a dependency in your `Cargo.toml`: - -```toml -iced_native = "0.9" -``` - -__Iced moves fast and the `master` branch can contain breaking changes!__ If -you want to learn about a specific release, check out [the release list]. - -[the release list]: https://github.com/iced-rs/iced/releases diff --git a/native/src/clipboard.rs b/native/src/clipboard.rs deleted file mode 100644 index e727c4a7..00000000 --- a/native/src/clipboard.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Access the clipboard. -use iced_futures::MaybeSend; - -use std::fmt; - -/// A clipboard action to be performed by some [`Command`]. -/// -/// [`Command`]: crate::Command -pub enum Action<T> { - /// Read the clipboard and produce `T` with the result. - Read(Box<dyn Fn(Option<String>) -> T>), - - /// Write the given contents to the clipboard. - Write(String), -} - -impl<T> Action<T> { - /// Maps the output of a clipboard [`Action`] using the provided closure. - pub fn map<A>( - self, - f: impl Fn(T) -> A + 'static + MaybeSend + Sync, - ) -> Action<A> - where - T: 'static, - { - match self { - Self::Read(o) => Action::Read(Box::new(move |s| f(o(s)))), - Self::Write(content) => Action::Write(content), - } - } -} - -impl<T> fmt::Debug for Action<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Read(_) => write!(f, "Action::Read"), - Self::Write(_) => write!(f, "Action::Write"), - } - } -} diff --git a/native/src/command.rs b/native/src/command.rs deleted file mode 100644 index cd4c51ff..00000000 --- a/native/src/command.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Run asynchronous actions. -mod action; - -pub use action::Action; - -use crate::core::widget; -use crate::futures::MaybeSend; - -use std::fmt; -use std::future::Future; - -/// A set of asynchronous actions to be performed by some runtime. -#[must_use = "`Command` must be returned to runtime to take effect"] -pub struct Command<T>(Internal<Action<T>>); - -#[derive(Debug)] -enum Internal<T> { - None, - Single(T), - Batch(Vec<T>), -} - -impl<T> Command<T> { - /// Creates an empty [`Command`]. - /// - /// In other words, a [`Command`] that does nothing. - pub const fn none() -> Self { - Self(Internal::None) - } - - /// Creates a [`Command`] that performs a single [`Action`]. - pub const fn single(action: Action<T>) -> Self { - Self(Internal::Single(action)) - } - - /// Creates a [`Command`] that performs a [`widget::Operation`]. - pub fn widget(operation: impl widget::Operation<T> + 'static) -> Self { - Self::single(Action::Widget(Box::new(operation))) - } - - /// 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; - - Command::single(Action::Future(Box::pin(future.map(f)))) - } - - /// Creates a [`Command`] that performs the actions of all the given - /// commands. - /// - /// Once this command is run, all the commands will be executed at once. - pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self { - let mut batch = Vec::new(); - - for Command(command) in commands { - match command { - Internal::None => {} - Internal::Single(command) => batch.push(command), - Internal::Batch(commands) => batch.extend(commands), - } - } - - Self(Internal::Batch(batch)) - } - - /// Applies a transformation to the result of a [`Command`]. - pub fn map<A>( - self, - f: impl Fn(T) -> A + 'static + MaybeSend + Sync + Clone, - ) -> Command<A> - where - T: 'static, - A: 'static, - { - match self.0 { - Internal::None => Command::none(), - Internal::Single(action) => Command::single(action.map(f)), - Internal::Batch(batch) => Command(Internal::Batch( - batch - .into_iter() - .map(|action| action.map(f.clone())) - .collect(), - )), - } - } - - /// Returns all of the actions of the [`Command`]. - pub fn actions(self) -> Vec<Action<T>> { - let Command(command) = self; - - match command { - Internal::None => Vec::new(), - Internal::Single(action) => vec![action], - Internal::Batch(batch) => batch, - } - } -} - -impl<T> fmt::Debug for Command<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Command(command) = self; - - command.fmt(f) - } -} diff --git a/native/src/command/action.rs b/native/src/command/action.rs deleted file mode 100644 index 6c74f0ef..00000000 --- a/native/src/command/action.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::clipboard; -use crate::core::widget; -use crate::font; -use crate::system; -use crate::window; - -use iced_futures::MaybeSend; - -use std::borrow::Cow; -use std::fmt; - -/// An action that a [`Command`] can perform. -/// -/// [`Command`]: crate::Command -pub enum Action<T> { - /// Run a [`Future`] to completion. - /// - /// [`Future`]: iced_futures::BoxFuture - Future(iced_futures::BoxFuture<T>), - - /// Run a clipboard action. - Clipboard(clipboard::Action<T>), - - /// Run a window action. - Window(window::Action<T>), - - /// Run a system action. - System(system::Action<T>), - - /// Run a widget action. - Widget(Box<dyn widget::Operation<T>>), - - /// Load a font from its bytes. - LoadFont { - /// The bytes of the font to load. - bytes: Cow<'static, [u8]>, - - /// The message to produce when the font has been loaded. - tagger: Box<dyn Fn(Result<(), font::Error>) -> T>, - }, -} - -impl<T> Action<T> { - /// Applies a transformation to the result of a [`Command`]. - /// - /// [`Command`]: crate::Command - pub fn map<A>( - self, - f: impl Fn(T) -> A + 'static + MaybeSend + Sync, - ) -> Action<A> - where - A: 'static, - T: 'static, - { - use iced_futures::futures::FutureExt; - - match self { - Self::Future(future) => Action::Future(Box::pin(future.map(f))), - Self::Clipboard(action) => Action::Clipboard(action.map(f)), - Self::Window(window) => Action::Window(window.map(f)), - Self::System(system) => Action::System(system.map(f)), - Self::Widget(operation) => { - Action::Widget(Box::new(widget::operation::map(operation, f))) - } - Self::LoadFont { bytes, tagger } => Action::LoadFont { - bytes, - tagger: Box::new(move |result| f(tagger(result))), - }, - } - } -} - -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::Clipboard(action) => { - write!(f, "Action::Clipboard({action:?})") - } - Self::Window(action) => write!(f, "Action::Window({action:?})"), - Self::System(action) => write!(f, "Action::System({action:?})"), - Self::Widget(_action) => write!(f, "Action::Widget"), - Self::LoadFont { .. } => write!(f, "Action::LoadFont"), - } - } -} diff --git a/native/src/debug/basic.rs b/native/src/debug/basic.rs deleted file mode 100644 index 32f725a1..00000000 --- a/native/src/debug/basic.rs +++ /dev/null @@ -1,226 +0,0 @@ -#![allow(missing_docs)] -use crate::core::time; - -use std::collections::VecDeque; - -/// A bunch of time measurements for debugging purposes. -#[derive(Debug)] -pub struct Debug { - is_enabled: bool, - - startup_start: time::Instant, - startup_duration: time::Duration, - - update_start: time::Instant, - update_durations: TimeBuffer, - - view_start: time::Instant, - view_durations: TimeBuffer, - - layout_start: time::Instant, - layout_durations: TimeBuffer, - - event_start: time::Instant, - event_durations: TimeBuffer, - - draw_start: time::Instant, - draw_durations: TimeBuffer, - - render_start: time::Instant, - render_durations: TimeBuffer, - - message_count: usize, - last_messages: VecDeque<String>, -} - -impl Debug { - /// Creates a new [`struct@Debug`]. - pub fn new() -> Self { - let now = time::Instant::now(); - - Self { - is_enabled: false, - startup_start: now, - startup_duration: time::Duration::from_secs(0), - - update_start: now, - update_durations: TimeBuffer::new(200), - - view_start: now, - view_durations: TimeBuffer::new(200), - - layout_start: now, - layout_durations: TimeBuffer::new(200), - - event_start: now, - event_durations: TimeBuffer::new(200), - - draw_start: now, - draw_durations: TimeBuffer::new(200), - - render_start: now, - render_durations: TimeBuffer::new(50), - - message_count: 0, - last_messages: VecDeque::new(), - } - } - - pub fn toggle(&mut self) { - self.is_enabled = !self.is_enabled; - } - - pub fn startup_started(&mut self) { - self.startup_start = time::Instant::now(); - } - - pub fn startup_finished(&mut self) { - self.startup_duration = time::Instant::now() - self.startup_start; - } - - pub fn update_started(&mut self) { - self.update_start = time::Instant::now(); - } - - pub fn update_finished(&mut self) { - self.update_durations - .push(time::Instant::now() - self.update_start); - } - - pub fn view_started(&mut self) { - self.view_start = time::Instant::now(); - } - - pub fn view_finished(&mut self) { - self.view_durations - .push(time::Instant::now() - self.view_start); - } - - pub fn layout_started(&mut self) { - self.layout_start = time::Instant::now(); - } - - pub fn layout_finished(&mut self) { - self.layout_durations - .push(time::Instant::now() - self.layout_start); - } - - pub fn event_processing_started(&mut self) { - self.event_start = time::Instant::now(); - } - - pub fn event_processing_finished(&mut self) { - self.event_durations - .push(time::Instant::now() - self.event_start); - } - - pub fn draw_started(&mut self) { - self.draw_start = time::Instant::now(); - } - - pub fn draw_finished(&mut self) { - self.draw_durations - .push(time::Instant::now() - self.draw_start); - } - - pub fn render_started(&mut self) { - self.render_start = time::Instant::now(); - } - - pub fn render_finished(&mut self) { - self.render_durations - .push(time::Instant::now() - self.render_start); - } - - pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) { - self.last_messages.push_back(format!("{message:?}")); - - if self.last_messages.len() > 10 { - let _ = self.last_messages.pop_front(); - } - - self.message_count += 1; - } - - pub fn overlay(&self) -> Vec<String> { - if !self.is_enabled { - return Vec::new(); - } - - let mut lines = Vec::new(); - - fn key_value<T: std::fmt::Debug>(key: &str, value: T) -> String { - format!("{key} {value:?}") - } - - lines.push(format!( - "{} {} - {}", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_VERSION"), - env!("CARGO_PKG_REPOSITORY"), - )); - lines.push(key_value("Startup:", self.startup_duration)); - lines.push(key_value("Update:", self.update_durations.average())); - lines.push(key_value("View:", self.view_durations.average())); - lines.push(key_value("Layout:", self.layout_durations.average())); - lines.push(key_value( - "Event processing:", - self.event_durations.average(), - )); - lines.push(key_value( - "Primitive generation:", - self.draw_durations.average(), - )); - lines.push(key_value("Render:", self.render_durations.average())); - lines.push(key_value("Message count:", self.message_count)); - lines.push(String::from("Last messages:")); - lines.extend(self.last_messages.iter().map(|msg| { - if msg.len() <= 100 { - format!(" {msg}") - } else { - format!(" {msg:.100}...") - } - })); - - lines - } -} - -impl Default for Debug { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug)] -struct TimeBuffer { - head: usize, - size: usize, - contents: Vec<time::Duration>, -} - -impl TimeBuffer { - fn new(capacity: usize) -> TimeBuffer { - TimeBuffer { - head: 0, - size: 0, - contents: vec![time::Duration::from_secs(0); capacity], - } - } - - fn push(&mut self, duration: time::Duration) { - self.head = (self.head + 1) % self.contents.len(); - self.contents[self.head] = duration; - self.size = (self.size + 1).min(self.contents.len()); - } - - fn average(&self) -> time::Duration { - let sum: time::Duration = if self.size == self.contents.len() { - self.contents[..].iter().sum() - } else { - self.contents[..self.size].iter().sum() - }; - - sum / self.size.max(1) as u32 - } -} diff --git a/native/src/debug/null.rs b/native/src/debug/null.rs deleted file mode 100644 index 2db0eebb..00000000 --- a/native/src/debug/null.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![allow(missing_docs)] -#[derive(Debug, Default)] -pub struct Debug; - -impl Debug { - pub fn new() -> Self { - Self - } - - pub fn startup_started(&mut self) {} - - pub fn startup_finished(&mut self) {} - - pub fn update_started(&mut self) {} - - pub fn update_finished(&mut self) {} - - pub fn view_started(&mut self) {} - - pub fn view_finished(&mut self) {} - - pub fn layout_started(&mut self) {} - - pub fn layout_finished(&mut self) {} - - pub fn event_processing_started(&mut self) {} - - pub fn event_processing_finished(&mut self) {} - - pub fn draw_started(&mut self) {} - - pub fn draw_finished(&mut self) {} - - pub fn render_started(&mut self) {} - - pub fn render_finished(&mut self) {} - - pub fn log_message<Message: std::fmt::Debug>( - &mut self, - _message: &Message, - ) { - } - - pub fn overlay(&self) -> Vec<String> { - Vec::new() - } -} diff --git a/native/src/font.rs b/native/src/font.rs deleted file mode 100644 index 15359694..00000000 --- a/native/src/font.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Load and use fonts. -pub use iced_core::font::*; - -use crate::command::{self, Command}; -use std::borrow::Cow; - -/// An error while loading a font. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Error {} - -/// Load a font from its bytes. -pub fn load( - bytes: impl Into<Cow<'static, [u8]>>, -) -> Command<Result<(), Error>> { - Command::single(command::Action::LoadFont { - bytes: bytes.into(), - tagger: Box::new(std::convert::identity), - }) -} diff --git a/native/src/keyboard.rs b/native/src/keyboard.rs deleted file mode 100644 index 012538e3..00000000 --- a/native/src/keyboard.rs +++ /dev/null @@ -1,2 +0,0 @@ -//! Track keyboard events. -pub use iced_core::keyboard::*; diff --git a/native/src/lib.rs b/native/src/lib.rs deleted file mode 100644 index aa45e57a..00000000 --- a/native/src/lib.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! A renderer-agnostic native GUI runtime. -//! -//!  -//! -//! `iced_native` takes [`iced_core`] and builds a native runtime on top of it, -//! featuring: -//! -//! - 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.8/core -//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.8/winit -//! [`druid`]: https://github.com/xi-editor/druid -//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle -//! [renderer]: crate::renderer -#![doc( - html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" -)] -#![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 -)] -#![forbid(unsafe_code, rust_2018_idioms)] -#![cfg_attr(docsrs, feature(doc_cfg))] -pub mod clipboard; -pub mod command; -pub mod font; -pub mod keyboard; -pub mod program; -pub mod system; -pub mod user_interface; -pub mod window; - -// We disable debug capabilities on release builds unless the `debug` feature -// is explicitly enabled. -#[cfg(feature = "debug")] -#[path = "debug/basic.rs"] -mod debug; -#[cfg(not(feature = "debug"))] -#[path = "debug/null.rs"] -mod debug; - -pub use iced_core as core; -pub use iced_futures as futures; - -pub use command::Command; -pub use debug::Debug; -pub use font::Font; -pub use program::Program; -pub use user_interface::UserInterface; diff --git a/native/src/program.rs b/native/src/program.rs deleted file mode 100644 index 44585cc5..00000000 --- a/native/src/program.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Build interactive programs using The Elm Architecture. -use crate::Command; - -use iced_core::text; -use iced_core::{Element, Renderer}; - -mod state; - -pub use state::State; - -/// The core of a user interface application following The Elm Architecture. -pub trait Program: Sized { - /// The graphics backend to use to draw the [`Program`]. - type Renderer: Renderer + text::Renderer; - - /// The type of __messages__ your [`Program`] will produce. - type Message: std::fmt::Debug + Send; - - /// Handles a __message__ and updates the state of the [`Program`]. - /// - /// This is where you define your __update logic__. All the __messages__, - /// produced by either user interactions or commands, will be handled by - /// this method. - /// - /// Any [`Command`] returned will be executed immediately in the - /// background by shells. - fn update(&mut self, message: Self::Message) -> Command<Self::Message>; - - /// Returns the widgets to display in the [`Program`]. - /// - /// These widgets can produce __messages__ based on user interaction. - fn view(&self) -> Element<'_, Self::Message, Self::Renderer>; -} diff --git a/native/src/program/state.rs b/native/src/program/state.rs deleted file mode 100644 index 2fa9934d..00000000 --- a/native/src/program/state.rs +++ /dev/null @@ -1,194 +0,0 @@ -use crate::core::event::{self, Event}; -use crate::core::mouse; -use crate::core::renderer; -use crate::core::{Clipboard, Point, Size}; -use crate::user_interface::{self, UserInterface}; -use crate::{Command, Debug, Program}; - -/// The execution state of a [`Program`]. It leverages caching, event -/// processing, and rendering primitive storage. -#[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, -{ - /// Creates a new [`State`] with the provided [`Program`], initializing its - /// primitive with the given logical bounds and renderer. - pub fn new( - mut program: P, - bounds: Size, - renderer: &mut P::Renderer, - debug: &mut Debug, - ) -> Self { - let user_interface = build_user_interface( - &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, - } - } - - /// Returns a reference to the [`Program`] of the [`State`]. - pub fn program(&self) -> &P { - &self.program - } - - /// Queues an event in the [`State`] for processing during an [`update`]. - /// - /// [`update`]: Self::update - pub fn queue_event(&mut self, event: Event) { - self.queued_events.push(event); - } - - /// Queues a message in the [`State`] for processing during an [`update`]. - /// - /// [`update`]: Self::update - pub fn queue_message(&mut self, message: P::Message) { - self.queued_messages.push(message); - } - - /// Returns whether the event queue of the [`State`] is empty or not. - pub fn is_queue_empty(&self) -> bool { - self.queued_events.is_empty() && self.queued_messages.is_empty() - } - - /// Returns the current [`mouse::Interaction`] of the [`State`]. - pub fn mouse_interaction(&self) -> mouse::Interaction { - self.mouse_interaction - } - - /// Processes all the queued events and messages, rebuilding and redrawing - /// the widgets of the linked [`Program`] if necessary. - /// - /// Returns a list containing the instances of [`Event`] that were not - /// captured by any widget, and the [`Command`] obtained from [`Program`] - /// after updating it, only if an update was necessary. - pub fn update( - &mut self, - bounds: Size, - cursor_position: Point, - renderer: &mut P::Renderer, - theme: &<P::Renderer as iced_core::Renderer>::Theme, - style: &renderer::Style, - clipboard: &mut dyn Clipboard, - debug: &mut Debug, - ) -> (Vec<Event>, Option<Command<P::Message>>) { - let mut user_interface = build_user_interface( - &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_position, - 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 command = if messages.is_empty() { - debug.draw_started(); - self.mouse_interaction = - user_interface.draw(renderer, theme, style, cursor_position); - debug.draw_finished(); - - self.cache = Some(user_interface.into_cache()); - - None - } else { - // When there are messages, we are forced to rebuild twice - // for now :^) - let temp_cache = user_interface.into_cache(); - - let commands = - Command::batch(messages.into_iter().map(|message| { - debug.log_message(&message); - - debug.update_started(); - let command = self.program.update(message); - debug.update_finished(); - - command - })); - - let mut user_interface = build_user_interface( - &mut self.program, - temp_cache, - renderer, - bounds, - debug, - ); - - debug.draw_started(); - self.mouse_interaction = - user_interface.draw(renderer, theme, style, cursor_position); - debug.draw_finished(); - - self.cache = Some(user_interface.into_cache()); - - Some(commands) - }; - - (uncaptured_events, command) - } -} - -fn build_user_interface<'a, P: Program>( - program: &'a mut P, - cache: user_interface::Cache, - renderer: &mut P::Renderer, - size: Size, - debug: &mut Debug, -) -> UserInterface<'a, P::Message, 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 -} diff --git a/native/src/system.rs b/native/src/system.rs deleted file mode 100644 index 61c8ff29..00000000 --- a/native/src/system.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Access the native system. -mod action; -mod information; - -pub use action::Action; -pub use information::Information; diff --git a/native/src/system/action.rs b/native/src/system/action.rs deleted file mode 100644 index dea9536f..00000000 --- a/native/src/system/action.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::system; - -use iced_futures::MaybeSend; -use std::fmt; - -/// An operation to be performed on the system. -pub enum Action<T> { - /// Query system information and produce `T` with the result. - QueryInformation(Box<dyn Closure<T>>), -} - -pub trait Closure<T>: Fn(system::Information) -> T + MaybeSend {} - -impl<T, O> Closure<O> for T where T: Fn(system::Information) -> O + MaybeSend {} - -impl<T> Action<T> { - /// Maps the output of a system [`Action`] using the provided closure. - pub fn map<A>( - self, - f: impl Fn(T) -> A + 'static + MaybeSend + Sync, - ) -> Action<A> - where - T: 'static, - { - match self { - Self::QueryInformation(o) => { - Action::QueryInformation(Box::new(move |s| f(o(s)))) - } - } - } -} - -impl<T> fmt::Debug for Action<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::QueryInformation(_) => write!(f, "Action::QueryInformation"), - } - } -} diff --git a/native/src/system/information.rs b/native/src/system/information.rs deleted file mode 100644 index 93e7a5a4..00000000 --- a/native/src/system/information.rs +++ /dev/null @@ -1,29 +0,0 @@ -/// Contains informations about the system (e.g. system name, processor, memory, graphics adapter). -#[derive(Clone, Debug)] -pub struct Information { - /// The operating system name - pub system_name: Option<String>, - /// Operating system kernel version - pub system_kernel: Option<String>, - /// Long operating system version - /// - /// Examples: - /// - MacOS 10.15 Catalina - /// - Windows 10 Pro - /// - Ubuntu 20.04 LTS (Focal Fossa) - pub system_version: Option<String>, - /// Short operating system version number - pub system_short_version: Option<String>, - /// Detailed processor model information - pub cpu_brand: String, - /// The number of physical cores on the processor - pub cpu_cores: Option<usize>, - /// Total RAM size, KB - pub memory_total: u64, - /// Memory used by this process, KB - pub memory_used: Option<u64>, - /// Underlying graphics backend for rendering - pub graphics_backend: String, - /// Model information for the active graphics adapter - pub graphics_adapter: String, -} diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs deleted file mode 100644 index 315027fa..00000000 --- a/native/src/user_interface.rs +++ /dev/null @@ -1,592 +0,0 @@ -//! Implement your own event loop to drive a user interface. -use crate::core::event::{self, Event}; -use crate::core::layout; -use crate::core::mouse; -use crate::core::renderer; -use crate::core::widget; -use crate::core::window; -use crate::core::{Clipboard, Point, Rectangle, Size, Vector}; -use crate::core::{Element, Layout, Shell}; - -/// A set of interactive graphical elements with a specific [`Layout`]. -/// -/// It can be updated and drawn. -/// -/// Iced tries to avoid dictating how to write your event loop. You are in -/// charge of using this type in your system in any way you want. -/// -/// # Example -/// The [`integration_opengl`] & [`integration_wgpu`] examples use a -/// [`UserInterface`] to integrate Iced in an existing graphical application. -/// -/// [`integration_opengl`]: https://github.com/iced-rs/iced/tree/0.8/examples/integration_opengl -/// [`integration_wgpu`]: https://github.com/iced-rs/iced/tree/0.8/examples/integration_wgpu -#[allow(missing_debug_implementations)] -pub struct UserInterface<'a, Message, Renderer> { - root: Element<'a, Message, Renderer>, - base: layout::Node, - state: widget::Tree, - overlay: Option<layout::Node>, - bounds: Size, -} - -impl<'a, Message, Renderer> UserInterface<'a, Message, Renderer> -where - Renderer: iced_core::Renderer, -{ - /// Builds a user interface for an [`Element`]. - /// - /// It is able to avoid expensive computations when using a [`Cache`] - /// obtained from a previous instance of a [`UserInterface`]. - /// - /// # Example - /// Imagine we want to build a [`UserInterface`] for - /// [the counter example that we previously wrote](index.html#usage). Here - /// is naive way to set up our application loop: - /// - /// ```no_run - /// # mod iced_wgpu { - /// # pub use iced_native::core::renderer::Null as Renderer; - /// # } - /// # - /// # pub struct Counter; - /// # - /// # impl Counter { - /// # pub fn new() -> Self { Counter } - /// # pub fn view(&self) -> iced_core::Element<(), Renderer> { unimplemented!() } - /// # pub fn update(&mut self, _: ()) {} - /// # } - /// use iced_native::core::Size; - /// use iced_native::user_interface::{self, UserInterface}; - /// use iced_wgpu::Renderer; - /// - /// // Initialization - /// let mut counter = Counter::new(); - /// let mut cache = user_interface::Cache::new(); - /// let mut renderer = Renderer::new(); - /// let mut window_size = Size::new(1024.0, 768.0); - /// - /// // Application loop - /// loop { - /// // Process system events here... - /// - /// // Build the user interface - /// let user_interface = UserInterface::build( - /// counter.view(), - /// window_size, - /// cache, - /// &mut renderer, - /// ); - /// - /// // Update and draw the user interface here... - /// // ... - /// - /// // Obtain the cache for the next iteration - /// cache = user_interface.into_cache(); - /// } - /// ``` - pub fn build<E: Into<Element<'a, Message, Renderer>>>( - root: E, - bounds: Size, - cache: Cache, - renderer: &mut Renderer, - ) -> Self { - let root = root.into(); - - let Cache { mut state } = cache; - state.diff(root.as_widget()); - - let base = - renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds)); - - UserInterface { - root, - base, - state, - overlay: None, - bounds, - } - } - - /// Updates the [`UserInterface`] by processing each provided [`Event`]. - /// - /// It returns __messages__ that may have been produced as a result of user - /// interactions. You should feed these to your __update logic__. - /// - /// # Example - /// Let's allow our [counter](index.html#usage) to change state by - /// completing [the previous example](#example): - /// - /// ```no_run - /// # mod iced_wgpu { - /// # pub use iced_native::core::renderer::Null as Renderer; - /// # } - /// # - /// # pub struct Counter; - /// # - /// # impl Counter { - /// # pub fn new() -> Self { Counter } - /// # pub fn view(&self) -> iced_core::Element<(), Renderer> { unimplemented!() } - /// # pub fn update(&mut self, _: ()) {} - /// # } - /// use iced_native::core::{clipboard, Size, Point}; - /// use iced_native::user_interface::{self, UserInterface}; - /// use iced_wgpu::Renderer; - /// - /// let mut counter = Counter::new(); - /// let mut cache = user_interface::Cache::new(); - /// let mut renderer = Renderer::new(); - /// let mut window_size = Size::new(1024.0, 768.0); - /// let mut cursor_position = Point::default(); - /// let mut clipboard = clipboard::Null; - /// - /// // Initialize our event storage - /// let mut events = Vec::new(); - /// let mut messages = Vec::new(); - /// - /// loop { - /// // Obtain system events... - /// - /// let mut user_interface = UserInterface::build( - /// counter.view(), - /// window_size, - /// cache, - /// &mut renderer, - /// ); - /// - /// // Update the user interface - /// let (state, event_statuses) = user_interface.update( - /// &events, - /// cursor_position, - /// &mut renderer, - /// &mut clipboard, - /// &mut messages - /// ); - /// - /// cache = user_interface.into_cache(); - /// - /// // Process the produced messages - /// for message in messages.drain(..) { - /// counter.update(message); - /// } - /// } - /// ``` - pub fn update( - &mut self, - events: &[Event], - cursor_position: Point, - renderer: &mut Renderer, - clipboard: &mut dyn Clipboard, - messages: &mut Vec<Message>, - ) -> (State, Vec<event::Status>) { - use std::mem::ManuallyDrop; - - let mut outdated = false; - let mut redraw_request = None; - - let mut manual_overlay = - ManuallyDrop::new(self.root.as_widget_mut().overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - )); - - let (base_cursor, overlay_statuses) = if manual_overlay.is_some() { - let bounds = self.bounds; - - let mut overlay = manual_overlay.as_mut().unwrap(); - let mut layout = overlay.layout(renderer, bounds, Vector::ZERO); - let mut event_statuses = Vec::new(); - - for event in events.iter().cloned() { - let mut shell = Shell::new(messages); - - let event_status = overlay.on_event( - event, - Layout::new(&layout), - cursor_position, - renderer, - clipboard, - &mut shell, - ); - - event_statuses.push(event_status); - - match (redraw_request, shell.redraw_request()) { - (None, Some(at)) => { - redraw_request = Some(at); - } - (Some(current), Some(new)) if new < current => { - redraw_request = Some(new); - } - _ => {} - } - - if shell.is_layout_invalid() { - let _ = ManuallyDrop::into_inner(manual_overlay); - - self.base = renderer.layout( - &self.root, - &layout::Limits::new(Size::ZERO, self.bounds), - ); - - manual_overlay = - ManuallyDrop::new(self.root.as_widget_mut().overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - )); - - if manual_overlay.is_none() { - break; - } - - overlay = manual_overlay.as_mut().unwrap(); - - shell.revalidate_layout(|| { - layout = overlay.layout(renderer, bounds, Vector::ZERO); - }); - } - - if shell.are_widgets_invalid() { - outdated = true; - } - } - - let base_cursor = manual_overlay - .as_ref() - .filter(|overlay| { - overlay.is_over(Layout::new(&layout), cursor_position) - }) - .map(|_| { - // TODO: Type-safe cursor availability - Point::new(-1.0, -1.0) - }) - .unwrap_or(cursor_position); - - self.overlay = Some(layout); - - (base_cursor, event_statuses) - } else { - (cursor_position, vec![event::Status::Ignored; events.len()]) - }; - - let _ = ManuallyDrop::into_inner(manual_overlay); - - let event_statuses = events - .iter() - .cloned() - .zip(overlay_statuses.into_iter()) - .map(|(event, overlay_status)| { - if matches!(overlay_status, event::Status::Captured) { - return overlay_status; - } - - let mut shell = Shell::new(messages); - - let event_status = self.root.as_widget_mut().on_event( - &mut self.state, - event, - Layout::new(&self.base), - base_cursor, - renderer, - clipboard, - &mut shell, - ); - - if matches!(event_status, event::Status::Captured) { - self.overlay = None; - } - - match (redraw_request, shell.redraw_request()) { - (None, Some(at)) => { - redraw_request = Some(at); - } - (Some(current), Some(new)) if new < current => { - redraw_request = Some(new); - } - _ => {} - } - - shell.revalidate_layout(|| { - self.base = renderer.layout( - &self.root, - &layout::Limits::new(Size::ZERO, self.bounds), - ); - - self.overlay = None; - }); - - if shell.are_widgets_invalid() { - outdated = true; - } - - event_status.merge(overlay_status) - }) - .collect(); - - ( - if outdated { - State::Outdated - } else { - State::Updated { redraw_request } - }, - event_statuses, - ) - } - - /// Draws the [`UserInterface`] with the provided [`Renderer`]. - /// - /// It returns the current [`mouse::Interaction`]. You should update the - /// icon of the mouse cursor accordingly in your system. - /// - /// [`Renderer`]: crate::Renderer - /// - /// # Example - /// We can finally draw our [counter](index.html#usage) by - /// [completing the last example](#example-1): - /// - /// ```no_run - /// # mod iced_wgpu { - /// # pub use iced_native::core::renderer::Null as Renderer; - /// # pub type Theme = (); - /// # } - /// # - /// # pub struct Counter; - /// # - /// # impl Counter { - /// # pub fn new() -> Self { Counter } - /// # pub fn view(&self) -> Element<(), Renderer> { unimplemented!() } - /// # pub fn update(&mut self, _: ()) {} - /// # } - /// use iced_native::core::clipboard; - /// use iced_native::core::renderer; - /// use iced_native::core::{Element, Size, Point}; - /// use iced_native::user_interface::{self, UserInterface}; - /// use iced_wgpu::{Renderer, Theme}; - /// - /// let mut counter = Counter::new(); - /// let mut cache = user_interface::Cache::new(); - /// let mut renderer = Renderer::new(); - /// let mut window_size = Size::new(1024.0, 768.0); - /// let mut cursor_position = Point::default(); - /// let mut clipboard = clipboard::Null; - /// let mut events = Vec::new(); - /// let mut messages = Vec::new(); - /// let mut theme = Theme::default(); - /// - /// loop { - /// // Obtain system events... - /// - /// let mut user_interface = UserInterface::build( - /// counter.view(), - /// window_size, - /// cache, - /// &mut renderer, - /// ); - /// - /// // Update the user interface - /// let event_statuses = user_interface.update( - /// &events, - /// cursor_position, - /// &mut renderer, - /// &mut clipboard, - /// &mut messages - /// ); - /// - /// // Draw the user interface - /// let mouse_cursor = user_interface.draw(&mut renderer, &theme, &renderer::Style::default(), cursor_position); - /// - /// cache = user_interface.into_cache(); - /// - /// for message in messages.drain(..) { - /// counter.update(message); - /// } - /// - /// // Update mouse cursor icon... - /// // Flush rendering operations... - /// } - /// ``` - pub fn draw( - &mut self, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - cursor_position: Point, - ) -> mouse::Interaction { - // TODO: Move to shell level (?) - renderer.clear(); - - let viewport = Rectangle::with_size(self.bounds); - - let base_cursor = if let Some(overlay) = self - .root - .as_widget_mut() - .overlay(&mut self.state, Layout::new(&self.base), renderer) - { - let overlay_layout = self.overlay.take().unwrap_or_else(|| { - overlay.layout(renderer, self.bounds, Vector::ZERO) - }); - - let new_cursor_position = if overlay - .is_over(Layout::new(&overlay_layout), cursor_position) - { - Point::new(-1.0, -1.0) - } else { - cursor_position - }; - - self.overlay = Some(overlay_layout); - - new_cursor_position - } else { - cursor_position - }; - - self.root.as_widget().draw( - &self.state, - renderer, - theme, - style, - Layout::new(&self.base), - base_cursor, - &viewport, - ); - - let base_interaction = self.root.as_widget().mouse_interaction( - &self.state, - Layout::new(&self.base), - cursor_position, - &viewport, - renderer, - ); - - let Self { - overlay, - root, - base, - .. - } = self; - - // TODO: Currently, we need to call Widget::overlay twice to - // implement the painter's algorithm properly. - // - // Once we have a proper persistent widget tree, we should be able to - // avoid this additional call. - overlay - .as_ref() - .and_then(|layout| { - root.as_widget_mut() - .overlay(&mut self.state, Layout::new(base), renderer) - .map(|overlay| { - let overlay_interaction = overlay.mouse_interaction( - Layout::new(layout), - cursor_position, - &viewport, - renderer, - ); - - let overlay_bounds = layout.bounds(); - - renderer.with_layer(overlay_bounds, |renderer| { - overlay.draw( - renderer, - theme, - style, - Layout::new(layout), - cursor_position, - ); - }); - - if overlay.is_over(Layout::new(layout), cursor_position) - { - overlay_interaction - } else { - base_interaction - } - }) - }) - .unwrap_or(base_interaction) - } - - /// Applies a [`widget::Operation`] to the [`UserInterface`]. - pub fn operate( - &mut self, - renderer: &Renderer, - operation: &mut dyn widget::Operation<Message>, - ) { - self.root.as_widget().operate( - &mut self.state, - Layout::new(&self.base), - renderer, - operation, - ); - - if let Some(mut overlay) = self.root.as_widget_mut().overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - ) { - if self.overlay.is_none() { - self.overlay = - Some(overlay.layout(renderer, self.bounds, Vector::ZERO)); - } - - overlay.operate( - Layout::new(self.overlay.as_ref().unwrap()), - renderer, - operation, - ); - } - } - - /// Relayouts and returns a new [`UserInterface`] using the provided - /// bounds. - pub fn relayout(self, bounds: Size, renderer: &mut Renderer) -> Self { - Self::build(self.root, bounds, Cache { state: self.state }, renderer) - } - - /// Extract the [`Cache`] of the [`UserInterface`], consuming it in the - /// process. - pub fn into_cache(self) -> Cache { - Cache { state: self.state } - } -} - -/// Reusable data of a specific [`UserInterface`]. -#[derive(Debug)] -pub struct Cache { - state: widget::Tree, -} - -impl Cache { - /// Creates an empty [`Cache`]. - /// - /// You should use this to initialize a [`Cache`] before building your first - /// [`UserInterface`]. - pub fn new() -> Cache { - Cache { - state: widget::Tree::empty(), - } - } -} - -impl Default for Cache { - fn default() -> Cache { - Cache::new() - } -} - -/// The resulting state after updating a [`UserInterface`]. -#[derive(Debug, Clone, Copy)] -pub enum State { - /// The [`UserInterface`] is outdated and needs to be rebuilt. - Outdated, - - /// The [`UserInterface`] is up-to-date and can be reused without - /// rebuilding. - Updated { - /// The [`Instant`] when a redraw should be performed. - redraw_request: Option<window::RedrawRequest>, - }, -} diff --git a/native/src/window.rs b/native/src/window.rs deleted file mode 100644 index aa3f35c7..00000000 --- a/native/src/window.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Build window-based GUI applications. -mod action; - -pub use action::Action; - -use crate::core::time::Instant; -use crate::core::window::Event; -use crate::futures::subscription::{self, Subscription}; - -/// Subscribes to the frames of the window of the running application. -/// -/// The resulting [`Subscription`] will produce items at a rate equal to the -/// refresh rate of the window. Note that this rate may be variable, as it is -/// normally managed by the graphics driver and/or the OS. -/// -/// 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), - _ => None, - }) -} diff --git a/native/src/window/action.rs b/native/src/window/action.rs deleted file mode 100644 index c1dbd84f..00000000 --- a/native/src/window/action.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crate::core::window::{Mode, UserAttention}; -use crate::futures::MaybeSend; - -use std::fmt; - -/// An operation to be performed on some window. -pub enum Action<T> { - /// Closes the current window and exits the application. - Close, - /// Moves the window with the left mouse button until the button is - /// released. - /// - /// There’s no guarantee that this will work unless the left mouse - /// button was pressed immediately before this function is called. - Drag, - /// Resize the window. - Resize { - /// The new logical width of the window - width: u32, - /// The new logical height of the window - height: u32, - }, - /// Sets the window to maximized or back - Maximize(bool), - /// Set the window to minimized or back - Minimize(bool), - /// Move the window. - /// - /// Unsupported on Wayland. - Move { - /// The new logical x location of the window - x: i32, - /// The new logical y location of the window - y: i32, - }, - /// Change the [`Mode`] of the window. - ChangeMode(Mode), - /// Fetch the current [`Mode`] of the window. - FetchMode(Box<dyn FnOnce(Mode) -> T + 'static>), - /// Toggle the window to maximized or back - ToggleMaximize, - /// Toggle whether window has decorations. - /// - /// ## Platform-specific - /// - **X11:** Not implemented. - /// - **Web:** Unsupported. - ToggleDecorations, - /// Request user attention to the window, this has no effect if the application - /// is already focused. How requesting for user attention manifests is platform dependent, - /// see [`UserAttention`] for details. - /// - /// Providing `None` will unset the request for user attention. Unsetting the request for - /// user attention might not be done automatically by the WM when the window receives input. - /// - /// ## Platform-specific - /// - /// - **iOS / Android / Web:** Unsupported. - /// - **macOS:** `None` has no effect. - /// - **X11:** Requests for user attention must be manually cleared. - /// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect. - RequestUserAttention(Option<UserAttention>), - /// Bring the window to the front and sets input focus. Has no effect if the window is - /// already in focus, minimized, or not visible. - /// - /// This method steals input focus from other applications. Do not use this method unless - /// you are certain that's what the user wants. Focus stealing can cause an extremely disruptive - /// user experience. - /// - /// ## Platform-specific - /// - /// - **Web / Wayland:** Unsupported. - GainFocus, - /// Change whether or not the window will always be on top of other windows. - /// - /// ## Platform-specific - /// - /// - **Web / Wayland:** Unsupported. - ChangeAlwaysOnTop(bool), - /// Fetch an identifier unique to the window. - FetchId(Box<dyn FnOnce(u64) -> T + 'static>), -} - -impl<T> Action<T> { - /// Maps the output of a window [`Action`] using the provided closure. - pub fn map<A>( - self, - f: impl Fn(T) -> A + 'static + MaybeSend + Sync, - ) -> Action<A> - where - T: 'static, - { - match self { - Self::Close => Action::Close, - Self::Drag => Action::Drag, - Self::Resize { width, height } => Action::Resize { width, height }, - Self::Maximize(maximized) => Action::Maximize(maximized), - Self::Minimize(minimized) => Action::Minimize(minimized), - Self::Move { x, y } => Action::Move { x, y }, - Self::ChangeMode(mode) => Action::ChangeMode(mode), - Self::FetchMode(o) => Action::FetchMode(Box::new(move |s| f(o(s)))), - Self::ToggleMaximize => Action::ToggleMaximize, - Self::ToggleDecorations => Action::ToggleDecorations, - Self::RequestUserAttention(attention_type) => { - Action::RequestUserAttention(attention_type) - } - Self::GainFocus => Action::GainFocus, - Self::ChangeAlwaysOnTop(on_top) => { - Action::ChangeAlwaysOnTop(on_top) - } - Self::FetchId(o) => Action::FetchId(Box::new(move |s| f(o(s)))), - } - } -} - -impl<T> fmt::Debug for Action<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Close => write!(f, "Action::Close"), - Self::Drag => write!(f, "Action::Drag"), - Self::Resize { width, height } => write!( - f, - "Action::Resize {{ widget: {width}, height: {height} }}" - ), - Self::Maximize(maximized) => { - write!(f, "Action::Maximize({maximized})") - } - Self::Minimize(minimized) => { - write!(f, "Action::Minimize({minimized}") - } - Self::Move { x, y } => { - write!(f, "Action::Move {{ x: {x}, y: {y} }}") - } - Self::ChangeMode(mode) => write!(f, "Action::SetMode({mode:?})"), - Self::FetchMode(_) => write!(f, "Action::FetchMode"), - Self::ToggleMaximize => write!(f, "Action::ToggleMaximize"), - Self::ToggleDecorations => write!(f, "Action::ToggleDecorations"), - Self::RequestUserAttention(_) => { - write!(f, "Action::RequestUserAttention") - } - Self::GainFocus => write!(f, "Action::GainFocus"), - Self::ChangeAlwaysOnTop(on_top) => { - write!(f, "Action::AlwaysOnTop({on_top})") - } - Self::FetchId(_) => write!(f, "Action::FetchId"), - } - } -} |