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