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