iced/
program.rs

1use crate::core::text;
2use crate::graphics::compositor;
3use crate::shell;
4use crate::theme;
5use crate::window;
6use crate::{Element, Executor, Result, Settings, Subscription, Task};
7
8/// The internal definition of a [`Program`].
9///
10/// You should not need to implement this trait directly. Instead, use the
11/// methods available in the [`Program`] struct.
12#[allow(missing_docs)]
13pub trait Program: Sized {
14    /// The state of the program.
15    type State;
16
17    /// The message of the program.
18    type Message: Send + std::fmt::Debug + 'static;
19
20    /// The theme of the program.
21    type Theme: Default + theme::Base;
22
23    /// The renderer of the program.
24    type Renderer: Renderer;
25
26    /// The executor of the program.
27    type Executor: Executor;
28
29    fn update(
30        &self,
31        state: &mut Self::State,
32        message: Self::Message,
33    ) -> Task<Self::Message>;
34
35    fn view<'a>(
36        &self,
37        state: &'a Self::State,
38        window: window::Id,
39    ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer>;
40
41    fn title(&self, _state: &Self::State, _window: window::Id) -> String {
42        String::from("A cool iced application!")
43    }
44
45    fn subscription(
46        &self,
47        _state: &Self::State,
48    ) -> Subscription<Self::Message> {
49        Subscription::none()
50    }
51
52    fn theme(&self, _state: &Self::State, _window: window::Id) -> Self::Theme {
53        <Self::Theme as Default>::default()
54    }
55
56    fn style(&self, _state: &Self::State, theme: &Self::Theme) -> theme::Style {
57        theme::Base::base(theme)
58    }
59
60    fn scale_factor(&self, _state: &Self::State, _window: window::Id) -> f64 {
61        1.0
62    }
63
64    /// Runs the [`Program`].
65    ///
66    /// The state of the [`Program`] must implement [`Default`].
67    /// If your state does not implement [`Default`], use [`run_with`]
68    /// instead.
69    ///
70    /// [`run_with`]: Self::run_with
71    fn run(
72        self,
73        settings: Settings,
74        window_settings: Option<window::Settings>,
75    ) -> Result
76    where
77        Self: 'static,
78        Self::State: Default,
79    {
80        self.run_with(settings, window_settings, || {
81            (Self::State::default(), Task::none())
82        })
83    }
84
85    /// Runs the [`Program`] with the given [`Settings`] and a closure that creates the initial state.
86    fn run_with<I>(
87        self,
88        settings: Settings,
89        window_settings: Option<window::Settings>,
90        initialize: I,
91    ) -> Result
92    where
93        Self: 'static,
94        I: FnOnce() -> (Self::State, Task<Self::Message>) + 'static,
95    {
96        use std::marker::PhantomData;
97
98        struct Instance<P: Program, I> {
99            program: P,
100            state: P::State,
101            _initialize: PhantomData<I>,
102        }
103
104        impl<P: Program, I: FnOnce() -> (P::State, Task<P::Message>)>
105            shell::Program for Instance<P, I>
106        {
107            type Message = P::Message;
108            type Theme = P::Theme;
109            type Renderer = P::Renderer;
110            type Flags = (P, I);
111            type Executor = P::Executor;
112
113            fn new(
114                (program, initialize): Self::Flags,
115            ) -> (Self, Task<Self::Message>) {
116                let (state, task) = initialize();
117
118                (
119                    Self {
120                        program,
121                        state,
122                        _initialize: PhantomData,
123                    },
124                    task,
125                )
126            }
127
128            fn title(&self, window: window::Id) -> String {
129                self.program.title(&self.state, window)
130            }
131
132            fn update(
133                &mut self,
134                message: Self::Message,
135            ) -> Task<Self::Message> {
136                self.program.update(&mut self.state, message)
137            }
138
139            fn view(
140                &self,
141                window: window::Id,
142            ) -> crate::Element<'_, Self::Message, Self::Theme, Self::Renderer>
143            {
144                self.program.view(&self.state, window)
145            }
146
147            fn subscription(&self) -> Subscription<Self::Message> {
148                self.program.subscription(&self.state)
149            }
150
151            fn theme(&self, window: window::Id) -> Self::Theme {
152                self.program.theme(&self.state, window)
153            }
154
155            fn style(&self, theme: &Self::Theme) -> theme::Style {
156                self.program.style(&self.state, theme)
157            }
158
159            fn scale_factor(&self, window: window::Id) -> f64 {
160                self.program.scale_factor(&self.state, window)
161            }
162        }
163
164        #[allow(clippy::needless_update)]
165        let renderer_settings = crate::graphics::Settings {
166            default_font: settings.default_font,
167            default_text_size: settings.default_text_size,
168            antialiasing: if settings.antialiasing {
169                Some(crate::graphics::Antialiasing::MSAAx4)
170            } else {
171                None
172            },
173            ..crate::graphics::Settings::default()
174        };
175
176        Ok(shell::program::run::<
177            Instance<Self, I>,
178            <Self::Renderer as compositor::Default>::Compositor,
179        >(
180            Settings {
181                id: settings.id,
182                fonts: settings.fonts,
183                default_font: settings.default_font,
184                default_text_size: settings.default_text_size,
185                antialiasing: settings.antialiasing,
186            }
187            .into(),
188            renderer_settings,
189            window_settings,
190            (self, initialize),
191        )?)
192    }
193}
194
195pub fn with_title<P: Program>(
196    program: P,
197    title: impl Fn(&P::State, window::Id) -> String,
198) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
199    struct WithTitle<P, Title> {
200        program: P,
201        title: Title,
202    }
203
204    impl<P, Title> Program for WithTitle<P, Title>
205    where
206        P: Program,
207        Title: Fn(&P::State, window::Id) -> String,
208    {
209        type State = P::State;
210        type Message = P::Message;
211        type Theme = P::Theme;
212        type Renderer = P::Renderer;
213        type Executor = P::Executor;
214
215        fn title(&self, state: &Self::State, window: window::Id) -> String {
216            (self.title)(state, window)
217        }
218
219        fn update(
220            &self,
221            state: &mut Self::State,
222            message: Self::Message,
223        ) -> Task<Self::Message> {
224            self.program.update(state, message)
225        }
226
227        fn view<'a>(
228            &self,
229            state: &'a Self::State,
230            window: window::Id,
231        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
232            self.program.view(state, window)
233        }
234
235        fn theme(
236            &self,
237            state: &Self::State,
238            window: window::Id,
239        ) -> Self::Theme {
240            self.program.theme(state, window)
241        }
242
243        fn subscription(
244            &self,
245            state: &Self::State,
246        ) -> Subscription<Self::Message> {
247            self.program.subscription(state)
248        }
249
250        fn style(
251            &self,
252            state: &Self::State,
253            theme: &Self::Theme,
254        ) -> theme::Style {
255            self.program.style(state, theme)
256        }
257
258        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f64 {
259            self.program.scale_factor(state, window)
260        }
261    }
262
263    WithTitle { program, title }
264}
265
266pub fn with_subscription<P: Program>(
267    program: P,
268    f: impl Fn(&P::State) -> Subscription<P::Message>,
269) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
270    struct WithSubscription<P, F> {
271        program: P,
272        subscription: F,
273    }
274
275    impl<P: Program, F> Program for WithSubscription<P, F>
276    where
277        F: Fn(&P::State) -> Subscription<P::Message>,
278    {
279        type State = P::State;
280        type Message = P::Message;
281        type Theme = P::Theme;
282        type Renderer = P::Renderer;
283        type Executor = P::Executor;
284
285        fn subscription(
286            &self,
287            state: &Self::State,
288        ) -> Subscription<Self::Message> {
289            (self.subscription)(state)
290        }
291
292        fn update(
293            &self,
294            state: &mut Self::State,
295            message: Self::Message,
296        ) -> Task<Self::Message> {
297            self.program.update(state, message)
298        }
299
300        fn view<'a>(
301            &self,
302            state: &'a Self::State,
303            window: window::Id,
304        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
305            self.program.view(state, window)
306        }
307
308        fn title(&self, state: &Self::State, window: window::Id) -> String {
309            self.program.title(state, window)
310        }
311
312        fn theme(
313            &self,
314            state: &Self::State,
315            window: window::Id,
316        ) -> Self::Theme {
317            self.program.theme(state, window)
318        }
319
320        fn style(
321            &self,
322            state: &Self::State,
323            theme: &Self::Theme,
324        ) -> theme::Style {
325            self.program.style(state, theme)
326        }
327
328        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f64 {
329            self.program.scale_factor(state, window)
330        }
331    }
332
333    WithSubscription {
334        program,
335        subscription: f,
336    }
337}
338
339pub fn with_theme<P: Program>(
340    program: P,
341    f: impl Fn(&P::State, window::Id) -> P::Theme,
342) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
343    struct WithTheme<P, F> {
344        program: P,
345        theme: F,
346    }
347
348    impl<P: Program, F> Program for WithTheme<P, F>
349    where
350        F: Fn(&P::State, window::Id) -> P::Theme,
351    {
352        type State = P::State;
353        type Message = P::Message;
354        type Theme = P::Theme;
355        type Renderer = P::Renderer;
356        type Executor = P::Executor;
357
358        fn theme(
359            &self,
360            state: &Self::State,
361            window: window::Id,
362        ) -> Self::Theme {
363            (self.theme)(state, window)
364        }
365
366        fn title(&self, state: &Self::State, window: window::Id) -> String {
367            self.program.title(state, window)
368        }
369
370        fn update(
371            &self,
372            state: &mut Self::State,
373            message: Self::Message,
374        ) -> Task<Self::Message> {
375            self.program.update(state, message)
376        }
377
378        fn view<'a>(
379            &self,
380            state: &'a Self::State,
381            window: window::Id,
382        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
383            self.program.view(state, window)
384        }
385
386        fn subscription(
387            &self,
388            state: &Self::State,
389        ) -> Subscription<Self::Message> {
390            self.program.subscription(state)
391        }
392
393        fn style(
394            &self,
395            state: &Self::State,
396            theme: &Self::Theme,
397        ) -> theme::Style {
398            self.program.style(state, theme)
399        }
400
401        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f64 {
402            self.program.scale_factor(state, window)
403        }
404    }
405
406    WithTheme { program, theme: f }
407}
408
409pub fn with_style<P: Program>(
410    program: P,
411    f: impl Fn(&P::State, &P::Theme) -> theme::Style,
412) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
413    struct WithStyle<P, F> {
414        program: P,
415        style: F,
416    }
417
418    impl<P: Program, F> Program for WithStyle<P, F>
419    where
420        F: Fn(&P::State, &P::Theme) -> theme::Style,
421    {
422        type State = P::State;
423        type Message = P::Message;
424        type Theme = P::Theme;
425        type Renderer = P::Renderer;
426        type Executor = P::Executor;
427
428        fn style(
429            &self,
430            state: &Self::State,
431            theme: &Self::Theme,
432        ) -> theme::Style {
433            (self.style)(state, theme)
434        }
435
436        fn title(&self, state: &Self::State, window: window::Id) -> String {
437            self.program.title(state, window)
438        }
439
440        fn update(
441            &self,
442            state: &mut Self::State,
443            message: Self::Message,
444        ) -> Task<Self::Message> {
445            self.program.update(state, message)
446        }
447
448        fn view<'a>(
449            &self,
450            state: &'a Self::State,
451            window: window::Id,
452        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
453            self.program.view(state, window)
454        }
455
456        fn subscription(
457            &self,
458            state: &Self::State,
459        ) -> Subscription<Self::Message> {
460            self.program.subscription(state)
461        }
462
463        fn theme(
464            &self,
465            state: &Self::State,
466            window: window::Id,
467        ) -> Self::Theme {
468            self.program.theme(state, window)
469        }
470
471        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f64 {
472            self.program.scale_factor(state, window)
473        }
474    }
475
476    WithStyle { program, style: f }
477}
478
479pub fn with_scale_factor<P: Program>(
480    program: P,
481    f: impl Fn(&P::State, window::Id) -> f64,
482) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
483    struct WithScaleFactor<P, F> {
484        program: P,
485        scale_factor: F,
486    }
487
488    impl<P: Program, F> Program for WithScaleFactor<P, F>
489    where
490        F: Fn(&P::State, window::Id) -> f64,
491    {
492        type State = P::State;
493        type Message = P::Message;
494        type Theme = P::Theme;
495        type Renderer = P::Renderer;
496        type Executor = P::Executor;
497
498        fn title(&self, state: &Self::State, window: window::Id) -> String {
499            self.program.title(state, window)
500        }
501
502        fn update(
503            &self,
504            state: &mut Self::State,
505            message: Self::Message,
506        ) -> Task<Self::Message> {
507            self.program.update(state, message)
508        }
509
510        fn view<'a>(
511            &self,
512            state: &'a Self::State,
513            window: window::Id,
514        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
515            self.program.view(state, window)
516        }
517
518        fn subscription(
519            &self,
520            state: &Self::State,
521        ) -> Subscription<Self::Message> {
522            self.program.subscription(state)
523        }
524
525        fn theme(
526            &self,
527            state: &Self::State,
528            window: window::Id,
529        ) -> Self::Theme {
530            self.program.theme(state, window)
531        }
532
533        fn style(
534            &self,
535            state: &Self::State,
536            theme: &Self::Theme,
537        ) -> theme::Style {
538            self.program.style(state, theme)
539        }
540
541        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f64 {
542            (self.scale_factor)(state, window)
543        }
544    }
545
546    WithScaleFactor {
547        program,
548        scale_factor: f,
549    }
550}
551
552pub fn with_executor<P: Program, E: Executor>(
553    program: P,
554) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
555    use std::marker::PhantomData;
556
557    struct WithExecutor<P, E> {
558        program: P,
559        executor: PhantomData<E>,
560    }
561
562    impl<P: Program, E> Program for WithExecutor<P, E>
563    where
564        E: Executor,
565    {
566        type State = P::State;
567        type Message = P::Message;
568        type Theme = P::Theme;
569        type Renderer = P::Renderer;
570        type Executor = E;
571
572        fn title(&self, state: &Self::State, window: window::Id) -> String {
573            self.program.title(state, window)
574        }
575
576        fn update(
577            &self,
578            state: &mut Self::State,
579            message: Self::Message,
580        ) -> Task<Self::Message> {
581            self.program.update(state, message)
582        }
583
584        fn view<'a>(
585            &self,
586            state: &'a Self::State,
587            window: window::Id,
588        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
589            self.program.view(state, window)
590        }
591
592        fn subscription(
593            &self,
594            state: &Self::State,
595        ) -> Subscription<Self::Message> {
596            self.program.subscription(state)
597        }
598
599        fn theme(
600            &self,
601            state: &Self::State,
602            window: window::Id,
603        ) -> Self::Theme {
604            self.program.theme(state, window)
605        }
606
607        fn style(
608            &self,
609            state: &Self::State,
610            theme: &Self::Theme,
611        ) -> theme::Style {
612            self.program.style(state, theme)
613        }
614
615        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f64 {
616            self.program.scale_factor(state, window)
617        }
618    }
619
620    WithExecutor {
621        program,
622        executor: PhantomData::<E>,
623    }
624}
625
626/// The renderer of some [`Program`].
627pub trait Renderer: text::Renderer + compositor::Default {}
628
629impl<T> Renderer for T where T: text::Renderer + compositor::Default {}