re_data_ui/
lib.rs

1//! Rerun Data Ui
2//!
3//! This crate provides ui elements for Rerun component data for the Rerun Viewer.
4
5#![warn(clippy::iter_over_hash_type)] //  TODO(#6198): enable everywhere
6
7use re_log_types::EntityPath;
8use re_types::reflection::ComponentDescriptorExt as _;
9use re_types::{ComponentDescriptor, RowId};
10use re_ui::UiExt as _;
11use re_viewer_context::{UiLayout, ViewerContext};
12
13mod annotation_context;
14mod app_id;
15mod blob;
16mod component;
17mod component_path;
18mod component_type;
19mod component_ui_registry;
20mod data_source;
21mod entity_db;
22mod entity_path;
23mod image;
24mod instance_path;
25mod store_id;
26mod tensor;
27mod video;
28
29mod extra_data_ui;
30pub mod item_ui;
31
32pub use crate::tensor::tensor_summary_ui_grid_contents;
33pub use component::ComponentPathLatestAtResults;
34pub use component_ui_registry::{add_to_registry, register_component_uis};
35pub use image::image_preview_ui;
36pub use instance_path::archetype_label_list_item_ui;
37use re_chunk_store::UnitChunkShared;
38use re_types_core::reflection::Reflection;
39use re_types_core::{ArchetypeName, Component};
40
41pub type ArchetypeComponentMap =
42    std::collections::BTreeMap<Option<ArchetypeName>, Vec<ComponentDescriptor>>;
43
44/// Components grouped by archetype.
45pub fn sorted_component_list_by_archetype_for_ui(
46    reflection: &Reflection,
47    iter: impl IntoIterator<Item = ComponentDescriptor>,
48) -> ArchetypeComponentMap {
49    let mut map = iter
50        .into_iter()
51        .fold(ArchetypeComponentMap::default(), |mut acc, descriptor| {
52            acc.entry(descriptor.archetype)
53                .or_default()
54                .push(descriptor);
55            acc
56        });
57
58    for (archetype, components) in &mut map {
59        if let Some(reflection) = archetype
60            .as_ref()
61            .and_then(|a| reflection.archetypes.get(a))
62        {
63            // Sort components by their importance
64            components.sort_by_key(|c| {
65                reflection
66                    .fields
67                    .iter()
68                    .position(|field| field.name == c.archetype_field_name())
69                    .unwrap_or(usize::MAX)
70            });
71        } else {
72            // As a fallback, sort by the short name, as that is what is shown in the UI.
73            components.sort_by_key(|c| c.display_name().to_owned());
74        }
75    }
76
77    map
78}
79
80/// Types implementing [`DataUi`] can display themselves in an [`egui::Ui`].
81pub trait DataUi {
82    /// If you need to lookup something in the chunk store, use the given query to do so.
83    fn data_ui(
84        &self,
85        ctx: &ViewerContext<'_>,
86        ui: &mut egui::Ui,
87        ui_layout: UiLayout,
88        query: &re_chunk_store::LatestAtQuery,
89        db: &re_entity_db::EntityDb,
90    );
91
92    /// Called [`Self::data_ui`] using the default query and recording.
93    fn data_ui_recording(&self, ctx: &ViewerContext<'_>, ui: &mut egui::Ui, ui_layout: UiLayout) {
94        ui.sanity_check();
95        self.data_ui(ctx, ui, ui_layout, &ctx.current_query(), ctx.recording());
96        ui.sanity_check();
97    }
98}
99
100/// Similar to [`DataUi`], but for data that is related to an entity (e.g. a component).
101///
102/// This is given the context of the entity it is part of so it can do queries.
103pub trait EntityDataUi {
104    /// If you need to lookup something in the chunk store, use the given query to do so.
105    #[expect(clippy::too_many_arguments)]
106    fn entity_data_ui(
107        &self,
108        ctx: &ViewerContext<'_>,
109        ui: &mut egui::Ui,
110        ui_layout: UiLayout,
111        entity_path: &EntityPath,
112        component_descriptor: &ComponentDescriptor,
113        row_id: Option<RowId>,
114        query: &re_chunk_store::LatestAtQuery,
115        db: &re_entity_db::EntityDb,
116    );
117}
118
119impl<T> EntityDataUi for T
120where
121    T: DataUi,
122{
123    fn entity_data_ui(
124        &self,
125        ctx: &ViewerContext<'_>,
126        ui: &mut egui::Ui,
127        ui_layout: UiLayout,
128        entity_path: &EntityPath,
129        _component_descriptor: &ComponentDescriptor,
130        _row_id: Option<RowId>,
131        query: &re_chunk_store::LatestAtQuery,
132        db: &re_entity_db::EntityDb,
133    ) {
134        // This ensures that UI state is maintained per entity. For example, the collapsed state for
135        // `AnnotationContext` component is not saved by all instances of the component.
136        ui.push_id(entity_path.hash(), |ui| {
137            self.data_ui(ctx, ui, ui_layout, query, db);
138        });
139    }
140}
141
142// ---------------------------------------------------------------------------
143
144pub fn annotations(
145    ctx: &ViewerContext<'_>,
146    query: &re_chunk_store::LatestAtQuery,
147    entity_path: &re_entity_db::EntityPath,
148) -> std::sync::Arc<re_viewer_context::Annotations> {
149    re_tracing::profile_function!();
150    let mut annotation_map = re_viewer_context::AnnotationMap::default();
151    annotation_map.load(ctx, query);
152    annotation_map.find(entity_path)
153}
154
155/// Finds and deserializes the given component type if its descriptor matches the given archetype name.
156fn find_and_deserialize_archetype_mono_component<C: Component>(
157    components: &[(ComponentDescriptor, UnitChunkShared)],
158    archetype_name: Option<ArchetypeName>,
159) -> Option<C> {
160    components.iter().find_map(|(descr, chunk)| {
161        (descr.component_type == Some(C::name()) && descr.archetype == archetype_name)
162            .then(|| chunk.component_mono::<C>(descr.component)?.ok())
163            .flatten()
164    })
165}