iced/
program.rs

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