1use crate::application;
3use crate::program::{self, Program};
4use crate::shell;
5use crate::theme;
6use crate::window;
7use crate::{Element, Executor, Font, Result, Settings, Subscription, Task};
8
9use iced_debug as debug;
10
11use std::borrow::Cow;
12
13pub fn daemon<State, Message, Theme, Renderer>(
24 boot: impl application::Boot<State, Message>,
25 update: impl application::Update<State, Message>,
26 view: impl for<'a> View<'a, State, Message, Theme, Renderer>,
27) -> Daemon<impl Program<State = State, Message = Message, Theme = Theme>>
28where
29 State: 'static,
30 Message: program::Message + 'static,
31 Theme: Default + theme::Base,
32 Renderer: program::Renderer,
33{
34 use std::marker::PhantomData;
35
36 struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {
37 boot: Boot,
38 update: Update,
39 view: View,
40 _state: PhantomData<State>,
41 _message: PhantomData<Message>,
42 _theme: PhantomData<Theme>,
43 _renderer: PhantomData<Renderer>,
44 }
45
46 impl<State, Message, Theme, Renderer, Boot, Update, View> Program
47 for Instance<State, Message, Theme, Renderer, Boot, Update, View>
48 where
49 Message: program::Message + 'static,
50 Theme: Default + theme::Base,
51 Renderer: program::Renderer,
52 Boot: application::Boot<State, Message>,
53 Update: application::Update<State, Message>,
54 View: for<'a> self::View<'a, State, Message, Theme, Renderer>,
55 {
56 type State = State;
57 type Message = Message;
58 type Theme = Theme;
59 type Renderer = Renderer;
60 type Executor = iced_futures::backend::default::Executor;
61
62 fn name() -> &'static str {
63 let name = std::any::type_name::<State>();
64
65 name.split("::").next().unwrap_or("a_cool_daemon")
66 }
67
68 fn boot(&self) -> (Self::State, Task<Self::Message>) {
69 self.boot.boot()
70 }
71
72 fn update(
73 &self,
74 state: &mut Self::State,
75 message: Self::Message,
76 ) -> Task<Self::Message> {
77 debug::hot(|| self.update.update(state, message))
78 }
79
80 fn view<'a>(
81 &self,
82 state: &'a Self::State,
83 window: window::Id,
84 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
85 debug::hot(|| self.view.view(state, window))
86 }
87 }
88
89 Daemon {
90 raw: Instance {
91 boot,
92 update,
93 view,
94 _state: PhantomData,
95 _message: PhantomData,
96 _theme: PhantomData,
97 _renderer: PhantomData,
98 },
99 settings: Settings::default(),
100 }
101}
102
103#[derive(Debug)]
111pub struct Daemon<P: Program> {
112 raw: P,
113 settings: Settings,
114}
115
116impl<P: Program> Daemon<P> {
117 pub fn run(self) -> Result
119 where
120 Self: 'static,
121 {
122 #[cfg(all(feature = "debug", not(target_arch = "wasm32")))]
123 let program = {
124 iced_debug::init(iced_debug::Metadata {
125 name: P::name(),
126 theme: None,
127 can_time_travel: cfg!(feature = "time-travel"),
128 });
129
130 iced_devtools::attach(self.raw)
131 };
132
133 #[cfg(any(not(feature = "debug"), target_arch = "wasm32"))]
134 let program = self.raw;
135
136 Ok(shell::run(program, self.settings, None)?)
137 }
138
139 pub fn settings(self, settings: Settings) -> Self {
141 Self { settings, ..self }
142 }
143
144 pub fn antialiasing(self, antialiasing: bool) -> Self {
146 Self {
147 settings: Settings {
148 antialiasing,
149 ..self.settings
150 },
151 ..self
152 }
153 }
154
155 pub fn default_font(self, default_font: Font) -> Self {
157 Self {
158 settings: Settings {
159 default_font,
160 ..self.settings
161 },
162 ..self
163 }
164 }
165
166 pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {
168 self.settings.fonts.push(font.into());
169 self
170 }
171
172 pub fn title(
174 self,
175 title: impl Title<P::State>,
176 ) -> Daemon<
177 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
178 > {
179 Daemon {
180 raw: program::with_title(self.raw, move |state, window| {
181 debug::hot(|| title.title(state, window))
182 }),
183 settings: self.settings,
184 }
185 }
186
187 pub fn subscription(
189 self,
190 f: impl Fn(&P::State) -> Subscription<P::Message>,
191 ) -> Daemon<
192 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
193 > {
194 Daemon {
195 raw: program::with_subscription(self.raw, move |state| {
196 debug::hot(|| f(state))
197 }),
198 settings: self.settings,
199 }
200 }
201
202 pub fn theme(
204 self,
205 f: impl Fn(&P::State, window::Id) -> P::Theme,
206 ) -> Daemon<
207 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
208 > {
209 Daemon {
210 raw: program::with_theme(self.raw, move |state, window| {
211 debug::hot(|| f(state, window))
212 }),
213 settings: self.settings,
214 }
215 }
216
217 pub fn style(
219 self,
220 f: impl Fn(&P::State, &P::Theme) -> theme::Style,
221 ) -> Daemon<
222 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
223 > {
224 Daemon {
225 raw: program::with_style(self.raw, move |state, theme| {
226 debug::hot(|| f(state, theme))
227 }),
228 settings: self.settings,
229 }
230 }
231
232 pub fn scale_factor(
234 self,
235 f: impl Fn(&P::State, window::Id) -> f64,
236 ) -> Daemon<
237 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
238 > {
239 Daemon {
240 raw: program::with_scale_factor(self.raw, move |state, window| {
241 debug::hot(|| f(state, window))
242 }),
243 settings: self.settings,
244 }
245 }
246
247 pub fn executor<E>(
249 self,
250 ) -> Daemon<
251 impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
252 >
253 where
254 E: Executor,
255 {
256 Daemon {
257 raw: program::with_executor::<P, E>(self.raw),
258 settings: self.settings,
259 }
260 }
261}
262
263pub trait Title<State> {
270 fn title(&self, state: &State, window: window::Id) -> String;
272}
273
274impl<State> Title<State> for &'static str {
275 fn title(&self, _state: &State, _window: window::Id) -> String {
276 self.to_string()
277 }
278}
279
280impl<T, State> Title<State> for T
281where
282 T: Fn(&State, window::Id) -> String,
283{
284 fn title(&self, state: &State, window: window::Id) -> String {
285 self(state, window)
286 }
287}
288
289pub trait View<'a, State, Message, Theme, Renderer> {
294 fn view(
296 &self,
297 state: &'a State,
298 window: window::Id,
299 ) -> Element<'a, Message, Theme, Renderer>;
300}
301
302impl<'a, T, State, Message, Theme, Renderer, Widget>
303 View<'a, State, Message, Theme, Renderer> for T
304where
305 T: Fn(&'a State, window::Id) -> Widget,
306 State: 'static,
307 Widget: Into<Element<'a, Message, Theme, Renderer>>,
308{
309 fn view(
310 &self,
311 state: &'a State,
312 window: window::Id,
313 ) -> Element<'a, Message, Theme, Renderer> {
314 self(state, window).into()
315 }
316}