mod command;
mod command_palette;
mod design_tokens;
mod syntax_highlighting;
mod context_ext;
pub mod drag_and_drop;
pub mod icons;
pub mod list_item;
mod markdown_utils;
pub mod modal;
mod section_collapsing_header;
pub mod toasts;
mod ui_ext;
use egui::NumExt as _;
pub use self::{
command::{UICommand, UICommandSender},
command_palette::CommandPalette,
context_ext::ContextExt,
design_tokens::DesignTokens,
icons::Icon,
markdown_utils::*,
section_collapsing_header::SectionCollapsingHeader,
syntax_highlighting::SyntaxHighlighting,
ui_ext::UiExt,
};
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() -> &'static DesignTokens {
use once_cell::sync::OnceCell;
static DESIGN_TOKENS: OnceCell<DesignTokens> = OnceCell::new();
DESIGN_TOKENS.get_or_init(DesignTokens::load)
}
pub fn apply_style_and_install_loaders(egui_ctx: &egui::Context) {
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.theme_preference = egui::ThemePreference::Dark;
o.fallback_theme = egui::Theme::Dark;
});
design_tokens().apply(egui_ctx);
egui_ctx.style_mut(|style| {
style.number_formatter = egui::style::NumberFormatter::new(format_with_decimals_in_range);
});
}
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 }
}