1mod color_table;
4mod command;
5mod command_palette;
6mod context_ext;
7mod design_tokens;
8pub mod drag_and_drop;
9pub mod filter_widget;
10mod help;
11mod icon_text;
12pub mod icons;
13pub mod list_item;
14mod markdown_utils;
15pub mod modal;
16pub mod notifications;
17mod section_collapsing_header;
18pub mod syntax_highlighting;
19mod ui_ext;
20mod ui_layout;
21
22use egui::Color32;
23use egui::NumExt as _;
24
25pub use self::{
26 color_table::{ColorTable, ColorToken, Hue, Scale},
27 command::{UICommand, UICommandSender},
28 command_palette::CommandPalette,
29 context_ext::ContextExt,
30 design_tokens::DesignTokens,
31 help::*,
32 icon_text::*,
33 icons::Icon,
34 markdown_utils::*,
35 section_collapsing_header::SectionCollapsingHeader,
36 syntax_highlighting::SyntaxHighlighting,
37 ui_ext::UiExt,
38 ui_layout::UiLayout,
39};
40
41#[cfg(feature = "arrow")]
42mod arrow_ui;
43
44#[cfg(feature = "arrow")]
45pub use self::arrow_ui::arrow_ui;
46
47pub const FULLSIZE_CONTENT: bool = cfg!(target_os = "macos");
52
53pub const CUSTOM_WINDOW_DECORATIONS: bool = false; pub const NATIVE_WINDOW_BAR: bool = !FULLSIZE_CONTENT && !CUSTOM_WINDOW_DECORATIONS;
61
62pub const INFO_COLOR: Color32 = Color32::from_rgb(0, 155, 255);
63pub const SUCCESS_COLOR: Color32 = Color32::from_rgb(0, 240, 32);
64
65pub struct TopBarStyle {
68 pub height: f32,
70
71 pub indent: f32,
74}
75
76#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
80pub enum LabelStyle {
81 #[default]
83 Normal,
84
85 Unnamed,
87}
88
89pub fn design_tokens() -> &'static DesignTokens {
93 use once_cell::sync::OnceCell;
94 static DESIGN_TOKENS: OnceCell<DesignTokens> = OnceCell::new();
95 DESIGN_TOKENS.get_or_init(DesignTokens::load)
96}
97
98pub fn apply_style_and_install_loaders(egui_ctx: &egui::Context) {
100 egui_extras::install_image_loaders(egui_ctx);
101
102 egui_ctx.include_bytes(
103 "bytes://logo_dark_mode",
104 include_bytes!("../data/logo_dark_mode.png"),
105 );
106 egui_ctx.include_bytes(
107 "bytes://logo_light_mode",
108 include_bytes!("../data/logo_light_mode.png"),
109 );
110
111 egui_ctx.options_mut(|o| {
112 o.theme_preference = egui::ThemePreference::Dark;
113 o.fallback_theme = egui::Theme::Dark;
114 });
115
116 design_tokens().apply(egui_ctx);
117
118 egui_ctx.style_mut(|style| {
119 style.number_formatter = egui::style::NumberFormatter::new(format_with_decimals_in_range);
120 });
121}
122
123fn format_with_decimals_in_range(
124 value: f64,
125 decimal_range: std::ops::RangeInclusive<usize>,
126) -> String {
127 fn format_with_decimals(value: f64, decimals: usize) -> String {
128 re_format::FloatFormatOptions::DEFAULT_f64
129 .with_decimals(decimals)
130 .with_strip_trailing_zeros(false)
131 .format(value)
132 }
133
134 let epsilon = 16.0 * f32::EPSILON; let min_decimals = *decimal_range.start();
137 let max_decimals = *decimal_range.end();
138 debug_assert!(min_decimals <= max_decimals);
139 debug_assert!(max_decimals < 100);
140 let max_decimals = max_decimals.at_most(16);
141 let min_decimals = min_decimals.at_most(max_decimals);
142
143 if min_decimals < max_decimals {
144 for decimals in min_decimals..max_decimals {
147 let text = format_with_decimals(value, decimals);
148 if let Some(parsed) = re_format::parse_f64(&text) {
149 if egui::emath::almost_equal(parsed as f32, value as f32, epsilon) {
150 return text;
152 }
153 }
154 }
155 }
159
160 format_with_decimals(value, max_decimals)
162}
163
164fn is_in_resizable_panel(ui: &egui::Ui) -> bool {
175 re_tracing::profile_function!();
176
177 let mut is_in_side_panel = false;
178
179 for frame in ui.stack().iter() {
180 if let Some(kind) = frame.kind() {
181 if kind.is_area() {
182 return false; }
184 if matches!(kind, egui::UiKind::LeftPanel | egui::UiKind::RightPanel) {
185 is_in_side_panel = true;
186 }
187 }
188 }
189
190 if is_in_side_panel {
191 true } else {
193 false }
195}