1use crate::application;
3use crate::message;
4use crate::program::{self, Program};
5use crate::shell;
6use crate::theme;
7use crate::window;
8use crate::{Element, Executor, Font, Preset, Result, Settings, Subscription, Task, Theme};
9
10#[cfg(feature = "hot")]
11use crate::hot::Hot;
12
13use std::borrow::Cow;
14
15pub fn daemon<State, Message, Theme, Renderer>(
26 boot: impl application::BootFn<State, Message>,
27 update: impl application::UpdateFn<State, Message>,
28 view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,
29) -> Daemon<impl Program<State = State, Message = Message, Theme = Theme>>
30where
31 State: 'static,
32 Message: Send + 'static,
33 Theme: theme::Base,
34 Renderer: program::Renderer,
35{
36 use std::marker::PhantomData;
37
38 struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {
39 boot: Boot,
40 update: Update,
41 view: View,
42 _state: PhantomData<State>,
43 _message: PhantomData<Message>,
44 _theme: PhantomData<Theme>,
45 _renderer: PhantomData<Renderer>,
46 }
47
48 impl<State, Message, Theme, Renderer, Boot, Update, View> Program
49 for Instance<State, Message, Theme, Renderer, Boot, Update, View>
50 where
51 Message: Send + 'static,
52 Theme: theme::Base,
53 Renderer: program::Renderer,
54 Boot: application::BootFn<State, Message>,
55 Update: application::UpdateFn<State, Message>,
56 View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,
57 {
58 type State = State;
59 type Message = Message;
60 type Theme = Theme;
61 type Renderer = Renderer;
62 type Executor = iced_futures::backend::default::Executor;
63
64 fn name() -> &'static str {
65 let name = std::any::type_name::<State>();
66
67 name.split("::").next().unwrap_or("a_cool_daemon")
68 }
69
70 fn settings(&self) -> Settings {
71 Settings::default()
72 }
73
74 fn window(&self) -> Option<iced_core::window::Settings> {
75 None
76 }
77
78 fn boot(&self) -> (Self::State, Task<Self::Message>) {
79 self.boot.boot()
80 }
81
82 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
83 self.update.update(state, message)
84 }
85
86 fn view<'a>(
87 &self,
88 state: &'a Self::State,
89 window: window::Id,
90 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
91 self.view.view(state, window)
92 }
93 }
94
95 Daemon {
96 raw: Instance {
97 boot,
98 update,
99 view,
100 _state: PhantomData,
101 _message: PhantomData,
102 _theme: PhantomData,
103 _renderer: PhantomData,
104 },
105 settings: Settings::default(),
106 presets: Vec::new(),
107 }
108}
109
110#[derive(Debug)]
118pub struct Daemon<P: Program> {
119 raw: P,
120 settings: Settings,
121 presets: Vec<Preset<P::State, P::Message>>,
122}
123
124impl<P: Program> Daemon<P> {
125 pub fn run(self) -> Result
127 where
128 Self: 'static,
129 P::Message: message::MaybeDebug + message::MaybeClone,
130 {
131 #[cfg(feature = "debug")]
132 iced_debug::init(iced_debug::Metadata {
133 name: P::name(),
134 theme: None,
135 can_time_travel: cfg!(feature = "time-travel"),
136 });
137
138 #[cfg(feature = "tester")]
139 let program = iced_tester::attach(self);
140
141 #[cfg(all(feature = "debug", not(feature = "tester")))]
142 let program = iced_devtools::attach(self);
143
144 #[cfg(not(any(feature = "tester", feature = "debug")))]
145 let program = self;
146
147 #[cfg(feature = "hot")]
148 let program = Hot::new(program);
149
150 Ok(shell::run(program)?)
151 }
152
153 pub fn settings(self, settings: Settings) -> Self {
155 Self { settings, ..self }
156 }
157
158 pub fn antialiasing(self, antialiasing: bool) -> Self {
160 Self {
161 settings: Settings {
162 antialiasing,
163 ..self.settings
164 },
165 ..self
166 }
167 }
168
169 pub fn default_font(self, default_font: Font) -> Self {
171 Self {
172 settings: Settings {
173 font: default_font,
174 ..self.settings
175 },
176 ..self
177 }
178 }
179
180 pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {
182 self.settings.fonts.push(font.into());
183 self
184 }
185
186 pub fn title(
188 self,
189 title: impl TitleFn<P::State>,
190 ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
191 Daemon {
192 raw: WithTitle {
193 program: self.raw,
194 title,
195 },
196 settings: self.settings,
197 presets: self.presets,
198 }
199 }
200
201 pub fn subscription(
203 self,
204 f: impl Fn(&P::State) -> Subscription<P::Message>,
205 ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
206 Daemon {
207 raw: program::with_subscription(self.raw, f),
208 settings: self.settings,
209 presets: self.presets,
210 }
211 }
212
213 pub fn theme(
215 self,
216 f: impl ThemeFn<P::State, P::Theme>,
217 ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
218 Daemon {
219 raw: WithTheme {
220 program: self.raw,
221 theme: f,
222 },
223 settings: self.settings,
224 presets: self.presets,
225 }
226 }
227
228 pub fn style(
230 self,
231 f: impl Fn(&P::State, &P::Theme) -> theme::Style,
232 ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
233 Daemon {
234 raw: program::with_style(self.raw, f),
235 settings: self.settings,
236 presets: self.presets,
237 }
238 }
239
240 pub fn scale_factor(
242 self,
243 f: impl Fn(&P::State, window::Id) -> f32,
244 ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
245 Daemon {
246 raw: WithScaleFactor {
247 program: self.raw,
248 scale_factor: f,
249 },
250 settings: self.settings,
251 presets: self.presets,
252 }
253 }
254
255 pub fn executor<E>(
257 self,
258 ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>>
259 where
260 E: Executor,
261 {
262 Daemon {
263 raw: program::with_executor::<P, E>(self.raw),
264 settings: self.settings,
265 presets: self.presets,
266 }
267 }
268
269 pub fn presets(self, presets: impl IntoIterator<Item = Preset<P::State, P::Message>>) -> Self {
275 Self {
276 presets: presets.into_iter().collect(),
277 ..self
278 }
279 }
280}
281
282impl<P: Program> Program for Daemon<P> {
283 type State = P::State;
284 type Message = P::Message;
285 type Theme = P::Theme;
286 type Renderer = P::Renderer;
287 type Executor = P::Executor;
288
289 fn name() -> &'static str {
290 P::name()
291 }
292
293 fn settings(&self) -> Settings {
294 self.settings.clone()
295 }
296
297 fn window(&self) -> Option<window::Settings> {
298 None
299 }
300
301 fn boot(&self) -> (Self::State, Task<Self::Message>) {
302 self.raw.boot()
303 }
304
305 #[inline]
306 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
307 self.raw.update(state, message)
308 }
309
310 #[inline]
311 fn view<'a>(
312 &self,
313 state: &'a Self::State,
314 window: window::Id,
315 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
316 self.raw.view(state, window)
317 }
318
319 #[inline]
320 fn title(&self, state: &Self::State, window: window::Id) -> String {
321 self.raw.title(state, window)
322 }
323
324 #[inline]
325 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
326 self.raw.subscription(state)
327 }
328
329 #[inline]
330 fn theme(&self, state: &Self::State, window: iced_core::window::Id) -> Option<Self::Theme> {
331 self.raw.theme(state, window)
332 }
333
334 #[inline]
335 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
336 self.raw.style(state, theme)
337 }
338
339 #[inline]
340 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
341 self.raw.scale_factor(state, window)
342 }
343
344 fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
345 &self.presets
346 }
347}
348
349pub trait TitleFn<State> {
356 fn title(&self, state: &State, window: window::Id) -> String;
358}
359
360impl<State> TitleFn<State> for &'static str {
361 fn title(&self, _state: &State, _window: window::Id) -> String {
362 self.to_string()
363 }
364}
365
366impl<T, State> TitleFn<State> for T
367where
368 T: Fn(&State, window::Id) -> String,
369{
370 fn title(&self, state: &State, window: window::Id) -> String {
371 self(state, window)
372 }
373}
374
375pub trait ViewFn<'a, State, Message, Theme, Renderer> {
380 fn view(&self, state: &'a State, window: window::Id) -> Element<'a, Message, Theme, Renderer>;
382}
383
384impl<'a, T, State, Message, Theme, Renderer, Widget> ViewFn<'a, State, Message, Theme, Renderer>
385 for T
386where
387 T: Fn(&'a State, window::Id) -> Widget,
388 State: 'static,
389 Widget: Into<Element<'a, Message, Theme, Renderer>>,
390{
391 #[inline]
392 fn view(&self, state: &'a State, window: window::Id) -> Element<'a, Message, Theme, Renderer> {
393 self(state, window).into()
394 }
395}
396
397pub trait ThemeFn<State, Theme> {
406 fn theme(&self, state: &State, window: window::Id) -> Option<Theme>;
411}
412
413impl<State> ThemeFn<State, Theme> for Theme {
414 fn theme(&self, _state: &State, _window: window::Id) -> Option<Theme> {
415 Some(self.clone())
416 }
417}
418
419impl<F, T, State, Theme> ThemeFn<State, Theme> for F
420where
421 F: Fn(&State, window::Id) -> T,
422 T: Into<Option<Theme>>,
423{
424 fn theme(&self, state: &State, window: window::Id) -> Option<Theme> {
425 (self)(state, window).into()
426 }
427}
428
429struct WithTitle<P, Title> {
431 program: P,
432 title: Title,
433}
434
435impl<P, Title> Program for WithTitle<P, Title>
436where
437 P: Program,
438 Title: TitleFn<P::State>,
439{
440 type State = P::State;
441 type Message = P::Message;
442 type Theme = P::Theme;
443 type Renderer = P::Renderer;
444 type Executor = P::Executor;
445
446 fn name() -> &'static str {
447 P::name()
448 }
449
450 #[inline]
451 fn settings(&self) -> Settings {
452 self.program.settings()
453 }
454
455 #[inline]
456 fn window(&self) -> Option<window::Settings> {
457 self.program.window()
458 }
459
460 #[inline]
461 fn boot(&self) -> (Self::State, Task<Self::Message>) {
462 self.program.boot()
463 }
464
465 #[inline]
466 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
467 self.program.update(state, message)
468 }
469
470 #[inline]
471 fn view<'a>(
472 &self,
473 state: &'a Self::State,
474 window: window::Id,
475 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
476 self.program.view(state, window)
477 }
478
479 #[inline]
480 fn title(&self, state: &Self::State, window: window::Id) -> String {
481 self.title.title(state, window)
482 }
483
484 #[inline]
485 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
486 self.program.subscription(state)
487 }
488
489 #[inline]
490 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
491 self.program.theme(state, window)
492 }
493
494 #[inline]
495 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
496 self.program.style(state, theme)
497 }
498
499 #[inline]
500 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
501 self.program.scale_factor(state, window)
502 }
503}
504
505struct WithTheme<P, Theme> {
507 program: P,
508 theme: Theme,
509}
510
511impl<P, Theme> Program for WithTheme<P, Theme>
512where
513 P: Program,
514 Theme: ThemeFn<P::State, P::Theme>,
515{
516 type State = P::State;
517 type Message = P::Message;
518 type Theme = P::Theme;
519 type Renderer = P::Renderer;
520 type Executor = P::Executor;
521
522 fn name() -> &'static str {
523 P::name()
524 }
525
526 #[inline]
527 fn settings(&self) -> Settings {
528 self.program.settings()
529 }
530
531 #[inline]
532 fn window(&self) -> Option<window::Settings> {
533 self.program.window()
534 }
535
536 #[inline]
537 fn boot(&self) -> (Self::State, Task<Self::Message>) {
538 self.program.boot()
539 }
540
541 #[inline]
542 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
543 self.program.update(state, message)
544 }
545
546 #[inline]
547 fn view<'a>(
548 &self,
549 state: &'a Self::State,
550 window: window::Id,
551 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
552 self.program.view(state, window)
553 }
554
555 #[inline]
556 fn title(&self, state: &Self::State, window: window::Id) -> String {
557 self.program.title(state, window)
558 }
559
560 #[inline]
561 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
562 self.program.subscription(state)
563 }
564
565 #[inline]
566 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
567 self.theme.theme(state, window)
568 }
569
570 #[inline]
571 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
572 self.program.style(state, theme)
573 }
574
575 #[inline]
576 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
577 self.program.scale_factor(state, window)
578 }
579}
580
581struct WithScaleFactor<P, F> {
583 program: P,
584 scale_factor: F,
585}
586
587impl<P, F> Program for WithScaleFactor<P, F>
588where
589 P: Program,
590 F: Fn(&P::State, window::Id) -> f32,
591{
592 type State = P::State;
593 type Message = P::Message;
594 type Theme = P::Theme;
595 type Renderer = P::Renderer;
596 type Executor = P::Executor;
597
598 fn name() -> &'static str {
599 P::name()
600 }
601
602 #[inline]
603 fn settings(&self) -> Settings {
604 self.program.settings()
605 }
606
607 #[inline]
608 fn window(&self) -> Option<window::Settings> {
609 self.program.window()
610 }
611
612 #[inline]
613 fn boot(&self) -> (Self::State, Task<Self::Message>) {
614 self.program.boot()
615 }
616
617 #[inline]
618 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
619 self.program.update(state, message)
620 }
621
622 #[inline]
623 fn view<'a>(
624 &self,
625 state: &'a Self::State,
626 window: window::Id,
627 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
628 self.program.view(state, window)
629 }
630
631 #[inline]
632 fn title(&self, state: &Self::State, window: window::Id) -> String {
633 self.program.title(state, window)
634 }
635
636 #[inline]
637 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
638 self.program.subscription(state)
639 }
640
641 #[inline]
642 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
643 self.program.theme(state, window)
644 }
645
646 #[inline]
647 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
648 self.program.style(state, theme)
649 }
650
651 #[inline]
652 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
653 (self.scale_factor)(state, window)
654 }
655}