egui_charts/icons/icon.rs
1//! Icon struct for compile-time embedded SVG icons
2
3use egui::Vec2;
4
5/// A compile-time embedded SVG icon.
6///
7/// Icons are embedded at compile time using `include_bytes!`, which means
8/// they are part of the binary and don't require filesystem access at runtime.
9/// Create your own with [`icon_from_path!`](crate::icon_from_path).
10///
11/// # Example
12///
13/// ```
14/// use egui::Vec2;
15/// use egui_charts::icons::icons;
16///
17/// # egui::__run_test_ui(|ui| {
18/// ui.add(icons::SETTINGS.as_image(Vec2::splat(20.0)));
19/// # });
20/// ```
21#[derive(Clone, Copy)]
22pub struct Icon {
23 /// Name/path of the icon (for debugging and cache keys)
24 pub name: &'static str,
25 /// Raw SVG bytes embedded at compile time
26 pub svg_bytes: &'static [u8],
27}
28
29impl Icon {
30 /// Create a new icon from embedded bytes.
31 ///
32 /// This is typically called via the `icon_from_path!` macro.
33 #[inline]
34 pub const fn new(name: &'static str, svg_bytes: &'static [u8]) -> Self {
35 Self { name, svg_bytes }
36 }
37
38 /// Convert to an egui Image widget with the specified size.
39 ///
40 /// # Arguments
41 ///
42 /// * `size` - The size to render the icon at (width and height)
43 #[inline]
44 pub fn as_image(&self, size: Vec2) -> egui::Image<'static> {
45 // The logical width in the URI lets the icon loader size strokes for the display scale.
46 let uri = format!("{}{}/{}", super::loader::URI_PREFIX, size.x, self.name);
47 egui::Image::from_bytes(uri, self.svg_bytes).fit_to_exact_size(size)
48 }
49
50 /// Convert to an egui Image widget with the specified size and tint color.
51 ///
52 /// # Arguments
53 ///
54 /// * `size` - The size to render the icon at
55 /// * `tint` - The color to tint the icon with
56 #[inline]
57 pub fn as_image_tinted(&self, size: Vec2, tint: egui::Color32) -> egui::Image<'static> {
58 self.as_image(size).tint(tint)
59 }
60
61 /// Convert to an egui Image widget with square dimensions.
62 ///
63 /// # Arguments
64 ///
65 /// * `size` - The size (both width and height) to render the icon at
66 #[inline]
67 pub fn as_image_square(&self, size: f32) -> egui::Image<'static> {
68 self.as_image(Vec2::splat(size))
69 }
70
71 /// Get the name/path of this icon (useful for debugging).
72 #[inline]
73 pub const fn name(&self) -> &'static str {
74 self.name
75 }
76
77 /// Get the raw SVG bytes.
78 #[inline]
79 pub const fn svg_bytes(&self) -> &'static [u8] {
80 self.svg_bytes
81 }
82
83 /// Get the size of the SVG data in bytes.
84 #[inline]
85 pub const fn byte_size(&self) -> usize {
86 self.svg_bytes.len()
87 }
88
89 /// Convert to an egui Button widget with the icon.
90 ///
91 /// The button will automatically tint the icon to match text color,
92 /// providing proper visual feedback for hover/active states.
93 ///
94 /// # Arguments
95 ///
96 /// * `size` - The size to render the icon at
97 #[inline]
98 pub fn as_button(&self, size: Vec2) -> egui::Button<'static> {
99 egui::Button::image(self.as_image(size)).image_tint_follows_text_color(true)
100 }
101
102 /// Convert to an egui Button widget with the icon and a text label.
103 ///
104 /// # Arguments
105 ///
106 /// * `size` - The size to render the icon at
107 /// * `label` - The text label to display next to the icon
108 #[inline]
109 pub fn as_button_with_label(
110 &self,
111 size: Vec2,
112 label: impl Into<egui::WidgetText>,
113 ) -> egui::Button<'static> {
114 egui::Button::image_and_text(self.as_image(size), label).image_tint_follows_text_color(true)
115 }
116
117 /// Convert to an egui Button widget with square icon dimensions.
118 ///
119 /// # Arguments
120 ///
121 /// * `size` - The size (both width and height) to render the icon at
122 #[inline]
123 pub fn as_button_square(&self, size: f32) -> egui::Button<'static> {
124 self.as_button(Vec2::splat(size))
125 }
126}
127
128impl std::fmt::Debug for Icon {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 f.debug_struct("Icon")
131 .field("name", &self.name)
132 .field("byte_size", &self.svg_bytes.len())
133 .finish()
134 }
135}
136
137impl PartialEq for Icon {
138 fn eq(&self, other: &Self) -> bool {
139 // Compare by name since bytes comparison would be expensive
140 self.name == other.name
141 }
142}
143
144impl Eq for Icon {}
145
146impl std::hash::Hash for Icon {
147 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
148 self.name.hash(state);
149 }
150}