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(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message>;
53
54 fn view<'a>(
55 &self,
56 state: &'a Self::State,
57 window: window::Id,
58 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer>;
59
60 fn title(&self, _state: &Self::State, _window: window::Id) -> String {
61 let mut title = String::new();
62
63 for (i, part) in Self::name().split("_").enumerate() {
64 use std::borrow::Cow;
65
66 let part = match part {
67 "a" | "an" | "of" | "in" | "and" => Cow::Borrowed(part),
68 _ => {
69 let mut part = part.to_owned();
70
71 if let Some(first_letter) = part.get_mut(0..1) {
72 first_letter.make_ascii_uppercase();
73 }
74
75 Cow::Owned(part)
76 }
77 };
78
79 if i > 0 {
80 title.push(' ');
81 }
82
83 title.push_str(&part);
84 }
85
86 format!("{title} - Iced")
87 }
88
89 fn subscription(&self, _state: &Self::State) -> Subscription<Self::Message> {
90 Subscription::none()
91 }
92
93 fn theme(&self, _state: &Self::State, _window: window::Id) -> Option<Self::Theme> {
94 None
95 }
96
97 fn style(&self, _state: &Self::State, theme: &Self::Theme) -> theme::Style {
98 theme::Base::base(theme)
99 }
100
101 fn scale_factor(&self, _state: &Self::State, _window: window::Id) -> f32 {
102 1.0
103 }
104
105 fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
106 &[]
107 }
108}
109
110pub fn with_title<P: Program>(
112 program: P,
113 title: impl Fn(&P::State, window::Id) -> String,
114) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
115 struct WithTitle<P, Title> {
116 program: P,
117 title: Title,
118 }
119
120 impl<P, Title> Program for WithTitle<P, Title>
121 where
122 P: Program,
123 Title: Fn(&P::State, window::Id) -> String,
124 {
125 type State = P::State;
126 type Message = P::Message;
127 type Theme = P::Theme;
128 type Renderer = P::Renderer;
129 type Executor = P::Executor;
130
131 fn title(&self, state: &Self::State, window: window::Id) -> String {
132 (self.title)(state, window)
133 }
134
135 fn name() -> &'static str {
136 P::name()
137 }
138
139 fn settings(&self) -> Settings {
140 self.program.settings()
141 }
142
143 fn window(&self) -> Option<window::Settings> {
144 self.program.window()
145 }
146
147 fn boot(&self) -> (Self::State, Task<Self::Message>) {
148 self.program.boot()
149 }
150
151 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
152 self.program.update(state, message)
153 }
154
155 fn view<'a>(
156 &self,
157 state: &'a Self::State,
158 window: window::Id,
159 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
160 self.program.view(state, window)
161 }
162
163 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
164 self.program.theme(state, window)
165 }
166
167 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
168 self.program.subscription(state)
169 }
170
171 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
172 self.program.style(state, theme)
173 }
174
175 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
176 self.program.scale_factor(state, window)
177 }
178 }
179
180 WithTitle { program, title }
181}
182
183pub fn with_subscription<P: Program>(
185 program: P,
186 f: impl Fn(&P::State) -> Subscription<P::Message>,
187) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
188 struct WithSubscription<P, F> {
189 program: P,
190 subscription: F,
191 }
192
193 impl<P: Program, F> Program for WithSubscription<P, F>
194 where
195 F: Fn(&P::State) -> Subscription<P::Message>,
196 {
197 type State = P::State;
198 type Message = P::Message;
199 type Theme = P::Theme;
200 type Renderer = P::Renderer;
201 type Executor = P::Executor;
202
203 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
204 (self.subscription)(state)
205 }
206
207 fn name() -> &'static str {
208 P::name()
209 }
210
211 fn settings(&self) -> Settings {
212 self.program.settings()
213 }
214
215 fn window(&self) -> Option<window::Settings> {
216 self.program.window()
217 }
218
219 fn boot(&self) -> (Self::State, Task<Self::Message>) {
220 self.program.boot()
221 }
222
223 fn update(&self, state: &mut Self::State, message: Self::Message) -> 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 title(&self, state: &Self::State, window: window::Id) -> String {
236 self.program.title(state, window)
237 }
238
239 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
240 self.program.theme(state, window)
241 }
242
243 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
244 self.program.style(state, theme)
245 }
246
247 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
248 self.program.scale_factor(state, window)
249 }
250 }
251
252 WithSubscription {
253 program,
254 subscription: f,
255 }
256}
257
258pub fn with_theme<P: Program>(
260 program: P,
261 f: impl Fn(&P::State, window::Id) -> Option<P::Theme>,
262) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
263 struct WithTheme<P, F> {
264 program: P,
265 theme: F,
266 }
267
268 impl<P: Program, F> Program for WithTheme<P, F>
269 where
270 F: Fn(&P::State, window::Id) -> Option<P::Theme>,
271 {
272 type State = P::State;
273 type Message = P::Message;
274 type Theme = P::Theme;
275 type Renderer = P::Renderer;
276 type Executor = P::Executor;
277
278 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
279 (self.theme)(state, window)
280 }
281
282 fn name() -> &'static str {
283 P::name()
284 }
285
286 fn settings(&self) -> Settings {
287 self.program.settings()
288 }
289
290 fn window(&self) -> Option<window::Settings> {
291 self.program.window()
292 }
293
294 fn boot(&self) -> (Self::State, Task<Self::Message>) {
295 self.program.boot()
296 }
297
298 fn title(&self, state: &Self::State, window: window::Id) -> String {
299 self.program.title(state, window)
300 }
301
302 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
303 self.program.update(state, message)
304 }
305
306 fn view<'a>(
307 &self,
308 state: &'a Self::State,
309 window: window::Id,
310 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
311 self.program.view(state, window)
312 }
313
314 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
315 self.program.subscription(state)
316 }
317
318 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
319 self.program.style(state, theme)
320 }
321
322 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
323 self.program.scale_factor(state, window)
324 }
325 }
326
327 WithTheme { program, theme: f }
328}
329
330pub fn with_style<P: Program>(
332 program: P,
333 f: impl Fn(&P::State, &P::Theme) -> theme::Style,
334) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
335 struct WithStyle<P, F> {
336 program: P,
337 style: F,
338 }
339
340 impl<P: Program, F> Program for WithStyle<P, F>
341 where
342 F: Fn(&P::State, &P::Theme) -> theme::Style,
343 {
344 type State = P::State;
345 type Message = P::Message;
346 type Theme = P::Theme;
347 type Renderer = P::Renderer;
348 type Executor = P::Executor;
349
350 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
351 (self.style)(state, theme)
352 }
353
354 fn name() -> &'static str {
355 P::name()
356 }
357
358 fn settings(&self) -> Settings {
359 self.program.settings()
360 }
361
362 fn window(&self) -> Option<window::Settings> {
363 self.program.window()
364 }
365
366 fn boot(&self) -> (Self::State, Task<Self::Message>) {
367 self.program.boot()
368 }
369
370 fn title(&self, state: &Self::State, window: window::Id) -> String {
371 self.program.title(state, window)
372 }
373
374 fn update(&self, state: &mut Self::State, message: Self::Message) -> 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(&self, state: &Self::State) -> Subscription<Self::Message> {
387 self.program.subscription(state)
388 }
389
390 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
391 self.program.theme(state, window)
392 }
393
394 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
395 self.program.scale_factor(state, window)
396 }
397 }
398
399 WithStyle { program, style: f }
400}
401
402pub fn with_scale_factor<P: Program>(
404 program: P,
405 f: impl Fn(&P::State, window::Id) -> f32,
406) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
407 struct WithScaleFactor<P, F> {
408 program: P,
409 scale_factor: F,
410 }
411
412 impl<P: Program, F> Program for WithScaleFactor<P, F>
413 where
414 F: Fn(&P::State, window::Id) -> f32,
415 {
416 type State = P::State;
417 type Message = P::Message;
418 type Theme = P::Theme;
419 type Renderer = P::Renderer;
420 type Executor = P::Executor;
421
422 fn title(&self, state: &Self::State, window: window::Id) -> String {
423 self.program.title(state, window)
424 }
425
426 fn name() -> &'static str {
427 P::name()
428 }
429
430 fn settings(&self) -> Settings {
431 self.program.settings()
432 }
433
434 fn window(&self) -> Option<window::Settings> {
435 self.program.window()
436 }
437
438 fn boot(&self) -> (Self::State, Task<Self::Message>) {
439 self.program.boot()
440 }
441
442 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
443 self.program.update(state, message)
444 }
445
446 fn view<'a>(
447 &self,
448 state: &'a Self::State,
449 window: window::Id,
450 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
451 self.program.view(state, window)
452 }
453
454 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
455 self.program.subscription(state)
456 }
457
458 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
459 self.program.theme(state, window)
460 }
461
462 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
463 self.program.style(state, theme)
464 }
465
466 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
467 (self.scale_factor)(state, window)
468 }
469 }
470
471 WithScaleFactor {
472 program,
473 scale_factor: f,
474 }
475}
476
477pub fn with_executor<P: Program, E: Executor>(
479 program: P,
480) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
481 use std::marker::PhantomData;
482
483 struct WithExecutor<P, E> {
484 program: P,
485 executor: PhantomData<E>,
486 }
487
488 impl<P: Program, E> Program for WithExecutor<P, E>
489 where
490 E: Executor,
491 {
492 type State = P::State;
493 type Message = P::Message;
494 type Theme = P::Theme;
495 type Renderer = P::Renderer;
496 type Executor = E;
497
498 fn title(&self, state: &Self::State, window: window::Id) -> String {
499 self.program.title(state, window)
500 }
501
502 fn name() -> &'static str {
503 P::name()
504 }
505
506 fn settings(&self) -> Settings {
507 self.program.settings()
508 }
509
510 fn window(&self) -> Option<window::Settings> {
511 self.program.window()
512 }
513
514 fn boot(&self) -> (Self::State, Task<Self::Message>) {
515 self.program.boot()
516 }
517
518 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
519 self.program.update(state, message)
520 }
521
522 fn view<'a>(
523 &self,
524 state: &'a Self::State,
525 window: window::Id,
526 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
527 self.program.view(state, window)
528 }
529
530 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
531 self.program.subscription(state)
532 }
533
534 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
535 self.program.theme(state, window)
536 }
537
538 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
539 self.program.style(state, theme)
540 }
541
542 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
543 self.program.scale_factor(state, window)
544 }
545 }
546
547 WithExecutor {
548 program,
549 executor: PhantomData::<E>,
550 }
551}
552
553pub trait Renderer: text::Renderer<Font = Font> + compositor::Default + renderer::Headless {}
555
556impl<T> Renderer for T where
557 T: text::Renderer<Font = Font> + compositor::Default + renderer::Headless
558{
559}
560
561pub struct Instance<P: Program> {
563 program: P,
564 state: P::State,
565}
566
567impl<P: Program> Instance<P> {
568 pub fn new(program: P) -> (Self, Task<P::Message>) {
570 let (state, task) = program.boot();
571
572 (Self { program, state }, task)
573 }
574
575 pub fn title(&self, window: window::Id) -> String {
577 self.program.title(&self.state, window)
578 }
579
580 pub fn update(&mut self, message: P::Message) -> Task<P::Message> {
582 self.program.update(&mut self.state, message)
583 }
584
585 pub fn view(&self, window: window::Id) -> Element<'_, P::Message, P::Theme, P::Renderer> {
587 self.program.view(&self.state, window)
588 }
589
590 pub fn subscription(&self) -> Subscription<P::Message> {
592 self.program.subscription(&self.state)
593 }
594
595 pub fn theme(&self, window: window::Id) -> Option<P::Theme> {
597 self.program.theme(&self.state, window)
598 }
599
600 pub fn style(&self, theme: &P::Theme) -> theme::Style {
602 self.program.style(&self.state, theme)
603 }
604
605 pub fn scale_factor(&self, window: window::Id) -> f32 {
607 self.program.scale_factor(&self.state, window)
608 }
609}