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