1use crate::message;
34use crate::program::{self, Program};
35use crate::shell;
36use crate::theme;
37use crate::window;
38use crate::{
39 Element, Executor, Font, Preset, Result, Settings, Size, Subscription,
40 Task, Theme,
41};
42
43use iced_debug as debug;
44
45use std::borrow::Cow;
46
47pub mod timed;
48
49pub use timed::timed;
50
51pub fn application<State, Message, Theme, Renderer>(
80 boot: impl BootFn<State, Message>,
81 update: impl UpdateFn<State, Message>,
82 view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,
83) -> Application<impl Program<State = State, Message = Message, Theme = Theme>>
84where
85 State: 'static,
86 Message: Send + 'static,
87 Theme: theme::Base,
88 Renderer: program::Renderer,
89{
90 use std::marker::PhantomData;
91
92 struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {
93 boot: Boot,
94 update: Update,
95 view: View,
96 _state: PhantomData<State>,
97 _message: PhantomData<Message>,
98 _theme: PhantomData<Theme>,
99 _renderer: PhantomData<Renderer>,
100 }
101
102 impl<State, Message, Theme, Renderer, Boot, Update, View> Program
103 for Instance<State, Message, Theme, Renderer, Boot, Update, View>
104 where
105 Message: Send + 'static,
106 Theme: theme::Base,
107 Renderer: program::Renderer,
108 Boot: self::BootFn<State, Message>,
109 Update: self::UpdateFn<State, Message>,
110 View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,
111 {
112 type State = State;
113 type Message = Message;
114 type Theme = Theme;
115 type Renderer = Renderer;
116 type Executor = iced_futures::backend::default::Executor;
117
118 fn name() -> &'static str {
119 let name = std::any::type_name::<State>();
120
121 name.split("::").next().unwrap_or("a_cool_application")
122 }
123
124 fn boot(&self) -> (State, Task<Message>) {
125 self.boot.boot()
126 }
127
128 fn update(
129 &self,
130 state: &mut Self::State,
131 message: Self::Message,
132 ) -> Task<Self::Message> {
133 self.update.update(state, message)
134 }
135
136 fn view<'a>(
137 &self,
138 state: &'a Self::State,
139 _window: window::Id,
140 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
141 self.view.view(state)
142 }
143
144 fn settings(&self) -> Settings {
145 Settings::default()
146 }
147
148 fn window(&self) -> Option<iced_core::window::Settings> {
149 Some(window::Settings::default())
150 }
151 }
152
153 Application {
154 raw: Instance {
155 boot,
156 update,
157 view,
158 _state: PhantomData,
159 _message: PhantomData,
160 _theme: PhantomData,
161 _renderer: PhantomData,
162 },
163 settings: Settings::default(),
164 window: window::Settings::default(),
165 presets: Vec::new(),
166 }
167}
168
169#[derive(Debug)]
177pub struct Application<P: Program> {
178 raw: P,
179 settings: Settings,
180 window: window::Settings,
181 presets: Vec<Preset<P::State, P::Message>>,
182}
183
184impl<P: Program> Application<P> {
185 pub fn run(self) -> Result
187 where
188 Self: 'static,
189 P::Message: message::MaybeDebug + message::MaybeClone,
190 {
191 #[cfg(feature = "debug")]
192 iced_debug::init(iced_debug::Metadata {
193 name: P::name(),
194 theme: None,
195 can_time_travel: cfg!(feature = "time-travel"),
196 });
197
198 #[cfg(feature = "tester")]
199 let program = iced_tester::attach(self);
200
201 #[cfg(all(feature = "debug", not(feature = "tester")))]
202 let program = iced_devtools::attach(self);
203
204 #[cfg(not(any(feature = "tester", feature = "debug")))]
205 let program = self;
206
207 Ok(shell::run(program)?)
208 }
209
210 pub fn settings(self, settings: Settings) -> Self {
212 Self { settings, ..self }
213 }
214
215 pub fn antialiasing(self, antialiasing: bool) -> Self {
217 Self {
218 settings: Settings {
219 antialiasing,
220 ..self.settings
221 },
222 ..self
223 }
224 }
225
226 pub fn default_font(self, default_font: Font) -> Self {
228 Self {
229 settings: Settings {
230 default_font,
231 ..self.settings
232 },
233 ..self
234 }
235 }
236
237 pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {
239 self.settings.fonts.push(font.into());
240 self
241 }
242
243 pub fn window(self, window: window::Settings) -> Self {
247 Self { window, ..self }
248 }
249
250 pub fn centered(self) -> Self {
252 Self {
253 window: window::Settings {
254 position: window::Position::Centered,
255 ..self.window
256 },
257 ..self
258 }
259 }
260
261 pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self {
263 Self {
264 window: window::Settings {
265 exit_on_close_request,
266 ..self.window
267 },
268 ..self
269 }
270 }
271
272 pub fn window_size(self, size: impl Into<Size>) -> Self {
274 Self {
275 window: window::Settings {
276 size: size.into(),
277 ..self.window
278 },
279 ..self
280 }
281 }
282
283 pub fn transparent(self, transparent: bool) -> Self {
285 Self {
286 window: window::Settings {
287 transparent,
288 ..self.window
289 },
290 ..self
291 }
292 }
293
294 pub fn resizable(self, resizable: bool) -> Self {
296 Self {
297 window: window::Settings {
298 resizable,
299 ..self.window
300 },
301 ..self
302 }
303 }
304
305 pub fn decorations(self, decorations: bool) -> Self {
307 Self {
308 window: window::Settings {
309 decorations,
310 ..self.window
311 },
312 ..self
313 }
314 }
315
316 pub fn position(self, position: window::Position) -> Self {
318 Self {
319 window: window::Settings {
320 position,
321 ..self.window
322 },
323 ..self
324 }
325 }
326
327 pub fn level(self, level: window::Level) -> Self {
329 Self {
330 window: window::Settings {
331 level,
332 ..self.window
333 },
334 ..self
335 }
336 }
337
338 pub fn title(
340 self,
341 title: impl TitleFn<P::State>,
342 ) -> Application<
343 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
344 > {
345 Application {
346 raw: program::with_title(self.raw, move |state, _window| {
347 title.title(state)
348 }),
349 settings: self.settings,
350 window: self.window,
351 presets: self.presets,
352 }
353 }
354
355 pub fn subscription(
357 self,
358 f: impl Fn(&P::State) -> Subscription<P::Message>,
359 ) -> Application<
360 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
361 > {
362 Application {
363 raw: program::with_subscription(self.raw, f),
364 settings: self.settings,
365 window: self.window,
366 presets: self.presets,
367 }
368 }
369
370 pub fn theme(
372 self,
373 f: impl ThemeFn<P::State, P::Theme>,
374 ) -> Application<
375 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
376 > {
377 Application {
378 raw: program::with_theme(self.raw, move |state, _window| {
379 f.theme(state)
380 }),
381 settings: self.settings,
382 window: self.window,
383 presets: self.presets,
384 }
385 }
386
387 pub fn style(
389 self,
390 f: impl Fn(&P::State, &P::Theme) -> theme::Style,
391 ) -> Application<
392 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
393 > {
394 Application {
395 raw: program::with_style(self.raw, f),
396 settings: self.settings,
397 window: self.window,
398 presets: self.presets,
399 }
400 }
401
402 pub fn scale_factor(
404 self,
405 f: impl Fn(&P::State) -> f32,
406 ) -> Application<
407 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
408 > {
409 Application {
410 raw: program::with_scale_factor(self.raw, move |state, _window| {
411 f(state)
412 }),
413 settings: self.settings,
414 window: self.window,
415 presets: self.presets,
416 }
417 }
418
419 pub fn executor<E>(
421 self,
422 ) -> Application<
423 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
424 >
425 where
426 E: Executor,
427 {
428 Application {
429 raw: program::with_executor::<P, E>(self.raw),
430 settings: self.settings,
431 window: self.window,
432 presets: self.presets,
433 }
434 }
435
436 pub fn presets(
442 self,
443 presets: impl IntoIterator<Item = Preset<P::State, P::Message>>,
444 ) -> Self {
445 Self {
446 presets: presets.into_iter().collect(),
447 ..self
448 }
449 }
450}
451
452impl<P: Program> Program for Application<P> {
453 type State = P::State;
454 type Message = P::Message;
455 type Theme = P::Theme;
456 type Renderer = P::Renderer;
457 type Executor = P::Executor;
458
459 fn name() -> &'static str {
460 P::name()
461 }
462
463 fn settings(&self) -> Settings {
464 self.settings.clone()
465 }
466
467 fn window(&self) -> Option<window::Settings> {
468 Some(self.window.clone())
469 }
470
471 fn boot(&self) -> (Self::State, Task<Self::Message>) {
472 self.raw.boot()
473 }
474
475 fn update(
476 &self,
477 state: &mut Self::State,
478 message: Self::Message,
479 ) -> Task<Self::Message> {
480 debug::hot(|| self.raw.update(state, message))
481 }
482
483 fn view<'a>(
484 &self,
485 state: &'a Self::State,
486 window: window::Id,
487 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
488 debug::hot(|| self.raw.view(state, window))
489 }
490
491 fn title(&self, state: &Self::State, window: window::Id) -> String {
492 debug::hot(|| self.raw.title(state, window))
493 }
494
495 fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {
496 debug::hot(|| self.raw.subscription(state))
497 }
498
499 fn theme(
500 &self,
501 state: &Self::State,
502 window: iced_core::window::Id,
503 ) -> Option<Self::Theme> {
504 debug::hot(|| self.raw.theme(state, window))
505 }
506
507 fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {
508 debug::hot(|| self.raw.style(state, theme))
509 }
510
511 fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {
512 debug::hot(|| self.raw.scale_factor(state, window))
513 }
514
515 fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
516 &self.presets
517 }
518}
519
520pub trait BootFn<State, Message> {
529 fn boot(&self) -> (State, Task<Message>);
531}
532
533impl<T, C, State, Message> BootFn<State, Message> for T
534where
535 T: Fn() -> C,
536 C: IntoBoot<State, Message>,
537{
538 fn boot(&self) -> (State, Task<Message>) {
539 self().into_boot()
540 }
541}
542
543pub trait IntoBoot<State, Message> {
545 fn into_boot(self) -> (State, Task<Message>);
547}
548
549impl<State, Message> IntoBoot<State, Message> for State {
550 fn into_boot(self) -> (State, Task<Message>) {
551 (self, Task::none())
552 }
553}
554
555impl<State, Message> IntoBoot<State, Message> for (State, Task<Message>) {
556 fn into_boot(self) -> (State, Task<Message>) {
557 self
558 }
559}
560
561pub trait TitleFn<State> {
568 fn title(&self, state: &State) -> String;
570}
571
572impl<State> TitleFn<State> for &'static str {
573 fn title(&self, _state: &State) -> String {
574 self.to_string()
575 }
576}
577
578impl<T, State> TitleFn<State> for T
579where
580 T: Fn(&State) -> String,
581{
582 fn title(&self, state: &State) -> String {
583 self(state)
584 }
585}
586
587pub trait UpdateFn<State, Message> {
592 fn update(&self, state: &mut State, message: Message) -> Task<Message>;
594}
595
596impl<State, Message> UpdateFn<State, Message> for () {
597 fn update(&self, _state: &mut State, _message: Message) -> Task<Message> {
598 Task::none()
599 }
600}
601
602impl<T, State, Message, C> UpdateFn<State, Message> for T
603where
604 T: Fn(&mut State, Message) -> C,
605 C: Into<Task<Message>>,
606{
607 fn update(&self, state: &mut State, message: Message) -> Task<Message> {
608 self(state, message).into()
609 }
610}
611
612pub trait ViewFn<'a, State, Message, Theme, Renderer> {
617 fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer>;
619}
620
621impl<'a, T, State, Message, Theme, Renderer, Widget>
622 ViewFn<'a, State, Message, Theme, Renderer> for T
623where
624 T: Fn(&'a State) -> Widget,
625 State: 'static,
626 Widget: Into<Element<'a, Message, Theme, Renderer>>,
627{
628 fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer> {
629 self(state).into()
630 }
631}
632
633pub trait ThemeFn<State, Theme> {
642 fn theme(&self, state: &State) -> Option<Theme>;
647}
648
649impl<State> ThemeFn<State, Theme> for Theme {
650 fn theme(&self, _state: &State) -> Option<Theme> {
651 Some(self.clone())
652 }
653}
654
655impl<F, T, State, Theme> ThemeFn<State, Theme> for F
656where
657 F: Fn(&State) -> T,
658 T: Into<Option<Theme>>,
659{
660 fn theme(&self, state: &State) -> Option<Theme> {
661 (self)(state).into()
662 }
663}