diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 3 | ||||
| -rw-r--r-- | src/multi_window.rs | 4 | ||||
| -rw-r--r-- | src/multi_window/application.rs | 244 | ||||
| -rw-r--r-- | src/settings.rs | 13 | ||||
| -rw-r--r-- | src/window.rs | 4 | ||||
| -rw-r--r-- | src/window/position.rs | 32 | ||||
| -rw-r--r-- | src/window/settings.rs | 76 | 
7 files changed, 252 insertions, 124 deletions
@@ -182,6 +182,9 @@ pub mod window;  #[cfg(feature = "advanced")]  pub mod advanced; +#[cfg(feature = "multi-window")] +pub mod multi_window; +  pub use style::theme;  pub use crate::core::alignment; diff --git a/src/multi_window.rs b/src/multi_window.rs new file mode 100644 index 00000000..5b7a00b4 --- /dev/null +++ b/src/multi_window.rs @@ -0,0 +1,4 @@ +//! Leverage multi-window support in your application. +mod application; + +pub use application::Application; diff --git a/src/multi_window/application.rs b/src/multi_window/application.rs new file mode 100644 index 00000000..0486159e --- /dev/null +++ b/src/multi_window/application.rs @@ -0,0 +1,244 @@ +use crate::window; +use crate::{Command, Element, Executor, Settings, Subscription}; + +pub use crate::style::application::{Appearance, StyleSheet}; + +/// An interactive cross-platform multi-window application. +/// +/// This trait is the main entrypoint of Iced. Once implemented, you can run +/// your GUI application by simply calling [`run`](#method.run). +/// +/// - On native platforms, it will run in its own windows. +/// - On the web, it will take control of the `<title>` and the `<body>` of the +///   document and display only the contents of the `window::Id::MAIN` window. +/// +/// An [`Application`] can execute asynchronous actions by returning a +/// [`Command`] in some of its methods. If you do not intend to perform any +/// background work in your program, the [`Sandbox`] trait offers a simplified +/// interface. +/// +/// When using an [`Application`] with the `debug` feature enabled, a debug view +/// can be toggled by pressing `F12`. +/// +/// # Examples +/// See the `examples/multi-window` example to see this multi-window `Application` trait in action. +/// +/// ## A simple "Hello, world!" +/// +/// If you just want to get started, here is a simple [`Application`] that +/// says "Hello, world!": +/// +/// ```no_run +/// use iced::{executor, window}; +/// use iced::{Command, Element, Settings, Theme}; +/// use iced::multi_window::{self, Application}; +/// +/// pub fn main() -> iced::Result { +///     Hello::run(Settings::default()) +/// } +/// +/// struct Hello; +/// +/// impl multi_window::Application for Hello { +///     type Executor = executor::Default; +///     type Flags = (); +///     type Message = (); +///     type Theme = Theme; +/// +///     fn new(_flags: ()) -> (Hello, Command<Self::Message>) { +///         (Hello, Command::none()) +///     } +/// +///     fn title(&self, _window: window::Id) -> String { +///         String::from("A cool application") +///     } +/// +///     fn update(&mut self, _message: Self::Message) -> Command<Self::Message> { +///         Command::none() +///     } +/// +///     fn view(&self, _window: window::Id) -> Element<Self::Message> { +///         "Hello, world!".into() +///     } +/// } +/// ``` +pub trait Application: Sized { +    /// The [`Executor`] that will run commands and subscriptions. +    /// +    /// The [default executor] can be a good starting point! +    /// +    /// [`Executor`]: Self::Executor +    /// [default executor]: crate::executor::Default +    type Executor: Executor; + +    /// The type of __messages__ your [`Application`] will produce. +    type Message: std::fmt::Debug + Send; + +    /// The theme of your [`Application`]. +    type Theme: Default + StyleSheet; + +    /// The data needed to initialize your [`Application`]. +    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. +    /// +    /// Additionally, you can return a [`Command`] if you need to perform some +    /// async action in the background on startup. This is useful if you want to +    /// load state from a file, perform an initial HTTP request, etc. +    /// +    /// [`run`]: Self::run +    fn new(flags: Self::Flags) -> (Self, Command<Self::Message>); + +    /// Returns the current title of the `window` of the [`Application`]. +    /// +    /// This title can be dynamic! The runtime will automatically update the +    /// title of your window when necessary. +    fn title(&self, window: window::Id) -> String; + +    /// Handles a __message__ and updates the state of the [`Application`]. +    /// +    /// 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. +    fn update(&mut self, message: Self::Message) -> Command<Self::Message>; + +    /// Returns the widgets to display in the `window` of the [`Application`]. +    /// +    /// These widgets can produce __messages__ based on user interaction. +    fn view( +        &self, +        window: window::Id, +    ) -> Element<'_, Self::Message, crate::Renderer<Self::Theme>>; + +    /// Returns the current [`Theme`] of the `window` of the [`Application`]. +    /// +    /// [`Theme`]: Self::Theme +    #[allow(unused_variables)] +    fn theme(&self, window: window::Id) -> Self::Theme { +        Self::Theme::default() +    } + +    /// Returns the current `Style` of the [`Theme`]. +    /// +    /// [`Theme`]: Self::Theme +    fn style(&self) -> <Self::Theme as StyleSheet>::Style { +        <Self::Theme as StyleSheet>::Style::default() +    } + +    /// 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`]. +    fn subscription(&self) -> Subscription<Self::Message> { +        Subscription::none() +    } + +    /// Returns the scale factor of the `window` of the [`Application`]. +    /// +    /// It can be used to dynamically control the size of the UI at runtime +    /// (i.e. zooming). +    /// +    /// For instance, a scale factor of `2.0` will make widgets twice as big, +    /// while a scale factor of `0.5` will shrink them to half their size. +    /// +    /// By default, it returns `1.0`. +    #[allow(unused_variables)] +    fn scale_factor(&self, window: window::Id) -> f64 { +        1.0 +    } + +    /// Runs the multi-window [`Application`]. +    /// +    /// On native platforms, this method will take control of the current thread +    /// until the [`Application`] exits. +    /// +    /// On the web platform, this method __will NOT return__ unless there is an +    /// [`Error`] during startup. +    /// +    /// [`Error`]: crate::Error +    fn run(settings: Settings<Self::Flags>) -> crate::Result +    where +        Self: 'static, +    { +        #[allow(clippy::needless_update)] +        let renderer_settings = crate::renderer::Settings { +            default_font: settings.default_font, +            default_text_size: settings.default_text_size, +            antialiasing: if settings.antialiasing { +                Some(crate::graphics::Antialiasing::MSAAx4) +            } else { +                None +            }, +            ..crate::renderer::Settings::default() +        }; + +        Ok(crate::shell::multi_window::run::< +            Instance<Self>, +            Self::Executor, +            crate::renderer::Compositor<Self::Theme>, +        >(settings.into(), renderer_settings)?) +    } +} + +struct Instance<A: Application>(A); + +impl<A> crate::runtime::multi_window::Program for Instance<A> +where +    A: Application, +{ +    type Renderer = crate::Renderer<A::Theme>; +    type Message = A::Message; + +    fn update(&mut self, message: Self::Message) -> Command<Self::Message> { +        self.0.update(message) +    } + +    fn view( +        &self, +        window: window::Id, +    ) -> Element<'_, Self::Message, Self::Renderer> { +        self.0.view(window) +    } +} + +impl<A> crate::shell::multi_window::Application for Instance<A> +where +    A: Application, +{ +    type Flags = A::Flags; + +    fn new(flags: Self::Flags) -> (Self, Command<A::Message>) { +        let (app, command) = A::new(flags); + +        (Instance(app), command) +    } + +    fn title(&self, window: window::Id) -> String { +        self.0.title(window) +    } + +    fn theme(&self, window: window::Id) -> A::Theme { +        self.0.theme(window) +    } + +    fn style(&self) -> <A::Theme as StyleSheet>::Style { +        self.0.style() +    } + +    fn subscription(&self) -> Subscription<Self::Message> { +        self.0.subscription() +    } + +    fn scale_factor(&self, window: window::Id) -> f64 { +        self.0.scale_factor(window) +    } +} diff --git a/src/settings.rs b/src/settings.rs index 42df31e4..d9476b61 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -46,14 +46,6 @@ pub struct Settings<Flags> {      ///      /// [`Canvas`]: crate::widget::Canvas      pub antialiasing: bool, - -    /// Whether the [`Application`] should exit when the user requests the -    /// window to close (e.g. the user presses the close button). -    /// -    /// By default, it is enabled. -    /// -    /// [`Application`]: crate::Application -    pub exit_on_close_request: bool,  }  impl<Flags> Settings<Flags> { @@ -71,7 +63,6 @@ impl<Flags> Settings<Flags> {              default_font: default_settings.default_font,              default_text_size: default_settings.default_text_size,              antialiasing: default_settings.antialiasing, -            exit_on_close_request: default_settings.exit_on_close_request,          }      }  } @@ -89,7 +80,6 @@ where              default_font: Font::default(),              default_text_size: Pixels(16.0),              antialiasing: false, -            exit_on_close_request: true,          }      }  } @@ -98,10 +88,9 @@ impl<Flags> From<Settings<Flags>> for iced_winit::Settings<Flags> {      fn from(settings: Settings<Flags>) -> iced_winit::Settings<Flags> {          iced_winit::Settings {              id: settings.id, -            window: settings.window.into(), +            window: settings.window,              flags: settings.flags,              fonts: settings.fonts, -            exit_on_close_request: settings.exit_on_close_request,          }      }  } diff --git a/src/window.rs b/src/window.rs index e4601575..9f96da52 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,12 +1,8 @@  //! Configure the window of your application in native platforms. -mod position; -mod settings;  pub mod icon;  pub use icon::Icon; -pub use position::Position; -pub use settings::{PlatformSpecific, Settings};  pub use crate::core::window::*;  pub use crate::runtime::window::*; diff --git a/src/window/position.rs b/src/window/position.rs deleted file mode 100644 index 6b9fac41..00000000 --- a/src/window/position.rs +++ /dev/null @@ -1,32 +0,0 @@ -/// The position of a window in a given screen. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Position { -    /// The platform-specific default position for a new window. -    Default, -    /// The window is completely centered on the screen. -    Centered, -    /// The window is positioned with specific coordinates: `(X, Y)`. -    /// -    /// When the decorations of the window are enabled, Windows 10 will add some -    /// invisible padding to the window. This padding gets included in the -    /// position. So if you have decorations enabled and want the window to be -    /// at (0, 0) you would have to set the position to -    /// `(PADDING_X, PADDING_Y)`. -    Specific(i32, i32), -} - -impl Default for Position { -    fn default() -> Self { -        Self::Default -    } -} - -impl From<Position> for iced_winit::Position { -    fn from(position: Position) -> Self { -        match position { -            Position::Default => Self::Default, -            Position::Centered => Self::Centered, -            Position::Specific(x, y) => Self::Specific(x, y), -        } -    } -} diff --git a/src/window/settings.rs b/src/window/settings.rs deleted file mode 100644 index 0ee573e5..00000000 --- a/src/window/settings.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::window::{Icon, Level, Position}; - -pub use iced_winit::settings::PlatformSpecific; - -/// The window settings of an application. -#[derive(Debug, Clone)] -pub struct Settings { -    /// The initial size of the window. -    pub size: (u32, u32), - -    /// The initial position of the window. -    pub position: Position, - -    /// The minimum size of the window. -    pub min_size: Option<(u32, u32)>, - -    /// The maximum size of the window. -    pub max_size: Option<(u32, u32)>, - -    /// Whether the window should be visible or not. -    pub visible: bool, - -    /// 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, - -    /// Whether the window should be transparent. -    pub transparent: bool, - -    /// The window [`Level`]. -    pub level: Level, - -    /// The icon of the window. -    pub icon: Option<Icon>, - -    /// Platform specific settings. -    pub platform_specific: PlatformSpecific, -} - -impl Default for Settings { -    fn default() -> Settings { -        Settings { -            size: (1024, 768), -            position: Position::default(), -            min_size: None, -            max_size: None, -            visible: true, -            resizable: true, -            decorations: true, -            transparent: false, -            level: Level::default(), -            icon: None, -            platform_specific: PlatformSpecific::default(), -        } -    } -} - -impl From<Settings> for iced_winit::settings::Window { -    fn from(settings: Settings) -> Self { -        Self { -            size: settings.size, -            position: iced_winit::Position::from(settings.position), -            min_size: settings.min_size, -            max_size: settings.max_size, -            visible: settings.visible, -            resizable: settings.resizable, -            decorations: settings.decorations, -            transparent: settings.transparent, -            level: settings.level, -            icon: settings.icon.map(Icon::into), -            platform_specific: settings.platform_specific, -        } -    } -}  | 
