zng_wgt_material_icons/
lib.rs

1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3//!
4//! Material icons for the [`Icon!`] widget.
5//!
6//! A map from name to icon codepoint is defined in a module for each font. The font files are embedded
7//! by default and can are registered using the [`MaterialIconsManager`] app extension. The extension
8//! also registers [`ICONS`] handlers that provide the icons.
9//!
10//! The icons are from the [Material Design Icons] project.
11//!
12//! [`Icon!`]: struct@zng_wgt_text::icon::Icon
13//! [`ICONS`]: struct@zng_wgt::ICONS
14//! [Material Design Icons]: https://github.com/google/material-design-icons
15//!
16//! # Crate
17//!
18#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
19#![warn(unused_extern_crates)]
20#![warn(missing_docs)]
21
22zng_wgt::enable_widget_macros!();
23
24/// Material icon fonts manager.
25///
26/// This app extension registers the fonts in `"embedded"` builds and registers [`ICONS`] handlers that provide the icons.
27///
28/// [`ICONS`]: struct@zng_wgt::ICONS
29#[derive(Default)]
30#[non_exhaustive]
31pub struct MaterialIconsManager;
32impl MaterialIconsManager {
33    #[cfg(all(
34        feature = "embedded",
35        any(feature = "outlined", feature = "filled", feature = "rounded", feature = "sharp")
36    ))]
37    fn register_fonts(&self) {
38        let sets = [
39            #[cfg(feature = "outlined")]
40            (outlined::FONT_NAME, outlined::FONT_BYTES),
41            #[cfg(feature = "filled")]
42            (filled::FONT_NAME, filled::FONT_BYTES),
43            #[cfg(feature = "rounded")]
44            (rounded::FONT_NAME, rounded::FONT_BYTES),
45            #[cfg(feature = "sharp")]
46            (sharp::FONT_NAME, sharp::FONT_BYTES),
47        ];
48
49        for (name, bytes) in sets {
50            let font = zng_ext_font::CustomFont::from_bytes(name, zng_ext_font::FontBytes::from_static(bytes), 0);
51            zng_ext_font::FONTS.register(font);
52        }
53    }
54}
55#[cfg(feature = "embedded")]
56impl zng_app::AppExtension for MaterialIconsManager {
57    #[cfg(any(feature = "outlined", feature = "filled", feature = "rounded", feature = "sharp"))]
58    fn init(&mut self) {
59        use zng_wgt::{ICONS, IconRequestArgs, prelude::UiNode, wgt_fn};
60        use zng_wgt_text::icon::{GlyphIcon, Icon};
61
62        self.register_fonts();
63
64        ICONS.register(wgt_fn!(|args: IconRequestArgs| {
65            if let Some(strong_key) = args.name().strip_prefix("material/") {
66                #[expect(clippy::type_complexity)]
67                let sets: &[(&str, fn(&str) -> Option<GlyphIcon>)] = &[
68                    #[cfg(feature = "outlined")]
69                    ("outlined/", outlined::get),
70                    #[cfg(feature = "filled")]
71                    ("filled/", filled::get),
72                    #[cfg(feature = "rounded")]
73                    ("rounded/", rounded::get),
74                    #[cfg(feature = "sharp")]
75                    ("sharp/", sharp::get),
76                ];
77                for (name, get) in sets {
78                    if let Some(key) = strong_key.strip_prefix(name)
79                        && let Some(ico) = get(key)
80                    {
81                        return Icon!(ico);
82                    }
83                }
84            }
85
86            UiNode::nil()
87        }));
88
89        ICONS.register_fallback(wgt_fn!(|args: IconRequestArgs| {
90            let sets = [
91                #[cfg(feature = "outlined")]
92                outlined::get,
93                #[cfg(feature = "filled")]
94                filled::get,
95                #[cfg(feature = "rounded")]
96                rounded::get,
97                #[cfg(feature = "sharp")]
98                sharp::get,
99            ];
100            for get in sets {
101                if let Some(ico) = get(args.name()) {
102                    return Icon!(ico);
103                }
104            }
105            UiNode::nil()
106        }));
107    }
108}
109
110#[cfg(any(feature = "outlined", feature = "filled", feature = "rounded", feature = "sharp"))]
111macro_rules! getters {
112    ($FONT_NAME:ident, $MAP:ident) => {
113        /// Gets the [`GlyphIcon`].
114        pub fn get(key: &str) -> Option<GlyphIcon> {
115            Some(GlyphIcon::new($FONT_NAME.clone(), *$MAP.get(key)?))
116        }
117
118        /// Require the [`GlyphIcon`], logs an error if not found.
119        ///
120        /// # Panics
121        ///
122        /// Panics if the `key` is not found.
123        ///
124        /// [`GlyphIcon`]: struct@zng_wgt_text::icon::GlyphIcon
125        pub fn req(key: &str) -> GlyphIcon {
126            match get(key) {
127                Some(g) => g,
128                None => {
129                    tracing::error!("icon {key:?} not found in `outlined`");
130                    GlyphIcon::new("", '\0')
131                }
132            }
133        }
134
135        /// All icons.
136        pub fn all() -> impl ExactSizeIterator<Item = (&'static str, GlyphIcon)> {
137            $MAP.entries()
138                .map(|(key, val)| (*key, GlyphIcon::new($FONT_NAME.clone(), *val)))
139        }
140    };
141}
142
143/// Outline icons.
144///  
145/// This is the "Material Icons Outlined" font.
146///
147/// # Icons
148///
149/// Use the [`ICONS`] service with key `"material/outlined/{name}"` or `"{name}"` to get an widget that renders the icon.
150///
151/// Use [`outlined::req`] to get a [`GlyphIcon`] directly for use in the [`Icon!`] widget.
152///
153/// [`Icon!`]: struct@zng_wgt_text::icon::Icon
154/// [`GlyphIcon`]: struct@zng_wgt_text::icon::GlyphIcon
155/// [`ICONS`]: struct@zng_wgt::ICONS
156///
157/// | Name | Icon |
158/// |------|------|
159#[doc = include_str!(concat!(env!("OUT_DIR"), "/generated.outlined.docs.txt"))]
160#[cfg(feature = "outlined")]
161pub mod outlined {
162    use zng_ext_font::FontName;
163    use zng_wgt_text::icon::GlyphIcon;
164
165    /// "Material Icons Outlined".
166    pub const FONT_NAME: FontName = FontName::from_static("Material Icons Outlined");
167
168    /// Embedded font bytes.
169    #[cfg(feature = "embedded")]
170    pub const FONT_BYTES: &[u8] = include_bytes!("../fonts/MaterialIconsOutlined-Regular.otf");
171
172    include!(concat!(env!("OUT_DIR"), "/generated.outlined.map.rs"));
173    getters!(FONT_NAME, MAP);
174}
175
176/// Filled icons.
177///
178/// This is the "Material Icons" font.
179///
180/// # Icons
181///
182/// Use the [`ICONS`] service with key `"material/filled/{name}"` or `"{name}"` to get an widget that renders the icon.
183///
184/// Use [`filled::req`] to get a [`GlyphIcon`] directly for use in the [`Icon!`] widget.
185///
186/// [`Icon!`]: struct@zng_wgt_text::icon::Icon
187/// [`GlyphIcon`]: struct@zng_wgt_text::icon::GlyphIcon
188/// [`ICONS`]: struct@zng_wgt::ICONS
189///
190/// | Name | Icon |
191/// |------|------|
192#[doc = include_str!(concat!(env!("OUT_DIR"), "/generated.filled.docs.txt"))]
193#[cfg(feature = "filled")]
194pub mod filled {
195    use zng_ext_font::FontName;
196    use zng_wgt_text::icon::GlyphIcon;
197
198    /// "Material Icons".
199    pub const FONT_NAME: FontName = FontName::from_static("Material Icons");
200
201    /// Embedded font bytes.
202    #[cfg(feature = "embedded")]
203    pub const FONT_BYTES: &[u8] = include_bytes!("../fonts/MaterialIcons-Regular.ttf");
204
205    include!(concat!(env!("OUT_DIR"), "/generated.filled.map.rs"));
206    getters!(FONT_NAME, MAP);
207}
208
209/// Rounded icons.
210///  
211/// This is the "Material Icons Rounded" font.
212///
213/// # Icons
214///
215/// Use the [`ICONS`] service with key `"material/rounded/{name}"` or `"{name}"` to get an widget that renders the icon.
216///
217/// Use [`rounded::req`] to get a [`GlyphIcon`] directly for use in the [`Icon!`] widget.
218///
219/// [`Icon!`]: struct@zng_wgt_text::icon::Icon
220/// [`GlyphIcon`]: struct@zng_wgt_text::icon::GlyphIcon
221/// [`ICONS`]: struct@zng_wgt::ICONS
222///
223/// | Name | Icon |
224/// |------|------|
225#[doc = include_str!(concat!(env!("OUT_DIR"), "/generated.rounded.docs.txt"))]
226#[cfg(feature = "rounded")]
227pub mod rounded {
228    use zng_ext_font::FontName;
229    use zng_wgt_text::icon::GlyphIcon;
230
231    /// "Material Icons Rounded".
232    pub const FONT_NAME: FontName = FontName::from_static("Material Icons Rounded");
233
234    /// Embedded font bytes.
235    #[cfg(feature = "embedded")]
236    pub const FONT_BYTES: &[u8] = include_bytes!("../fonts/MaterialIconsRound-Regular.otf");
237
238    include!(concat!(env!("OUT_DIR"), "/generated.rounded.map.rs"));
239    getters!(FONT_NAME, MAP);
240}
241
242/// Sharp icons.
243///  
244/// This is the "Material Icons Sharp" font.
245///
246/// # Icons
247///
248/// Use the [`ICONS`] service with key `"material/sharp/{name}"` or `"{name}"` to get an widget that renders the icon.
249///
250/// Use [`sharp::req`] to get a [`GlyphIcon`] directly for use in the [`Icon!`] widget.
251///
252/// [`Icon!`]: struct@zng_wgt_text::icon::Icon
253/// [`GlyphIcon`]: struct@zng_wgt_text::icon::GlyphIcon
254/// [`ICONS`]: struct@zng_wgt::ICONS
255///
256/// | Name | Icon |
257/// |------|------|
258#[doc = include_str!(concat!(env!("OUT_DIR"), "/generated.sharp.docs.txt"))]
259#[cfg(feature = "sharp")]
260pub mod sharp {
261    use zng_ext_font::FontName;
262    use zng_wgt_text::icon::GlyphIcon;
263
264    /// "Material Icons Sharp".
265    pub const FONT_NAME: FontName = FontName::from_static("Material Icons Sharp");
266
267    /// Embedded font bytes.
268    #[cfg(feature = "embedded")]
269    pub const FONT_BYTES: &[u8] = include_bytes!("../fonts/MaterialIconsSharp-Regular.otf");
270
271    include!(concat!(env!("OUT_DIR"), "/generated.sharp.map.rs"));
272    getters!(FONT_NAME, MAP);
273}