//! Create and run iced applications step by step. //! //! # Example //! ```no_run //! use iced::widget::{button, column, text, Column}; //! use iced::Theme; //! //! pub fn main() -> iced::Result { //! iced::program("A counter", update, view) //! .theme(|_| Theme::Dark) //! .centered() //! .run() //! } //! //! #[derive(Debug, Clone)] //! enum Message { //! Increment, //! } //! //! fn update(value: &mut u64, message: Message) { //! match message { //! Message::Increment => *value += 1, //! } //! } //! //! fn view(value: &u64) -> Column { //! column![ //! text(value), //! button("+").on_press(Message::Increment), //! ] //! } //! ``` use crate::application::Application; use crate::core::text; use crate::executor::{self, Executor}; use crate::graphics::compositor; use crate::window; use crate::{Command, Element, Font, Result, Settings, Size, Subscription}; pub use crate::application::{Appearance, DefaultStyle}; use std::borrow::Cow; /// Creates an iced [`Program`] given its title, update, and view logic. /// /// # Example /// ```no_run /// use iced::widget::{button, column, text, Column}; /// /// pub fn main() -> iced::Result { /// iced::program("A counter", update, view).run() /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// Increment, /// } /// /// fn update(value: &mut u64, message: Message) { /// match message { /// Message::Increment => *value += 1, /// } /// } /// /// fn view(value: &u64) -> Column { /// column![ /// text(value), /// button("+").on_press(Message::Increment), /// ] /// } /// ``` pub fn program( title: impl Title, update: impl Update, view: impl for<'a> self::View<'a, State, Message, Theme, Renderer>, ) -> Program> where State: 'static, Message: Send + std::fmt::Debug, Theme: Default + DefaultStyle, Renderer: self::Renderer, { use std::marker::PhantomData; struct Application { update: Update, view: View, _state: PhantomData, _message: PhantomData, _theme: PhantomData, _renderer: PhantomData, } impl Definition for Application where Message: Send + std::fmt::Debug, Theme: Default + DefaultStyle, Renderer: self::Renderer, Update: self::Update, View: for<'a> self::View<'a, State, Message, Theme, Renderer>, { type State = State; type Message = Message; type Theme = Theme; type Renderer = Renderer; type Executor = executor::Default; fn load(&self) -> Command { Command::none() } fn update( &self, state: &mut Self::State, message: Self::Message, ) -> Command { self.update.update(state, message).into() } fn view<'a>( &self, state: &'a Self::State, ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { self.view.view(state).into() } } Program { raw: Application { update, view, _state: PhantomData, _message: PhantomData, _theme: PhantomData, _renderer: PhantomData, }, settings: Settings::default(), } .title(title) } /// The underlying definition and configuration of an iced application. /// /// You can use this API to create and run iced applications /// step by step—without coupling your logic to a trait /// or a specific type. /// /// You can create a [`Program`] with the [`program`] helper. /// /// [`run`]: Program::run #[derive(Debug)] pub struct Program { raw: P, settings: Settings, } impl Program

{ /// Runs the underlying [`Application`] of the [`Program`]. /// /// The state of the [`Program`] must implement [`Default`]. /// If your state does not implement [`Default`], use [`run_with`] /// instead. /// /// [`run_with`]: Self::run_with pub fn run(self) -> Result where Self: 'static, P::State: Default, { self.run_with(P::State::default) } /// Runs the underlying [`Application`] of the [`Program`] with a /// closure that creates the initial state. pub fn run_with( self, initialize: impl Fn() -> P::State + Clone + 'static, ) -> Result where Self: 'static, { use std::marker::PhantomData; struct Instance { program: P, state: P::State, _initialize: PhantomData, } impl P::State> Application for Instance { type Message = P::Message; type Theme = P::Theme; type Renderer = P::Renderer; type Flags = (P, I); type Executor = P::Executor; fn new( (program, initialize): Self::Flags, ) -> (Self, Command) { let state = initialize(); let command = program.load(); ( Self { program, state, _initialize: PhantomData, }, command, ) } fn title(&self) -> String { self.program.title(&self.state) } fn update( &mut self, message: Self::Message, ) -> Command { self.program.update(&mut self.state, message) } fn view( &self, ) -> crate::Element<'_, Self::Message, Self::Theme, Self::Renderer> { self.program.view(&self.state) } fn subscription(&self) -> Subscription { self.program.subscription(&self.state) } fn theme(&self) -> Self::Theme { self.program.theme(&self.state) } fn style(&self, theme: &Self::Theme) -> Appearance { self.program.style(&self.state, theme) } } let Self { raw, settings } = self; Instance::run(Settings { flags: (raw, initialize), id: settings.id, window: settings.window, fonts: settings.fonts, default_font: settings.default_font, default_text_size: settings.default_text_size, antialiasing: settings.antialiasing, }) } /// Sets the [`Settings`] that will be used to run the [`Program`]. pub fn settings(self, settings: Settings) -> Self { Self { settings, ..self } } /// Sets the [`Settings::antialiasing`] of the [`Program`]. pub fn antialiasing(self, antialiasing: bool) -> Self { Self { settings: Settings { antialiasing, ..self.settings }, ..self } } /// Sets the default [`Font`] of the [`Program`]. pub fn default_font(self, default_font: Font) -> Self { Self { settings: Settings { default_font, ..self.settings }, ..self } } /// Adds a font to the list of fonts that will be loaded at the start of the [`Program`]. pub fn font(mut self, font: impl Into>) -> Self { self.settings.fonts.push(font.into()); self } /// Sets the [`window::Settings::position`] to [`window::Position::Centered`] in the [`Program`]. pub fn centered(self) -> Self { Self { settings: Settings { window: window::Settings { position: window::Position::Centered, ..self.settings.window }, ..self.settings }, ..self } } /// Sets the [`window::Settings::exit_on_close_request`] of the [`Program`]. pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self { Self { settings: Settings { window: window::Settings { exit_on_close_request, ..self.settings.window }, ..self.settings }, ..self } } /// Sets the [`window::Settings::size`] of the [`Program`]. pub fn window_size(self, size: impl Into) -> Self { Self { settings: Settings { window: window::Settings { size: size.into(), ..self.settings.window }, ..self.settings }, ..self } } /// Sets the [`window::Settings::transparent`] of the [`Program`]. pub fn transparent(self, transparent: bool) -> Self { Self { settings: Settings { window: window::Settings { transparent, ..self.settings.window }, ..self.settings }, ..self } } /// Sets the [`Title`] of the [`Program`]. pub(crate) fn title( self, title: impl Title, ) -> Program< impl Definition, > { Program { raw: with_title(self.raw, title), settings: self.settings, } } /// Runs the [`Command`] produced by the closure at startup. pub fn load( self, f: impl Fn() -> Command, ) -> Program< impl Definition, > { Program { raw: with_load(self.raw, f), settings: self.settings, } } /// Sets the subscription logic of the [`Program`]. pub fn subscription( self, f: impl Fn(&P::State) -> Subscription, ) -> Program< impl Definition, > { Program { raw: with_subscription(self.raw, f), settings: self.settings, } } /// Sets the theme logic of the [`Program`]. pub fn theme( self, f: impl Fn(&P::State) -> P::Theme, ) -> Program< impl Definition, > { Program { raw: with_theme(self.raw, f), settings: self.settings, } } /// Sets the style logic of the [`Program`]. pub fn style( self, f: impl Fn(&P::State, &P::Theme) -> Appearance, ) -> Program< impl Definition, > { Program { raw: with_style(self.raw, f), settings: self.settings, } } } /// The internal definition of a [`Program`]. /// /// You should not need to implement this trait directly. Instead, use the /// methods available in the [`Program`] struct. #[allow(missing_docs)] pub trait Definition: Sized { /// The state of the program. type State; /// The message of the program. type Message: Send + std::fmt::Debug; /// The theme of the program. type Theme: Default + DefaultStyle; /// The renderer of the program. type Renderer: Renderer; /// The executor of the program. type Executor: Executor; fn load(&self) -> Command; fn update( &self, state: &mut Self::State, message: Self::Message, ) -> Command; fn view<'a>( &self, state: &'a Self::State, ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer>; fn title(&self, _state: &Self::State) -> String { String::from("A cool iced application!") } fn subscription( &self, _state: &Self::State, ) -> Subscription { Subscription::none() } fn theme(&self, _state: &Self::State) -> Self::Theme { Self::Theme::default() } fn style(&self, _state: &Self::State, theme: &Self::Theme) -> Appearance { DefaultStyle::default_style(theme) } } fn with_title( program: P, title: impl Title, ) -> impl Definition { struct WithTitle { program: P, title: Title, } impl Definition for WithTitle where P: Definition, Title: self::Title, { type State = P::State; type Message = P::Message; type Theme = P::Theme; type Renderer = P::Renderer; type Executor = P::Executor; fn load(&self) -> Command { self.program.load() } fn title(&self, state: &Self::State) -> String { self.title.title(state) } fn update( &self, state: &mut Self::State, message: Self::Message, ) -> Command { self.program.update(state, message) } fn view<'a>( &self, state: &'a Self::State, ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { self.program.view(state) } fn theme(&self, state: &Self::State) -> Self::Theme { self.program.theme(state) } fn subscription( &self, state: &Self::State, ) -> Subscription { self.program.subscription(state) } fn style( &self, state: &Self::State, theme: &Self::Theme, ) -> Appearance { self.program.style(state, theme) } } WithTitle { program, title } } fn with_load( program: P, f: impl Fn() -> Command, ) -> impl Definition { struct WithLoad { program: P, load: F, } impl Definition for WithLoad where F: Fn() -> Command, { type State = P::State; type Message = P::Message; type Theme = P::Theme; type Renderer = P::Renderer; type Executor = executor::Default; fn load(&self) -> Command { Command::batch([self.program.load(), (self.load)()]) } fn update( &self, state: &mut Self::State, message: Self::Message, ) -> Command { self.program.update(state, message) } fn view<'a>( &self, state: &'a Self::State, ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { self.program.view(state) } fn title(&self, state: &Self::State) -> String { self.program.title(state) } fn subscription( &self, state: &Self::State, ) -> Subscription { self.program.subscription(state) } fn theme(&self, state: &Self::State) -> Self::Theme { self.program.theme(state) } fn style( &self, state: &Self::State, theme: &Self::Theme, ) -> Appearance { self.program.style(state, theme) } } WithLoad { program, load: f } } fn with_subscription( program: P, f: impl Fn(&P::State) -> Subscription, ) -> impl Definition { struct WithSubscription { program: P, subscription: F, } impl Definition for WithSubscription where F: Fn(&P::State) -> Subscription, { type State = P::State; type Message = P::Message; type Theme = P::Theme; type Renderer = P::Renderer; type Executor = executor::Default; fn subscription( &self, state: &Self::State, ) -> Subscription { (self.subscription)(state) } fn load(&self) -> Command { self.program.load() } fn update( &self, state: &mut Self::State, message: Self::Message, ) -> Command { self.program.update(state, message) } fn view<'a>( &self, state: &'a Self::State, ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { self.program.view(state) } fn title(&self, state: &Self::State) -> String { self.program.title(state) } fn theme(&self, state: &Self::State) -> Self::Theme { self.program.theme(state) } fn style( &self, state: &Self::State, theme: &Self::Theme, ) -> Appearance { self.program.style(state, theme) } } WithSubscription { program, subscription: f, } } fn with_theme( program: P, f: impl Fn(&P::State) -> P::Theme, ) -> impl Definition { struct WithTheme { program: P, theme: F, } impl Definition for WithTheme where F: Fn(&P::State) -> P::Theme, { type State = P::State; type Message = P::Message; type Theme = P::Theme; type Renderer = P::Renderer; type Executor = P::Executor; fn theme(&self, state: &Self::State) -> Self::Theme { (self.theme)(state) } fn load(&self) -> Command { self.program.load() } fn title(&self, state: &Self::State) -> String { self.program.title(state) } fn update( &self, state: &mut Self::State, message: Self::Message, ) -> Command { self.program.update(state, message) } fn view<'a>( &self, state: &'a Self::State, ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { self.program.view(state) } fn subscription( &self, state: &Self::State, ) -> Subscription { self.program.subscription(state) } fn style( &self, state: &Self::State, theme: &Self::Theme, ) -> Appearance { self.program.style(state, theme) } } WithTheme { program, theme: f } } fn with_style( program: P, f: impl Fn(&P::State, &P::Theme) -> Appearance, ) -> impl Definition { struct WithStyle { program: P, style: F, } impl Definition for WithStyle where F: Fn(&P::State, &P::Theme) -> Appearance, { type State = P::State; type Message = P::Message; type Theme = P::Theme; type Renderer = P::Renderer; type Executor = P::Executor; fn style( &self, state: &Self::State, theme: &Self::Theme, ) -> Appearance { (self.style)(state, theme) } fn load(&self) -> Command { self.program.load() } fn title(&self, state: &Self::State) -> String { self.program.title(state) } fn update( &self, state: &mut Self::State, message: Self::Message, ) -> Command { self.program.update(state, message) } fn view<'a>( &self, state: &'a Self::State, ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { self.program.view(state) } fn subscription( &self, state: &Self::State, ) -> Subscription { self.program.subscription(state) } fn theme(&self, state: &Self::State) -> Self::Theme { self.program.theme(state) } } WithStyle { program, style: f } } /// The title logic of some [`Program`]. /// /// This trait is implemented both for `&static str` and /// any closure `Fn(&State) -> String`. /// /// This trait allows the [`program`] builder to take any of them. pub trait Title { /// Produces the title of the [`Program`]. fn title(&self, state: &State) -> String; } impl Title for &'static str { fn title(&self, _state: &State) -> String { self.to_string() } } impl Title for T where T: Fn(&State) -> String, { fn title(&self, state: &State) -> String { self(state) } } /// The update logic of some [`Program`]. /// /// This trait allows the [`program`] builder to take any closure that /// returns any `Into>`. pub trait Update { /// Processes the message and updates the state of the [`Program`]. fn update( &self, state: &mut State, message: Message, ) -> impl Into>; } impl Update for T where T: Fn(&mut State, Message) -> C, C: Into>, { fn update( &self, state: &mut State, message: Message, ) -> impl Into> { self(state, message) } } /// The view logic of some [`Program`]. /// /// This trait allows the [`program`] builder to take any closure that /// returns any `Into>`. pub trait View<'a, State, Message, Theme, Renderer> { /// Produces the widget of the [`Program`]. fn view( &self, state: &'a State, ) -> impl Into>; } impl<'a, T, State, Message, Theme, Renderer, Widget> View<'a, State, Message, Theme, Renderer> for T where T: Fn(&'a State) -> Widget, State: 'static, Widget: Into>, { fn view( &self, state: &'a State, ) -> impl Into> { self(state) } } /// The renderer of some [`Program`]. pub trait Renderer: text::Renderer + compositor::Default {} impl Renderer for T where T: text::Renderer + compositor::Default {}