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