Skip to main content

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