Skip to main content

iced/
application.rs

1//! Create and run iced applications step by step.
2//!
3//! # Example
4//! ```no_run,standalone_crate
5//! use iced::widget::{button, column, text, Widget};
6//! use iced::Theme;
7//!
8//! pub fn main() -> iced::Result {
9//!     iced::application(u64::default, 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) -> impl Widget<Message> {
27//!     column![
28//!         text(value),
29//!         button("+").on_press(Message::Increment),
30//!     ]
31//! }
32//! ```
33use crate::backend;
34use crate::core::Widget;
35use crate::message;
36use crate::program::{self, Program};
37use crate::shell;
38use crate::theme;
39use crate::widget::text;
40use crate::window;
41use crate::{
42    Backend, Executor, Font, Never, Preset, Result, Settings, Size, Subscription, Task, Theme,
43};
44
45#[cfg(feature = "hot")]
46use crate::hot::Hot;
47
48use std::borrow::Cow;
49
50pub mod timed;
51
52pub use timed::timed;
53
54/// Creates an iced [`Application`] given its boot, update, and view logic.
55///
56/// # Example
57/// ```no_run,standalone_crate
58/// use iced::widget::{button, column, text, Widget};
59///
60/// pub fn main() -> iced::Result {
61///     iced::application(u64::default, update, view).run()
62/// }
63///
64/// #[derive(Debug, Clone)]
65/// enum Message {
66///     Increment,
67/// }
68///
69/// fn update(value: &mut u64, message: Message) {
70///     match message {
71///         Message::Increment => *value += 1,
72///     }
73/// }
74///
75/// fn view(value: &u64) -> impl Widget<Message> {
76///     column![
77///         text(value),
78///         button("+").on_press(Message::Increment),
79///     ]
80/// }
81/// ```
82pub fn application<State, Message, Theme, Renderer>(
83    boot: impl BootFn<State, Message>,
84    update: impl UpdateFn<State, Message>,
85    view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,
86) -> Application<impl Program<State = State, Message = Message, Theme = Theme>>
87where
88    State: 'static,
89    Message: Send + 'static,
90    Theme: theme::Base,
91    Renderer: program::Renderer,
92{
93    use std::marker::PhantomData;
94
95    struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {
96        boot: Boot,
97        update: Update,
98        view: View,
99        _state: PhantomData<State>,
100        _message: PhantomData<Message>,
101        _theme: PhantomData<Theme>,
102        _renderer: PhantomData<Renderer>,
103    }
104
105    impl<State, Message, Theme, Renderer, Boot, Update, View> Program
106        for Instance<State, Message, Theme, Renderer, Boot, Update, View>
107    where
108        Message: Send + 'static,
109        Theme: theme::Base,
110        Renderer: program::Renderer,
111        Boot: self::BootFn<State, Message>,
112        Update: self::UpdateFn<State, Message>,
113        View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,
114    {
115        type State = State;
116        type Message = Message;
117        type Theme = Theme;
118        type Renderer = Renderer;
119        type Executor = iced_futures::backend::default::Executor;
120
121        fn name() -> &'static str {
122            let name = std::any::type_name::<State>();
123
124            name.split("::").next().unwrap_or("a_cool_application")
125        }
126
127        fn boot(&self) -> (State, Task<Message>) {
128            self.boot.boot()
129        }
130
131        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
132            self.update.update(state, message)
133        }
134
135        fn view<'a>(
136            &self,
137            state: &'a Self::State,
138            _window: window::Id,
139        ) -> impl Widget<Message, Theme, Renderer> + 'a {
140            self.view.view(state)
141        }
142
143        fn settings(&self) -> Settings {
144            Settings::default()
145        }
146
147        fn window(&self) -> Option<iced_core::window::Settings> {
148            Some(window::Settings::default())
149        }
150    }
151
152    Application {
153        raw: Instance {
154            boot,
155            update,
156            view,
157            _state: PhantomData,
158            _message: PhantomData,
159            _theme: PhantomData,
160            _renderer: PhantomData,
161        },
162        settings: Settings::default(),
163        window: window::Settings::default(),
164        presets: Vec::new(),
165    }
166}
167
168/// The underlying definition and configuration of an iced application.
169///
170/// You can use this API to create and run iced applications
171/// step by step—without coupling your logic to a trait
172/// or a specific type.
173///
174/// You can create an [`Application`] with the [`application`] helper.
175#[derive(Debug)]
176pub struct Application<P: Program> {
177    raw: P,
178    settings: Settings,
179    window: window::Settings,
180    presets: Vec<Preset<P::State, P::Message>>,
181}
182
183impl<P: Program> Application<P> {
184    /// Runs the [`Application`].
185    pub fn run(self) -> Result
186    where
187        Self: 'static,
188        P::Message: message::MaybeDebug + message::MaybeClone,
189    {
190        #[cfg(feature = "debug")]
191        iced_debug::init(iced_debug::Metadata {
192            name: P::name(),
193            theme: None,
194            can_time_travel: cfg!(feature = "time-travel"),
195        });
196
197        #[cfg(feature = "tester")]
198        let program = iced_tester::attach(self);
199
200        #[cfg(all(
201            feature = "debug",
202            not(feature = "tester"),
203            not(target_arch = "wasm32")
204        ))]
205        let program = iced_devtools::attach(self);
206
207        #[cfg(not(any(
208            feature = "tester",
209            all(feature = "debug", not(target_arch = "wasm32"))
210        )))]
211        let program = self;
212
213        #[cfg(feature = "hot")]
214        let program = Hot::new(program);
215
216        Ok(shell::run(program)?)
217    }
218
219    /// Sets the [`Settings`] that will be used to run the [`Application`].
220    pub fn settings(self, settings: Settings) -> Self {
221        Self { settings, ..self }
222    }
223
224    /// Sets the [`Settings::antialiasing`] of the [`Application`].
225    pub fn antialiasing(self, antialiasing: bool) -> Self {
226        Self {
227            settings: Settings {
228                antialiasing,
229                ..self.settings
230            },
231            ..self
232        }
233    }
234
235    /// Sets the default [`Font`] of the [`Application`].
236    pub fn font(self, font: Font) -> Self {
237        Self {
238            settings: Settings {
239                font,
240                ..self.settings
241            },
242            ..self
243        }
244    }
245
246    /// Sets the default [`text::LineHeight`] of the [`Application`].
247    pub fn line_height(self, line_height: text::LineHeight) -> Self {
248        Self {
249            settings: Settings {
250                line_height,
251                ..self.settings
252            },
253            ..self
254        }
255    }
256
257    /// Adds a set of fonts to the list of fonts that will be loaded at the start of the [`Application`].
258    pub fn fonts(mut self, fonts: impl IntoIterator<Item = impl Into<Cow<'static, [u8]>>>) -> Self {
259        self.settings
260            .fonts
261            .extend(fonts.into_iter().map(Into::into));
262
263        self
264    }
265
266    /// Sets the [`window::Settings`] of the [`Application`].
267    ///
268    /// Overwrites any previous [`window::Settings`].
269    pub fn window(self, window: window::Settings) -> Self {
270        Self { window, ..self }
271    }
272
273    /// Sets the [`window::Settings::position`] to [`window::Position::Centered`] in the [`Application`].
274    pub fn centered(self) -> Self {
275        Self {
276            window: window::Settings {
277                position: window::Position::Centered,
278                ..self.window
279            },
280            ..self
281        }
282    }
283
284    /// Sets the [`window::Settings::exit_on_close_request`] of the [`Application`].
285    pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self {
286        Self {
287            window: window::Settings {
288                exit_on_close_request,
289                ..self.window
290            },
291            ..self
292        }
293    }
294
295    /// Sets the [`window::Settings::size`] of the [`Application`].
296    pub fn window_size(self, size: impl Into<Size>) -> Self {
297        Self {
298            window: window::Settings {
299                size: size.into(),
300                ..self.window
301            },
302            ..self
303        }
304    }
305
306    /// Sets the [`window::Settings::transparent`] of the [`Application`].
307    pub fn transparent(self, transparent: bool) -> Self {
308        Self {
309            window: window::Settings {
310                transparent,
311                ..self.window
312            },
313            ..self
314        }
315    }
316
317    /// Sets the [`window::Settings::resizable`] of the [`Application`].
318    pub fn resizable(self, resizable: bool) -> Self {
319        Self {
320            window: window::Settings {
321                resizable,
322                ..self.window
323            },
324            ..self
325        }
326    }
327
328    /// Sets the [`window::Settings::decorations`] of the [`Application`].
329    pub fn decorations(self, decorations: bool) -> Self {
330        Self {
331            window: window::Settings {
332                decorations,
333                ..self.window
334            },
335            ..self
336        }
337    }
338
339    /// Sets the [`window::Settings::position`] of the [`Application`].
340    pub fn position(self, position: window::Position) -> Self {
341        Self {
342            window: window::Settings {
343                position,
344                ..self.window
345            },
346            ..self
347        }
348    }
349
350    /// Sets the [`window::Settings::level`] of the [`Application`].
351    pub fn level(self, level: window::Level) -> Self {
352        Self {
353            window: window::Settings {
354                level,
355                ..self.window
356            },
357            ..self
358        }
359    }
360
361    /// Sets the [`Backend`] of the [`Application`].
362    pub fn backend(self, backend: Backend) -> Self {
363        Self {
364            settings: Settings {
365                backend,
366                ..self.settings
367            },
368            ..self
369        }
370    }
371
372    /// Sets the [`backend::PowerPreference`] of the [`Application`].
373    pub fn power_preference(self, power_preference: backend::PowerPreference) -> Self {
374        Self {
375            settings: Settings {
376                power_preference,
377                ..self.settings
378            },
379            ..self
380        }
381    }
382
383    /// Sets the title of the [`Application`].
384    pub fn title(
385        self,
386        title: impl TitleFn<P::State>,
387    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
388        Application {
389            raw: with_title(self.raw, title),
390            settings: self.settings,
391            window: self.window,
392            presets: self.presets,
393        }
394    }
395
396    /// Sets the subscription logic of the [`Application`].
397    pub fn subscription(
398        self,
399        f: impl Fn(&P::State) -> Subscription<P::Message>,
400    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
401        Application {
402            raw: program::with_subscription(self.raw, f),
403            settings: self.settings,
404            window: self.window,
405            presets: self.presets,
406        }
407    }
408
409    /// Sets the theme logic of the [`Application`].
410    pub fn theme(
411        self,
412        f: impl ThemeFn<P::State, P::Theme>,
413    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
414        Application {
415            raw: with_theme(self.raw, f),
416            settings: self.settings,
417            window: self.window,
418            presets: self.presets,
419        }
420    }
421
422    /// Sets the style logic of the [`Application`].
423    pub fn style(
424        self,
425        f: impl Fn(&P::State, &P::Theme) -> theme::Style,
426    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
427        Application {
428            raw: program::with_style(self.raw, f),
429            settings: self.settings,
430            window: self.window,
431            presets: self.presets,
432        }
433    }
434
435    /// Sets the scale factor of the [`Application`].
436    pub fn scale_factor(
437        self,
438        f: impl Fn(&P::State) -> f32,
439    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
440        Application {
441            raw: with_scale_factor(self.raw, f),
442            settings: self.settings,
443            window: self.window,
444            presets: self.presets,
445        }
446    }
447
448    /// Sets the executor of the [`Application`].
449    pub fn executor<E>(
450        self,
451    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>>
452    where
453        E: Executor,
454    {
455        Application {
456            raw: program::with_executor::<P, E>(self.raw),
457            settings: self.settings,
458            window: self.window,
459            presets: self.presets,
460        }
461    }
462
463    /// Sets the boot presets of the [`Application`].
464    ///
465    /// Presets can be used to override the default booting strategy
466    /// of your application during testing to create reproducible
467    /// environments.
468    pub fn presets(self, presets: impl IntoIterator<Item = Preset<P::State, P::Message>>) -> Self {
469        Self {
470            presets: presets.into_iter().collect(),
471            ..self
472        }
473    }
474}
475
476impl<P: Program> Program for Application<P> {
477    type State = P::State;
478    type Message = P::Message;
479    type Theme = P::Theme;
480    type Renderer = P::Renderer;
481    type Executor = P::Executor;
482
483    fn name() -> &'static str {
484        P::name()
485    }
486
487    fn settings(&self) -> Settings {
488        self.settings.clone()
489    }
490
491    fn window(&self) -> Option<window::Settings> {
492        Some(self.window.clone())
493    }
494
495    #[inline]
496    fn boot(&self) -> (Self::State, Task<Self::Message>) {
497        self.raw.boot()
498    }
499
500    #[inline]
501    fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
502        self.raw.update(state, message)
503    }
504
505    #[inline]
506    fn view<'a>(
507        &self,
508        state: &'a Self::State,
509        window: window::Id,
510    ) -> impl Widget<P::Message, P::Theme, P::Renderer> + 'a {
511        self.raw.view(state, window)
512    }
513
514    #[inline]
515    fn title(&self, state: &Self::State, window: window::Id) -> String {
516        self.raw.title(state, window)
517    }
518
519    #[inline]
520    fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
521        self.raw.subscription(state)
522    }
523
524    #[inline]
525    fn theme(&self, state: &Self::State, window: iced_core::window::Id) -> Option<Self::Theme> {
526        self.raw.theme(state, window)
527    }
528
529    #[inline]
530    fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
531        self.raw.style(state, theme)
532    }
533
534    #[inline]
535    fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
536        self.raw.scale_factor(state, window)
537    }
538
539    fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
540        &self.presets
541    }
542}
543
544/// The logic to initialize the `State` of some [`Application`].
545///
546/// This trait is implemented for both `Fn() -> State` and
547/// `Fn() -> (State, Task<Message>)`.
548///
549/// In practice, this means that [`application`] can both take
550/// simple functions like `State::default` and more advanced ones
551/// that return a [`Task`].
552pub trait BootFn<State, Message> {
553    /// Initializes the [`Application`] state.
554    fn boot(&self) -> (State, Task<Message>);
555}
556
557impl<T, C, State, Message> BootFn<State, Message> for T
558where
559    T: Fn() -> C,
560    C: IntoBoot<State, Message>,
561{
562    fn boot(&self) -> (State, Task<Message>) {
563        self().into_boot()
564    }
565}
566
567/// The initial state of some [`Application`].
568pub trait IntoBoot<State, Message> {
569    /// Turns some type into the initial state of some [`Application`].
570    fn into_boot(self) -> (State, Task<Message>);
571}
572
573impl<State, Message> IntoBoot<State, Message> for State {
574    fn into_boot(self) -> (State, Task<Message>) {
575        (self, Task::none())
576    }
577}
578
579impl<State, Message> IntoBoot<State, Message> for (State, Task<Message>) {
580    fn into_boot(self) -> (State, Task<Message>) {
581        self
582    }
583}
584
585/// The title logic of some [`Application`].
586///
587/// This trait is implemented both for `&'static str` and
588/// any closure `Fn(&State) -> String`.
589///
590/// This trait allows the [`Application::title`] builder to take any of them.
591pub trait TitleFn<State> {
592    /// Produces the title of the [`Application`].
593    fn title(&self, state: &State) -> String;
594}
595
596impl<State> TitleFn<State> for &'static str {
597    #[inline]
598    fn title(&self, _state: &State) -> String {
599        self.to_string()
600    }
601}
602
603impl<T, State> TitleFn<State> for T
604where
605    T: Fn(&State) -> String,
606{
607    #[inline]
608    fn title(&self, state: &State) -> String {
609        (self)(state)
610    }
611}
612
613/// The theme logic of some [`Application`].
614///
615/// Any implementors of this trait can be provided as an argument to
616/// [`Application::theme`].
617///
618/// `iced` provides two implementors:
619/// - the built-in [`Theme`] itself
620/// - and any `Fn(&State) -> impl Into<Option<Theme>>`.
621pub trait ThemeFn<State, Theme>
622where
623    Theme: theme::Base,
624{
625    /// Returns the theme of the [`Application`] for the current state.
626    ///
627    /// If `None` is returned, `iced` will try to use a theme that
628    /// matches the system color scheme.
629    fn theme(&self, state: &State) -> Option<Theme>;
630}
631
632impl<State> ThemeFn<State, Theme> for Theme {
633    #[inline]
634    fn theme(&self, _state: &State) -> Option<Theme> {
635        Some(self.clone())
636    }
637}
638
639impl<F, T, State, Theme> ThemeFn<State, Theme> for F
640where
641    F: Fn(&State) -> T,
642    T: Into<Option<Theme>>,
643    Theme: theme::Base,
644{
645    #[inline]
646    fn theme(&self, state: &State) -> Option<Theme> {
647        (self)(state).into()
648    }
649}
650
651/// The update logic of some [`Application`].
652///
653/// This trait allows the [`application`] builder to take any closure that
654/// returns any `Into<Task<Message>>`.
655pub trait UpdateFn<State, Message> {
656    /// Processes the message and updates the state of the [`Application`].
657    fn update(&self, state: &mut State, message: Message) -> Task<Message>;
658}
659
660impl<State> UpdateFn<State, Never> for () {
661    fn update(&self, _state: &mut State, _message: Never) -> Task<Never> {
662        Task::none()
663    }
664}
665
666impl<T, State, Message, C> UpdateFn<State, Message> for T
667where
668    T: Fn(&mut State, Message) -> C,
669    C: Into<Task<Message>>,
670{
671    fn update(&self, state: &mut State, message: Message) -> Task<Message> {
672        self(state, message).into()
673    }
674}
675
676/// The view logic of some [`Application`].
677///
678/// This trait allows the [`application`] builder to take any closure that
679/// returns any widget.
680pub trait ViewFn<'a, State, Message, Theme, Renderer> {
681    /// Produces the widget of the [`Application`].
682    fn view(&self, state: &'a State) -> impl Widget<Message, Theme, Renderer> + 'a;
683}
684
685impl<'a, T, State, Message, Theme, Renderer, W> ViewFn<'a, State, Message, Theme, Renderer> for T
686where
687    T: Fn(&'a State) -> W,
688    State: 'static,
689    Message: 'static,
690    Theme: 'static,
691    Renderer: 'static,
692    W: Widget<Message, Theme, Renderer> + 'a,
693{
694    #[inline]
695    fn view(&self, state: &'a State) -> impl Widget<Message, Theme, Renderer> + 'a {
696        self(state)
697    }
698}
699
700/// Decorates a [`Program`] with the given title function.
701fn with_title<P: Program>(
702    program: P,
703    title: impl TitleFn<P::State>,
704) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
705    struct WithTitle<P, Title> {
706        program: P,
707        title: Title,
708    }
709
710    impl<P, Title> Program for WithTitle<P, Title>
711    where
712        P: Program,
713        Title: TitleFn<P::State>,
714    {
715        type State = P::State;
716        type Message = P::Message;
717        type Theme = P::Theme;
718        type Renderer = P::Renderer;
719        type Executor = P::Executor;
720
721        #[inline]
722        fn title(&self, state: &Self::State, _window: window::Id) -> String {
723            self.title.title(state)
724        }
725
726        #[inline]
727        fn name() -> &'static str {
728            P::name()
729        }
730
731        #[inline]
732        fn settings(&self) -> Settings {
733            self.program.settings()
734        }
735
736        #[inline]
737        fn window(&self) -> Option<window::Settings> {
738            self.program.window()
739        }
740
741        #[inline]
742        fn boot(&self) -> (Self::State, Task<Self::Message>) {
743            self.program.boot()
744        }
745
746        #[inline]
747        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
748            self.program.update(state, message)
749        }
750
751        #[inline]
752        fn view<'a>(
753            &self,
754            state: &'a Self::State,
755            window: window::Id,
756        ) -> impl Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
757            self.program.view(state, window)
758        }
759
760        #[inline]
761        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
762            self.program.theme(state, window)
763        }
764
765        #[inline]
766        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
767            self.program.subscription(state)
768        }
769
770        #[inline]
771        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
772            self.program.style(state, theme)
773        }
774
775        #[inline]
776        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
777            self.program.scale_factor(state, window)
778        }
779    }
780
781    WithTitle { program, title }
782}
783
784/// Decorates a [`Program`] with the given theme function.
785fn with_theme<P: Program>(
786    program: P,
787    f: impl ThemeFn<P::State, P::Theme>,
788) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
789    struct WithTheme<P, F> {
790        program: P,
791        theme: F,
792    }
793
794    impl<P: Program, F> Program for WithTheme<P, F>
795    where
796        F: ThemeFn<P::State, P::Theme>,
797    {
798        type State = P::State;
799        type Message = P::Message;
800        type Theme = P::Theme;
801        type Renderer = P::Renderer;
802        type Executor = P::Executor;
803
804        #[inline]
805        fn theme(&self, state: &Self::State, _window: window::Id) -> Option<Self::Theme> {
806            self.theme.theme(state)
807        }
808
809        #[inline]
810        fn name() -> &'static str {
811            P::name()
812        }
813
814        #[inline]
815        fn settings(&self) -> Settings {
816            self.program.settings()
817        }
818
819        #[inline]
820        fn window(&self) -> Option<window::Settings> {
821            self.program.window()
822        }
823
824        #[inline]
825        fn boot(&self) -> (Self::State, Task<Self::Message>) {
826            self.program.boot()
827        }
828
829        #[inline]
830        fn title(&self, state: &Self::State, window: window::Id) -> String {
831            self.program.title(state, window)
832        }
833
834        #[inline]
835        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
836            self.program.update(state, message)
837        }
838
839        #[inline]
840        fn view<'a>(
841            &self,
842            state: &'a Self::State,
843            window: window::Id,
844        ) -> impl Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
845            self.program.view(state, window)
846        }
847
848        #[inline]
849        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
850            self.program.subscription(state)
851        }
852
853        #[inline]
854        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
855            self.program.style(state, theme)
856        }
857
858        #[inline]
859        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
860            self.program.scale_factor(state, window)
861        }
862    }
863
864    WithTheme { program, theme: f }
865}
866
867/// Decorates a [`Program`] with the given scale factor function.
868fn with_scale_factor<P: Program>(
869    program: P,
870    f: impl Fn(&P::State) -> f32,
871) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
872    struct WithScaleFactor<P, F> {
873        program: P,
874        scale_factor: F,
875    }
876
877    impl<P, F> Program for WithScaleFactor<P, F>
878    where
879        P: Program,
880        F: Fn(&P::State) -> f32,
881    {
882        type State = P::State;
883        type Message = P::Message;
884        type Theme = P::Theme;
885        type Renderer = P::Renderer;
886        type Executor = P::Executor;
887
888        #[inline]
889        fn title(&self, state: &Self::State, window: window::Id) -> String {
890            self.program.title(state, window)
891        }
892
893        #[inline]
894        fn name() -> &'static str {
895            P::name()
896        }
897
898        #[inline]
899        fn settings(&self) -> Settings {
900            self.program.settings()
901        }
902
903        #[inline]
904        fn window(&self) -> Option<window::Settings> {
905            self.program.window()
906        }
907
908        #[inline]
909        fn boot(&self) -> (Self::State, Task<Self::Message>) {
910            self.program.boot()
911        }
912
913        #[inline]
914        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
915            self.program.update(state, message)
916        }
917
918        #[inline]
919        fn view<'a>(
920            &self,
921            state: &'a Self::State,
922            window: window::Id,
923        ) -> impl Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
924            self.program.view(state, window)
925        }
926
927        #[inline]
928        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
929            self.program.subscription(state)
930        }
931
932        #[inline]
933        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
934            self.program.theme(state, window)
935        }
936
937        #[inline]
938        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
939            self.program.style(state, theme)
940        }
941
942        #[inline]
943        fn scale_factor(&self, state: &Self::State, _window: window::Id) -> f32 {
944            (self.scale_factor)(state)
945        }
946    }
947
948    WithScaleFactor {
949        program,
950        scale_factor: f,
951    }
952}