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#[allow(missing_docs)]
13pub trait Program: Sized {
14 type State;
16
17 type Message: Send + std::fmt::Debug + 'static;
19
20 type Theme: Default + theme::Base;
22
23 type Renderer: Renderer;
25
26 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 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 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
626pub trait Renderer: text::Renderer + compositor::Default {}
628
629impl<T> Renderer for T where T: text::Renderer + compositor::Default {}