re_ui/
icons.rs

1use std::fmt::Formatter;
2use std::hash::{DefaultHasher, Hash as _, Hasher as _};
3
4use egui::{Atom, Image, ImageSource};
5
6use crate::DesignTokens;
7
8#[derive(Clone, Copy)]
9pub struct Icon {
10    /// Human-readable unique id.
11    ///
12    /// This usually ends with `.png` or `.svg`.
13    uri: &'static str,
14
15    /// The raw contents of e.g. a PNG or SVG file.
16    image_bytes: &'static [u8],
17}
18
19impl std::fmt::Debug for Icon {
20    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
21        let mut hasher = DefaultHasher::new();
22        self.image_bytes.hash(&mut hasher);
23        let hash = hasher.finish();
24
25        f.debug_struct("Icon")
26            .field("uri", &self.uri)
27            .field(
28                "image_bytes",
29                &format!("len: {}, hash: {:#x}", self.image_bytes.len(), hash),
30            )
31            .finish()
32    }
33}
34
35impl Icon {
36    #[inline]
37    pub const fn new(uri: &'static str, image_bytes: &'static [u8]) -> Self {
38        Self { uri, image_bytes }
39    }
40
41    pub fn uri(&self) -> &'static str {
42        self.uri
43    }
44
45    #[inline]
46    pub fn as_image_source(&self) -> ImageSource<'static> {
47        ImageSource::Bytes {
48            uri: self.uri.into(),
49            bytes: self.image_bytes.into(),
50        }
51    }
52
53    pub fn load_image(
54        &self,
55        egui_ctx: &egui::Context,
56        size_hint: egui::SizeHint,
57    ) -> egui::load::ImageLoadResult {
58        egui_ctx.include_bytes(self.uri(), self.image_bytes);
59        egui_ctx.try_load_image(self.uri(), size_hint)
60    }
61
62    #[inline]
63    pub fn as_image(&self) -> Image<'static> {
64        let scale = if self.uri.ends_with(".svg") {
65            1.0
66        } else {
67            0.5 // Because we save all png icons as 2x
68        };
69        // Default size is the same size as the source data specifies
70        Image::new(self.as_image_source()).fit_to_original_size(scale)
71    }
72
73    #[inline]
74    pub fn as_button(&self) -> egui::Button<'_> {
75        egui::Button::image(self.as_image()).image_tint_follows_text_color(true)
76    }
77
78    #[inline]
79    pub fn as_button_with_label(
80        &self,
81        tokens: &DesignTokens,
82        label: impl Into<egui::WidgetText>,
83    ) -> egui::Button<'_> {
84        egui::Button::image_and_text(self.as_image().tint(tokens.label_button_icon_color), label)
85    }
86}
87
88impl From<&'static Icon> for Image<'static> {
89    #[inline]
90    fn from(icon: &'static Icon) -> Self {
91        icon.as_image()
92    }
93}
94
95impl From<&Icon> for Atom<'static> {
96    #[inline]
97    fn from(icon: &Icon) -> Self {
98        Atom::from(icon.as_image())
99    }
100}
101
102impl From<Icon> for Atom<'static> {
103    #[inline]
104    fn from(icon: Icon) -> Self {
105        Atom::from(icon.as_image())
106    }
107}
108
109/// Macro to create an [`Icon`], using the file path as the id.
110///
111/// This avoids specifying the id manually, which is error-prone (duplicate IDs lead to silent
112/// display bugs).
113macro_rules! icon_from_path {
114    ($path:literal) => {
115        Icon::new($path, include_bytes!($path))
116    };
117}
118
119pub const RERUN_MENU: Icon = icon_from_path!("../data/icons/rerun_menu.svg");
120
121pub const RERUN_IO_TEXT: Icon = icon_from_path!("../data/icons/rerun_io.svg");
122
123pub const HELP: Icon = icon_from_path!("../data/icons/help.svg");
124
125pub const PLAY: Icon = icon_from_path!("../data/icons/play.svg");
126pub const FOLLOW: Icon = icon_from_path!("../data/icons/follow.svg");
127pub const PAUSE: Icon = icon_from_path!("../data/icons/pause.svg");
128pub const ARROW_LEFT: Icon = icon_from_path!("../data/icons/arrow_left.svg");
129pub const ARROW_RIGHT: Icon = icon_from_path!("../data/icons/arrow_right.svg");
130pub const ARROW_UP: Icon = icon_from_path!("../data/icons/arrow_up.svg");
131pub const ARROW_DOWN: Icon = icon_from_path!("../data/icons/arrow_down.svg");
132pub const LOOP: Icon = icon_from_path!("../data/icons/loop.svg");
133pub const FILTER: Icon = icon_from_path!("../data/icons/filter.svg");
134
135pub const NOTIFICATION: Icon = icon_from_path!("../data/icons/notification.svg");
136pub const RIGHT_PANEL_TOGGLE: Icon = icon_from_path!("../data/icons/right_panel_toggle.svg");
137pub const BOTTOM_PANEL_TOGGLE: Icon = icon_from_path!("../data/icons/bottom_panel_toggle.svg");
138pub const LEFT_PANEL_TOGGLE: Icon = icon_from_path!("../data/icons/left_panel_toggle.svg");
139
140pub const MINIMIZE: Icon = icon_from_path!("../data/icons/minimize.svg");
141pub const MAXIMIZE: Icon = icon_from_path!("../data/icons/maximize.svg");
142pub const EXPAND: Icon = icon_from_path!("../data/icons/expand.svg");
143pub const COLUMN_VISIBILITY: Icon = icon_from_path!("../data/icons/column_visibility.svg");
144
145pub const VISIBLE: Icon = icon_from_path!("../data/icons/visible.svg");
146pub const INVISIBLE: Icon = icon_from_path!("../data/icons/invisible.svg");
147
148pub const ADD: Icon = icon_from_path!("../data/icons/add.svg");
149
150pub const REMOVE: Icon = icon_from_path!("../data/icons/remove.svg");
151pub const TRASH: Icon = icon_from_path!("../data/icons/trash.svg");
152
153pub const RESET: Icon = icon_from_path!("../data/icons/reset.svg");
154
155pub const EDIT: Icon = icon_from_path!("../data/icons/edit.svg");
156pub const MORE: Icon = icon_from_path!("../data/icons/more.svg");
157
158pub const CLOSE: Icon = icon_from_path!("../data/icons/close.svg");
159pub const CLOSE_SMALL: Icon = icon_from_path!("../data/icons/close_small.svg");
160
161/// Used for HTTP URLs that lead out of the app.
162///
163/// Remember to also use `.on_hover_cursor(egui::CursorIcon::PointingHand)`,
164/// but don't add `.on_hover_text(url)`.
165pub const EXTERNAL_LINK: Icon = icon_from_path!("../data/icons/external_link.svg");
166pub const DISCORD: Icon = icon_from_path!("../data/icons/discord.svg");
167
168pub const URL: Icon = icon_from_path!("../data/icons/url.svg");
169
170pub const CONTAINER_HORIZONTAL: Icon = icon_from_path!("../data/icons/container_horizontal.svg");
171pub const CONTAINER_GRID: Icon = icon_from_path!("../data/icons/container_grid.svg");
172pub const CONTAINER_TABS: Icon = icon_from_path!("../data/icons/container_tabs.svg");
173pub const CONTAINER_VERTICAL: Icon = icon_from_path!("../data/icons/container_vertical.svg");
174
175pub const VIEW_2D: Icon = icon_from_path!("../data/icons/view_2d.svg");
176pub const VIEW_3D: Icon = icon_from_path!("../data/icons/view_3d.svg");
177pub const VIEW_DATAFRAME: Icon = icon_from_path!("../data/icons/view_dataframe.svg");
178pub const VIEW_GRAPH: Icon = icon_from_path!("../data/icons/view_graph.svg");
179pub const VIEW_GENERIC: Icon = icon_from_path!("../data/icons/view_generic.svg");
180pub const VIEW_HISTOGRAM: Icon = icon_from_path!("../data/icons/view_histogram.svg");
181pub const VIEW_LOG: Icon = icon_from_path!("../data/icons/view_log.svg");
182pub const VIEW_MAP: Icon = icon_from_path!("../data/icons/view_map.svg");
183pub const VIEW_TENSOR: Icon = icon_from_path!("../data/icons/view_tensor.svg");
184pub const VIEW_TEXT: Icon = icon_from_path!("../data/icons/view_text.svg");
185pub const VIEW_TIMESERIES: Icon = icon_from_path!("../data/icons/view_timeseries.svg");
186pub const VIEW_UNKNOWN: Icon = icon_from_path!("../data/icons/view_unknown.svg");
187
188pub const GROUP: Icon = icon_from_path!("../data/icons/group.svg");
189pub const ENTITY: Icon = icon_from_path!("../data/icons/entity.svg");
190pub const ENTITY_EMPTY: Icon = icon_from_path!("../data/icons/entity_empty.svg");
191pub const ENTITY_RESERVED: Icon = icon_from_path!("../data/icons/entity_reserved.svg");
192pub const ENTITY_RESERVED_EMPTY: Icon = icon_from_path!("../data/icons/entity_reserved_empty.svg");
193
194/// Link within the viewer
195pub const INTERNAL_LINK: Icon = icon_from_path!("../data/icons/internal_link.svg");
196
197pub const COMPONENT_TEMPORAL: Icon = icon_from_path!("../data/icons/component.svg");
198pub const COMPONENT_STATIC: Icon = icon_from_path!("../data/icons/component_static.svg");
199
200pub const APPLICATION: Icon = icon_from_path!("../data/icons/application.svg");
201pub const DATA_SOURCE: Icon = icon_from_path!("../data/icons/data_source.svg");
202pub const TABLE: Icon = icon_from_path!("../data/icons/table.svg");
203pub const DATASET: Icon = icon_from_path!("../data/icons/dataset.svg");
204pub const RECORDING: Icon = icon_from_path!("../data/icons/recording.svg");
205pub const BLUEPRINT: Icon = icon_from_path!("../data/icons/blueprint.svg");
206
207pub const GITHUB: Icon = icon_from_path!("../data/icons/github.svg");
208
209pub const INFO: Icon = icon_from_path!("../data/icons/info.svg");
210pub const WARNING: Icon = icon_from_path!("../data/icons/warn.svg");
211pub const ERROR: Icon = icon_from_path!("../data/icons/error.svg");
212pub const SUCCESS: Icon = icon_from_path!("../data/icons/success.svg");
213pub const VIDEO_ERROR: Icon = icon_from_path!("../data/icons/video_error.svg");
214
215// drag and drop icons
216pub const DND_ADD_NEW: Icon = icon_from_path!("../data/icons/dnd_add_new.svg");
217pub const DND_ADD_TO_EXISTING: Icon = icon_from_path!("../data/icons/dnd_add_to_existing.svg");
218pub const DND_MOVE: Icon = icon_from_path!("../data/icons/dnd_move.svg");
219pub const DND_HANDLE: Icon = icon_from_path!("../data/icons/dnd_handle.svg");
220
221/// `>`
222pub const BREADCRUMBS_SEPARATOR: Icon = icon_from_path!("../data/icons/breadcrumbs_separator.svg");
223
224pub const SEARCH: Icon = icon_from_path!("../data/icons/search.svg");
225pub const SETTINGS: Icon = icon_from_path!("../data/icons/settings.svg");
226
227/// Shortcut icons
228pub const LEFT_MOUSE_CLICK: Icon = icon_from_path!("../data/icons/lmc.svg");
229pub const RIGHT_MOUSE_CLICK: Icon = icon_from_path!("../data/icons/rmc.svg");
230pub const SCROLL: Icon = icon_from_path!("../data/icons/scroll.svg");
231pub const SHIFT: Icon = icon_from_path!("../data/icons/shift.svg");
232pub const CONTROL: Icon = icon_from_path!("../data/icons/control.svg");
233pub const COMMAND: Icon = icon_from_path!("../data/icons/command.svg");
234pub const OPTION: Icon = icon_from_path!("../data/icons/option.svg");
235pub const COPY: Icon = icon_from_path!("../data/icons/copy.svg");
236pub const DOWNLOAD: Icon = icon_from_path!("../data/icons/download.svg");