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