muda/items/
icon.rs

1// Copyright 2022-2022 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.inner
3// SPDX-License-Identifier: MIT
4
5use std::{cell::RefCell, mem, rc::Rc};
6
7use crate::{
8    accelerator::Accelerator,
9    icon::{Icon, NativeIcon},
10    sealed::IsMenuItemBase,
11    IsMenuItem, MenuId, MenuItemKind,
12};
13
14/// An icon menu item inside a [`Menu`] or [`Submenu`]
15/// and usually contains an icon and a text.
16///
17/// [`Menu`]: crate::Menu
18/// [`Submenu`]: crate::Submenu
19#[derive(Clone)]
20pub struct IconMenuItem {
21    pub(crate) id: Rc<MenuId>,
22    pub(crate) inner: Rc<RefCell<crate::platform_impl::MenuChild>>,
23}
24
25impl IsMenuItemBase for IconMenuItem {}
26impl IsMenuItem for IconMenuItem {
27    fn kind(&self) -> MenuItemKind {
28        MenuItemKind::Icon(self.clone())
29    }
30
31    fn id(&self) -> &MenuId {
32        self.id()
33    }
34
35    fn into_id(self) -> MenuId {
36        self.into_id()
37    }
38}
39
40impl IconMenuItem {
41    /// Create a new icon menu item.
42    ///
43    /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic
44    ///   for this icon menu item. To display a `&` without assigning a mnemenonic, use `&&`.
45    pub fn new<S: AsRef<str>>(
46        text: S,
47        enabled: bool,
48        icon: Option<Icon>,
49        accelerator: Option<Accelerator>,
50    ) -> Self {
51        let item = crate::platform_impl::MenuChild::new_icon(
52            text.as_ref(),
53            enabled,
54            icon,
55            accelerator,
56            None,
57        );
58        Self {
59            id: Rc::new(item.id().clone()),
60            inner: Rc::new(RefCell::new(item)),
61        }
62    }
63
64    /// Create a new icon menu item with the specified id.
65    ///
66    /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic
67    ///   for this icon menu item. To display a `&` without assigning a mnemenonic, use `&&`.
68    pub fn with_id<I: Into<MenuId>, S: AsRef<str>>(
69        id: I,
70        text: S,
71        enabled: bool,
72        icon: Option<Icon>,
73        accelerator: Option<Accelerator>,
74    ) -> Self {
75        let id = id.into();
76        Self {
77            id: Rc::new(id.clone()),
78            inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new_icon(
79                text.as_ref(),
80                enabled,
81                icon,
82                accelerator,
83                Some(id),
84            ))),
85        }
86    }
87
88    /// Create a new icon menu item but with a native icon.
89    ///
90    /// See [`IconMenuItem::new`] for more info.
91    ///
92    /// ## Platform-specific:
93    ///
94    /// - **Windows / Linux**: Unsupported.
95    pub fn with_native_icon<S: AsRef<str>>(
96        text: S,
97        enabled: bool,
98        native_icon: Option<NativeIcon>,
99        accelerator: Option<Accelerator>,
100    ) -> Self {
101        let item = crate::platform_impl::MenuChild::new_native_icon(
102            text.as_ref(),
103            enabled,
104            native_icon,
105            accelerator,
106            None,
107        );
108        Self {
109            id: Rc::new(item.id().clone()),
110            inner: Rc::new(RefCell::new(item)),
111        }
112    }
113
114    /// Create a new icon menu item but with the specified id and a native icon.
115    ///
116    /// See [`IconMenuItem::new`] for more info.
117    ///
118    /// ## Platform-specific:
119    ///
120    /// - **Windows / Linux**: Unsupported.
121    pub fn with_id_and_native_icon<I: Into<MenuId>, S: AsRef<str>>(
122        id: I,
123        text: S,
124        enabled: bool,
125        native_icon: Option<NativeIcon>,
126        accelerator: Option<Accelerator>,
127    ) -> Self {
128        let id = id.into();
129        Self {
130            id: Rc::new(id.clone()),
131            inner: Rc::new(RefCell::new(
132                crate::platform_impl::MenuChild::new_native_icon(
133                    text.as_ref(),
134                    enabled,
135                    native_icon,
136                    accelerator,
137                    Some(id),
138                ),
139            )),
140        }
141    }
142
143    /// Returns a unique identifier associated with this submenu.
144    pub fn id(&self) -> &MenuId {
145        &self.id
146    }
147
148    /// Get the text for this check menu item.
149    pub fn text(&self) -> String {
150        self.inner.borrow().text()
151    }
152
153    /// Set the text for this check menu item. `text` could optionally contain
154    /// an `&` before a character to assign this character as the mnemonic
155    /// for this check menu item. To display a `&` without assigning a mnemenonic, use `&&`.
156    pub fn set_text<S: AsRef<str>>(&self, text: S) {
157        self.inner.borrow_mut().set_text(text.as_ref())
158    }
159
160    /// Get whether this check menu item is enabled or not.
161    pub fn is_enabled(&self) -> bool {
162        self.inner.borrow().is_enabled()
163    }
164
165    /// Enable or disable this check menu item.
166    pub fn set_enabled(&self, enabled: bool) {
167        self.inner.borrow_mut().set_enabled(enabled)
168    }
169
170    /// Set this icon menu item accelerator.
171    pub fn set_accelerator(&self, accelerator: Option<Accelerator>) -> crate::Result<()> {
172        self.inner.borrow_mut().set_accelerator(accelerator)
173    }
174
175    /// Change this menu item icon or remove it.
176    pub fn set_icon(&self, icon: Option<Icon>) {
177        self.inner.borrow_mut().set_icon(icon)
178    }
179
180    /// Change this menu item icon to a native image or remove it.
181    ///
182    /// ## Platform-specific:
183    ///
184    /// - **Windows / Linux**: Unsupported.
185    pub fn set_native_icon(&self, _icon: Option<NativeIcon>) {
186        #[cfg(target_os = "macos")]
187        self.inner.borrow_mut().set_native_icon(_icon)
188    }
189
190    /// Convert this menu item into its menu ID.
191    pub fn into_id(mut self) -> MenuId {
192        // Note: `Rc::into_inner` is available from Rust 1.70
193        if let Some(id) = Rc::get_mut(&mut self.id) {
194            mem::take(id)
195        } else {
196            self.id().clone()
197        }
198    }
199}