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#[allow(missing_docs)]
18pub trait Program: Sized {
19 type State;
21
22 type Message: Send + std::fmt::Debug + 'static;
24
25 type Theme: Default + DefaultStyle;
27
28 type Renderer: Renderer;
30
31 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 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 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
635pub trait Renderer: text::Renderer + compositor::Default {}
637
638impl<T> Renderer for T where T: text::Renderer + compositor::Default {}