Skip to main content

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