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!(|args| {
31    if args.yield_until_app() {
32        return;
33    }
34    zng_app::APP.on_init(zng_app::hn!(|_| {
35        use zng_wgt::{ICONS, IconRequestArgs, prelude::UiNode, wgt_fn};
36        use zng_wgt_text::icon::{GlyphIcon, Icon};
37
38        #[cfg(feature = "usage_recorder")]
39        usage_recorder::on_init();
40
41        // register fonts
42        let sets = [
43            #[cfg(feature = "outlined")]
44            (outlined::FONT_NAME, outlined::FONT_BYTES),
45            #[cfg(feature = "filled")]
46            (filled::FONT_NAME, filled::FONT_BYTES),
47            #[cfg(feature = "rounded")]
48            (rounded::FONT_NAME, rounded::FONT_BYTES),
49            #[cfg(feature = "sharp")]
50            (sharp::FONT_NAME, sharp::FONT_BYTES),
51        ];
52        for (name, bytes) in sets {
53            let font = zng_ext_font::CustomFont::from_bytes(name, zng_ext_font::FontBytes::from_static(bytes), 0);
54            zng_ext_font::FONTS.register(font);
55        }
56
57        // register icons
58        ICONS.register(wgt_fn!(|args: IconRequestArgs| {
59            if let Some(strong_key) = args.name().strip_prefix("material/") {
60                #[expect(clippy::type_complexity)]
61                let sets: &[(&str, fn(&str) -> Option<GlyphIcon>)] = &[
62                    #[cfg(feature = "outlined")]
63                    ("outlined/", outlined::get),
64                    #[cfg(feature = "filled")]
65                    ("filled/", filled::get),
66                    #[cfg(feature = "rounded")]
67                    ("rounded/", rounded::get),
68                    #[cfg(feature = "sharp")]
69                    ("sharp/", sharp::get),
70                ];
71                for (name, get) in sets {
72                    if let Some(key) = strong_key.strip_prefix(name)
73                        && let Some(ico) = get(key)
74                    {
75                        return Icon!(ico);
76                    }
77                }
78            }
79
80            UiNode::nil()
81        }));
82
83        ICONS.register_fallback(wgt_fn!(|args: IconRequestArgs| {
84            let sets = [
85                #[cfg(feature = "outlined")]
86                outlined::get,
87                #[cfg(feature = "filled")]
88                filled::get,
89                #[cfg(feature = "rounded")]
90                rounded::get,
91                #[cfg(feature = "sharp")]
92                sharp::get,
93            ];
94            for get in sets {
95                if let Some(ico) = get(args.name()) {
96                    return Icon!(ico);
97                }
98            }
99            UiNode::nil()
100        }));
101    }));
102});
103
104#[cfg(any(feature = "outlined", feature = "filled", feature = "rounded", feature = "sharp"))]
105macro_rules! getters {
106    ($FONT_NAME:ident, $MAP:ident) => {
107        /// Gets the [`GlyphIcon`].
108        pub fn get(key: &str) -> Option<GlyphIcon> {
109            let icon = GlyphIcon::new($FONT_NAME.clone(), *$MAP.get(key)?);
110            #[cfg(feature = "usage_recorder")]
111            USAGE.insert(key);
112            Some(icon)
113        }
114
115        #[cfg(feature = "usage_recorder")]
116        pub(crate) static USAGE: std::sync::LazyLock<crate::usage_recorder::UsageRecorder> = std::sync::LazyLock::new(Default::default);
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!(concat!(env!("OUT_DIR"), "/generated.outlined.ttf"));
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!(concat!(env!("OUT_DIR"), "/generated.filled.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!(concat!(env!("OUT_DIR"), "/generated.rounded.ttf"));
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!(concat!(env!("OUT_DIR"), "/generated.sharp.ttf"));
270
271    include!(concat!(env!("OUT_DIR"), "/generated.sharp.map.rs"));
272    getters!(FONT_NAME, MAP);
273}