diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/application.rs | 77 | ||||
-rw-r--r-- | src/element.rs | 9 | ||||
-rw-r--r-- | src/executor.rs | 68 | ||||
-rw-r--r-- | src/lib.rs | 29 | ||||
-rw-r--r-- | src/native.rs | 113 | ||||
-rw-r--r-- | src/sandbox.rs | 9 | ||||
-rw-r--r-- | src/settings.rs | 37 | ||||
-rw-r--r-- | src/web.rs | 1 | ||||
-rw-r--r-- | src/widget.rs | 60 | ||||
-rw-r--r-- | src/window.rs | 6 | ||||
-rw-r--r-- | src/window/mode.rs | 9 | ||||
-rw-r--r-- | src/window/settings.rs | 22 |
12 files changed, 292 insertions, 148 deletions
diff --git a/src/application.rs b/src/application.rs index a4d20e68..2ee3337f 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,4 +1,4 @@ -use crate::{Command, Element, Settings}; +use crate::{window, Command, Element, Executor, Settings, Subscription}; /// An interactive cross-platform application. /// @@ -19,7 +19,7 @@ use crate::{Command, Element, Settings}; /// before](index.html#overview). We just need to fill in the gaps: /// /// ```no_run -/// use iced::{button, Application, Button, Column, Command, Element, Settings, Text}; +/// use iced::{button, executor, Application, Button, Column, Command, Element, Settings, Text}; /// /// pub fn main() { /// Counter::run(Settings::default()) @@ -39,6 +39,7 @@ use crate::{Command, Element, Settings}; /// } /// /// impl Application for Counter { +/// type Executor = executor::Null; /// type Message = Message; /// /// fn new() -> (Self, Command<Message>) { @@ -80,10 +81,18 @@ use crate::{Command, Element, Settings}; /// } /// ``` pub trait Application: Sized { + /// The [`Executor`] that will run commands and subscriptions. + /// + /// The [`executor::Default`] can be a good starting point! + /// + /// [`Executor`]: trait.Executor.html + /// [`executor::Default`]: executor/struct.Default.html + type Executor: Executor; + /// The type of __messages__ your [`Application`] will produce. /// /// [`Application`]: trait.Application.html - type Message: std::fmt::Debug + Send + Clone; + type Message: std::fmt::Debug + Send; /// Initializes the [`Application`]. /// @@ -117,6 +126,20 @@ pub trait Application: Sized { /// [`Command`]: struct.Command.html fn update(&mut self, message: Self::Message) -> Command<Self::Message>; + /// Returns the event [`Subscription`] for the current state of the + /// application. + /// + /// A [`Subscription`] will be kept alive as long as you keep returning it, + /// and the __messages__ produced will be handled by + /// [`update`](#tymethod.update). + /// + /// By default, this method returns an empty [`Subscription`]. + /// + /// [`Subscription`]: struct.Subscription.html + fn subscription(&self) -> Subscription<Self::Message> { + Subscription::none() + } + /// Returns the widgets to display in the [`Application`]. /// /// These widgets can produce __messages__ based on user interaction. @@ -124,6 +147,20 @@ pub trait Application: Sized { /// [`Application`]: trait.Application.html fn view(&mut self) -> Element<'_, Self::Message>; + /// Returns the current [`Application`] mode. + /// + /// The runtime will automatically transition your application if a new mode + /// is returned. + /// + /// Currently, the mode only has an effect in native platforms. + /// + /// By default, an application will run in windowed mode. + /// + /// [`Application`]: trait.Application.html + fn mode(&self) -> window::Mode { + window::Mode::Windowed + } + /// Runs the [`Application`]. /// /// This method will take control of the current thread and __will NOT @@ -132,12 +169,23 @@ pub trait Application: Sized { /// It should probably be that last thing you call in your `main` function. /// /// [`Application`]: trait.Application.html - fn run(settings: Settings) + fn run(_settings: Settings) where Self: 'static, { #[cfg(not(target_arch = "wasm32"))] - <Instance<Self> as iced_winit::Application>::run(settings.into()); + <Instance<Self> as iced_winit::Application>::run( + _settings.into(), + iced_wgpu::Settings { + default_font: _settings.default_font, + antialiasing: if _settings.antialiasing { + Some(iced_wgpu::settings::Antialiasing::MSAAx4) + } else { + None + }, + ..iced_wgpu::Settings::default() + }, + ); #[cfg(target_arch = "wasm32")] <Instance<Self> as iced_web::Application>::run(); @@ -151,7 +199,8 @@ impl<A> iced_winit::Application for Instance<A> where A: Application, { - type Renderer = iced_wgpu::Renderer; + type Backend = iced_wgpu::window::Backend; + type Executor = A::Executor; type Message = A::Message; fn new() -> (Self, Command<A::Message>) { @@ -164,10 +213,21 @@ where self.0.title() } + fn mode(&self) -> iced_winit::Mode { + match self.0.mode() { + window::Mode::Windowed => iced_winit::Mode::Windowed, + window::Mode::Fullscreen => iced_winit::Mode::Fullscreen, + } + } + fn update(&mut self, message: Self::Message) -> Command<Self::Message> { self.0.update(message) } + fn subscription(&self) -> Subscription<Self::Message> { + self.0.subscription() + } + fn view(&mut self) -> Element<'_, Self::Message> { self.0.view() } @@ -179,6 +239,7 @@ where A: Application, { type Message = A::Message; + type Executor = A::Executor; fn new() -> (Self, Command<A::Message>) { let (app, command) = A::new(); @@ -194,6 +255,10 @@ where self.0.update(message) } + fn subscription(&self) -> Subscription<Self::Message> { + self.0.subscription() + } + fn view(&mut self) -> Element<'_, Self::Message> { self.0.view() } diff --git a/src/element.rs b/src/element.rs new file mode 100644 index 00000000..e5356fb6 --- /dev/null +++ b/src/element.rs @@ -0,0 +1,9 @@ +/// A generic widget. +/// +/// This is an alias of an `iced_native` element with a default `Renderer`. +#[cfg(not(target_arch = "wasm32"))] +pub type Element<'a, Message> = + iced_winit::Element<'a, Message, iced_wgpu::Renderer>; + +#[cfg(target_arch = "wasm32")] +pub use iced_web::Element; diff --git a/src/executor.rs b/src/executor.rs new file mode 100644 index 00000000..b4be5264 --- /dev/null +++ b/src/executor.rs @@ -0,0 +1,68 @@ +//! Choose your preferred executor to power your application. +pub use crate::common::{executor::Null, Executor}; + +pub use platform::Default; + +#[cfg(not(target_arch = "wasm32"))] +mod platform { + use iced_futures::{executor, futures}; + + #[cfg(feature = "tokio")] + type Executor = executor::Tokio; + + #[cfg(all(not(feature = "tokio"), feature = "async-std"))] + type Executor = executor::AsyncStd; + + #[cfg(not(any(feature = "tokio", feature = "async-std")))] + type Executor = executor::ThreadPool; + + /// A default cross-platform executor. + /// + /// - On native platforms, it will use: + /// - `iced_futures::executor::Tokio` when the `tokio` feature is enabled. + /// - `iced_futures::executor::AsyncStd` when the `async-std` feature is + /// enabled. + /// - `iced_futures::executor::ThreadPool` otherwise. + /// - On the Web, it will use `iced_futures::executor::WasmBindgen`. + #[derive(Debug)] + pub struct Default(Executor); + + impl super::Executor for Default { + fn new() -> Result<Self, futures::io::Error> { + Ok(Default(Executor::new()?)) + } + + fn spawn( + &self, + future: impl futures::Future<Output = ()> + Send + 'static, + ) { + let _ = self.0.spawn(future); + } + + fn enter<R>(&self, f: impl FnOnce() -> R) -> R { + self.0.enter(f) + } + } +} + +#[cfg(target_arch = "wasm32")] +mod platform { + use iced_futures::{executor::WasmBindgen, futures, Executor}; + + /// A default cross-platform executor. + /// + /// - On native platforms, it will use `iced_futures::executor::ThreadPool`. + /// - On the Web, it will use `iced_futures::executor::WasmBindgen`. + #[derive(Debug)] + pub struct Default(WasmBindgen); + + impl Executor for Default { + fn new() -> Result<Self, futures::io::Error> { + Ok(Default(WasmBindgen::new()?)) + } + + fn spawn(&self, future: impl futures::Future<Output = ()> + 'static) { + self.0.spawn(future); + } + } +} @@ -171,23 +171,38 @@ //! //! [Elm]: https://elm-lang.org/ //! [The Elm Architecture]: https://guide.elm-lang.org/architecture/ -//! [documentation]: https://docs.rs/iced //! [examples]: https://github.com/hecrj/iced/tree/master/examples //! [`Application`]: trait.Application.html #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] -#![deny(unsafe_code)] -#![deny(rust_2018_idioms)] +#![forbid(unsafe_code)] +#![forbid(rust_2018_idioms)] mod application; -#[cfg_attr(target_arch = "wasm32", path = "web.rs")] -#[cfg_attr(not(target_arch = "wasm32"), path = "native.rs")] -mod platform; +mod element; mod sandbox; +pub mod executor; pub mod settings; +pub mod widget; +pub mod window; + +#[doc(no_inline)] +pub use widget::*; pub use application::Application; -pub use platform::*; +pub use element::Element; +pub use executor::Executor; pub use sandbox::Sandbox; pub use settings::Settings; + +#[cfg(not(target_arch = "wasm32"))] +use iced_winit as common; + +#[cfg(target_arch = "wasm32")] +use iced_web as common; + +pub use common::{ + futures, Align, Background, Color, Command, Font, HorizontalAlignment, + Length, Point, Size, Space, Subscription, Vector, VerticalAlignment, +}; diff --git a/src/native.rs b/src/native.rs deleted file mode 100644 index 926b2d11..00000000 --- a/src/native.rs +++ /dev/null @@ -1,113 +0,0 @@ -pub use iced_winit::{ - Align, Background, Color, Command, Font, HorizontalAlignment, Length, - VerticalAlignment, -}; - -pub mod widget { - //! Display information and interactive controls in your application. - //! - //! # Re-exports - //! For convenience, the contents of this module are available at the root - //! module. Therefore, you can directly type: - //! - //! ``` - //! use iced::{button, Button}; - //! ``` - //! - //! # Stateful widgets - //! Some widgets need to keep track of __local state__. - //! - //! These widgets have their own module with a `State` type. For instance, a - //! [`TextInput`] has some [`text_input::State`]. - //! - //! [`TextInput`]: text_input/struct.TextInput.html - //! [`text_input::State`]: text_input/struct.State.html - pub mod button { - //! Allow your users to perform actions by pressing a button. - //! - //! A [`Button`] has some local [`State`]. - //! - //! [`Button`]: type.Button.html - //! [`State`]: struct.State.html - - /// A widget that produces a message when clicked. - /// - /// This is an alias of an `iced_native` button with a default - /// `Renderer`. - pub type Button<'a, Message> = - iced_winit::Button<'a, Message, iced_wgpu::Renderer>; - - pub use iced_winit::button::State; - } - - pub mod scrollable { - //! Navigate an endless amount of content with a scrollbar. - - /// A widget that can vertically display an infinite amount of content - /// with a scrollbar. - /// - /// This is an alias of an `iced_native` scrollable with a default - /// `Renderer`. - pub type Scrollable<'a, Message> = - iced_winit::Scrollable<'a, Message, iced_wgpu::Renderer>; - - pub use iced_winit::scrollable::State; - } - - pub mod text_input { - //! Ask for information using text fields. - //! - //! A [`TextInput`] has some local [`State`]. - //! - //! [`TextInput`]: struct.TextInput.html - //! [`State`]: struct.State.html - pub use iced_winit::text_input::{State, TextInput}; - } - - pub mod slider { - //! Display an interactive selector of a single value from a range of - //! values. - //! - //! A [`Slider`] has some local [`State`]. - //! - //! [`Slider`]: struct.Slider.html - //! [`State`]: struct.State.html - pub use iced_winit::slider::{Slider, State}; - } - - pub use iced_winit::{Checkbox, Image, Radio, Text}; - - #[doc(no_inline)] - pub use { - button::Button, scrollable::Scrollable, slider::Slider, - text_input::TextInput, - }; - - /// A container that distributes its contents vertically. - /// - /// This is an alias of an `iced_native` column with a default `Renderer`. - pub type Column<'a, Message> = - iced_winit::Column<'a, Message, iced_wgpu::Renderer>; - - /// A container that distributes its contents horizontally. - /// - /// This is an alias of an `iced_native` row with a default `Renderer`. - pub type Row<'a, Message> = - iced_winit::Row<'a, Message, iced_wgpu::Renderer>; - - /// An element decorating some content. - /// - /// This is an alias of an `iced_native` container with a default - /// `Renderer`. - pub type Container<'a, Message> = - iced_winit::Container<'a, Message, iced_wgpu::Renderer>; -} - -#[doc(no_inline)] -pub use widget::*; - -/// A generic widget. -/// -/// This is an alias of an `iced_native` element with a default `Renderer`. -pub type Element<'a, Message> = - iced_winit::Element<'a, Message, iced_wgpu::Renderer>; diff --git a/src/sandbox.rs b/src/sandbox.rs index acf7f5e0..2c0332ff 100644 --- a/src/sandbox.rs +++ b/src/sandbox.rs @@ -1,4 +1,4 @@ -use crate::{Application, Command, Element, Settings}; +use crate::{executor, Application, Command, Element, Settings, Subscription}; /// A sandboxed [`Application`]. /// @@ -81,7 +81,7 @@ pub trait Sandbox { /// The type of __messages__ your [`Sandbox`] will produce. /// /// [`Sandbox`]: trait.Sandbox.html - type Message: std::fmt::Debug + Send + Clone; + type Message: std::fmt::Debug + Send; /// Initializes the [`Sandbox`]. /// @@ -133,6 +133,7 @@ impl<T> Application for T where T: Sandbox, { + type Executor = executor::Null; type Message = T::Message; fn new() -> (Self, Command<T::Message>) { @@ -149,6 +150,10 @@ where Command::none() } + fn subscription(&self) -> Subscription<T::Message> { + Subscription::none() + } + fn view(&mut self) -> Element<'_, T::Message> { T::view(self) } diff --git a/src/settings.rs b/src/settings.rs index 2556c51b..32ec583c 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,33 +1,30 @@ //! Configure your application. +use crate::window; /// The settings of an application. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct Settings { - /// The [`Window`] settings. + /// The window settings. /// /// They will be ignored on the Web. /// /// [`Window`]: struct.Window.html - pub window: Window, -} - -/// The window settings of an application. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Window { - /// The size of the window. - pub size: (u32, u32), + pub window: window::Settings, - /// Whether the window should be resizable or not. - pub resizable: bool, -} + /// The bytes of the font that will be used by default. + /// + /// If `None` is provided, a default system font will be chosen. + // TODO: Add `name` for web compatibility + pub default_font: Option<&'static [u8]>, -impl Default for Window { - fn default() -> Window { - Window { - size: (1024, 768), - resizable: true, - } - } + /// If set to true, the renderer will try to perform antialiasing for some + /// primitives. + /// + /// Enabling it can produce a smoother result in some widgets, like the + /// `Canvas`, at a performance cost. + /// + /// By default, it is disabled. + pub antialiasing: bool, } #[cfg(not(target_arch = "wasm32"))] @@ -37,6 +34,8 @@ impl From<Settings> for iced_winit::Settings { window: iced_winit::settings::Window { size: settings.window.size, resizable: settings.window.resizable, + decorations: settings.window.decorations, + platform_specific: Default::default(), }, } } diff --git a/src/web.rs b/src/web.rs deleted file mode 100644 index 31f1a6fc..00000000 --- a/src/web.rs +++ /dev/null @@ -1 +0,0 @@ -pub use iced_web::*; diff --git a/src/widget.rs b/src/widget.rs new file mode 100644 index 00000000..7d3a1cef --- /dev/null +++ b/src/widget.rs @@ -0,0 +1,60 @@ +//! Display information and interactive controls in your application. +//! +//! # Re-exports +//! For convenience, the contents of this module are available at the root +//! module. Therefore, you can directly type: +//! +//! ``` +//! use iced::{button, Button}; +//! ``` +//! +//! # Stateful widgets +//! Some widgets need to keep track of __local state__. +//! +//! These widgets have their own module with a `State` type. For instance, a +//! [`TextInput`] has some [`text_input::State`]. +//! +//! [`TextInput`]: text_input/struct.TextInput.html +//! [`text_input::State`]: text_input/struct.State.html +#[cfg(not(target_arch = "wasm32"))] +mod platform { + pub use iced_wgpu::widget::*; + + pub mod image { + //! Display images in your user interface. + pub use iced_winit::image::{Handle, Image}; + } + + pub mod svg { + //! Display vector graphics in your user interface. + pub use iced_winit::svg::{Handle, Svg}; + } + + pub use iced_winit::Text; + + #[doc(no_inline)] + pub use { + button::Button, checkbox::Checkbox, container::Container, image::Image, + progress_bar::ProgressBar, radio::Radio, scrollable::Scrollable, + slider::Slider, svg::Svg, text_input::TextInput, + }; + + /// A container that distributes its contents vertically. + /// + /// This is an alias of an `iced_native` column with a default `Renderer`. + pub type Column<'a, Message> = + iced_winit::Column<'a, Message, iced_wgpu::Renderer>; + + /// A container that distributes its contents horizontally. + /// + /// This is an alias of an `iced_native` row with a default `Renderer`. + pub type Row<'a, Message> = + iced_winit::Row<'a, Message, iced_wgpu::Renderer>; +} + +#[cfg(target_arch = "wasm32")] +mod platform { + pub use iced_web::widget::*; +} + +pub use platform::*; diff --git a/src/window.rs b/src/window.rs new file mode 100644 index 00000000..54ea2a02 --- /dev/null +++ b/src/window.rs @@ -0,0 +1,6 @@ +//! Configure the window of your application in native platforms. +mod mode; +mod settings; + +pub use mode::Mode; +pub use settings::Settings; diff --git a/src/window/mode.rs b/src/window/mode.rs new file mode 100644 index 00000000..37464711 --- /dev/null +++ b/src/window/mode.rs @@ -0,0 +1,9 @@ +/// The mode of a window-based application. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Mode { + /// The application appears in its own window. + Windowed, + + /// The application takes the whole screen of its current monitor. + Fullscreen, +} diff --git a/src/window/settings.rs b/src/window/settings.rs new file mode 100644 index 00000000..a31d2af2 --- /dev/null +++ b/src/window/settings.rs @@ -0,0 +1,22 @@ +/// The window settings of an application. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Settings { + /// The size of the window. + pub size: (u32, u32), + + /// Whether the window should be resizable or not. + pub resizable: bool, + + /// Whether the window should have a border, a title bar, etc. or not. + pub decorations: bool, +} + +impl Default for Settings { + fn default() -> Settings { + Settings { + size: (1024, 768), + resizable: true, + decorations: true, + } + } +} |