1use crate::backend;
34use crate::message;
35use crate::program::{self, Program};
36use crate::shell;
37use crate::theme;
38use crate::widget::text;
39use crate::window;
40use crate::{
41 Backend, Element, Executor, Font, Never, Preset, Result, Settings, Size, Subscription, Task,
42 Theme,
43};
44
45#[cfg(feature = "hot")]
46use crate::hot::Hot;
47
48use std::borrow::Cow;
49
50pub mod timed;
51
52pub use timed::timed;
53
54pub fn application<State, Message, Theme, Renderer>(
83 boot: impl BootFn<State, Message>,
84 update: impl UpdateFn<State, Message>,
85 view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,
86) -> Application<impl Program<State = State, Message = Message, Theme = Theme>>
87where
88 State: 'static,
89 Message: Send + 'static,
90 Theme: theme::Base,
91 Renderer: program::Renderer,
92{
93 use std::marker::PhantomData;
94
95 struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {
96 boot: Boot,
97 update: Update,
98 view: View,
99 _state: PhantomData<State>,
100 _message: PhantomData<Message>,
101 _theme: PhantomData<Theme>,
102 _renderer: PhantomData<Renderer>,
103 }
104
105 impl<State, Message, Theme, Renderer, Boot, Update, View> Program
106 for Instance<State, Message, Theme, Renderer, Boot, Update, View>
107 where
108 Message: Send + 'static,
109 Theme: theme::Base,
110 Renderer: program::Renderer,
111 Boot: self::BootFn<State, Message>,
112 Update: self::UpdateFn<State, Message>,
113 View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,
114 {
115 type State = State;
116 type Message = Message;
117 type Theme = Theme;
118 type Renderer = Renderer;
119 type Executor = iced_futures::backend::default::Executor;
120
121 fn name() -> &'static str {
122 let name = std::any::type_name::<State>();
123
124 name.split("::").next().unwrap_or("a_cool_application")
125 }
126
127 fn boot(&self) -> (State, Task<Message>) {
128 self.boot.boot()
129 }
130
131 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
132 self.update.update(state, message)
133 }
134
135 fn view<'a>(
136 &self,
137 state: &'a Self::State,
138 _window: window::Id,
139 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
140 self.view.view(state)
141 }
142
143 fn settings(&self) -> Settings {
144 Settings::default()
145 }
146
147 fn window(&self) -> Option<iced_core::window::Settings> {
148 Some(window::Settings::default())
149 }
150 }
151
152 Application {
153 raw: Instance {
154 boot,
155 update,
156 view,
157 _state: PhantomData,
158 _message: PhantomData,
159 _theme: PhantomData,
160 _renderer: PhantomData,
161 },
162 settings: Settings::default(),
163 window: window::Settings::default(),
164 presets: Vec::new(),
165 }
166}
167
168#[derive(Debug)]
176pub struct Application<P: Program> {
177 raw: P,
178 settings: Settings,
179 window: window::Settings,
180 presets: Vec<Preset<P::State, P::Message>>,
181}
182
183impl<P: Program> Application<P> {
184 pub fn run(self) -> Result
186 where
187 Self: 'static,
188 P::Message: message::MaybeDebug + message::MaybeClone,
189 {
190 #[cfg(feature = "debug")]
191 iced_debug::init(iced_debug::Metadata {
192 name: P::name(),
193 theme: None,
194 can_time_travel: cfg!(feature = "time-travel"),
195 });
196
197 #[cfg(feature = "tester")]
198 let program = iced_tester::attach(self);
199
200 #[cfg(all(
201 feature = "debug",
202 not(feature = "tester"),
203 not(target_arch = "wasm32")
204 ))]
205 let program = iced_devtools::attach(self);
206
207 #[cfg(not(any(
208 feature = "tester",
209 all(feature = "debug", not(target_arch = "wasm32"))
210 )))]
211 let program = self;
212
213 #[cfg(feature = "hot")]
214 let program = Hot::new(program);
215
216 Ok(shell::run(program)?)
217 }
218
219 pub fn settings(self, settings: Settings) -> Self {
221 Self { settings, ..self }
222 }
223
224 pub fn antialiasing(self, antialiasing: bool) -> Self {
226 Self {
227 settings: Settings {
228 antialiasing,
229 ..self.settings
230 },
231 ..self
232 }
233 }
234
235 pub fn font(self, font: Font) -> Self {
237 Self {
238 settings: Settings {
239 font,
240 ..self.settings
241 },
242 ..self
243 }
244 }
245
246 pub fn line_height(self, line_height: text::LineHeight) -> Self {
248 Self {
249 settings: Settings {
250 line_height,
251 ..self.settings
252 },
253 ..self
254 }
255 }
256
257 pub fn fonts(mut self, fonts: impl IntoIterator<Item = impl Into<Cow<'static, [u8]>>>) -> Self {
259 self.settings
260 .fonts
261 .extend(fonts.into_iter().map(Into::into));
262
263 self
264 }
265
266 pub fn window(self, window: window::Settings) -> Self {
270 Self { window, ..self }
271 }
272
273 pub fn centered(self) -> Self {
275 Self {
276 window: window::Settings {
277 position: window::Position::Centered,
278 ..self.window
279 },
280 ..self
281 }
282 }
283
284 pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self {
286 Self {
287 window: window::Settings {
288 exit_on_close_request,
289 ..self.window
290 },
291 ..self
292 }
293 }
294
295 pub fn window_size(self, size: impl Into<Size>) -> Self {
297 Self {
298 window: window::Settings {
299 size: size.into(),
300 ..self.window
301 },
302 ..self
303 }
304 }
305
306 pub fn transparent(self, transparent: bool) -> Self {
308 Self {
309 window: window::Settings {
310 transparent,
311 ..self.window
312 },
313 ..self
314 }
315 }
316
317 pub fn resizable(self, resizable: bool) -> Self {
319 Self {
320 window: window::Settings {
321 resizable,
322 ..self.window
323 },
324 ..self
325 }
326 }
327
328 pub fn decorations(self, decorations: bool) -> Self {
330 Self {
331 window: window::Settings {
332 decorations,
333 ..self.window
334 },
335 ..self
336 }
337 }
338
339 pub fn position(self, position: window::Position) -> Self {
341 Self {
342 window: window::Settings {
343 position,
344 ..self.window
345 },
346 ..self
347 }
348 }
349
350 pub fn level(self, level: window::Level) -> Self {
352 Self {
353 window: window::Settings {
354 level,
355 ..self.window
356 },
357 ..self
358 }
359 }
360
361 pub fn backend(self, backend: Backend) -> Self {
363 Self {
364 settings: Settings {
365 backend,
366 ..self.settings
367 },
368 ..self
369 }
370 }
371
372 pub fn power_preference(self, power_preference: backend::PowerPreference) -> Self {
374 Self {
375 settings: Settings {
376 power_preference,
377 ..self.settings
378 },
379 ..self
380 }
381 }
382
383 pub fn title(
385 self,
386 title: impl TitleFn<P::State>,
387 ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
388 Application {
389 raw: with_title(self.raw, title),
390 settings: self.settings,
391 window: self.window,
392 presets: self.presets,
393 }
394 }
395
396 pub fn subscription(
398 self,
399 f: impl Fn(&P::State) -> Subscription<P::Message>,
400 ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
401 Application {
402 raw: program::with_subscription(self.raw, f),
403 settings: self.settings,
404 window: self.window,
405 presets: self.presets,
406 }
407 }
408
409 pub fn theme(
411 self,
412 f: impl ThemeFn<P::State, P::Theme>,
413 ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
414 Application {
415 raw: with_theme(self.raw, f),
416 settings: self.settings,
417 window: self.window,
418 presets: self.presets,
419 }
420 }
421
422 pub fn style(
424 self,
425 f: impl Fn(&P::State, &P::Theme) -> theme::Style,
426 ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
427 Application {
428 raw: program::with_style(self.raw, f),
429 settings: self.settings,
430 window: self.window,
431 presets: self.presets,
432 }
433 }
434
435 pub fn scale_factor(
437 self,
438 f: impl Fn(&P::State) -> f32,
439 ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {
440 Application {
441 raw: with_scale_factor(self.raw, f),
442 settings: self.settings,
443 window: self.window,
444 presets: self.presets,
445 }
446 }
447
448 pub fn executor<E>(
450 self,
451 ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>>
452 where
453 E: Executor,
454 {
455 Application {
456 raw: program::with_executor::<P, E>(self.raw),
457 settings: self.settings,
458 window: self.window,
459 presets: self.presets,
460 }
461 }
462
463 pub fn presets(self, presets: impl IntoIterator<Item = Preset<P::State, P::Message>>) -> Self {
469 Self {
470 presets: presets.into_iter().collect(),
471 ..self
472 }
473 }
474}
475
476impl<P: Program> Program for Application<P> {
477 type State = P::State;
478 type Message = P::Message;
479 type Theme = P::Theme;
480 type Renderer = P::Renderer;
481 type Executor = P::Executor;
482
483 fn name() -> &'static str {
484 P::name()
485 }
486
487 fn settings(&self) -> Settings {
488 self.settings.clone()
489 }
490
491 fn window(&self) -> Option<window::Settings> {
492 Some(self.window.clone())
493 }
494
495 #[inline]
496 fn boot(&self) -> (Self::State, Task<Self::Message>) {
497 self.raw.boot()
498 }
499
500 #[inline]
501 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
502 self.raw.update(state, message)
503 }
504
505 #[inline]
506 fn view<'a>(
507 &self,
508 state: &'a Self::State,
509 window: window::Id,
510 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
511 self.raw.view(state, window)
512 }
513
514 #[inline]
515 fn title(&self, state: &Self::State, window: window::Id) -> String {
516 self.raw.title(state, window)
517 }
518
519 #[inline]
520 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
521 self.raw.subscription(state)
522 }
523
524 #[inline]
525 fn theme(&self, state: &Self::State, window: iced_core::window::Id) -> Option<Self::Theme> {
526 self.raw.theme(state, window)
527 }
528
529 #[inline]
530 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
531 self.raw.style(state, theme)
532 }
533
534 #[inline]
535 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
536 self.raw.scale_factor(state, window)
537 }
538
539 fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
540 &self.presets
541 }
542}
543
544pub trait BootFn<State, Message> {
553 fn boot(&self) -> (State, Task<Message>);
555}
556
557impl<T, C, State, Message> BootFn<State, Message> for T
558where
559 T: Fn() -> C,
560 C: IntoBoot<State, Message>,
561{
562 fn boot(&self) -> (State, Task<Message>) {
563 self().into_boot()
564 }
565}
566
567pub trait IntoBoot<State, Message> {
569 fn into_boot(self) -> (State, Task<Message>);
571}
572
573impl<State, Message> IntoBoot<State, Message> for State {
574 fn into_boot(self) -> (State, Task<Message>) {
575 (self, Task::none())
576 }
577}
578
579impl<State, Message> IntoBoot<State, Message> for (State, Task<Message>) {
580 fn into_boot(self) -> (State, Task<Message>) {
581 self
582 }
583}
584
585pub trait TitleFn<State> {
592 fn title(&self, state: &State) -> String;
594}
595
596impl<State> TitleFn<State> for &'static str {
597 #[inline]
598 fn title(&self, _state: &State) -> String {
599 self.to_string()
600 }
601}
602
603impl<T, State> TitleFn<State> for T
604where
605 T: Fn(&State) -> String,
606{
607 #[inline]
608 fn title(&self, state: &State) -> String {
609 (self)(state)
610 }
611}
612
613pub trait ThemeFn<State, Theme>
622where
623 Theme: theme::Base,
624{
625 fn theme(&self, state: &State) -> Option<Theme>;
630}
631
632impl<State> ThemeFn<State, Theme> for Theme {
633 #[inline]
634 fn theme(&self, _state: &State) -> Option<Theme> {
635 Some(self.clone())
636 }
637}
638
639impl<F, T, State, Theme> ThemeFn<State, Theme> for F
640where
641 F: Fn(&State) -> T,
642 T: Into<Option<Theme>>,
643 Theme: theme::Base,
644{
645 #[inline]
646 fn theme(&self, state: &State) -> Option<Theme> {
647 (self)(state).into()
648 }
649}
650
651pub trait UpdateFn<State, Message> {
656 fn update(&self, state: &mut State, message: Message) -> Task<Message>;
658}
659
660impl<State> UpdateFn<State, Never> for () {
661 fn update(&self, _state: &mut State, _message: Never) -> Task<Never> {
662 Task::none()
663 }
664}
665
666impl<T, State, Message, C> UpdateFn<State, Message> for T
667where
668 T: Fn(&mut State, Message) -> C,
669 C: Into<Task<Message>>,
670{
671 fn update(&self, state: &mut State, message: Message) -> Task<Message> {
672 self(state, message).into()
673 }
674}
675
676pub trait ViewFn<'a, State, Message, Theme, Renderer> {
681 fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer>;
683}
684
685impl<'a, T, State, Message, Theme, Renderer, Widget> ViewFn<'a, State, Message, Theme, Renderer>
686 for T
687where
688 T: Fn(&'a State) -> Widget,
689 State: 'static,
690 Widget: Into<Element<'a, Message, Theme, Renderer>>,
691{
692 #[inline]
693 fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer> {
694 self(state).into()
695 }
696}
697
698fn with_title<P: Program>(
700 program: P,
701 title: impl TitleFn<P::State>,
702) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
703 struct WithTitle<P, Title> {
704 program: P,
705 title: Title,
706 }
707
708 impl<P, Title> Program for WithTitle<P, Title>
709 where
710 P: Program,
711 Title: TitleFn<P::State>,
712 {
713 type State = P::State;
714 type Message = P::Message;
715 type Theme = P::Theme;
716 type Renderer = P::Renderer;
717 type Executor = P::Executor;
718
719 #[inline]
720 fn title(&self, state: &Self::State, _window: window::Id) -> String {
721 self.title.title(state)
722 }
723
724 #[inline]
725 fn name() -> &'static str {
726 P::name()
727 }
728
729 #[inline]
730 fn settings(&self) -> Settings {
731 self.program.settings()
732 }
733
734 #[inline]
735 fn window(&self) -> Option<window::Settings> {
736 self.program.window()
737 }
738
739 #[inline]
740 fn boot(&self) -> (Self::State, Task<Self::Message>) {
741 self.program.boot()
742 }
743
744 #[inline]
745 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
746 self.program.update(state, message)
747 }
748
749 #[inline]
750 fn view<'a>(
751 &self,
752 state: &'a Self::State,
753 window: window::Id,
754 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
755 self.program.view(state, window)
756 }
757
758 #[inline]
759 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
760 self.program.theme(state, window)
761 }
762
763 #[inline]
764 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
765 self.program.subscription(state)
766 }
767
768 #[inline]
769 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
770 self.program.style(state, theme)
771 }
772
773 #[inline]
774 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
775 self.program.scale_factor(state, window)
776 }
777 }
778
779 WithTitle { program, title }
780}
781
782fn with_theme<P: Program>(
784 program: P,
785 f: impl ThemeFn<P::State, P::Theme>,
786) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
787 struct WithTheme<P, F> {
788 program: P,
789 theme: F,
790 }
791
792 impl<P: Program, F> Program for WithTheme<P, F>
793 where
794 F: ThemeFn<P::State, P::Theme>,
795 {
796 type State = P::State;
797 type Message = P::Message;
798 type Theme = P::Theme;
799 type Renderer = P::Renderer;
800 type Executor = P::Executor;
801
802 #[inline]
803 fn theme(&self, state: &Self::State, _window: window::Id) -> Option<Self::Theme> {
804 self.theme.theme(state)
805 }
806
807 #[inline]
808 fn name() -> &'static str {
809 P::name()
810 }
811
812 #[inline]
813 fn settings(&self) -> Settings {
814 self.program.settings()
815 }
816
817 #[inline]
818 fn window(&self) -> Option<window::Settings> {
819 self.program.window()
820 }
821
822 #[inline]
823 fn boot(&self) -> (Self::State, Task<Self::Message>) {
824 self.program.boot()
825 }
826
827 #[inline]
828 fn title(&self, state: &Self::State, window: window::Id) -> String {
829 self.program.title(state, window)
830 }
831
832 #[inline]
833 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
834 self.program.update(state, message)
835 }
836
837 #[inline]
838 fn view<'a>(
839 &self,
840 state: &'a Self::State,
841 window: window::Id,
842 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
843 self.program.view(state, window)
844 }
845
846 #[inline]
847 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
848 self.program.subscription(state)
849 }
850
851 #[inline]
852 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
853 self.program.style(state, theme)
854 }
855
856 #[inline]
857 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
858 self.program.scale_factor(state, window)
859 }
860 }
861
862 WithTheme { program, theme: f }
863}
864
865fn with_scale_factor<P: Program>(
867 program: P,
868 f: impl Fn(&P::State) -> f32,
869) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {
870 struct WithScaleFactor<P, F> {
871 program: P,
872 scale_factor: F,
873 }
874
875 impl<P, F> Program for WithScaleFactor<P, F>
876 where
877 P: Program,
878 F: Fn(&P::State) -> f32,
879 {
880 type State = P::State;
881 type Message = P::Message;
882 type Theme = P::Theme;
883 type Renderer = P::Renderer;
884 type Executor = P::Executor;
885
886 #[inline]
887 fn title(&self, state: &Self::State, window: window::Id) -> String {
888 self.program.title(state, window)
889 }
890
891 #[inline]
892 fn name() -> &'static str {
893 P::name()
894 }
895
896 #[inline]
897 fn settings(&self) -> Settings {
898 self.program.settings()
899 }
900
901 #[inline]
902 fn window(&self) -> Option<window::Settings> {
903 self.program.window()
904 }
905
906 #[inline]
907 fn boot(&self) -> (Self::State, Task<Self::Message>) {
908 self.program.boot()
909 }
910
911 #[inline]
912 fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {
913 self.program.update(state, message)
914 }
915
916 #[inline]
917 fn view<'a>(
918 &self,
919 state: &'a Self::State,
920 window: window::Id,
921 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
922 self.program.view(state, window)
923 }
924
925 #[inline]
926 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
927 self.program.subscription(state)
928 }
929
930 #[inline]
931 fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {
932 self.program.theme(state, window)
933 }
934
935 #[inline]
936 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
937 self.program.style(state, theme)
938 }
939
940 #[inline]
941 fn scale_factor(&self, state: &Self::State, _window: window::Id) -> f32 {
942 (self.scale_factor)(state)
943 }
944 }
945
946 WithScaleFactor {
947 program,
948 scale_factor: f,
949 }
950}