pub mod alert;
mod color_table;
mod command;
mod command_palette;
mod context_ext;
#[cfg(debug_assertions)]
pub mod debug_only;
mod design_tokens;
pub mod drag_and_drop;
pub mod egui_ext;
pub mod filter_widget;
mod fuzzy;
mod help;
mod hot_reload_design_tokens;
mod icon_text;
pub mod icons;
mod link_button;
pub mod list_item;
pub mod loading_indicator;
mod markdown_utils;
pub mod menu;
pub mod modal;
pub mod notifications;
mod relative_time_range;
mod section_collapsing_header;
pub mod syntax_highlighting;
pub mod text_edit;
pub mod time;
mod time_drag_value;
mod ui_ext;
mod ui_layout;
mod url_decorator;
#[cfg(target_os = "linux")]
mod wayland;
mod button;
mod combo_item;
pub mod re_form;
#[cfg(feature = "testing")]
pub mod testing;
use egui::NumExt as _;
use re_log::debug_assert;
pub use self::button::*;
pub use self::combo_item::*;
pub use self::command::{
CommandEnvironment, RecordingCommand, RecordingCommandKind, RecordingCommandSender,
RedapServerCommand, RedapServerCommandKind, RedapServerCommandSender, ResolvedCommand,
SetPlaybackSpeed, TableCommand, TableCommandKind, TableCommandSender, UICommand,
UICommandSender, consume_timeline_shortcut, listen_for_kb_shortcuts, refresh_shortcuts,
};
pub use self::command_palette::{
CmdRow, CommandPalette, CommandPaletteProvider, MatchGroup, MatchedCmd, RowState,
paint_command_row,
};
pub use self::context_ext::ContextExt;
pub use self::design_tokens::{
AlertVisuals, ButtonVisuals, DesignTokens, TableStyle, WindowFrameConfig,
};
pub use self::egui_ext::widget_ext::*;
pub use self::fuzzy::{FuzzyMatch, FuzzyQuery};
pub use self::help::*;
pub use self::hot_reload_design_tokens::{DesignTokensAlreadyInitializedError, design_tokens_of};
pub use self::icon_text::*;
pub use self::icons::Icon;
pub use self::link_button::LinkButton;
pub use self::markdown_utils::*;
pub use self::notifications::Link;
pub use self::relative_time_range::{
RelativeTimeRange, relative_time_range_boundary_label_text, relative_time_range_label_text,
};
pub use self::section_collapsing_header::SectionCollapsingHeader;
pub use self::syntax_highlighting::SyntaxHighlighting;
pub use self::time_drag_value::TimeDragValue;
pub use self::ui_ext::UiExt;
pub use self::ui_layout::UiLayout;
pub use self::url_decorator::{UrlDecorator, UrlDecoratorFn};
pub fn fullsize_content(os: egui::os::OperatingSystem) -> bool {
os == egui::os::OperatingSystem::Mac
}
pub fn supports_custom_decorations(os: egui::os::OperatingSystem) -> bool {
matches!(
os,
egui::os::OperatingSystem::Windows | egui::os::OperatingSystem::Nix
)
}
pub fn viewport_with_window_chrome(
viewport: egui::ViewportBuilder,
custom_decorations: bool,
) -> egui::ViewportBuilder {
let os = egui::os::OperatingSystem::default();
let fullsize_content = fullsize_content(os);
viewport
.with_decorations(!custom_decorations)
.with_fullsize_content_view(fullsize_content)
.with_title_shown(!fullsize_content)
.with_titlebar_shown(!fullsize_content)
.with_transparent(supports_custom_decorations(os))
}
pub fn custom_window_decorations_default() -> bool {
cfg_select! {
target_os = "linux" => {
use std::sync::OnceLock;
static CACHE: OnceLock<bool> = OnceLock::new();
*CACHE.get_or_init(|| {
if std::env::var_os("WAYLAND_DISPLAY").is_none()
|| std::env::var_os("WAYLAND_SOCKET").is_some()
{
return true;
}
wayland::should_draw_own_decorations()
})
}
target_os = "windows" => {
true
}
target_os = "macos" => {
false
}
_ => {
false
}
}
}
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 trait HasDesignTokens {
fn tokens(&self) -> &'static DesignTokens;
}
impl HasDesignTokens for egui::Context {
fn tokens(&self) -> &'static DesignTokens {
design_tokens_of(self.theme())
}
}
impl HasDesignTokens for egui::Style {
fn tokens(&self) -> &'static DesignTokens {
design_tokens_of_visuals(&self.visuals)
}
}
impl HasDesignTokens for egui::Visuals {
fn tokens(&self) -> &'static DesignTokens {
design_tokens_of_visuals(self)
}
}
pub fn try_set_design_tokens(
dark: DesignTokens,
light: DesignTokens,
) -> Result<(), DesignTokensAlreadyInitializedError> {
self::hot_reload_design_tokens::try_set_design_tokens(dark, 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);
#[cfg(debug_assertions)]
{
style.debug.warn_if_rect_changes_id = false;
}
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)
&& 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 }
}