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>
381where
382 Renderer: core::Renderer,
383{
384 fn view(
386 &self,
387 state: &'a State,
388 window: window::Id,
389 ) -> impl core::Widget<Message, Theme, Renderer> + 'a;
390}
391
392impl<'a, T, State, Message, Theme, Renderer, W> ViewFn<'a, State, Message, Theme, Renderer> for T
393where
394 T: Fn(&'a State, window::Id) -> W,
395 State: 'static,
396 W: core::Widget<Message, Theme, Renderer> + 'a,
397 Renderer: core::Renderer,
398{
399 #[inline]
400 fn view(
401 &self,
402 state: &'a State,
403 window: window::Id,
404 ) -> impl core::Widget<Message, Theme, Renderer> + 'a {
405 self(state, window)
406 }
407}
408
409pub trait ThemeFn<State, Theme> {
418 fn theme(&self, state: &State, window: window::Id) -> Option<Theme>;
423}
424
425impl<State> ThemeFn<State, Theme> for Theme {
426 fn theme(&self, _state: &State, _window: window::Id) -> Option<Theme> {
427 Some(self.clone())
428 }
429}
430
431impl<F, T, State, Theme> ThemeFn<State, Theme> for F
432where
433 F: Fn(&State, window::Id) -> T,
434 T: Into<Option<Theme>>,
435{
436 fn theme(&self, state: &State, window: window::Id) -> Option<Theme> {
437 (self)(state, window).into()
438 }
439}
440
441struct WithTitle<P, Title> {
443 program: P,
444 title: Title,
445}
446
447impl<P, Title> Program for WithTitle<P, Title>
448where
449 P: Program,
450 Title: TitleFn<P::State>,
451{
452 type State = P::State;
453 type Message = P::Message;
454 type Theme = P::Theme;
455 type Renderer = P::Renderer;
456 type Executor = P::Executor;
457
458 fn name() -> &'static str {
459 P::name()
460 }
461
462 #[inline]
463 fn settings(&self) -> Settings {
464 self.program.settings()
465 }
466
467 #[inline]
468 fn window(&self) -> Option<window::Settings> {
469 self.program.window()
470 }
471
472 #[inline]
473 fn boot(&self) -> (Self::State, Task<Self::Message>) {
474 self.program.boot()
475 }
476
477 #[inline]
478 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
479 self.program.update(state, message)
480 }
481
482 #[inline]
483 fn view<'a>(
484 &self,
485 state: &'a Self::State,
486 window: window::Id,
487 ) -> impl core::Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
488 self.program.view(state, window)
489 }
490
491 #[inline]
492 fn title(&self, state: &Self::State, window: window::Id) -> String {
493 self.title.title(state, window)
494 }
495
496 #[inline]
497 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
498 self.program.subscription(state)
499 }
500
501 #[inline]
502 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
503 self.program.theme(state, window)
504 }
505
506 #[inline]
507 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
508 self.program.style(state, theme)
509 }
510
511 #[inline]
512 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
513 self.program.scale_factor(state, window)
514 }
515}
516
517struct WithTheme<P, Theme> {
519 program: P,
520 theme: Theme,
521}
522
523impl<P, Theme> Program for WithTheme<P, Theme>
524where
525 P: Program,
526 Theme: ThemeFn<P::State, P::Theme>,
527{
528 type State = P::State;
529 type Message = P::Message;
530 type Theme = P::Theme;
531 type Renderer = P::Renderer;
532 type Executor = P::Executor;
533
534 fn name() -> &'static str {
535 P::name()
536 }
537
538 #[inline]
539 fn settings(&self) -> Settings {
540 self.program.settings()
541 }
542
543 #[inline]
544 fn window(&self) -> Option<window::Settings> {
545 self.program.window()
546 }
547
548 #[inline]
549 fn boot(&self) -> (Self::State, Task<Self::Message>) {
550 self.program.boot()
551 }
552
553 #[inline]
554 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
555 self.program.update(state, message)
556 }
557
558 #[inline]
559 fn view<'a>(
560 &self,
561 state: &'a Self::State,
562 window: window::Id,
563 ) -> impl core::Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
564 self.program.view(state, window)
565 }
566
567 #[inline]
568 fn title(&self, state: &Self::State, window: window::Id) -> String {
569 self.program.title(state, window)
570 }
571
572 #[inline]
573 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
574 self.program.subscription(state)
575 }
576
577 #[inline]
578 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
579 self.theme.theme(state, window)
580 }
581
582 #[inline]
583 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
584 self.program.style(state, theme)
585 }
586
587 #[inline]
588 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
589 self.program.scale_factor(state, window)
590 }
591}
592
593struct WithScaleFactor<P, F> {
595 program: P,
596 scale_factor: F,
597}
598
599impl<P, F> Program for WithScaleFactor<P, F>
600where
601 P: Program,
602 F: Fn(&P::State, window::Id) -> f32,
603{
604 type State = P::State;
605 type Message = P::Message;
606 type Theme = P::Theme;
607 type Renderer = P::Renderer;
608 type Executor = P::Executor;
609
610 fn name() -> &'static str {
611 P::name()
612 }
613
614 #[inline]
615 fn settings(&self) -> Settings {
616 self.program.settings()
617 }
618
619 #[inline]
620 fn window(&self) -> Option<window::Settings> {
621 self.program.window()
622 }
623
624 #[inline]
625 fn boot(&self) -> (Self::State, Task<Self::Message>) {
626 self.program.boot()
627 }
628
629 #[inline]
630 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
631 self.program.update(state, message)
632 }
633
634 #[inline]
635 fn view<'a>(
636 &self,
637 state: &'a Self::State,
638 window: window::Id,
639 ) -> impl core::Widget<Self::Message, Self::Theme, Self::Renderer> + 'a {
640 self.program.view(state, window)
641 }
642
643 #[inline]
644 fn title(&self, state: &Self::State, window: window::Id) -> String {
645 self.program.title(state, window)
646 }
647
648 #[inline]
649 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
650 self.program.subscription(state)
651 }
652
653 #[inline]
654 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
655 self.program.theme(state, window)
656 }
657
658 #[inline]
659 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
660 self.program.style(state, theme)
661 }
662
663 #[inline]
664 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
665 (self.scale_factor)(state, window)
666 }
667}