iced/
application.rs

1//! Create and run iced applications step by step.
2//!
3//! # Example
4//! ```no_run
5//! use iced::widget::{button, column, text, Column};
6//! use iced::Theme;
7//!
8//! pub fn main() -> iced::Result {
9//!     iced::application("A counter", update, view)
10//!         .theme(|_| Theme::Dark)
11//!         .centered()
12//!         .run()
13//! }
14//!
15//! #[derive(Debug, Clone)]
16//! enum Message {
17//!     Increment,
18//! }
19//!
20//! fn update(value: &mut u64, message: Message) {
21//!     match message {
22//!         Message::Increment => *value += 1,
23//!     }
24//! }
25//!
26//! fn view(value: &u64) -> Column<Message> {
27//!     column![
28//!         text(value),
29//!         button("+").on_press(Message::Increment),
30//!     ]
31//! }
32//! ```
33use crate::program::{self, Program};
34#[cfg(not(feature = "winit"))]
35use crate::runtime::{Appearance, DefaultStyle};
36#[cfg(feature = "winit")]
37pub use crate::shell::program::{Appearance, DefaultStyle};
38use crate::window;
39use crate::{Element, Executor, Font, Settings, Size, Subscription, Task};
40
41use std::borrow::Cow;
42
43/// Creates an iced [`Application`] given its title, update, and view logic.
44///
45/// # Example
46/// ```no_run
47/// use iced::widget::{button, column, text, Column};
48///
49/// pub fn main() -> iced::Result {
50///     iced::application("A counter", update, view).run()
51/// }
52///
53/// #[derive(Debug, Clone)]
54/// enum Message {
55///     Increment,
56/// }
57///
58/// fn update(value: &mut u64, message: Message) {
59///     match message {
60///         Message::Increment => *value += 1,
61///     }
62/// }
63///
64/// fn view(value: &u64) -> Column<Message> {
65///     column![
66///         text(value),
67///         button("+").on_press(Message::Increment),
68///     ]
69/// }
70/// ```
71pub fn application<State, Message, Theme, Renderer>(
72    title: impl Title<State>,
73    update: impl Update<State, Message>,
74    view: impl for<'a> self::View<'a, State, Message, Theme, Renderer>,
75) -> Application<impl Program<State = State, Message = Message, Theme = Theme>>
76where
77    State: 'static,
78    Message: Send + std::fmt::Debug + 'static,
79    Theme: Default + DefaultStyle,
80    Renderer: program::Renderer,
81{
82    use std::marker::PhantomData;
83
84    struct Instance<State, Message, Theme, Renderer, Update, View> {
85        update: Update,
86        view: View,
87        _state: PhantomData<State>,
88        _message: PhantomData<Message>,
89        _theme: PhantomData<Theme>,
90        _renderer: PhantomData<Renderer>,
91    }
92
93    impl<State, Message, Theme, Renderer, Update, View> Program
94        for Instance<State, Message, Theme, Renderer, Update, View>
95    where
96        Message: Send + std::fmt::Debug + 'static,
97        Theme: Default + DefaultStyle,
98        Renderer: program::Renderer,
99        Update: self::Update<State, Message>,
100        View: for<'a> self::View<'a, State, Message, Theme, Renderer>,
101    {
102        type State = State;
103        type Message = Message;
104        type Theme = Theme;
105        type Renderer = Renderer;
106        type Executor = iced_futures::backend::default::Executor;
107
108        fn update(
109            &self,
110            state: &mut Self::State,
111            message: Self::Message,
112        ) -> Task<Self::Message> {
113            self.update.update(state, message).into()
114        }
115
116        fn view<'a>(
117            &self,
118            state: &'a Self::State,
119            _window: window::Id,
120        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
121            self.view.view(state).into()
122        }
123    }
124
125    Application {
126        raw: Instance {
127            update,
128            view,
129            _state: PhantomData,
130            _message: PhantomData,
131            _theme: PhantomData,
132            _renderer: PhantomData,
133        },
134        settings: Settings::default(),
135        window: window::Settings::default(),
136    }
137    .title(title)
138}
139
140/// The underlying definition and configuration of an iced application.
141///
142/// You can use this API to create and run iced applications
143/// step by step—without coupling your logic to a trait
144/// or a specific type.
145///
146/// You can create an [`Application`] with the [`application`] helper.
147#[derive(Debug)]
148pub struct Application<P: Program> {
149    raw: P,
150    settings: Settings,
151    window: window::Settings,
152}
153
154impl<P: Program> Application<P> {
155    #[cfg(feature = "winit")]
156    /// Runs the [`Application`].
157    ///
158    /// The state of the [`Application`] must implement [`Default`].
159    /// If your state does not implement [`Default`], use [`run_with`]
160    /// instead.
161    ///
162    /// [`run_with`]: Self::run_with
163    pub fn run(self) -> crate::Result
164    where
165        Self: 'static,
166        P::State: Default,
167    {
168        self.raw.run(self.settings, Some(self.window))
169    }
170
171    #[cfg(feature = "winit")]
172    /// Runs the [`Application`] with a closure that creates the initial state.
173    pub fn run_with<I>(self, initialize: I) -> crate::Result
174    where
175        Self: 'static,
176        I: FnOnce() -> (P::State, Task<P::Message>) + 'static,
177    {
178        self.raw
179            .run_with(self.settings, Some(self.window), initialize)
180    }
181
182    /// Sets the [`Settings`] that will be used to run the [`Application`].
183    pub fn settings(self, settings: Settings) -> Self {
184        Self { settings, ..self }
185    }
186
187    /// Sets the [`Settings::antialiasing`] of the [`Application`].
188    pub fn antialiasing(self, antialiasing: bool) -> Self {
189        Self {
190            settings: Settings {
191                antialiasing,
192                ..self.settings
193            },
194            ..self
195        }
196    }
197
198    /// Sets the default [`Font`] of the [`Application`].
199    pub fn default_font(self, default_font: Font) -> Self {
200        Self {
201            settings: Settings {
202                default_font,
203                ..self.settings
204            },
205            ..self
206        }
207    }
208
209    /// Adds a font to the list of fonts that will be loaded at the start of the [`Application`].
210    pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {
211        self.settings.fonts.push(font.into());
212        self
213    }
214
215    /// Sets the [`window::Settings`] of the [`Application`].
216    ///
217    /// Overwrites any previous [`window::Settings`].
218    pub fn window(self, window: window::Settings) -> Self {
219        Self { window, ..self }
220    }
221
222    /// Sets the [`window::Settings::position`] to [`window::Position::Centered`] in the [`Application`].
223    pub fn centered(self) -> Self {
224        Self {
225            window: window::Settings {
226                position: window::Position::Centered,
227                ..self.window
228            },
229            ..self
230        }
231    }
232
233    /// Sets the [`window::Settings::exit_on_close_request`] of the [`Application`].
234    pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self {
235        Self {
236            window: window::Settings {
237                exit_on_close_request,
238                ..self.window
239            },
240            ..self
241        }
242    }
243
244    /// Sets the [`window::Settings::size`] of the [`Application`].
245    pub fn window_size(self, size: impl Into<Size>) -> Self {
246        Self {
247            window: window::Settings {
248                size: size.into(),
249                ..self.window
250            },
251            ..self
252        }
253    }
254
255    /// Sets the [`window::Settings::transparent`] of the [`Application`].
256    pub fn transparent(self, transparent: bool) -> Self {
257        Self {
258            window: window::Settings {
259                transparent,
260                ..self.window
261            },
262            ..self
263        }
264    }
265
266    /// Sets the [`window::Settings::resizable`] of the [`Application`].
267    pub fn resizable(self, resizable: bool) -> Self {
268        Self {
269            window: window::Settings {
270                resizable,
271                ..self.window
272            },
273            ..self
274        }
275    }
276
277    /// Sets the [`window::Settings::decorations`] of the [`Application`].
278    pub fn decorations(self, decorations: bool) -> Self {
279        Self {
280            window: window::Settings {
281                decorations,
282                ..self.window
283            },
284            ..self
285        }
286    }
287
288    /// Sets the [`window::Settings::position`] of the [`Application`].
289    pub fn position(self, position: window::Position) -> Self {
290        Self {
291            window: window::Settings {
292                position,
293                ..self.window
294            },
295            ..self
296        }
297    }
298
299    /// Sets the [`window::Settings::level`] of the [`Application`].
300    pub fn level(self, level: window::Level) -> Self {
301        Self {
302            window: window::Settings {
303                level,
304                ..self.window
305            },
306            ..self
307        }
308    }
309
310    /// Sets the [`Title`] of the [`Application`].
311    pub(crate) fn title(
312        self,
313        title: impl Title<P::State>,
314    ) -> Application<
315        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
316    > {
317        Application {
318            raw: program::with_title(self.raw, move |state, _window| {
319                title.title(state)
320            }),
321            settings: self.settings,
322            window: self.window,
323        }
324    }
325
326    /// Sets the subscription logic of the [`Application`].
327    pub fn subscription(
328        self,
329        f: impl Fn(&P::State) -> Subscription<P::Message>,
330    ) -> Application<
331        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
332    > {
333        Application {
334            raw: program::with_subscription(self.raw, f),
335            settings: self.settings,
336            window: self.window,
337        }
338    }
339
340    /// Sets the theme logic of the [`Application`].
341    pub fn theme(
342        self,
343        f: impl Fn(&P::State) -> P::Theme,
344    ) -> Application<
345        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
346    > {
347        Application {
348            raw: program::with_theme(self.raw, move |state, _window| f(state)),
349            settings: self.settings,
350            window: self.window,
351        }
352    }
353
354    /// Sets the style logic of the [`Application`].
355    pub fn style(
356        self,
357        f: impl Fn(&P::State, &P::Theme) -> Appearance,
358    ) -> Application<
359        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
360    > {
361        Application {
362            raw: program::with_style(self.raw, f),
363            settings: self.settings,
364            window: self.window,
365        }
366    }
367
368    /// Sets the scale factor of the [`Application`].
369    pub fn scale_factor(
370        self,
371        f: impl Fn(&P::State) -> f64,
372    ) -> Application<
373        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
374    > {
375        Application {
376            raw: program::with_scale_factor(self.raw, move |state, _window| {
377                f(state)
378            }),
379            settings: self.settings,
380            window: self.window,
381        }
382    }
383
384    /// Sets the executor of the [`Application`].
385    pub fn executor<E>(
386        self,
387    ) -> Application<
388        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
389    >
390    where
391        E: Executor,
392    {
393        Application {
394            raw: program::with_executor::<P, E>(self.raw),
395            settings: self.settings,
396            window: self.window,
397        }
398    }
399}
400
401/// The title logic of some [`Application`].
402///
403/// This trait is implemented both for `&static str` and
404/// any closure `Fn(&State) -> String`.
405///
406/// This trait allows the [`application`] builder to take any of them.
407pub trait Title<State> {
408    /// Produces the title of the [`Application`].
409    fn title(&self, state: &State) -> String;
410}
411
412impl<State> Title<State> for &'static str {
413    fn title(&self, _state: &State) -> String {
414        self.to_string()
415    }
416}
417
418impl<T, State> Title<State> for T
419where
420    T: Fn(&State) -> String,
421{
422    fn title(&self, state: &State) -> String {
423        self(state)
424    }
425}
426
427/// The update logic of some [`Application`].
428///
429/// This trait allows the [`application`] builder to take any closure that
430/// returns any `Into<Task<Message>>`.
431pub trait Update<State, Message> {
432    /// Processes the message and updates the state of the [`Application`].
433    fn update(
434        &self,
435        state: &mut State,
436        message: Message,
437    ) -> impl Into<Task<Message>>;
438}
439
440impl<State, Message> Update<State, Message> for () {
441    fn update(
442        &self,
443        _state: &mut State,
444        _message: Message,
445    ) -> impl Into<Task<Message>> {
446    }
447}
448
449impl<T, State, Message, C> Update<State, Message> for T
450where
451    T: Fn(&mut State, Message) -> C,
452    C: Into<Task<Message>>,
453{
454    fn update(
455        &self,
456        state: &mut State,
457        message: Message,
458    ) -> impl Into<Task<Message>> {
459        self(state, message)
460    }
461}
462
463/// The view logic of some [`Application`].
464///
465/// This trait allows the [`application`] builder to take any closure that
466/// returns any `Into<Element<'_, Message>>`.
467pub trait View<'a, State, Message, Theme, Renderer> {
468    /// Produces the widget of the [`Application`].
469    fn view(
470        &self,
471        state: &'a State,
472    ) -> impl Into<Element<'a, Message, Theme, Renderer>>;
473}
474
475impl<'a, T, State, Message, Theme, Renderer, Widget>
476    View<'a, State, Message, Theme, Renderer> for T
477where
478    T: Fn(&'a State) -> Widget,
479    State: 'static,
480    Widget: Into<Element<'a, Message, Theme, Renderer>>,
481{
482    fn view(
483        &self,
484        state: &'a State,
485    ) -> impl Into<Element<'a, Message, Theme, Renderer>> {
486        self(state)
487    }
488}