1use crate::{image::Image, menu::*, Manager, Runtime};
6
7pub struct MenuBuilder<'m, R: Runtime, M: Manager<R>> {
41 pub(crate) id: Option<MenuId>,
42 pub(crate) manager: &'m M,
43 pub(crate) items: Vec<crate::Result<MenuItemKind<R>>>,
44}
45
46impl<'m, R: Runtime, M: Manager<R>> MenuBuilder<'m, R, M> {
47 pub fn new(manager: &'m M) -> Self {
49 Self {
50 id: None,
51 items: Vec::new(),
52 manager,
53 }
54 }
55
56 pub fn with_id<I: Into<MenuId>>(manager: &'m M, id: I) -> Self {
58 Self {
59 id: Some(id.into()),
60 items: Vec::new(),
61 manager,
62 }
63 }
64
65 pub fn build(self) -> crate::Result<Menu<R>> {
67 let menu = if let Some(id) = self.id {
68 Menu::with_id(self.manager, id)?
69 } else {
70 Menu::new(self.manager)?
71 };
72
73 for item in self.items {
74 let item = item?;
75 menu.append(&item)?;
76 }
77
78 Ok(menu)
79 }
80}
81
82pub struct SubmenuBuilder<'m, R: Runtime, M: Manager<R>> {
115 pub(crate) id: Option<MenuId>,
116 pub(crate) manager: &'m M,
117 pub(crate) text: String,
118 pub(crate) enabled: bool,
119 pub(crate) items: Vec<crate::Result<MenuItemKind<R>>>,
120 pub(crate) icon: Option<crate::image::Image<'m>>,
121 pub(crate) native_icon: Option<NativeIcon>,
122}
123
124impl<'m, R: Runtime, M: Manager<R>> SubmenuBuilder<'m, R, M> {
125 pub fn new<S: AsRef<str>>(manager: &'m M, text: S) -> Self {
130 Self {
131 id: None,
132 items: Vec::new(),
133 text: text.as_ref().to_string(),
134 enabled: true,
135 manager,
136 icon: None,
137 native_icon: None,
138 }
139 }
140
141 pub fn with_id<I: Into<MenuId>, S: AsRef<str>>(manager: &'m M, id: I, text: S) -> Self {
146 Self {
147 id: Some(id.into()),
148 text: text.as_ref().to_string(),
149 enabled: true,
150 items: Vec::new(),
151 manager,
152 icon: None,
153 native_icon: None,
154 }
155 }
156
157 pub fn submenu_icon(mut self, icon: crate::image::Image<'m>) -> Self {
160 self.icon = Some(icon);
161 self.native_icon = None;
162 self
163 }
164
165 pub fn submenu_native_icon(mut self, icon: NativeIcon) -> Self {
168 self.native_icon = Some(icon);
169 self.icon = None;
170 self
171 }
172
173 pub fn enabled(mut self, enabled: bool) -> Self {
175 self.enabled = enabled;
176 self
177 }
178
179 pub fn build(self) -> crate::Result<Submenu<R>> {
181 let submenu = if let Some(id) = self.id {
182 if let Some(icon) = self.icon {
183 Submenu::with_id_and_icon(self.manager, id, self.text, self.enabled, Some(icon))?
184 } else if let Some(native_icon) = self.native_icon {
185 Submenu::with_id_and_native_icon(
186 self.manager,
187 id,
188 self.text,
189 self.enabled,
190 Some(native_icon),
191 )?
192 } else {
193 Submenu::with_id(self.manager, id, self.text, self.enabled)?
194 }
195 } else if let Some(icon) = self.icon {
196 Submenu::new_with_icon(self.manager, self.text, self.enabled, Some(icon))?
197 } else if let Some(native_icon) = self.native_icon {
198 Submenu::new_with_native_icon(self.manager, self.text, self.enabled, Some(native_icon))?
199 } else {
200 Submenu::new(self.manager, self.text, self.enabled)?
201 };
202
203 for item in self.items {
204 let item = item?;
205 submenu.append(&item)?;
206 }
207
208 Ok(submenu)
209 }
210}
211
212macro_rules! shared_menu_builder {
213 ($menu: ty) => {
214 impl<'m, R: Runtime, M: Manager<R>> $menu {
215 pub fn id<I: Into<MenuId>>(mut self, id: I) -> Self {
217 self.id.replace(id.into());
218 self
219 }
220
221 pub fn item(mut self, item: &dyn IsMenuItem<R>) -> Self {
223 self.items.push(Ok(item.kind()));
224 self
225 }
226
227 pub fn items(mut self, items: &[&dyn IsMenuItem<R>]) -> Self {
229 for item in items {
230 self = self.item(*item);
231 }
232 self
233 }
234
235 pub fn text<I: Into<MenuId>, S: AsRef<str>>(mut self, id: I, text: S) -> Self {
237 self
238 .items
239 .push(MenuItem::with_id(self.manager, id, text, true, None::<&str>).map(|i| i.kind()));
240 self
241 }
242
243 pub fn check<I: Into<MenuId>, S: AsRef<str>>(mut self, id: I, text: S) -> Self {
245 self.items.push(
246 CheckMenuItem::with_id(self.manager, id, text, true, true, None::<&str>)
247 .map(|i| i.kind()),
248 );
249 self
250 }
251
252 pub fn icon<I: Into<MenuId>, S: AsRef<str>>(
254 mut self,
255 id: I,
256 text: S,
257 icon: Image<'_>,
258 ) -> Self {
259 self.items.push(
260 IconMenuItem::with_id(self.manager, id, text, true, Some(icon), None::<&str>)
261 .map(|i| i.kind()),
262 );
263 self
264 }
265
266 pub fn native_icon<I: Into<MenuId>, S: AsRef<str>>(
272 mut self,
273 id: I,
274 text: S,
275 icon: NativeIcon,
276 ) -> Self {
277 self.items.push(
278 IconMenuItem::with_id_and_native_icon(
279 self.manager,
280 id,
281 text,
282 true,
283 Some(icon),
284 None::<&str>,
285 )
286 .map(|i| i.kind()),
287 );
288 self
289 }
290
291 pub fn separator(mut self) -> Self {
293 self
294 .items
295 .push(PredefinedMenuItem::separator(self.manager).map(|i| i.kind()));
296 self
297 }
298
299 pub fn copy(mut self) -> Self {
301 self
302 .items
303 .push(PredefinedMenuItem::copy(self.manager, None).map(|i| i.kind()));
304 self
305 }
306
307 pub fn copy_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
309 self
310 .items
311 .push(PredefinedMenuItem::copy(self.manager, Some(text.as_ref())).map(|i| i.kind()));
312 self
313 }
314
315 pub fn cut(mut self) -> Self {
317 self
318 .items
319 .push(PredefinedMenuItem::cut(self.manager, None).map(|i| i.kind()));
320 self
321 }
322
323 pub fn cut_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
325 self
326 .items
327 .push(PredefinedMenuItem::cut(self.manager, Some(text.as_ref())).map(|i| i.kind()));
328 self
329 }
330
331 pub fn paste(mut self) -> Self {
333 self
334 .items
335 .push(PredefinedMenuItem::paste(self.manager, None).map(|i| i.kind()));
336 self
337 }
338
339 pub fn paste_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
341 self
342 .items
343 .push(PredefinedMenuItem::paste(self.manager, Some(text.as_ref())).map(|i| i.kind()));
344 self
345 }
346
347 pub fn select_all(mut self) -> Self {
349 self
350 .items
351 .push(PredefinedMenuItem::select_all(self.manager, None).map(|i| i.kind()));
352 self
353 }
354
355 pub fn select_all_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
357 self.items.push(
358 PredefinedMenuItem::select_all(self.manager, Some(text.as_ref())).map(|i| i.kind()),
359 );
360 self
361 }
362
363 pub fn undo(mut self) -> Self {
369 self
370 .items
371 .push(PredefinedMenuItem::undo(self.manager, None).map(|i| i.kind()));
372 self
373 }
374
375 pub fn undo_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
381 self
382 .items
383 .push(PredefinedMenuItem::undo(self.manager, Some(text.as_ref())).map(|i| i.kind()));
384 self
385 }
386 pub fn redo(mut self) -> Self {
392 self
393 .items
394 .push(PredefinedMenuItem::redo(self.manager, None).map(|i| i.kind()));
395 self
396 }
397
398 pub fn redo_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
404 self
405 .items
406 .push(PredefinedMenuItem::redo(self.manager, Some(text.as_ref())).map(|i| i.kind()));
407 self
408 }
409
410 pub fn minimize(mut self) -> Self {
416 self
417 .items
418 .push(PredefinedMenuItem::minimize(self.manager, None).map(|i| i.kind()));
419 self
420 }
421
422 pub fn minimize_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
428 self
429 .items
430 .push(PredefinedMenuItem::minimize(self.manager, Some(text.as_ref())).map(|i| i.kind()));
431 self
432 }
433
434 pub fn maximize(mut self) -> Self {
440 self
441 .items
442 .push(PredefinedMenuItem::maximize(self.manager, None).map(|i| i.kind()));
443 self
444 }
445
446 pub fn maximize_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
452 self
453 .items
454 .push(PredefinedMenuItem::maximize(self.manager, Some(text.as_ref())).map(|i| i.kind()));
455 self
456 }
457
458 pub fn fullscreen(mut self) -> Self {
464 self
465 .items
466 .push(PredefinedMenuItem::fullscreen(self.manager, None).map(|i| i.kind()));
467 self
468 }
469
470 pub fn fullscreen_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
476 self.items.push(
477 PredefinedMenuItem::fullscreen(self.manager, Some(text.as_ref())).map(|i| i.kind()),
478 );
479 self
480 }
481
482 pub fn hide(mut self) -> Self {
488 self
489 .items
490 .push(PredefinedMenuItem::hide(self.manager, None).map(|i| i.kind()));
491 self
492 }
493
494 pub fn hide_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
500 self
501 .items
502 .push(PredefinedMenuItem::hide(self.manager, Some(text.as_ref())).map(|i| i.kind()));
503 self
504 }
505
506 pub fn hide_others(mut self) -> Self {
512 self
513 .items
514 .push(PredefinedMenuItem::hide_others(self.manager, None).map(|i| i.kind()));
515 self
516 }
517
518 pub fn hide_others_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
524 self.items.push(
525 PredefinedMenuItem::hide_others(self.manager, Some(text.as_ref())).map(|i| i.kind()),
526 );
527 self
528 }
529
530 pub fn show_all(mut self) -> Self {
536 self
537 .items
538 .push(PredefinedMenuItem::show_all(self.manager, None).map(|i| i.kind()));
539 self
540 }
541
542 pub fn show_all_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
548 self
549 .items
550 .push(PredefinedMenuItem::show_all(self.manager, Some(text.as_ref())).map(|i| i.kind()));
551 self
552 }
553
554 pub fn close_window(mut self) -> Self {
560 self
561 .items
562 .push(PredefinedMenuItem::close_window(self.manager, None).map(|i| i.kind()));
563 self
564 }
565
566 pub fn close_window_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
572 self.items.push(
573 PredefinedMenuItem::close_window(self.manager, Some(text.as_ref())).map(|i| i.kind()),
574 );
575 self
576 }
577
578 pub fn quit(mut self) -> Self {
584 self
585 .items
586 .push(PredefinedMenuItem::quit(self.manager, None).map(|i| i.kind()));
587 self
588 }
589
590 pub fn quit_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
596 self
597 .items
598 .push(PredefinedMenuItem::quit(self.manager, Some(text.as_ref())).map(|i| i.kind()));
599 self
600 }
601
602 pub fn about(mut self, metadata: Option<AboutMetadata<'_>>) -> Self {
604 self
605 .items
606 .push(PredefinedMenuItem::about(self.manager, None, metadata).map(|i| i.kind()));
607 self
608 }
609
610 pub fn about_with_text<S: AsRef<str>>(
612 mut self,
613 text: S,
614 metadata: Option<AboutMetadata<'_>>,
615 ) -> Self {
616 self.items.push(
617 PredefinedMenuItem::about(self.manager, Some(text.as_ref()), metadata).map(|i| i.kind()),
618 );
619 self
620 }
621
622 pub fn services(mut self) -> Self {
628 self
629 .items
630 .push(PredefinedMenuItem::services(self.manager, None).map(|i| i.kind()));
631 self
632 }
633
634 pub fn services_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
640 self
641 .items
642 .push(PredefinedMenuItem::services(self.manager, Some(text.as_ref())).map(|i| i.kind()));
643 self
644 }
645 }
646 };
647}
648
649shared_menu_builder!(MenuBuilder<'m, R, M>);
650shared_menu_builder!(SubmenuBuilder<'m, R, M>);