use std::collections::BTreeMap;
use re_arrow_store::LatestAtQuery;
use re_data_store::EntityPath;
use re_log_types::{
component_types::InstanceKey, external::arrow2, Component, ComponentName,
DeserializableComponent,
};
use re_query::ComponentWithInstances;
use crate::{misc::ViewerContext, ui::UiVerbosity};
use super::{DataUi, EntityDataUi};
type ComponentUiCallback = Box<
dyn Fn(
&mut ViewerContext<'_>,
&mut egui::Ui,
UiVerbosity,
&LatestAtQuery,
&EntityPath,
&ComponentWithInstances,
&InstanceKey,
),
>;
pub struct ComponentUiRegistry {
components: BTreeMap<ComponentName, ComponentUiCallback>,
}
impl Default for ComponentUiRegistry {
fn default() -> Self {
let mut registry = Self {
components: Default::default(),
};
registry.add::<re_log_types::component_types::AnnotationContext>();
registry.add::<re_log_types::component_types::ColorRGBA>();
registry.add::<re_log_types::component_types::LineStrip2D>();
registry.add::<re_log_types::component_types::LineStrip3D>();
registry.add::<re_log_types::component_types::Mesh3D>();
registry.add::<re_log_types::component_types::Rect2D>();
registry.add::<re_log_types::component_types::Tensor>();
registry.add::<re_log_types::component_types::TextEntry>();
registry.add::<re_log_types::component_types::Transform>();
registry.add::<re_log_types::component_types::Vec2D>();
registry.add::<re_log_types::component_types::Vec3D>();
registry.add::<re_log_types::ViewCoordinates>();
registry
}
}
impl ComponentUiRegistry {
fn add<C: DeserializableComponent + EntityDataUi>(&mut self)
where
for<'a> &'a C::ArrayType: IntoIterator,
{
self.components.insert(
C::name(),
Box::new(
|ctx, ui, verbosity, query, entity_path, component, instance| match component
.lookup::<C>(instance)
{
Ok(component) => {
component.entity_data_ui(ctx, ui, verbosity, entity_path, query);
}
Err(re_query::QueryError::ComponentNotFound) => {
ui.weak("(not found)");
}
Err(err) => {
re_log::warn_once!("Expected component {}, {}", C::name(), err);
}
},
),
);
}
#[allow(clippy::too_many_arguments)]
pub fn ui(
&self,
ctx: &mut crate::misc::ViewerContext<'_>,
ui: &mut egui::Ui,
verbosity: crate::ui::UiVerbosity,
query: &LatestAtQuery,
entity_path: &EntityPath,
component: &ComponentWithInstances,
instance_key: &InstanceKey,
) {
crate::profile_function!(component.name().full_name());
if component.name() == InstanceKey::name() {
ui.label(instance_key.to_string());
return;
}
if let Some(ui_callback) = self.components.get(&component.name()) {
(*ui_callback)(
ctx,
ui,
verbosity,
query,
entity_path,
component,
instance_key,
);
} else {
if let Some(value) = component.lookup_arrow(instance_key) {
let bytes = arrow2::compute::aggregate::estimated_bytes_size(value.as_ref());
if bytes < 256 {
let mut repr = String::new();
let display = arrow2::array::get_display(value.as_ref(), "null");
display(&mut repr, 0).unwrap();
ui.label(repr);
} else {
ui.label(format!("{bytes} bytes"));
}
} else {
ui.weak("(null)");
}
}
}
}
impl DataUi for re_log_types::component_types::TextEntry {
fn data_ui(
&self,
_ctx: &mut ViewerContext<'_>,
ui: &mut egui::Ui,
verbosity: UiVerbosity,
_query: &re_arrow_store::LatestAtQuery,
) {
use crate::ui::view_text::level_to_rich_text;
let Self { body, level } = self;
match verbosity {
UiVerbosity::Small => {
ui.horizontal(|ui| {
if let Some(level) = level {
ui.label(level_to_rich_text(ui, level));
}
ui.label(format!("{body:?}")); });
}
UiVerbosity::All | UiVerbosity::Reduced => {
egui::Grid::new("text_entry").num_columns(2).show(ui, |ui| {
ui.label("level:");
if let Some(level) = level {
ui.label(level_to_rich_text(ui, level));
}
ui.end_row();
ui.label("body:");
ui.label(format!("{body:?}")); ui.end_row();
});
}
}
}
}
impl DataUi for re_log_types::component_types::Mesh3D {
fn data_ui(
&self,
ctx: &mut ViewerContext<'_>,
ui: &mut egui::Ui,
verbosity: UiVerbosity,
query: &re_arrow_store::LatestAtQuery,
) {
match self {
re_log_types::Mesh3D::Encoded(mesh) => mesh.data_ui(ctx, ui, verbosity, query),
re_log_types::Mesh3D::Raw(mesh) => mesh.data_ui(ctx, ui, verbosity, query),
}
}
}
impl DataUi for re_log_types::component_types::EncodedMesh3D {
fn data_ui(
&self,
_ctx: &mut ViewerContext<'_>,
ui: &mut egui::Ui,
_verbosity: UiVerbosity,
_query: &re_arrow_store::LatestAtQuery,
) {
ui.label(format!("{} mesh", self.format));
}
}
impl DataUi for re_log_types::component_types::RawMesh3D {
fn data_ui(
&self,
_ctx: &mut ViewerContext<'_>,
ui: &mut egui::Ui,
_verbosity: UiVerbosity,
_query: &re_arrow_store::LatestAtQuery,
) {
ui.label(format!(
"mesh ({} triangles)",
re_format::format_number(self.num_triangles())
));
}
}