1pub use iced_graphics as graphics;
3pub use iced_runtime as runtime;
4pub use iced_runtime::core;
5pub use iced_runtime::futures;
6
7pub mod message;
8
9mod preset;
10
11pub use preset::Preset;
12
13use crate::core::renderer;
14use crate::core::text;
15use crate::core::theme;
16use crate::core::window;
17use crate::core::{Element, Font, Settings};
18use crate::futures::{Executor, Subscription};
19use crate::graphics::compositor;
20use crate::runtime::Task;
21
22#[allow(missing_docs)]
27pub trait Program: Sized {
28 type State;
30
31 type Message: Send + 'static;
33
34 type Theme: theme::Base;
36
37 type Renderer: Renderer;
39
40 type Executor: Executor;
42
43 fn name() -> &'static str;
45
46 fn settings(&self) -> Settings;
47
48 fn window(&self) -> Option<window::Settings>;
49
50 fn boot(&self) -> (Self::State, Task<Self::Message>);
51
52 fn update(
53 &self,
54 state: &mut Self::State,
55 message: Self::Message,
56 ) -> Task<Self::Message>;
57
58 fn view<'a>(
59 &self,
60 state: &'a Self::State,
61 window: window::Id,
62 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer>;
63
64 fn title(&self, _state: &Self::State, _window: window::Id) -> String {
65 let mut title = String::new();
66
67 for (i, part) in Self::name().split("_").enumerate() {
68 use std::borrow::Cow;
69
70 let part = match part {
71 "a" | "an" | "of" | "in" | "and" => Cow::Borrowed(part),
72 _ => {
73 let mut part = part.to_owned();
74
75 if let Some(first_letter) = part.get_mut(0..1) {
76 first_letter.make_ascii_uppercase();
77 }
78
79 Cow::Owned(part)
80 }
81 };
82
83 if i > 0 {
84 title.push(' ');
85 }
86
87 title.push_str(&part);
88 }
89
90 format!("{title} - Iced")
91 }
92
93 fn subscription(
94 &self,
95 _state: &Self::State,
96 ) -> Subscription<Self::Message> {
97 Subscription::none()
98 }
99
100 fn theme(
101 &self,
102 _state: &Self::State,
103 _window: window::Id,
104 ) -> Option<Self::Theme> {
105 None
106 }
107
108 fn style(&self, _state: &Self::State, theme: &Self::Theme) -> theme::Style {
109 theme::Base::base(theme)
110 }
111
112 fn scale_factor(&self, _state: &Self::State, _window: window::Id) -> f32 {
113 1.0
114 }
115
116 fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
117 &[]
118 }
119}
120
121pub fn with_title<P: Program>(
123 program: P,
124 title: impl Fn(&P::State, window::Id) -> String,
125) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
126 struct WithTitle<P, Title> {
127 program: P,
128 title: Title,
129 }
130
131 impl<P, Title> Program for WithTitle<P, Title>
132 where
133 P: Program,
134 Title: Fn(&P::State, window::Id) -> String,
135 {
136 type State = P::State;
137 type Message = P::Message;
138 type Theme = P::Theme;
139 type Renderer = P::Renderer;
140 type Executor = P::Executor;
141
142 fn title(&self, state: &Self::State, window: window::Id) -> String {
143 (self.title)(state, window)
144 }
145
146 fn name() -> &'static str {
147 P::name()
148 }
149
150 fn settings(&self) -> Settings {
151 self.program.settings()
152 }
153
154 fn window(&self) -> Option<window::Settings> {
155 self.program.window()
156 }
157
158 fn boot(&self) -> (Self::State, Task<Self::Message>) {
159 self.program.boot()
160 }
161
162 fn update(
163 &self,
164 state: &mut Self::State,
165 message: Self::Message,
166 ) -> Task<Self::Message> {
167 self.program.update(state, message)
168 }
169
170 fn view<'a>(
171 &self,
172 state: &'a Self::State,
173 window: window::Id,
174 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
175 self.program.view(state, window)
176 }
177
178 fn theme(
179 &self,
180 state: &Self::State,
181 window: window::Id,
182 ) -> Option<Self::Theme> {
183 self.program.theme(state, window)
184 }
185
186 fn subscription(
187 &self,
188 state: &Self::State,
189 ) -> Subscription<Self::Message> {
190 self.program.subscription(state)
191 }
192
193 fn style(
194 &self,
195 state: &Self::State,
196 theme: &Self::Theme,
197 ) -> theme::Style {
198 self.program.style(state, theme)
199 }
200
201 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
202 self.program.scale_factor(state, window)
203 }
204 }
205
206 WithTitle { program, title }
207}
208
209pub fn with_subscription<P: Program>(
211 program: P,
212 f: impl Fn(&P::State) -> Subscription<P::Message>,
213) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
214 struct WithSubscription<P, F> {
215 program: P,
216 subscription: F,
217 }
218
219 impl<P: Program, F> Program for WithSubscription<P, F>
220 where
221 F: Fn(&P::State) -> Subscription<P::Message>,
222 {
223 type State = P::State;
224 type Message = P::Message;
225 type Theme = P::Theme;
226 type Renderer = P::Renderer;
227 type Executor = P::Executor;
228
229 fn subscription(
230 &self,
231 state: &Self::State,
232 ) -> Subscription<Self::Message> {
233 (self.subscription)(state)
234 }
235
236 fn name() -> &'static str {
237 P::name()
238 }
239
240 fn settings(&self) -> Settings {
241 self.program.settings()
242 }
243
244 fn window(&self) -> Option<window::Settings> {
245 self.program.window()
246 }
247
248 fn boot(&self) -> (Self::State, Task<Self::Message>) {
249 self.program.boot()
250 }
251
252 fn update(
253 &self,
254 state: &mut Self::State,
255 message: Self::Message,
256 ) -> Task<Self::Message> {
257 self.program.update(state, message)
258 }
259
260 fn view<'a>(
261 &self,
262 state: &'a Self::State,
263 window: window::Id,
264 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
265 self.program.view(state, window)
266 }
267
268 fn title(&self, state: &Self::State, window: window::Id) -> String {
269 self.program.title(state, window)
270 }
271
272 fn theme(
273 &self,
274 state: &Self::State,
275 window: window::Id,
276 ) -> Option<Self::Theme> {
277 self.program.theme(state, window)
278 }
279
280 fn style(
281 &self,
282 state: &Self::State,
283 theme: &Self::Theme,
284 ) -> theme::Style {
285 self.program.style(state, theme)
286 }
287
288 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
289 self.program.scale_factor(state, window)
290 }
291 }
292
293 WithSubscription {
294 program,
295 subscription: f,
296 }
297}
298
299pub fn with_theme<P: Program>(
301 program: P,
302 f: impl Fn(&P::State, window::Id) -> Option<P::Theme>,
303) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
304 struct WithTheme<P, F> {
305 program: P,
306 theme: F,
307 }
308
309 impl<P: Program, F> Program for WithTheme<P, F>
310 where
311 F: Fn(&P::State, window::Id) -> Option<P::Theme>,
312 {
313 type State = P::State;
314 type Message = P::Message;
315 type Theme = P::Theme;
316 type Renderer = P::Renderer;
317 type Executor = P::Executor;
318
319 fn theme(
320 &self,
321 state: &Self::State,
322 window: window::Id,
323 ) -> Option<Self::Theme> {
324 (self.theme)(state, window)
325 }
326
327 fn name() -> &'static str {
328 P::name()
329 }
330
331 fn settings(&self) -> Settings {
332 self.program.settings()
333 }
334
335 fn window(&self) -> Option<window::Settings> {
336 self.program.window()
337 }
338
339 fn boot(&self) -> (Self::State, Task<Self::Message>) {
340 self.program.boot()
341 }
342
343 fn title(&self, state: &Self::State, window: window::Id) -> String {
344 self.program.title(state, window)
345 }
346
347 fn update(
348 &self,
349 state: &mut Self::State,
350 message: Self::Message,
351 ) -> Task<Self::Message> {
352 self.program.update(state, message)
353 }
354
355 fn view<'a>(
356 &self,
357 state: &'a Self::State,
358 window: window::Id,
359 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
360 self.program.view(state, window)
361 }
362
363 fn subscription(
364 &self,
365 state: &Self::State,
366 ) -> Subscription<Self::Message> {
367 self.program.subscription(state)
368 }
369
370 fn style(
371 &self,
372 state: &Self::State,
373 theme: &Self::Theme,
374 ) -> theme::Style {
375 self.program.style(state, theme)
376 }
377
378 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
379 self.program.scale_factor(state, window)
380 }
381 }
382
383 WithTheme { program, theme: f }
384}
385
386pub fn with_style<P: Program>(
388 program: P,
389 f: impl Fn(&P::State, &P::Theme) -> theme::Style,
390) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
391 struct WithStyle<P, F> {
392 program: P,
393 style: F,
394 }
395
396 impl<P: Program, F> Program for WithStyle<P, F>
397 where
398 F: Fn(&P::State, &P::Theme) -> theme::Style,
399 {
400 type State = P::State;
401 type Message = P::Message;
402 type Theme = P::Theme;
403 type Renderer = P::Renderer;
404 type Executor = P::Executor;
405
406 fn style(
407 &self,
408 state: &Self::State,
409 theme: &Self::Theme,
410 ) -> theme::Style {
411 (self.style)(state, theme)
412 }
413
414 fn name() -> &'static str {
415 P::name()
416 }
417
418 fn settings(&self) -> Settings {
419 self.program.settings()
420 }
421
422 fn window(&self) -> Option<window::Settings> {
423 self.program.window()
424 }
425
426 fn boot(&self) -> (Self::State, Task<Self::Message>) {
427 self.program.boot()
428 }
429
430 fn title(&self, state: &Self::State, window: window::Id) -> String {
431 self.program.title(state, window)
432 }
433
434 fn update(
435 &self,
436 state: &mut Self::State,
437 message: Self::Message,
438 ) -> Task<Self::Message> {
439 self.program.update(state, message)
440 }
441
442 fn view<'a>(
443 &self,
444 state: &'a Self::State,
445 window: window::Id,
446 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
447 self.program.view(state, window)
448 }
449
450 fn subscription(
451 &self,
452 state: &Self::State,
453 ) -> Subscription<Self::Message> {
454 self.program.subscription(state)
455 }
456
457 fn theme(
458 &self,
459 state: &Self::State,
460 window: window::Id,
461 ) -> Option<Self::Theme> {
462 self.program.theme(state, window)
463 }
464
465 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
466 self.program.scale_factor(state, window)
467 }
468 }
469
470 WithStyle { program, style: f }
471}
472
473pub fn with_scale_factor<P: Program>(
475 program: P,
476 f: impl Fn(&P::State, window::Id) -> f32,
477) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
478 struct WithScaleFactor<P, F> {
479 program: P,
480 scale_factor: F,
481 }
482
483 impl<P: Program, F> Program for WithScaleFactor<P, F>
484 where
485 F: Fn(&P::State, window::Id) -> f32,
486 {
487 type State = P::State;
488 type Message = P::Message;
489 type Theme = P::Theme;
490 type Renderer = P::Renderer;
491 type Executor = P::Executor;
492
493 fn title(&self, state: &Self::State, window: window::Id) -> String {
494 self.program.title(state, window)
495 }
496
497 fn name() -> &'static str {
498 P::name()
499 }
500
501 fn settings(&self) -> Settings {
502 self.program.settings()
503 }
504
505 fn window(&self) -> Option<window::Settings> {
506 self.program.window()
507 }
508
509 fn boot(&self) -> (Self::State, Task<Self::Message>) {
510 self.program.boot()
511 }
512
513 fn update(
514 &self,
515 state: &mut Self::State,
516 message: Self::Message,
517 ) -> Task<Self::Message> {
518 self.program.update(state, message)
519 }
520
521 fn view<'a>(
522 &self,
523 state: &'a Self::State,
524 window: window::Id,
525 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
526 self.program.view(state, window)
527 }
528
529 fn subscription(
530 &self,
531 state: &Self::State,
532 ) -> Subscription<Self::Message> {
533 self.program.subscription(state)
534 }
535
536 fn theme(
537 &self,
538 state: &Self::State,
539 window: window::Id,
540 ) -> Option<Self::Theme> {
541 self.program.theme(state, window)
542 }
543
544 fn style(
545 &self,
546 state: &Self::State,
547 theme: &Self::Theme,
548 ) -> theme::Style {
549 self.program.style(state, theme)
550 }
551
552 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
553 (self.scale_factor)(state, window)
554 }
555 }
556
557 WithScaleFactor {
558 program,
559 scale_factor: f,
560 }
561}
562
563pub fn with_executor<P: Program, E: Executor>(
565 program: P,
566) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
567 use std::marker::PhantomData;
568
569 struct WithExecutor<P, E> {
570 program: P,
571 executor: PhantomData<E>,
572 }
573
574 impl<P: Program, E> Program for WithExecutor<P, E>
575 where
576 E: Executor,
577 {
578 type State = P::State;
579 type Message = P::Message;
580 type Theme = P::Theme;
581 type Renderer = P::Renderer;
582 type Executor = E;
583
584 fn title(&self, state: &Self::State, window: window::Id) -> String {
585 self.program.title(state, window)
586 }
587
588 fn name() -> &'static str {
589 P::name()
590 }
591
592 fn settings(&self) -> Settings {
593 self.program.settings()
594 }
595
596 fn window(&self) -> Option<window::Settings> {
597 self.program.window()
598 }
599
600 fn boot(&self) -> (Self::State, Task<Self::Message>) {
601 self.program.boot()
602 }
603
604 fn update(
605 &self,
606 state: &mut Self::State,
607 message: Self::Message,
608 ) -> Task<Self::Message> {
609 self.program.update(state, message)
610 }
611
612 fn view<'a>(
613 &self,
614 state: &'a Self::State,
615 window: window::Id,
616 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
617 self.program.view(state, window)
618 }
619
620 fn subscription(
621 &self,
622 state: &Self::State,
623 ) -> Subscription<Self::Message> {
624 self.program.subscription(state)
625 }
626
627 fn theme(
628 &self,
629 state: &Self::State,
630 window: window::Id,
631 ) -> Option<Self::Theme> {
632 self.program.theme(state, window)
633 }
634
635 fn style(
636 &self,
637 state: &Self::State,
638 theme: &Self::Theme,
639 ) -> theme::Style {
640 self.program.style(state, theme)
641 }
642
643 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
644 self.program.scale_factor(state, window)
645 }
646 }
647
648 WithExecutor {
649 program,
650 executor: PhantomData::<E>,
651 }
652}
653
654pub trait Renderer:
656 text::Renderer<Font = Font> + compositor::Default + renderer::Headless
657{
658}
659
660impl<T> Renderer for T where
661 T: text::Renderer<Font = Font> + compositor::Default + renderer::Headless
662{
663}
664
665pub struct Instance<P: Program> {
667 program: P,
668 state: P::State,
669}
670
671impl<P: Program> Instance<P> {
672 pub fn new(program: P) -> (Self, Task<P::Message>) {
674 let (state, task) = program.boot();
675
676 (Self { program, state }, task)
677 }
678
679 pub fn title(&self, window: window::Id) -> String {
681 self.program.title(&self.state, window)
682 }
683
684 pub fn update(&mut self, message: P::Message) -> Task<P::Message> {
686 self.program.update(&mut self.state, message)
687 }
688
689 pub fn view(
691 &self,
692 window: window::Id,
693 ) -> Element<'_, P::Message, P::Theme, P::Renderer> {
694 self.program.view(&self.state, window)
695 }
696
697 pub fn subscription(&self) -> Subscription<P::Message> {
699 self.program.subscription(&self.state)
700 }
701
702 pub fn theme(&self, window: window::Id) -> Option<P::Theme> {
704 self.program.theme(&self.state, window)
705 }
706
707 pub fn style(&self, theme: &P::Theme) -> theme::Style {
709 self.program.style(&self.state, theme)
710 }
711
712 pub fn scale_factor(&self, window: window::Id) -> f32 {
714 self.program.scale_factor(&self.state, window)
715 }
716}