#![warn(clippy::iter_over_hash_type)]
pub mod alert;
mod color_table;
mod command;
mod command_palette;
mod context_ext;
mod design_tokens;
pub mod drag_and_drop;
pub mod filter_widget;
mod help;
mod hot_reload_design_tokens;
mod icon_text;
pub mod icons;
pub mod list_item;
mod markdown_utils;
pub mod modal;
pub mod notifications;
mod section_collapsing_header;
pub mod syntax_highlighting;
mod time_drag_value;
mod ui_ext;
mod ui_layout;
use egui::NumExt as _;
pub use self::{
command::{UICommand, UICommandSender},
command_palette::CommandPalette,
context_ext::ContextExt,
design_tokens::{DesignTokens, TableStyle},
help::*,
hot_reload_design_tokens::design_tokens_of,
icon_text::*,
icons::Icon,
markdown_utils::*,
section_collapsing_header::SectionCollapsingHeader,
syntax_highlighting::SyntaxHighlighting,
time_drag_value::TimeDragValue,
ui_ext::UiExt,
ui_layout::UiLayout,
};
#[cfg(feature = "arrow")]
mod arrow_ui;
pub mod menu;
pub mod time;
#[cfg(feature = "arrow")]
pub use self::arrow_ui::arrow_ui;
pub const FULLSIZE_CONTENT: bool = cfg!(target_os = "macos");
pub const CUSTOM_WINDOW_DECORATIONS: bool = false;
pub const NATIVE_WINDOW_BAR: bool = !FULLSIZE_CONTENT && !CUSTOM_WINDOW_DECORATIONS;
pub struct TopBarStyle {
pub height: f32,
pub indent: f32,
}
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
pub enum LabelStyle {
#[default]
Normal,
Unnamed,
}
pub fn design_tokens_of_visuals(visuals: &egui::Visuals) -> &'static DesignTokens {
if visuals.dark_mode {
design_tokens_of(egui::Theme::Dark)
} else {
design_tokens_of(egui::Theme::Light)
}
}
pub fn apply_style_and_install_loaders(egui_ctx: &egui::Context) {
re_tracing::profile_function!();
egui_extras::install_image_loaders(egui_ctx);
egui_ctx.include_bytes(
"bytes://logo_dark_mode",
include_bytes!("../data/logo_dark_mode.png"),
);
egui_ctx.include_bytes(
"bytes://logo_light_mode",
include_bytes!("../data/logo_light_mode.png"),
);
egui_ctx.options_mut(|o| {
o.fallback_theme = egui::Theme::Dark; });
set_themes(egui_ctx);
#[cfg(hot_reload_design_tokens)]
{
let egui_ctx = egui_ctx.clone();
hot_reload_design_tokens::install_hot_reload(move || {
re_log::debug!("Hot-reloading design tokens…");
hot_reload_design_tokens::hot_reload_design_tokens();
set_themes(&egui_ctx);
egui_ctx.request_repaint();
});
}
}
fn set_themes(egui_ctx: &egui::Context) {
design_tokens_of(egui::Theme::Dark).set_fonts(egui_ctx);
for theme in [egui::Theme::Dark, egui::Theme::Light] {
let mut style = std::sync::Arc::unwrap_or_clone(egui_ctx.style_of(theme));
design_tokens_of(theme).apply(&mut style);
egui_ctx.set_style_of(theme, style);
}
}
fn format_with_decimals_in_range(
value: f64,
decimal_range: std::ops::RangeInclusive<usize>,
) -> String {
fn format_with_decimals(value: f64, decimals: usize) -> String {
re_format::FloatFormatOptions::DEFAULT_f64
.with_decimals(decimals)
.with_strip_trailing_zeros(false)
.format(value)
}
let epsilon = 16.0 * f32::EPSILON;
let min_decimals = *decimal_range.start();
let max_decimals = *decimal_range.end();
debug_assert!(min_decimals <= max_decimals);
debug_assert!(max_decimals < 100);
let max_decimals = max_decimals.at_most(16);
let min_decimals = min_decimals.at_most(max_decimals);
if min_decimals < max_decimals {
for decimals in min_decimals..max_decimals {
let text = format_with_decimals(value, decimals);
if let Some(parsed) = re_format::parse_f64(&text) {
if egui::emath::almost_equal(parsed as f32, value as f32, epsilon) {
return text;
}
}
}
}
format_with_decimals(value, max_decimals)
}
fn is_in_resizable_panel(ui: &egui::Ui) -> bool {
re_tracing::profile_function!();
let mut is_in_side_panel = false;
for frame in ui.stack().iter() {
if let Some(kind) = frame.kind() {
if kind.is_area() {
return false; }
if matches!(kind, egui::UiKind::LeftPanel | egui::UiKind::RightPanel) {
is_in_side_panel = true;
}
}
}
if is_in_side_panel {
true } else {
false }
}