1use crate::program::{self, Program};
34use crate::shell;
35use crate::theme;
36use crate::window;
37use crate::{
38 Element, Executor, Font, Result, Settings, Size, Subscription, Task,
39};
40
41use iced_debug as debug;
42
43use std::borrow::Cow;
44
45pub mod timed;
46
47pub use timed::timed;
48
49pub fn application<State, Message, Theme, Renderer>(
78 boot: impl Boot<State, Message>,
79 update: impl Update<State, Message>,
80 view: impl for<'a> View<'a, State, Message, Theme, Renderer>,
81) -> Application<impl Program<State = State, Message = Message, Theme = Theme>>
82where
83 State: 'static,
84 Message: program::Message + 'static,
85 Theme: Default + theme::Base,
86 Renderer: program::Renderer,
87{
88 use std::marker::PhantomData;
89
90 struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {
91 boot: Boot,
92 update: Update,
93 view: View,
94 _state: PhantomData<State>,
95 _message: PhantomData<Message>,
96 _theme: PhantomData<Theme>,
97 _renderer: PhantomData<Renderer>,
98 }
99
100 impl<State, Message, Theme, Renderer, Boot, Update, View> Program
101 for Instance<State, Message, Theme, Renderer, Boot, Update, View>
102 where
103 Message: program::Message + 'static,
104 Theme: Default + theme::Base,
105 Renderer: program::Renderer,
106 Boot: self::Boot<State, Message>,
107 Update: self::Update<State, Message>,
108 View: for<'a> self::View<'a, State, Message, Theme, Renderer>,
109 {
110 type State = State;
111 type Message = Message;
112 type Theme = Theme;
113 type Renderer = Renderer;
114 type Executor = iced_futures::backend::default::Executor;
115
116 fn name() -> &'static str {
117 let name = std::any::type_name::<State>();
118
119 name.split("::").next().unwrap_or("a_cool_application")
120 }
121
122 fn boot(&self) -> (State, Task<Message>) {
123 self.boot.boot()
124 }
125
126 fn update(
127 &self,
128 state: &mut Self::State,
129 message: Self::Message,
130 ) -> Task<Self::Message> {
131 debug::hot(|| self.update.update(state, message))
132 }
133
134 fn view<'a>(
135 &self,
136 state: &'a Self::State,
137 _window: window::Id,
138 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
139 debug::hot(|| self.view.view(state))
140 }
141 }
142
143 Application {
144 raw: Instance {
145 boot,
146 update,
147 view,
148 _state: PhantomData,
149 _message: PhantomData,
150 _theme: PhantomData,
151 _renderer: PhantomData,
152 },
153 settings: Settings::default(),
154 window: window::Settings::default(),
155 }
156}
157
158#[derive(Debug)]
166pub struct Application<P: Program> {
167 raw: P,
168 settings: Settings,
169 window: window::Settings,
170}
171
172impl<P: Program> Application<P> {
173 pub fn run(self) -> Result
175 where
176 Self: 'static,
177 {
178 #[cfg(all(feature = "debug", not(target_arch = "wasm32")))]
179 let program = {
180 iced_debug::init(iced_debug::Metadata {
181 name: P::name(),
182 theme: None,
183 can_time_travel: cfg!(feature = "time-travel"),
184 });
185
186 iced_devtools::attach(self.raw)
187 };
188
189 #[cfg(any(not(feature = "debug"), target_arch = "wasm32"))]
190 let program = self.raw;
191
192 Ok(shell::run(program, self.settings, Some(self.window))?)
193 }
194
195 pub fn settings(self, settings: Settings) -> Self {
197 Self { settings, ..self }
198 }
199
200 pub fn antialiasing(self, antialiasing: bool) -> Self {
202 Self {
203 settings: Settings {
204 antialiasing,
205 ..self.settings
206 },
207 ..self
208 }
209 }
210
211 pub fn default_font(self, default_font: Font) -> Self {
213 Self {
214 settings: Settings {
215 default_font,
216 ..self.settings
217 },
218 ..self
219 }
220 }
221
222 pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {
224 self.settings.fonts.push(font.into());
225 self
226 }
227
228 pub fn window(self, window: window::Settings) -> Self {
232 Self { window, ..self }
233 }
234
235 pub fn centered(self) -> Self {
237 Self {
238 window: window::Settings {
239 position: window::Position::Centered,
240 ..self.window
241 },
242 ..self
243 }
244 }
245
246 pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self {
248 Self {
249 window: window::Settings {
250 exit_on_close_request,
251 ..self.window
252 },
253 ..self
254 }
255 }
256
257 pub fn window_size(self, size: impl Into<Size>) -> Self {
259 Self {
260 window: window::Settings {
261 size: size.into(),
262 ..self.window
263 },
264 ..self
265 }
266 }
267
268 pub fn transparent(self, transparent: bool) -> Self {
270 Self {
271 window: window::Settings {
272 transparent,
273 ..self.window
274 },
275 ..self
276 }
277 }
278
279 pub fn resizable(self, resizable: bool) -> Self {
281 Self {
282 window: window::Settings {
283 resizable,
284 ..self.window
285 },
286 ..self
287 }
288 }
289
290 pub fn decorations(self, decorations: bool) -> Self {
292 Self {
293 window: window::Settings {
294 decorations,
295 ..self.window
296 },
297 ..self
298 }
299 }
300
301 pub fn position(self, position: window::Position) -> Self {
303 Self {
304 window: window::Settings {
305 position,
306 ..self.window
307 },
308 ..self
309 }
310 }
311
312 pub fn level(self, level: window::Level) -> Self {
314 Self {
315 window: window::Settings {
316 level,
317 ..self.window
318 },
319 ..self
320 }
321 }
322
323 pub fn title(
325 self,
326 title: impl Title<P::State>,
327 ) -> Application<
328 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
329 > {
330 Application {
331 raw: program::with_title(self.raw, move |state, _window| {
332 debug::hot(|| title.title(state))
333 }),
334 settings: self.settings,
335 window: self.window,
336 }
337 }
338
339 pub fn subscription(
341 self,
342 f: impl Fn(&P::State) -> Subscription<P::Message>,
343 ) -> Application<
344 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
345 > {
346 Application {
347 raw: program::with_subscription(self.raw, move |state| {
348 debug::hot(|| f(state))
349 }),
350 settings: self.settings,
351 window: self.window,
352 }
353 }
354
355 pub fn theme(
357 self,
358 f: impl Fn(&P::State) -> P::Theme,
359 ) -> Application<
360 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
361 > {
362 Application {
363 raw: program::with_theme(self.raw, move |state, _window| {
364 debug::hot(|| f(state))
365 }),
366 settings: self.settings,
367 window: self.window,
368 }
369 }
370
371 pub fn style(
373 self,
374 f: impl Fn(&P::State, &P::Theme) -> theme::Style,
375 ) -> Application<
376 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
377 > {
378 Application {
379 raw: program::with_style(self.raw, move |state, theme| {
380 debug::hot(|| f(state, theme))
381 }),
382 settings: self.settings,
383 window: self.window,
384 }
385 }
386
387 pub fn scale_factor(
389 self,
390 f: impl Fn(&P::State) -> f64,
391 ) -> Application<
392 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
393 > {
394 Application {
395 raw: program::with_scale_factor(self.raw, move |state, _window| {
396 debug::hot(|| f(state))
397 }),
398 settings: self.settings,
399 window: self.window,
400 }
401 }
402
403 pub fn executor<E>(
405 self,
406 ) -> Application<
407 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
408 >
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 }
417 }
418}
419
420pub trait Boot<State, Message> {
429 fn boot(&self) -> (State, Task<Message>);
431}
432
433impl<T, C, State, Message> Boot<State, Message> for T
434where
435 T: Fn() -> C,
436 C: IntoBoot<State, Message>,
437{
438 fn boot(&self) -> (State, Task<Message>) {
439 self().into_boot()
440 }
441}
442
443pub trait IntoBoot<State, Message> {
445 fn into_boot(self) -> (State, Task<Message>);
447}
448
449impl<State, Message> IntoBoot<State, Message> for State {
450 fn into_boot(self) -> (State, Task<Message>) {
451 (self, Task::none())
452 }
453}
454
455impl<State, Message> IntoBoot<State, Message> for (State, Task<Message>) {
456 fn into_boot(self) -> (State, Task<Message>) {
457 self
458 }
459}
460
461pub trait Title<State> {
468 fn title(&self, state: &State) -> String;
470}
471
472impl<State> Title<State> for &'static str {
473 fn title(&self, _state: &State) -> String {
474 self.to_string()
475 }
476}
477
478impl<T, State> Title<State> for T
479where
480 T: Fn(&State) -> String,
481{
482 fn title(&self, state: &State) -> String {
483 self(state)
484 }
485}
486
487pub trait Update<State, Message> {
492 fn update(&self, state: &mut State, message: Message) -> Task<Message>;
494}
495
496impl<State, Message> Update<State, Message> for () {
497 fn update(&self, _state: &mut State, _message: Message) -> Task<Message> {
498 Task::none()
499 }
500}
501
502impl<T, State, Message, C> Update<State, Message> for T
503where
504 T: Fn(&mut State, Message) -> C,
505 C: Into<Task<Message>>,
506{
507 fn update(&self, state: &mut State, message: Message) -> Task<Message> {
508 self(state, message).into()
509 }
510}
511
512pub trait View<'a, State, Message, Theme, Renderer> {
517 fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer>;
519}
520
521impl<'a, T, State, Message, Theme, Renderer, Widget>
522 View<'a, State, Message, Theme, Renderer> for T
523where
524 T: Fn(&'a State) -> Widget,
525 State: 'static,
526 Widget: Into<Element<'a, Message, Theme, Renderer>>,
527{
528 fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer> {
529 self(state).into()
530 }
531}