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>
681where
682    Renderer: crate::core::Renderer,
683{
684    /// Produces the widget of the [`Application`].
685    fn view(&self, state: &'a State) -> impl Widget<Message, Theme, Renderer> + 'a;
686}
687
688impl<'a, T, State, Message, Theme, Renderer, W> ViewFn<'a, State, Message, Theme, Renderer> for T
689where
690    T: Fn(&'a State) -> W,
691    State: 'static,
692    Message: 'static,
693    Theme: 'static,
694    Renderer: 'static,
695    W: Widget<Message, Theme, Renderer> + 'a,
696    Renderer: crate::core::Renderer,
697{
698    #[inline]
699    fn view(&self, state: &'a State) -> impl Widget<Message, Theme, Renderer> + 'a {
700        self(state)
701    }
702}
703
704/// Decorates a [`Program`] with the given title function.
705fn with_title<P: Program>(
706    program: P,
707    title: impl TitleFn<P::State>,
708) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
709    struct WithTitle<P, Title> {
710        program: P,
711        title: Title,
712    }
713
714    impl<P, Title> Program for WithTitle<P, Title>
715    where
716        P: Program,
717        Title: TitleFn<P::State>,
718    {
719        type State = P::State;
720        type Message = P::Message;
721        type Theme = P::Theme;
722        type Renderer = P::Renderer;
723        type Executor = P::Executor;
724
725        #[inline]
726        fn title(&self, state: &Self::State, _window: window::Id) -> String {
727            self.title.title(state)
728        }
729
730        #[inline]
731        fn name() -> &'static str {
732            P::name()
733        }
734
735        #[inline]
736        fn settings(&self) -> Settings {
737            self.program.settings()
738        }
739
740        #[inline]
741        fn window(&self) -> Option<window::Settings> {
742            self.program.window()
743        }
744
745        #[inline]
746        fn boot(&self) -> (Self::State, Task<Self::Message>) {
747            self.program.boot()
748        }
749
750        #[inline]
751        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
752            self.program.update(state, message)
753        }
754
755        #[inline]
756        fn view<'a>(
757            &self,
758            state: &'a Self::State,
759            window: window::Id,
760        ) -> impl Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
761            self.program.view(state, window)
762        }
763
764        #[inline]
765        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
766            self.program.theme(state, window)
767        }
768
769        #[inline]
770        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
771            self.program.subscription(state)
772        }
773
774        #[inline]
775        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
776            self.program.style(state, theme)
777        }
778
779        #[inline]
780        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
781            self.program.scale_factor(state, window)
782        }
783    }
784
785    WithTitle { program, title }
786}
787
788/// Decorates a [`Program`] with the given theme function.
789fn with_theme<P: Program>(
790    program: P,
791    f: impl ThemeFn<P::State, P::Theme>,
792) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
793    struct WithTheme<P, F> {
794        program: P,
795        theme: F,
796    }
797
798    impl<P: Program, F> Program for WithTheme<P, F>
799    where
800        F: ThemeFn<P::State, P::Theme>,
801    {
802        type State = P::State;
803        type Message = P::Message;
804        type Theme = P::Theme;
805        type Renderer = P::Renderer;
806        type Executor = P::Executor;
807
808        #[inline]
809        fn theme(&self, state: &Self::State, _window: window::Id) -> Option<Self::Theme> {
810            self.theme.theme(state)
811        }
812
813        #[inline]
814        fn name() -> &'static str {
815            P::name()
816        }
817
818        #[inline]
819        fn settings(&self) -> Settings {
820            self.program.settings()
821        }
822
823        #[inline]
824        fn window(&self) -> Option<window::Settings> {
825            self.program.window()
826        }
827
828        #[inline]
829        fn boot(&self) -> (Self::State, Task<Self::Message>) {
830            self.program.boot()
831        }
832
833        #[inline]
834        fn title(&self, state: &Self::State, window: window::Id) -> String {
835            self.program.title(state, window)
836        }
837
838        #[inline]
839        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
840            self.program.update(state, message)
841        }
842
843        #[inline]
844        fn view<'a>(
845            &self,
846            state: &'a Self::State,
847            window: window::Id,
848        ) -> impl Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
849            self.program.view(state, window)
850        }
851
852        #[inline]
853        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
854            self.program.subscription(state)
855        }
856
857        #[inline]
858        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
859            self.program.style(state, theme)
860        }
861
862        #[inline]
863        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
864            self.program.scale_factor(state, window)
865        }
866    }
867
868    WithTheme { program, theme: f }
869}
870
871/// Decorates a [`Program`] with the given scale factor function.
872fn with_scale_factor<P: Program>(
873    program: P,
874    f: impl Fn(&P::State) -> f32,
875) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
876    struct WithScaleFactor<P, F> {
877        program: P,
878        scale_factor: F,
879    }
880
881    impl<P, F> Program for WithScaleFactor<P, F>
882    where
883        P: Program,
884        F: Fn(&P::State) -> f32,
885    {
886        type State = P::State;
887        type Message = P::Message;
888        type Theme = P::Theme;
889        type Renderer = P::Renderer;
890        type Executor = P::Executor;
891
892        #[inline]
893        fn title(&self, state: &Self::State, window: window::Id) -> String {
894            self.program.title(state, window)
895        }
896
897        #[inline]
898        fn name() -> &'static str {
899            P::name()
900        }
901
902        #[inline]
903        fn settings(&self) -> Settings {
904            self.program.settings()
905        }
906
907        #[inline]
908        fn window(&self) -> Option<window::Settings> {
909            self.program.window()
910        }
911
912        #[inline]
913        fn boot(&self) -> (Self::State, Task<Self::Message>) {
914            self.program.boot()
915        }
916
917        #[inline]
918        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
919            self.program.update(state, message)
920        }
921
922        #[inline]
923        fn view<'a>(
924            &self,
925            state: &'a Self::State,
926            window: window::Id,
927        ) -> impl Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
928            self.program.view(state, window)
929        }
930
931        #[inline]
932        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
933            self.program.subscription(state)
934        }
935
936        #[inline]
937        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
938            self.program.theme(state, window)
939        }
940
941        #[inline]
942        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
943            self.program.style(state, theme)
944        }
945
946        #[inline]
947        fn scale_factor(&self, state: &Self::State, _window: window::Id) -> f32 {
948            (self.scale_factor)(state)
949        }
950    }
951
952    WithScaleFactor {
953        program,
954        scale_factor: f,
955    }
956}