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_viewer_context::{AppContext, StoreViewContext, UiLayout};
11
12mod annotation_context_ui;
13mod app_id_ui;
14mod blob_ui;
15mod component_path_ui;
16mod component_type_ui;
17mod component_ui_registry;
18mod data_source_ui;
19mod entity_db_ui;
20mod entity_path_ui;
21mod image_ui;
22mod instance_path_ui;
23mod latest_all_instance_ui;
24mod latest_at_instance_ui;
25mod store_id_ui;
26mod tensor_ui;
27mod transform_frames_ui;
28mod video_ui;
29
30mod extra_data_ui;
31pub mod item_ui;
32
33pub use self::component_ui_registry::{add_to_registry, register_component_uis};
34pub use self::image_ui::image_preview_ui;
35pub use self::instance_path_ui::archetype_label_list_item_ui;
36pub use self::latest_all_instance_ui::LatestAllInstanceResult;
37pub use self::latest_at_instance_ui::LatestAtInstanceResult;
38pub use self::tensor_ui::tensor_summary_ui_grid_contents;
39
40use re_chunk_store::UnitChunkShared;
41use re_types_core::reflection::Reflection;
42use re_types_core::{ArchetypeName, Component};
43
44pub type ArchetypeComponentMap =
45    std::collections::BTreeMap<Option<ArchetypeName>, Vec<ComponentDescriptor>>;
46
47/// Components grouped by archetype.
48pub fn sorted_component_list_by_archetype_for_ui(
49    reflection: &Reflection,
50    iter: impl IntoIterator<Item = ComponentDescriptor>,
51) -> ArchetypeComponentMap {
52    let mut map = iter
53        .into_iter()
54        .fold(ArchetypeComponentMap::default(), |mut acc, descriptor| {
55            acc.entry(descriptor.archetype)
56                .or_default()
57                .push(descriptor);
58            acc
59        });
60
61    for (archetype, components) in &mut map {
62        if let Some(reflection) = archetype
63            .as_ref()
64            .and_then(|a| reflection.archetypes.get(a))
65        {
66            // Sort components by their importance
67            components.sort_by_key(|c| {
68                reflection
69                    .fields
70                    .iter()
71                    .position(|field| field.name == c.archetype_field_name())
72                    .unwrap_or(usize::MAX)
73            });
74        } else {
75            // As a fallback, sort by the short name, as that is what is shown in the UI.
76            components.sort_by_key(|c| c.display_name().to_owned());
77        }
78    }
79
80    map
81}
82
83/// Types implementing [`AppUi`] can display themselves in an [`egui::Ui`] using only an [`AppContext`].
84pub trait AppUi {
85    /// If you need to lookup something in the chunk store, use the given query to do so.
86    fn app_ui(&self, ctx: &AppContext<'_>, ui: &mut egui::Ui, ui_layout: UiLayout);
87}
88
89/// Types implementing [`DataUi`] can display themselves in an [`egui::Ui`].
90///
91/// Use this for things that live inside of a recording.
92pub trait DataUi {
93    fn data_ui(&self, ctx: &StoreViewContext<'_>, ui: &mut egui::Ui, ui_layout: UiLayout);
94}
95
96// Blanket implementation of DataUi for everything that already implements AppUi:
97impl<T> DataUi for T
98where
99    T: AppUi,
100{
101    fn data_ui(&self, ctx: &StoreViewContext<'_>, ui: &mut egui::Ui, ui_layout: UiLayout) {
102        self.app_ui(ctx.app_ctx, ui, ui_layout);
103    }
104}
105
106/// Similar to [`DataUi`], but for data that is related to an entity (e.g. a component).
107///
108/// This is given the context of the entity it is part of so it can do queries.
109pub trait EntityDataUi {
110    /// If you need to lookup something in the chunk store, use the given query to do so.
111    fn entity_data_ui(
112        &self,
113        ctx: &StoreViewContext<'_>,
114        ui: &mut egui::Ui,
115        ui_layout: UiLayout,
116        entity_path: &EntityPath,
117        component_descriptor: &ComponentDescriptor,
118        row_id: Option<RowId>,
119    );
120}
121
122impl<T> EntityDataUi for T
123where
124    T: DataUi,
125{
126    fn entity_data_ui(
127        &self,
128        ctx: &StoreViewContext<'_>,
129        ui: &mut egui::Ui,
130        ui_layout: UiLayout,
131        entity_path: &EntityPath,
132        _component_descriptor: &ComponentDescriptor,
133        _row_id: Option<RowId>,
134    ) {
135        // This ensures that UI state is maintained per entity. For example, the collapsed state for
136        // `AnnotationContext` component is not saved by all instances of the component.
137        ui.push_id(entity_path.hash(), |ui| {
138            self.data_ui(ctx, ui, ui_layout);
139        });
140    }
141}
142
143// ---------------------------------------------------------------------------
144
145pub fn annotations(
146    ctx: &StoreViewContext<'_>,
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.db, &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}