From c4c5216e3b69d732b0518d510f95675a4ba7010b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 30 Mar 2020 18:00:15 +0200 Subject: Allow passing external state to `Application::new` --- examples/clock/src/main.rs | 3 +- examples/download_progress/src/main.rs | 3 +- examples/events/src/main.rs | 3 +- examples/pokedex/src/main.rs | 3 +- examples/solar_system/src/main.rs | 9 +++--- examples/stopwatch/src/main.rs | 3 +- examples/todos/src/main.rs | 3 +- src/application.rs | 49 ++++++++++++++++++++----------- src/sandbox.rs | 5 ++-- src/settings.rs | 12 ++++++-- web/src/lib.rs | 30 +++++++++++-------- winit/src/application.rs | 21 ++++++++++---- winit/src/settings.rs | 50 ++++++++++++++++++++++++++++++++ winit/src/settings/mod.rs | 53 ---------------------------------- 14 files changed, 145 insertions(+), 102 deletions(-) create mode 100644 winit/src/settings.rs delete mode 100644 winit/src/settings/mod.rs diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs index d8266f06..1fd19bc6 100644 --- a/examples/clock/src/main.rs +++ b/examples/clock/src/main.rs @@ -23,8 +23,9 @@ enum Message { impl Application for Clock { type Executor = executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Self, Command) { + fn new(_flags: ()) -> (Self, Command) { ( Clock { now: chrono::Local::now().into(), diff --git a/examples/download_progress/src/main.rs b/examples/download_progress/src/main.rs index 6c3094f7..c37ae678 100644 --- a/examples/download_progress/src/main.rs +++ b/examples/download_progress/src/main.rs @@ -26,8 +26,9 @@ pub enum Message { impl Application for Example { type Executor = executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Example, Command) { + fn new(_flags: ()) -> (Example, Command) { ( Example::Idle { button: button::State::new(), diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs index 0c9dca05..066fc230 100644 --- a/examples/events/src/main.rs +++ b/examples/events/src/main.rs @@ -22,8 +22,9 @@ enum Message { impl Application for Events { type Executor = executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Events, Command) { + fn new(_flags: ()) -> (Events, Command) { (Events::default(), Command::none()) } diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs index 4449b901..600ef632 100644 --- a/examples/pokedex/src/main.rs +++ b/examples/pokedex/src/main.rs @@ -29,8 +29,9 @@ enum Message { impl Application for Pokedex { type Executor = iced::executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Pokedex, Command) { + fn new(_flags: ()) -> (Pokedex, Command) { ( Pokedex::Loading, Command::perform(Pokemon::search(), Message::PokemonFound), diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs index 4c239806..1967b7c5 100644 --- a/examples/solar_system/src/main.rs +++ b/examples/solar_system/src/main.rs @@ -7,8 +7,8 @@ //! //! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system use iced::{ - canvas, executor, Application, Canvas, Color, Command, Container, Element, - Length, Point, Settings, Size, Subscription, Vector, + canvas, executor, window, Application, Canvas, Color, Command, Container, + Element, Length, Point, Settings, Size, Subscription, Vector, }; use std::time::Instant; @@ -33,8 +33,9 @@ enum Message { impl Application for SolarSystem { type Executor = executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Self, Command) { + fn new(_flags: ()) -> (Self, Command) { ( SolarSystem { state: State::new(), @@ -95,7 +96,7 @@ impl State { pub fn new() -> State { let now = Instant::now(); - let (width, height) = Settings::default().window.size; + let (width, height) = window::Settings::default().size; State { start: now, diff --git a/examples/stopwatch/src/main.rs b/examples/stopwatch/src/main.rs index d84c4817..5a54ed2b 100644 --- a/examples/stopwatch/src/main.rs +++ b/examples/stopwatch/src/main.rs @@ -30,8 +30,9 @@ enum Message { impl Application for Stopwatch { type Executor = iced_futures::executor::AsyncStd; type Message = Message; + type Flags = (); - fn new() -> (Stopwatch, Command) { + fn new(_flags: ()) -> (Stopwatch, Command) { ( Stopwatch { duration: Duration::default(), diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 7e866b19..c9cbcc69 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -40,8 +40,9 @@ enum Message { impl Application for Todos { type Executor = iced::executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Todos, Command) { + fn new(_flags: ()) -> (Todos, Command) { ( Todos::Loading, Command::perform(SavedState::load(), Message::Loaded), diff --git a/src/application.rs b/src/application.rs index 2ee3337f..551a9a79 100644 --- a/src/application.rs +++ b/src/application.rs @@ -41,8 +41,9 @@ use crate::{window, Command, Element, Executor, Settings, Subscription}; /// impl Application for Counter { /// type Executor = executor::Null; /// type Message = Message; +/// type Flags = (); /// -/// fn new() -> (Self, Command) { +/// fn new(_flags: ()) -> (Self, Command) { /// (Self::default(), Command::none()) /// } /// @@ -94,7 +95,13 @@ pub trait Application: Sized { /// [`Application`]: trait.Application.html type Message: std::fmt::Debug + Send; - /// Initializes the [`Application`]. + /// The data needed to initialize your [`Application`]. + /// + /// [`Application`]: trait.Application.html + type Flags; + + /// Initializes the [`Application`] with the flags provided to + /// [`run`] as part of the [`Settings`]: /// /// Here is where you should return the initial state of your app. /// @@ -104,7 +111,9 @@ pub trait Application: Sized { /// request, etc. /// /// [`Application`]: trait.Application.html - fn new() -> (Self, Command); + /// [`run`]: #method.run.html + /// [`Settings`]: struct.Settings.html + fn new(flags: Self::Flags) -> (Self, Command); /// Returns the current title of the [`Application`]. /// @@ -169,26 +178,30 @@ 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"))] - as iced_winit::Application>::run( - _settings.into(), - iced_wgpu::Settings { - default_font: _settings.default_font, - antialiasing: if _settings.antialiasing { + { + let wgpu_settings = iced_wgpu::Settings { + default_font: settings.default_font, + antialiasing: if settings.antialiasing { Some(iced_wgpu::settings::Antialiasing::MSAAx4) } else { None }, ..iced_wgpu::Settings::default() - }, - ); + }; + + as iced_winit::Application>::run( + settings.into(), + wgpu_settings, + ); + } #[cfg(target_arch = "wasm32")] - as iced_web::Application>::run(); + as iced_web::Application>::run(settings.flags); } } @@ -201,10 +214,11 @@ where { type Backend = iced_wgpu::window::Backend; type Executor = A::Executor; + type Flags = A::Flags; type Message = A::Message; - fn new() -> (Self, Command) { - let (app, command) = A::new(); + fn new(flags: Self::Flags) -> (Self, Command) { + let (app, command) = A::new(flags); (Instance(app), command) } @@ -238,11 +252,12 @@ impl iced_web::Application for Instance where A: Application, { - type Message = A::Message; type Executor = A::Executor; + type Message = A::Message; + type Flags = A::Flags; - fn new() -> (Self, Command) { - let (app, command) = A::new(); + fn new(flags: Self::Flags) -> (Self, Command) { + let (app, command) = A::new(flags); (Instance(app), command) } diff --git a/src/sandbox.rs b/src/sandbox.rs index 2c0332ff..4ea8de98 100644 --- a/src/sandbox.rs +++ b/src/sandbox.rs @@ -121,7 +121,7 @@ pub trait Sandbox { /// It should probably be that last thing you call in your `main` function. /// /// [`Sandbox`]: trait.Sandbox.html - fn run(settings: Settings) + fn run(settings: Settings<()>) where Self: 'static + Sized, { @@ -134,9 +134,10 @@ where T: Sandbox, { type Executor = executor::Null; + type Flags = (); type Message = T::Message; - fn new() -> (Self, Command) { + fn new(_flags: ()) -> (Self, Command) { (T::new(), Command::none()) } diff --git a/src/settings.rs b/src/settings.rs index 32ec583c..f36ec85f 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -3,7 +3,7 @@ use crate::window; /// The settings of an application. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct Settings { +pub struct Settings { /// The window settings. /// /// They will be ignored on the Web. @@ -11,6 +11,11 @@ pub struct Settings { /// [`Window`]: struct.Window.html pub window: window::Settings, + /// The data needed to initialize an [`Application`]. + /// + /// [`Application`]: trait.Application.html + pub flags: Flags, + /// The bytes of the font that will be used by default. /// /// If `None` is provided, a default system font will be chosen. @@ -28,8 +33,8 @@ pub struct Settings { } #[cfg(not(target_arch = "wasm32"))] -impl From for iced_winit::Settings { - fn from(settings: Settings) -> iced_winit::Settings { +impl From> for iced_winit::Settings { + fn from(settings: Settings) -> iced_winit::Settings { iced_winit::Settings { window: iced_winit::settings::Window { size: settings.window.size, @@ -37,6 +42,7 @@ impl From for iced_winit::Settings { decorations: settings.window.decorations, platform_specific: Default::default(), }, + flags: settings.flags, } } } diff --git a/web/src/lib.rs b/web/src/lib.rs index 1de00545..bc46c541 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -94,11 +94,6 @@ pub use executor::Executor; /// An [`Application`](trait.Application.html) can execute asynchronous actions /// by returning a [`Command`](struct.Command.html) in some of its methods. pub trait Application { - /// The type of __messages__ your [`Application`] will produce. - /// - /// [`Application`]: trait.Application.html - type Message: Send; - /// The [`Executor`] that will run commands and subscriptions. /// /// The [`executor::WasmBindgen`] can be a good choice for the Web. @@ -107,6 +102,16 @@ pub trait Application { /// [`executor::Default`]: executor/struct.Default.html type Executor: Executor; + /// The type of __messages__ your [`Application`] will produce. + /// + /// [`Application`]: trait.Application.html + type Message: Send; + + /// The data needed to initialize your [`Application`]. + /// + /// [`Application`]: trait.Application.html + type Flags; + /// Initializes the [`Application`]. /// /// Here is where you should return the initial state of your app. @@ -117,7 +122,7 @@ pub trait Application { /// request, etc. /// /// [`Application`]: trait.Application.html - fn new() -> (Self, Command) + fn new(flags: Self::Flags) -> (Self, Command) where Self: Sized; @@ -165,21 +170,16 @@ pub trait Application { /// Runs the [`Application`]. /// /// [`Application`]: trait.Application.html - fn run() + fn run(flags: Self::Flags) where Self: 'static + Sized, { use futures::stream::StreamExt; - let (app, command) = Self::new(); - let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let body = document.body().unwrap(); - let mut title = app.title(); - document.set_title(&title); - let (sender, receiver) = iced_futures::futures::channel::mpsc::unbounded(); @@ -187,6 +187,12 @@ pub trait Application { Self::Executor::new().expect("Create executor"), sender.clone(), ); + + let (app, command) = Self::new(flags); + + let mut title = app.title(); + document.set_title(&title); + runtime.spawn(command); let application = Rc::new(RefCell::new(app)); diff --git a/winit/src/application.rs b/winit/src/application.rs index b9d5fed8..d5f957bf 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -28,7 +28,13 @@ pub trait Application: Sized { /// [`Application`]: trait.Application.html type Message: std::fmt::Debug + Send; - /// Initializes the [`Application`]. + /// The data needed to initialize your [`Application`]. + /// + /// [`Application`]: trait.Application.html + type Flags; + + /// Initializes the [`Application`] with the flags provided to + /// [`run`] as part of the [`Settings`]: /// /// Here is where you should return the initial state of your app. /// @@ -38,7 +44,9 @@ pub trait Application: Sized { /// request, etc. /// /// [`Application`]: trait.Application.html - fn new() -> (Self, Command); + /// [`run`]: #method.run.html + /// [`Settings`]: struct.Settings.html + fn new(flags: Self::Flags) -> (Self, Command); /// Returns the current title of the [`Application`]. /// @@ -90,7 +98,7 @@ pub trait Application: Sized { Mode::Windowed } - /// Runs the [`Application`]. + /// Runs the [`Application`] with the provided [`Settings`]. /// /// This method will take control of the current thread and __will NOT /// return__. @@ -98,8 +106,9 @@ pub trait Application: Sized { /// It should probably be that last thing you call in your `main` function. /// /// [`Application`]: trait.Application.html + /// [`Settings`]: struct.Settings.html fn run( - settings: Settings, + settings: Settings, backend_settings: ::Settings, ) where Self: 'static, @@ -123,7 +132,9 @@ pub trait Application: Sized { Runtime::new(executor, Proxy::new(event_loop.create_proxy())) }; - let (mut application, init_command) = runtime.enter(Self::new); + let flags = settings.flags; + let (mut application, init_command) = + runtime.enter(|| Self::new(flags)); runtime.spawn(init_command); let subscription = application.subscription(); diff --git a/winit/src/settings.rs b/winit/src/settings.rs new file mode 100644 index 00000000..d58c51f0 --- /dev/null +++ b/winit/src/settings.rs @@ -0,0 +1,50 @@ +//! Configure your application. +#[cfg(target_os = "windows")] +#[path = "settings/windows.rs"] +mod platform; +#[cfg(not(target_os = "windows"))] +#[path = "settings/not_windows.rs"] +mod platform; + +pub use platform::PlatformSpecific; + +/// The settings of an application. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct Settings { + /// The [`Window`] settings + /// + /// [`Window`]: struct.Window.html + pub window: Window, + + /// The data needed to initialize an [`Application`]. + /// + /// [`Application`]: trait.Application.html + pub flags: Flags, +} + +/// The window settings of an application. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Window { + /// 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. + pub decorations: bool, + + /// Platform specific settings. + pub platform_specific: platform::PlatformSpecific, +} + +impl Default for Window { + fn default() -> Window { + Window { + size: (1024, 768), + resizable: true, + decorations: true, + platform_specific: Default::default(), + } + } +} diff --git a/winit/src/settings/mod.rs b/winit/src/settings/mod.rs deleted file mode 100644 index b2290b46..00000000 --- a/winit/src/settings/mod.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Configure your application. -#[cfg(target_os = "windows")] -#[path = "windows.rs"] -mod platform; -#[cfg(not(target_os = "windows"))] -#[path = "not_windows.rs"] -mod platform; - -pub use platform::PlatformSpecific; - -/// The settings of an application. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Settings { - /// The [`Window`] settings - /// - /// [`Window`]: struct.Window.html - pub window: Window, -} - -impl Default for Settings { - fn default() -> Settings { - Settings { - window: Window::default(), - } - } -} - -/// The window settings of an application. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Window { - /// 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. - pub decorations: bool, - - /// Platform specific settings. - pub platform_specific: platform::PlatformSpecific, -} - -impl Default for Window { - fn default() -> Window { - Window { - size: (1024, 768), - resizable: true, - decorations: true, - platform_specific: Default::default(), - } - } -} -- cgit