From 9a5f3e5ef4bb6de2bcb7b7dd9cb4526639e38672 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 5 Aug 2024 16:02:27 +0200 Subject: [PATCH 01/18] Basic query view property archetype + (very) WIP UI code The `DataframeQuery` archetype does _not_ include selected components nor point-of-view components for the time being. Lots of TODO/WIP --- Cargo.lock | 1 + crates/store/re_types/Cargo.toml | 1 + .../rerun/blueprint/archetypes.fbs | 1 + .../blueprint/archetypes/dataframe_query.fbs | 37 ++ .../rerun/blueprint/components.fbs | 3 + .../components/latest_at_queries.fbs | 14 + .../components/time_range_queries.fbs | 14 + .../rerun/blueprint/components/timeline.fbs | 16 + .../definitions/rerun/blueprint/datatypes.fbs | 2 + .../blueprint/datatypes/latest_at_query.fbs | 15 + .../blueprint/datatypes/time_range_query.fbs | 18 + .../src/blueprint/archetypes/.gitattributes | 1 + .../blueprint/archetypes/dataframe_query.rs | 268 ++++++++ .../re_types/src/blueprint/archetypes/mod.rs | 2 + .../src/blueprint/components/.gitattributes | 3 + .../blueprint/components/latest_at_queries.rs | 181 ++++++ .../components/latest_at_queries_ext.rs | 30 + .../re_types/src/blueprint/components/mod.rs | 9 + .../components/time_range_queries.rs | 181 ++++++ .../components/time_range_queries_ext.rs | 30 + .../src/blueprint/components/timeline.rs | 105 ++++ .../src/blueprint/components/timeline_ext.rs | 13 + .../src/blueprint/datatypes/.gitattributes | 2 + .../blueprint/datatypes/latest_at_query.rs | 284 +++++++++ .../datatypes/latest_at_query_ext.rs | 12 + .../re_types/src/blueprint/datatypes/mod.rs | 6 + .../blueprint/datatypes/time_range_query.rs | 343 +++++++++++ .../datatypes/time_range_query_ext.rs | 12 + crates/viewer/re_edit_ui/src/lib.rs | 5 +- crates/viewer/re_edit_ui/src/timeline.rs | 37 ++ .../src/latest_at_table.rs | 14 +- .../viewer/re_space_view_dataframe/src/lib.rs | 1 + .../src/space_view_class.rs | 161 +++-- .../src/time_range_table.rs | 17 +- .../re_space_view_dataframe/src/utils.rs | 4 +- .../re_space_view_dataframe/src/view_query.rs | 571 ++++++++++++++++++ .../src/blueprint/validation_gen/mod.rs | 6 + crates/viewer/re_viewer/src/reflection/mod.rs | 43 ++ rerun_cpp/src/rerun/blueprint/archetypes.hpp | 1 + .../rerun/blueprint/archetypes/.gitattributes | 2 + .../blueprint/archetypes/dataframe_query.cpp | 48 ++ .../blueprint/archetypes/dataframe_query.hpp | 95 +++ rerun_cpp/src/rerun/blueprint/components.hpp | 3 + .../rerun/blueprint/components/.gitattributes | 5 + .../components/latest_at_queries.cpp | 81 +++ .../components/latest_at_queries.hpp | 63 ++ .../components/time_range_queries.cpp | 81 +++ .../components/time_range_queries.hpp | 63 ++ .../rerun/blueprint/components/timeline.hpp | 63 ++ rerun_cpp/src/rerun/blueprint/datatypes.hpp | 2 + .../rerun/blueprint/datatypes/.gitattributes | 4 + .../blueprint/datatypes/latest_at_query.cpp | 86 +++ .../blueprint/datatypes/latest_at_query.hpp | 56 ++ .../blueprint/datatypes/time_range_query.cpp | 98 +++ .../blueprint/datatypes/time_range_query.hpp | 59 ++ .../rerun/blueprint/archetypes/.gitattributes | 1 + .../rerun/blueprint/archetypes/__init__.py | 2 + .../blueprint/archetypes/dataframe_query.py | 111 ++++ .../rerun/blueprint/components/.gitattributes | 3 + .../rerun/blueprint/components/__init__.py | 28 + .../blueprint/components/latest_at_queries.py | 84 +++ .../components/time_range_queries.py | 85 +++ .../rerun/blueprint/components/timeline.py | 36 ++ .../rerun/blueprint/datatypes/.gitattributes | 2 + .../rerun/blueprint/datatypes/__init__.py | 24 + .../blueprint/datatypes/latest_at_query.py | 104 ++++ .../blueprint/datatypes/time_range_query.py | 126 ++++ 67 files changed, 3821 insertions(+), 58 deletions(-) create mode 100644 crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs create mode 100644 crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs create mode 100644 crates/store/re_types/src/blueprint/components/latest_at_queries.rs create mode 100644 crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs create mode 100644 crates/store/re_types/src/blueprint/components/time_range_queries.rs create mode 100644 crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs create mode 100644 crates/store/re_types/src/blueprint/components/timeline.rs create mode 100644 crates/store/re_types/src/blueprint/components/timeline_ext.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/time_range_query.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs create mode 100644 crates/viewer/re_edit_ui/src/timeline.rs create mode 100644 crates/viewer/re_space_view_dataframe/src/view_query.rs create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/timeline.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py diff --git a/Cargo.lock b/Cargo.lock index 1d8e01757dfd..ec05f3e144ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5153,6 +5153,7 @@ dependencies = [ "re_build_tools", "re_format", "re_log", + "re_log_types", "re_tracing", "re_types_builder", "re_types_core", diff --git a/crates/store/re_types/Cargo.toml b/crates/store/re_types/Cargo.toml index 3ba68c8b578b..74bb2546817f 100644 --- a/crates/store/re_types/Cargo.toml +++ b/crates/store/re_types/Cargo.toml @@ -51,6 +51,7 @@ testing = [] # Rerun re_format.workspace = true re_log.workspace = true +re_log_types.workspace = true re_tracing.workspace = true re_types_core.workspace = true diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs index b5fefe42a8c6..deb19bd78a5a 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs @@ -2,6 +2,7 @@ include "./archetypes/background.fbs"; include "./archetypes/container_blueprint.fbs"; +include "./archetypes/dataframe_query.fbs"; include "./archetypes/dataframe_view_mode.fbs"; include "./archetypes/panel_blueprint.fbs"; include "./archetypes/plot_legend.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs new file mode 100644 index 000000000000..a43fa4dbdc10 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs @@ -0,0 +1,37 @@ +namespace rerun.blueprint.archetypes; + + +/// Configuration for the dataframe view +// Rationale behind the present data modelling: +// - Avoid using `union` at all cost. +// - An explicit "mode" enum maps well with a UI toggle and API parameter, and enabled a hard disambiguation when +// settings are present for both the latest at and range modes. +// - Timestamps are hard-invalidated by a change of timeline. So we keep them on a per-timeline basis. +// - On the contrary, chances are high that the user prefers to have their pov components _not_ invalidated by a change +// of timeline. +// - That is even though a component might _technically_ be soft-invalidated by a change of timeline (e.g. if it was +// not logged on that particular timeline). But we have to deal regardless with potentially invalid component, so this +// doesn't change the story much. +//TODO: docs +table DataframeQuery ( + "attr.rerun.scope": "blueprint", + "attr.rust.generate_field_info" +) { + // --- Optional --- + + /// Name of the timeline this applies to. + timeline: rerun.blueprint.components.Timeline ("attr.rerun.component_optional", nullable, order: 100); + + /// Type of query: latest at or range + //TODO(ab): rename component + mode: rerun.blueprint.components.DataframeViewMode ("attr.rerun.component_optional", nullable,order: 200); + + /// Times (1 for latest at, 2 for range) + latest_at_queries: rerun.blueprint.components.LatestAtQueries ("attr.rerun.component_optional", nullable,order: 400); + + /// Times (1 for latest at, 2 for range) + time_range_queries: rerun.blueprint.components.TimeRangeQueries ("attr.rerun.component_optional", nullable,order: 500); + + //TODO(ab): add (optional) PoV components, which range query supports +} + diff --git a/crates/store/re_types/definitions/rerun/blueprint/components.fbs b/crates/store/re_types/definitions/rerun/blueprint/components.fbs index 1c1fb76aa8fc..cda76572484c 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components.fbs @@ -12,6 +12,7 @@ include "./components/grid_columns.fbs"; include "./components/included_content.fbs"; include "./components/included_space_view.fbs"; include "./components/interactive.fbs"; +include "./components/latest_at_queries.fbs"; include "./components/lock_range_during_zoom.fbs"; include "./components/panel_state.fbs"; include "./components/query_expression.fbs"; @@ -23,6 +24,8 @@ include "./components/space_view_class.fbs"; include "./components/space_view_maximized.fbs"; include "./components/space_view_origin.fbs"; include "./components/tensor_dimension_index_slider.fbs"; +include "./components/time_range_queries.fbs"; +include "./components/timeline.fbs"; include "./components/view_fit.fbs"; include "./components/viewer_recommendation_hash.fbs"; include "./components/visible.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs new file mode 100644 index 000000000000..a91b248f12c6 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs @@ -0,0 +1,14 @@ + +namespace rerun.blueprint.components; + +// --- +//TODO: sane default +/// Component(s) used as point-of-view for a query. +table LatestAtQueries ( + "attr.arrow.transparent", + "attr.rust.derive": "Default, PartialEq, Eq", + "attr.rust.repr": "transparent", + "attr.rerun.scope": "blueprint" +) { + value: [rerun.blueprint.datatypes.LatestAtQuery] (order: 100); +} \ No newline at end of file diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs new file mode 100644 index 000000000000..e93c325fd7dc --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs @@ -0,0 +1,14 @@ + +namespace rerun.blueprint.components; + +// --- +//TODO: sane default +/// Component(s) used as point-of-view for a query. +table TimeRangeQueries ( + "attr.arrow.transparent", + "attr.rust.derive": "Default, PartialEq, Eq", + "attr.rust.repr": "transparent", + "attr.rerun.scope": "blueprint" +) { + value: [rerun.blueprint.datatypes.TimeRangeQuery] (order: 100); +} \ No newline at end of file diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs new file mode 100644 index 000000000000..1b5a4f3bec05 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs @@ -0,0 +1,16 @@ + +namespace rerun.blueprint.components; + +// --- +//TODO: sane default +/// A timeline +table Timeline ( + "attr.arrow.transparent", + "attr.python.aliases": "str", + "attr.python.array_aliases": "str, Sequence[str]", + "attr.rust.derive": "Default, PartialEq, Eq, PartialOrd, Ord", + "attr.rust.repr": "transparent", + "attr.rerun.scope": "blueprint" +) { + value: rerun.datatypes.Utf8 (order: 100); +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs index 5aaad0c14271..27ed9388ebd5 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs @@ -1,4 +1,6 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/fbs/mod.rs +include "./datatypes/latest_at_query.fbs"; include "./datatypes/tensor_dimension_index_slider.fbs"; +include "./datatypes/time_range_query.fbs"; include "./datatypes/utf8_list.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs new file mode 100644 index 000000000000..87673ca21d17 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs @@ -0,0 +1,15 @@ +namespace rerun.blueprint.datatypes; + + +/// Visible time range bounds for a specific timeline. +// Has to be a table because flatbuffer doesn't support strings in structs. +table LatestAtQuery ( + "attr.rust.derive": "PartialEq, Eq", + "attr.rerun.scope": "blueprint" +) { + /// Name of the timeline this applies to. + timeline: rerun.datatypes.Utf8 (order: 100); + + /// Time range to use for this timeline. + time: rerun.datatypes.TimeInt (order: 200); +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs new file mode 100644 index 000000000000..c736c5648f67 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs @@ -0,0 +1,18 @@ +namespace rerun.blueprint.datatypes; + + +/// Visible time range bounds for a specific timeline. +// Has to be a table because flatbuffer doesn't support strings in structs. +table TimeRangeQuery ( + "attr.rust.derive": "PartialEq, Eq", + "attr.rerun.scope": "blueprint" +) { + /// Name of the timeline this applies to. + timeline: rerun.datatypes.Utf8 (order: 100); + + /// Start + start: rerun.datatypes.TimeInt (order: 200); + + /// End + end: rerun.datatypes.TimeInt (order: 300); +} diff --git a/crates/store/re_types/src/blueprint/archetypes/.gitattributes b/crates/store/re_types/src/blueprint/archetypes/.gitattributes index d91f6e760346..3769b8b507be 100644 --- a/crates/store/re_types/src/blueprint/archetypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/archetypes/.gitattributes @@ -2,6 +2,7 @@ .gitattributes linguist-generated=true background.rs linguist-generated=true +dataframe_query.rs linguist-generated=true dataframe_view_mode.rs linguist-generated=true mod.rs linguist-generated=true plot_legend.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs new file mode 100644 index 000000000000..7768a56cc5f2 --- /dev/null +++ b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs @@ -0,0 +1,268 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Archetype**: Configuration for the dataframe view +#[derive(Clone, Debug)] +pub struct DataframeQuery { + /// Name of the timeline this applies to. + pub timeline: Option, + + /// Type of query: latest at or range + pub mode: Option, + + /// Times (1 for latest at, 2 for range) + pub latest_at_queries: Option, + + /// Times (1 for latest at, 2 for range) + pub time_range_queries: Option, +} + +impl ::re_types_core::SizeBytes for DataframeQuery { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.timeline.heap_size_bytes() + + self.mode.heap_size_bytes() + + self.latest_at_queries.heap_size_bytes() + + self.time_range_queries.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + && >::is_pod() + && >::is_pod() + && >::is_pod() + } +} + +static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = + once_cell::sync::Lazy::new(|| []); + +static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.DataframeQueryIndicator".into()]); + +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.blueprint.components.Timeline".into(), + "rerun.blueprint.components.DataframeViewMode".into(), + "rerun.blueprint.components.LatestAtQueries".into(), + "rerun.blueprint.components.TimeRangeQueries".into(), + ] + }); + +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 5usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.blueprint.components.DataframeQueryIndicator".into(), + "rerun.blueprint.components.Timeline".into(), + "rerun.blueprint.components.DataframeViewMode".into(), + "rerun.blueprint.components.LatestAtQueries".into(), + "rerun.blueprint.components.TimeRangeQueries".into(), + ] + }); + +impl DataframeQuery { + /// The total number of components in the archetype: 0 required, 1 recommended, 4 optional + pub const NUM_COMPONENTS: usize = 5usize; +} + +/// Indicator component for the [`DataframeQuery`] [`::re_types_core::Archetype`] +pub type DataframeQueryIndicator = ::re_types_core::GenericIndicatorComponent; + +impl ::re_types_core::Archetype for DataframeQuery { + type Indicator = DataframeQueryIndicator; + + #[inline] + fn name() -> ::re_types_core::ArchetypeName { + "rerun.blueprint.archetypes.DataframeQuery".into() + } + + #[inline] + fn display_name() -> &'static str { + "Dataframe query" + } + + #[inline] + fn indicator() -> MaybeOwnedComponentBatch<'static> { + static INDICATOR: DataframeQueryIndicator = DataframeQueryIndicator::DEFAULT; + MaybeOwnedComponentBatch::Ref(&INDICATOR) + } + + #[inline] + fn required_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + REQUIRED_COMPONENTS.as_slice().into() + } + + #[inline] + fn recommended_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + RECOMMENDED_COMPONENTS.as_slice().into() + } + + #[inline] + fn optional_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + OPTIONAL_COMPONENTS.as_slice().into() + } + + #[inline] + fn all_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + ALL_COMPONENTS.as_slice().into() + } + + #[inline] + fn from_arrow_components( + arrow_data: impl IntoIterator)>, + ) -> DeserializationResult { + re_tracing::profile_function!(); + use ::re_types_core::{Loggable as _, ResultExt as _}; + let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data + .into_iter() + .map(|(name, array)| (name.full_name(), array)) + .collect(); + let timeline = + if let Some(array) = arrays_by_name.get("rerun.blueprint.components.Timeline") { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#timeline")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let mode = if let Some(array) = + arrays_by_name.get("rerun.blueprint.components.DataframeViewMode") + { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#mode")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let latest_at_queries = + if let Some(array) = arrays_by_name.get("rerun.blueprint.components.LatestAtQueries") { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#latest_at_queries")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let time_range_queries = if let Some(array) = + arrays_by_name.get("rerun.blueprint.components.TimeRangeQueries") + { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#time_range_queries")? + .into_iter() + .next() + .flatten() + } else { + None + }; + Ok(Self { + timeline, + mode, + latest_at_queries, + time_range_queries, + }) + } +} + +impl ::re_types_core::AsComponents for DataframeQuery { + fn as_component_batches(&self) -> Vec> { + re_tracing::profile_function!(); + use ::re_types_core::Archetype as _; + [ + Some(Self::indicator()), + self.timeline + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.mode + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.latest_at_queries + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.time_range_queries + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + ] + .into_iter() + .flatten() + .collect() + } +} + +impl ::re_types_core::ArchetypeReflectionMarker for DataframeQuery {} + +impl DataframeQuery { + /// Create a new `DataframeQuery`. + #[inline] + pub fn new() -> Self { + Self { + timeline: None, + mode: None, + latest_at_queries: None, + time_range_queries: None, + } + } + + /// Name of the timeline this applies to. + #[inline] + pub fn with_timeline( + mut self, + timeline: impl Into, + ) -> Self { + self.timeline = Some(timeline.into()); + self + } + + /// Type of query: latest at or range + #[inline] + pub fn with_mode( + mut self, + mode: impl Into, + ) -> Self { + self.mode = Some(mode.into()); + self + } + + /// Times (1 for latest at, 2 for range) + #[inline] + pub fn with_latest_at_queries( + mut self, + latest_at_queries: impl Into, + ) -> Self { + self.latest_at_queries = Some(latest_at_queries.into()); + self + } + + /// Times (1 for latest at, 2 for range) + #[inline] + pub fn with_time_range_queries( + mut self, + time_range_queries: impl Into, + ) -> Self { + self.time_range_queries = Some(time_range_queries.into()); + self + } +} diff --git a/crates/store/re_types/src/blueprint/archetypes/mod.rs b/crates/store/re_types/src/blueprint/archetypes/mod.rs index 59809a82d174..ce7f3454cb5f 100644 --- a/crates/store/re_types/src/blueprint/archetypes/mod.rs +++ b/crates/store/re_types/src/blueprint/archetypes/mod.rs @@ -1,6 +1,7 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs mod background; +mod dataframe_query; mod dataframe_view_mode; mod plot_legend; mod scalar_axis; @@ -15,6 +16,7 @@ mod visible_time_ranges_ext; mod visual_bounds2d; pub use self::background::Background; +pub use self::dataframe_query::DataframeQuery; pub use self::dataframe_view_mode::DataframeViewMode; pub use self::plot_legend::PlotLegend; pub use self::scalar_axis::ScalarAxis; diff --git a/crates/store/re_types/src/blueprint/components/.gitattributes b/crates/store/re_types/src/blueprint/components/.gitattributes index 072eb67ff413..f2a0d54cc97d 100644 --- a/crates/store/re_types/src/blueprint/components/.gitattributes +++ b/crates/store/re_types/src/blueprint/components/.gitattributes @@ -8,6 +8,7 @@ corner2d.rs linguist-generated=true dataframe_view_mode.rs linguist-generated=true included_content.rs linguist-generated=true interactive.rs linguist-generated=true +latest_at_queries.rs linguist-generated=true lock_range_during_zoom.rs linguist-generated=true mod.rs linguist-generated=true panel_state.rs linguist-generated=true @@ -18,6 +19,8 @@ sort_order.rs linguist-generated=true space_view_class.rs linguist-generated=true space_view_origin.rs linguist-generated=true tensor_dimension_index_slider.rs linguist-generated=true +time_range_queries.rs linguist-generated=true +timeline.rs linguist-generated=true view_fit.rs linguist-generated=true viewer_recommendation_hash.rs linguist-generated=true visible.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/components/latest_at_queries.rs b/crates/store/re_types/src/blueprint/components/latest_at_queries.rs new file mode 100644 index 000000000000..40799a8a059b --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/latest_at_queries.rs @@ -0,0 +1,181 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: Component(s) used as point-of-view for a query. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[repr(transparent)] +pub struct LatestAtQueries(pub Vec); + +impl ::re_types_core::SizeBytes for LatestAtQueries { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + } +} + +impl, T: IntoIterator> From + for LatestAtQueries +{ + fn from(v: T) -> Self { + Self(v.into_iter().map(|v| v.into()).collect()) + } +} + +::re_types_core::macros::impl_into_cow!(LatestAtQueries); + +impl ::re_types_core::Loggable for LatestAtQueries { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.LatestAtQueries".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::List(std::sync::Arc::new(Field::new( + "item", + ::arrow_datatype(), + false, + ))) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data0): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + let datum = datum.map(|datum| datum.into_owned().0); + (datum.is_some(), datum) + }) + .unzip(); + let data0_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; + let offsets = arrow2::offset::Offsets::::try_from_lengths( + data0 + .iter() + .map(|opt| opt.as_ref().map_or(0, |datum| datum.len())), + )? + .into(); + let data0_inner_data: Vec<_> = data0.into_iter().flatten().flatten().collect(); + let data0_inner_bitmap: Option = None; + ListArray::try_new( + Self::arrow_datatype(), + offsets, + { + _ = data0_inner_bitmap; + crate::blueprint::datatypes::LatestAtQuery::to_arrow_opt( + data0_inner_data.into_iter().map(Some), + )? + }, + data0_bitmap, + )? + .boxed() + } + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::>() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.LatestAtQueries#value")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + crate::blueprint::datatypes::LatestAtQuery::from_arrow_opt(arrow_data_inner) + .with_context("rerun.blueprint.components.LatestAtQueries#value")? + .into_iter() + .collect::>() + }; + let offsets = arrow_data.offsets(); + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets.iter().zip(offsets.lengths()), + arrow_data.validity(), + ) + .map(|elem| { + elem.map(|(start, len)| { + let start = *start as usize; + let end = start + len; + if end > arrow_data_inner.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_inner.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = unsafe { arrow_data_inner.get_unchecked(start..end) }; + let data = data + .iter() + .cloned() + .map(Option::unwrap_or_default) + .collect(); + Ok(data) + }) + .transpose() + }) + .collect::>>>()? + } + .into_iter() + } + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .map(|res| res.map(|v| Some(Self(v)))) + .collect::>>>() + .with_context("rerun.blueprint.components.LatestAtQueries#value") + .with_context("rerun.blueprint.components.LatestAtQueries")?) + } +} diff --git a/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs new file mode 100644 index 000000000000..1eff72fd58ca --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs @@ -0,0 +1,30 @@ +use super::LatestAtQueries; +use crate::blueprint::datatypes::LatestAtQuery; + +impl LatestAtQueries { + /// Retrieves the query for a given timeline. + pub fn query_for_timeline(&self, timeline_name: &str) -> Option<&LatestAtQuery> { + self.0 + .iter() + .find(|query| query.timeline.as_str() == timeline_name) + } + + /// Sets the query for a given timeline. + /// + /// If the query is `None`, the timeline will be removed from the list of latest queries. + pub fn set_query_for_timeline(&mut self, timeline_name: &str, query: Option) { + if let Some(query) = query { + if let Some(existing_query) = self + .0 + .iter_mut() + .find(|query| query.timeline.as_str() == timeline_name) + { + *existing_query = query; + } else { + self.0.push(query); + } + } else { + self.0.retain(|q| q.timeline.as_str() != timeline_name); + } + } +} diff --git a/crates/store/re_types/src/blueprint/components/mod.rs b/crates/store/re_types/src/blueprint/components/mod.rs index ad247e647a88..e66d5e398307 100644 --- a/crates/store/re_types/src/blueprint/components/mod.rs +++ b/crates/store/re_types/src/blueprint/components/mod.rs @@ -9,6 +9,8 @@ mod dataframe_view_mode; mod included_content; mod interactive; mod interactive_ext; +mod latest_at_queries; +mod latest_at_queries_ext; mod lock_range_during_zoom; mod panel_state; mod panel_state_ext; @@ -22,6 +24,10 @@ mod space_view_origin; mod space_view_origin_ext; mod tensor_dimension_index_slider; mod tensor_dimension_index_slider_ext; +mod time_range_queries; +mod time_range_queries_ext; +mod timeline; +mod timeline_ext; mod view_fit; mod viewer_recommendation_hash; mod viewer_recommendation_hash_ext; @@ -38,6 +44,7 @@ pub use self::corner2d::Corner2D; pub use self::dataframe_view_mode::DataframeViewMode; pub use self::included_content::IncludedContent; pub use self::interactive::Interactive; +pub use self::latest_at_queries::LatestAtQueries; pub use self::lock_range_during_zoom::LockRangeDuringZoom; pub use self::panel_state::PanelState; pub use self::query_expression::QueryExpression; @@ -47,6 +54,8 @@ pub use self::sort_order::SortOrder; pub use self::space_view_class::SpaceViewClass; pub use self::space_view_origin::SpaceViewOrigin; pub use self::tensor_dimension_index_slider::TensorDimensionIndexSlider; +pub use self::time_range_queries::TimeRangeQueries; +pub use self::timeline::Timeline; pub use self::view_fit::ViewFit; pub use self::viewer_recommendation_hash::ViewerRecommendationHash; pub use self::visible::Visible; diff --git a/crates/store/re_types/src/blueprint/components/time_range_queries.rs b/crates/store/re_types/src/blueprint/components/time_range_queries.rs new file mode 100644 index 000000000000..205a6adcf937 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/time_range_queries.rs @@ -0,0 +1,181 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: Component(s) used as point-of-view for a query. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[repr(transparent)] +pub struct TimeRangeQueries(pub Vec); + +impl ::re_types_core::SizeBytes for TimeRangeQueries { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + } +} + +impl, T: IntoIterator> From + for TimeRangeQueries +{ + fn from(v: T) -> Self { + Self(v.into_iter().map(|v| v.into()).collect()) + } +} + +::re_types_core::macros::impl_into_cow!(TimeRangeQueries); + +impl ::re_types_core::Loggable for TimeRangeQueries { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.TimeRangeQueries".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::List(std::sync::Arc::new(Field::new( + "item", + ::arrow_datatype(), + false, + ))) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data0): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + let datum = datum.map(|datum| datum.into_owned().0); + (datum.is_some(), datum) + }) + .unzip(); + let data0_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; + let offsets = arrow2::offset::Offsets::::try_from_lengths( + data0 + .iter() + .map(|opt| opt.as_ref().map_or(0, |datum| datum.len())), + )? + .into(); + let data0_inner_data: Vec<_> = data0.into_iter().flatten().flatten().collect(); + let data0_inner_bitmap: Option = None; + ListArray::try_new( + Self::arrow_datatype(), + offsets, + { + _ = data0_inner_bitmap; + crate::blueprint::datatypes::TimeRangeQuery::to_arrow_opt( + data0_inner_data.into_iter().map(Some), + )? + }, + data0_bitmap, + )? + .boxed() + } + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::>() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.TimeRangeQueries#value")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + crate::blueprint::datatypes::TimeRangeQuery::from_arrow_opt(arrow_data_inner) + .with_context("rerun.blueprint.components.TimeRangeQueries#value")? + .into_iter() + .collect::>() + }; + let offsets = arrow_data.offsets(); + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets.iter().zip(offsets.lengths()), + arrow_data.validity(), + ) + .map(|elem| { + elem.map(|(start, len)| { + let start = *start as usize; + let end = start + len; + if end > arrow_data_inner.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_inner.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = unsafe { arrow_data_inner.get_unchecked(start..end) }; + let data = data + .iter() + .cloned() + .map(Option::unwrap_or_default) + .collect(); + Ok(data) + }) + .transpose() + }) + .collect::>>>()? + } + .into_iter() + } + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .map(|res| res.map(|v| Some(Self(v)))) + .collect::>>>() + .with_context("rerun.blueprint.components.TimeRangeQueries#value") + .with_context("rerun.blueprint.components.TimeRangeQueries")?) + } +} diff --git a/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs new file mode 100644 index 000000000000..5c54fa06f4cb --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs @@ -0,0 +1,30 @@ +use super::TimeRangeQueries; +use crate::blueprint::datatypes::TimeRangeQuery; + +impl TimeRangeQueries { + /// Retrieves the query for a given timeline. + pub fn query_for_timeline(&self, timeline_name: &str) -> Option<&TimeRangeQuery> { + self.0 + .iter() + .find(|query| query.timeline.as_str() == timeline_name) + } + + /// Sets the query for a given timeline. + /// + /// If the query is `None`, the timeline will be removed from the list of time range queries. + pub fn set_query_for_timeline(&mut self, timeline_name: &str, query: Option) { + if let Some(query) = query { + if let Some(existing_query) = self + .0 + .iter_mut() + .find(|query| query.timeline.as_str() == timeline_name) + { + *existing_query = query; + } else { + self.0.push(query); + } + } else { + self.0.retain(|q| q.timeline.as_str() != timeline_name); + } + } +} diff --git a/crates/store/re_types/src/blueprint/components/timeline.rs b/crates/store/re_types/src/blueprint/components/timeline.rs new file mode 100644 index 000000000000..37301240be69 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/timeline.rs @@ -0,0 +1,105 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: A timeline +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct Timeline(pub crate::datatypes::Utf8); + +impl ::re_types_core::SizeBytes for Timeline { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +impl> From for Timeline { + fn from(v: T) -> Self { + Self(v.into()) + } +} + +impl std::borrow::Borrow for Timeline { + #[inline] + fn borrow(&self) -> &crate::datatypes::Utf8 { + &self.0 + } +} + +impl std::ops::Deref for Timeline { + type Target = crate::datatypes::Utf8; + + #[inline] + fn deref(&self) -> &crate::datatypes::Utf8 { + &self.0 + } +} + +impl std::ops::DerefMut for Timeline { + #[inline] + fn deref_mut(&mut self) -> &mut crate::datatypes::Utf8 { + &mut self.0 + } +} + +::re_types_core::macros::impl_into_cow!(Timeline); + +impl ::re_types_core::Loggable for Timeline { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.Timeline".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + crate::datatypes::Utf8::arrow_datatype() + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + crate::datatypes::Utf8::to_arrow_opt(data.into_iter().map(|datum| { + datum.map(|datum| match datum.into() { + ::std::borrow::Cow::Borrowed(datum) => ::std::borrow::Cow::Borrowed(&datum.0), + ::std::borrow::Cow::Owned(datum) => ::std::borrow::Cow::Owned(datum.0), + }) + })) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + crate::datatypes::Utf8::from_arrow_opt(arrow_data) + .map(|v| v.into_iter().map(|v| v.map(Self)).collect()) + } +} diff --git a/crates/store/re_types/src/blueprint/components/timeline_ext.rs b/crates/store/re_types/src/blueprint/components/timeline_ext.rs new file mode 100644 index 000000000000..04d91586be5e --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/timeline_ext.rs @@ -0,0 +1,13 @@ +use re_log_types::TimelineName; + +use super::Timeline; + +impl Timeline { + pub fn timeline_name(&self) -> TimelineName { + TimelineName::from(self.0.as_str()) + } + + pub fn set_timeline_name(&mut self, timeline_name: TimelineName) { + self.0 = timeline_name.as_str().into() + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/.gitattributes b/crates/store/re_types/src/blueprint/datatypes/.gitattributes index f4557edfa342..0f6ee351e568 100644 --- a/crates/store/re_types/src/blueprint/datatypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/datatypes/.gitattributes @@ -1,5 +1,7 @@ # DO NOT EDIT! This file is generated by crates/build/re_types_builder/src/lib.rs .gitattributes linguist-generated=true +latest_at_query.rs linguist-generated=true mod.rs linguist-generated=true tensor_dimension_index_slider.rs linguist-generated=true +time_range_query.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs b/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs new file mode 100644 index 000000000000..d64d2f2e9518 --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs @@ -0,0 +1,284 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Datatype**: Visible time range bounds for a specific timeline. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LatestAtQuery { + /// Name of the timeline this applies to. + pub timeline: crate::datatypes::Utf8, + + /// Time range to use for this timeline. + pub time: crate::datatypes::TimeInt, +} + +impl ::re_types_core::SizeBytes for LatestAtQuery { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.timeline.heap_size_bytes() + self.time.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() && ::is_pod() + } +} + +::re_types_core::macros::impl_into_cow!(LatestAtQuery); + +impl ::re_types_core::Loggable for LatestAtQuery { + type Name = ::re_types_core::DatatypeName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.datatypes.LatestAtQuery".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::Struct(std::sync::Arc::new(vec![ + Field::new( + "timeline", + ::arrow_datatype(), + false, + ), + Field::new("time", ::arrow_datatype(), false), + ])) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + (datum.is_some(), datum) + }) + .unzip(); + let bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + StructArray::new( + Self::arrow_datatype(), + vec![ + { + let (somes, timeline): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.timeline.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let timeline_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + let offsets = arrow2::offset::Offsets::::try_from_lengths( + timeline.iter().map(|opt| { + opt.as_ref().map(|datum| datum.0.len()).unwrap_or_default() + }), + )? + .into(); + let inner_data: arrow2::buffer::Buffer = timeline + .into_iter() + .flatten() + .flat_map(|datum| datum.0 .0) + .collect(); + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + unsafe { + Utf8Array::::new_unchecked( + DataType::Utf8, + offsets, + inner_data, + timeline_bitmap, + ) + } + .boxed() + } + }, + { + let (somes, time): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.time.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let time_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + DataType::Int64, + time.into_iter() + .map(|datum| datum.map(|datum| datum.0).unwrap_or_default()) + .collect(), + time_bitmap, + ) + .boxed() + }, + ], + bitmap, + ) + .boxed() + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.LatestAtQuery")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let (arrow_data_fields, arrow_data_arrays) = + (arrow_data.fields(), arrow_data.values()); + let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data_fields + .iter() + .map(|field| field.name.as_str()) + .zip(arrow_data_arrays) + .collect(); + let timeline = { + if !arrays_by_name.contains_key("timeline") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "timeline", + )) + .with_context("rerun.blueprint.datatypes.LatestAtQuery"); + } + let arrow_data = &**arrays_by_name["timeline"]; + { + let arrow_data = arrow_data + .as_any() + .downcast_ref::>() + .ok_or_else(|| { + let expected = DataType::Utf8; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#timeline")?; + let arrow_data_buf = arrow_data.values(); + let offsets = arrow_data.offsets(); + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets.iter().zip(offsets.lengths()), + arrow_data.validity(), + ) + .map(|elem| { + elem.map(|(start, len)| { + let start = *start as usize; + let end = start + len; + if end > arrow_data_buf.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_buf.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_buf.clone().sliced_unchecked(start, len) }; + Ok(data) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt.map(|res_or_opt| { + res_or_opt.map(|v| { + crate::datatypes::Utf8(::re_types_core::ArrowString(v)) + }) + }) + }) + .collect::>>>() + .with_context("rerun.blueprint.datatypes.LatestAtQuery#timeline")? + .into_iter() + } + }; + let time = { + if !arrays_by_name.contains_key("time") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "time", + )) + .with_context("rerun.blueprint.datatypes.LatestAtQuery"); + } + let arrow_data = &**arrays_by_name["time"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::Int64; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#time")? + .into_iter() + .map(|opt| opt.copied()) + .map(|res_or_opt| res_or_opt.map(crate::datatypes::TimeInt)) + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + ::itertools::izip!(timeline, time), + arrow_data.validity(), + ) + .map(|opt| { + opt.map(|(timeline, time)| { + Ok(Self { + timeline: timeline + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#timeline")?, + time: time + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#time")?, + }) + }) + .transpose() + }) + .collect::>>() + .with_context("rerun.blueprint.datatypes.LatestAtQuery")? + } + }) + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs b/crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs new file mode 100644 index 000000000000..5b2c1ad2138e --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs @@ -0,0 +1,12 @@ +use re_types_core::datatypes::{TimeInt, Utf8}; + +use super::LatestAtQuery; + +impl Default for LatestAtQuery { + fn default() -> Self { + Self { + timeline: Utf8::from("log_time"), + time: TimeInt::MAX, + } + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/mod.rs b/crates/store/re_types/src/blueprint/datatypes/mod.rs index d0dadbc2b6d8..9a8d6aef70dd 100644 --- a/crates/store/re_types/src/blueprint/datatypes/mod.rs +++ b/crates/store/re_types/src/blueprint/datatypes/mod.rs @@ -1,5 +1,11 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +mod latest_at_query; +mod latest_at_query_ext; mod tensor_dimension_index_slider; +mod time_range_query; +mod time_range_query_ext; +pub use self::latest_at_query::LatestAtQuery; pub use self::tensor_dimension_index_slider::TensorDimensionIndexSlider; +pub use self::time_range_query::TimeRangeQuery; diff --git a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs new file mode 100644 index 000000000000..b5eb7bed6fff --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs @@ -0,0 +1,343 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Datatype**: Visible time range bounds for a specific timeline. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TimeRangeQuery { + /// Name of the timeline this applies to. + pub timeline: crate::datatypes::Utf8, + + /// Start + pub start: crate::datatypes::TimeInt, + + /// End + pub end: crate::datatypes::TimeInt, +} + +impl ::re_types_core::SizeBytes for TimeRangeQuery { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.timeline.heap_size_bytes() + self.start.heap_size_bytes() + self.end.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + && ::is_pod() + && ::is_pod() + } +} + +::re_types_core::macros::impl_into_cow!(TimeRangeQuery); + +impl ::re_types_core::Loggable for TimeRangeQuery { + type Name = ::re_types_core::DatatypeName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.datatypes.TimeRangeQuery".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::Struct(std::sync::Arc::new(vec![ + Field::new( + "timeline", + ::arrow_datatype(), + false, + ), + Field::new( + "start", + ::arrow_datatype(), + false, + ), + Field::new("end", ::arrow_datatype(), false), + ])) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + (datum.is_some(), datum) + }) + .unzip(); + let bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + StructArray::new( + Self::arrow_datatype(), + vec![ + { + let (somes, timeline): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.timeline.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let timeline_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + let offsets = arrow2::offset::Offsets::::try_from_lengths( + timeline.iter().map(|opt| { + opt.as_ref().map(|datum| datum.0.len()).unwrap_or_default() + }), + )? + .into(); + let inner_data: arrow2::buffer::Buffer = timeline + .into_iter() + .flatten() + .flat_map(|datum| datum.0 .0) + .collect(); + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + unsafe { + Utf8Array::::new_unchecked( + DataType::Utf8, + offsets, + inner_data, + timeline_bitmap, + ) + } + .boxed() + } + }, + { + let (somes, start): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.start.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let start_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + DataType::Int64, + start + .into_iter() + .map(|datum| datum.map(|datum| datum.0).unwrap_or_default()) + .collect(), + start_bitmap, + ) + .boxed() + }, + { + let (somes, end): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.end.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let end_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + DataType::Int64, + end.into_iter() + .map(|datum| datum.map(|datum| datum.0).unwrap_or_default()) + .collect(), + end_bitmap, + ) + .boxed() + }, + ], + bitmap, + ) + .boxed() + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let (arrow_data_fields, arrow_data_arrays) = + (arrow_data.fields(), arrow_data.values()); + let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data_fields + .iter() + .map(|field| field.name.as_str()) + .zip(arrow_data_arrays) + .collect(); + let timeline = { + if !arrays_by_name.contains_key("timeline") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "timeline", + )) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery"); + } + let arrow_data = &**arrays_by_name["timeline"]; + { + let arrow_data = arrow_data + .as_any() + .downcast_ref::>() + .ok_or_else(|| { + let expected = DataType::Utf8; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#timeline")?; + let arrow_data_buf = arrow_data.values(); + let offsets = arrow_data.offsets(); + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets.iter().zip(offsets.lengths()), + arrow_data.validity(), + ) + .map(|elem| { + elem.map(|(start, len)| { + let start = *start as usize; + let end = start + len; + if end > arrow_data_buf.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_buf.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_buf.clone().sliced_unchecked(start, len) }; + Ok(data) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt.map(|res_or_opt| { + res_or_opt.map(|v| { + crate::datatypes::Utf8(::re_types_core::ArrowString(v)) + }) + }) + }) + .collect::>>>() + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#timeline")? + .into_iter() + } + }; + let start = { + if !arrays_by_name.contains_key("start") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "start", + )) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery"); + } + let arrow_data = &**arrays_by_name["start"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::Int64; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#start")? + .into_iter() + .map(|opt| opt.copied()) + .map(|res_or_opt| res_or_opt.map(crate::datatypes::TimeInt)) + }; + let end = { + if !arrays_by_name.contains_key("end") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "end", + )) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery"); + } + let arrow_data = &**arrays_by_name["end"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::Int64; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#end")? + .into_iter() + .map(|opt| opt.copied()) + .map(|res_or_opt| res_or_opt.map(crate::datatypes::TimeInt)) + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + ::itertools::izip!(timeline, start, end), + arrow_data.validity(), + ) + .map(|opt| { + opt.map(|(timeline, start, end)| { + Ok(Self { + timeline: timeline + .ok_or_else(DeserializationError::missing_data) + .with_context( + "rerun.blueprint.datatypes.TimeRangeQuery#timeline", + )?, + start: start + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#start")?, + end: end + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#end")?, + }) + }) + .transpose() + }) + .collect::>>() + .with_context("rerun.blueprint.datatypes.TimeRangeQuery")? + } + }) + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs b/crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs new file mode 100644 index 000000000000..d8d54d875aeb --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs @@ -0,0 +1,12 @@ +use super::TimeRangeQuery; +use re_types_core::datatypes::{TimeInt, Utf8}; + +impl Default for TimeRangeQuery { + fn default() -> Self { + Self { + timeline: Utf8::from("log_time"), + start: TimeInt::MIN, + end: TimeInt::MAX, + } + } +} diff --git a/crates/viewer/re_edit_ui/src/lib.rs b/crates/viewer/re_edit_ui/src/lib.rs index 8f576ff86329..d99d0eec86dd 100644 --- a/crates/viewer/re_edit_ui/src/lib.rs +++ b/crates/viewer/re_edit_ui/src/lib.rs @@ -9,6 +9,7 @@ mod marker_shape; mod radius; mod range1d; mod response_utils; +mod timeline; mod transforms; mod visual_bounds2d; @@ -20,7 +21,7 @@ use datatype_editors::{ use re_types::{ blueprint::components::{ BackgroundKind, Corner2D, DataframeViewMode, LockRangeDuringZoom, SortKey, SortOrder, - ViewFit, Visible, + Timeline, ViewFit, Visible, }, components::{ AggregationPolicy, AlbedoFactor, AxisLength, ChannelDatatype, Color, ColorModel, Colormap, @@ -61,6 +62,8 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { registry.add_singleline_edit_or_view::(edit_bool); registry.add_singleline_edit_or_view::(edit_bool); + registry.add_singleline_edit_or_view::(timeline::edit_timeline); + registry.add_display_ui(Text::name(), Box::new(display_text_ui)); registry.add_singleline_edit_or_view::(edit_singleline_string); registry.add_multiline_edit_or_view::(edit_multiline_string); diff --git a/crates/viewer/re_edit_ui/src/timeline.rs b/crates/viewer/re_edit_ui/src/timeline.rs new file mode 100644 index 000000000000..9f95bae29956 --- /dev/null +++ b/crates/viewer/re_edit_ui/src/timeline.rs @@ -0,0 +1,37 @@ +use re_types::blueprint::components; +use re_types_core::LoggableBatch as _; +use re_viewer_context::{MaybeMutRef, ViewerContext}; + +pub(crate) fn edit_timeline( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + value: &mut MaybeMutRef<'_, components::Timeline>, +) -> egui::Response { + if let Some(value) = value.as_mut() { + let mut current_value = value.timeline_name(); + let id_source = value.name(); + let mut changed = false; + let mut combobox_response = egui::ComboBox::from_id_source(id_source) + .selected_text(current_value.as_str()) + .show_ui(ui, |ui| { + for timeline in ctx.recording().timelines() { + let response = ui.selectable_value( + &mut current_value, + *timeline.name(), + timeline.name().as_str(), + ); + + changed |= response.changed(); + } + }); + + if changed { + value.set_timeline_name(current_value); + combobox_response.response.mark_changed(); + } + + combobox_response.response + } else { + ui.label(value.timeline_name().as_str()) + } +} diff --git a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs index 6eccb88c94f4..567487bf9eb3 100644 --- a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs @@ -1,9 +1,9 @@ -use std::collections::BTreeSet; - +use re_chunk_store::LatestAtQuery; use re_data_ui::item_ui::instance_path_button; use re_entity_db::InstancePath; use re_log_types::Instance; use re_viewer_context::{Item, UiLayout, ViewQuery, ViewerContext}; +use std::collections::BTreeSet; use crate::{ table_ui::table_ui, @@ -17,7 +17,9 @@ use crate::{ pub(crate) fn latest_at_table_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, + //TODO: remove this parameter, pass space view id and BTreeSet instead query: &ViewQuery<'_>, + latest_at_query: LatestAtQuery, ) { re_tracing::profile_function!(); @@ -27,7 +29,6 @@ pub(crate) fn latest_at_table_ui( // These are the entity paths whose content we must display. let sorted_entity_paths = sorted_visible_entity_path(ctx, query); - let latest_at_query = query.latest_at_query(); let sorted_instance_paths: Vec<_>; let sorted_components: BTreeSet<_>; @@ -51,7 +52,7 @@ pub(crate) fn latest_at_table_ui( sorted_instance_paths_for( entity_path, ctx.recording_store(), - &query.timeline, + &latest_at_query.timeline(), &latest_at_query, ) }) @@ -63,7 +64,7 @@ pub(crate) fn latest_at_table_ui( .iter() .flat_map(|entity_path| { ctx.recording_store() - .all_components_on_timeline(&query.timeline, entity_path) + .all_components_on_timeline(&latest_at_query.timeline(), entity_path) .unwrap_or_default() }) // TODO(#4466): make showing/hiding indicators components an explicit optional @@ -160,7 +161,8 @@ pub(crate) fn latest_at_table_ui( .latest_at(&latest_at_query, *component_name) .into_unit() .and_then(|unit| { - unit.index(&query.timeline).map(|index| (index, unit)) + unit.index(&latest_at_query.timeline()) + .map(|index| (index, unit)) })?; unit.component_batch_raw(component_name) diff --git a/crates/viewer/re_space_view_dataframe/src/lib.rs b/crates/viewer/re_space_view_dataframe/src/lib.rs index b3d8a9436846..525e98202e21 100644 --- a/crates/viewer/re_space_view_dataframe/src/lib.rs +++ b/crates/viewer/re_space_view_dataframe/src/lib.rs @@ -7,6 +7,7 @@ mod space_view_class; mod table_ui; mod time_range_table; mod utils; +mod view_query; mod visualizer_system; pub use space_view_class::DataframeSpaceView; diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index dc94679a0b9f..05812afd0dca 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -1,19 +1,21 @@ use egui::Ui; -use std::any::Any; - -use re_log_types::EntityPath; +use re_chunk_store::LatestAtQuery; +use re_log_types::{EntityPath, ResolvedTimeRange}; use re_space_view::view_property_ui; -use re_types::blueprint::{archetypes, components}; -use re_types_core::datatypes::TimeRange; +use re_types::blueprint::components::{LatestAtQueries, Timeline}; +use re_types::blueprint::{archetypes, components, datatypes}; +use re_types_core::datatypes::{TimeRange, Utf8}; use re_types_core::SpaceViewClassIdentifier; use re_ui::list_item; use re_viewer_context::{ - QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, - SpaceViewStateExt, SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, - ViewerContext, + QueryContext, QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, + SpaceViewState, SpaceViewStateExt, SpaceViewSystemExecutionError, SystemExecutionOutput, + TypedComponentFallbackProvider, ViewQuery, ViewerContext, }; use re_viewport_blueprint::ViewProperty; +use std::any::Any; +use crate::view_query::{Query, QueryMode}; use crate::{ latest_at_table::latest_at_table_ui, time_range_table::time_range_table_ui, visualizer_system::EmptySystem, @@ -130,20 +132,25 @@ mode sets the default time range to _everything_. You can override this in the s _space_origin: &EntityPath, space_view_id: SpaceViewId, ) -> Result<(), SpaceViewSystemExecutionError> { - let settings = ViewProperty::from_archetype::( - ctx.blueprint_db(), - ctx.blueprint_query, - space_view_id, - ); - - let mode = - settings.component_or_fallback::(ctx, self, state)?; + // let settings = ViewProperty::from_archetype::( + // ctx.blueprint_db(), + // ctx.blueprint_query, + // space_view_id, + // ); + // + // let mode = + // settings.component_or_fallback::(ctx, self, state)?; list_item::list_item_scope(ui, "dataframe_view_selection_ui", |ui| { //TODO(ab): ideally we'd drop the "Dataframe" part in the UI label - view_property_ui::(ctx, ui, space_view_id, self, state); + //view_property_ui::(ctx, ui, space_view_id, self, state); - ui.add_enabled_ui(mode == components::DataframeViewMode::TimeRange, |ui| { + view_property_ui::(ctx, ui, space_view_id, self, state); + super::view_query::Query::ui(ctx, ui, self, state, space_view_id); + + //TODO: fix this :scream: + let view_query = Query::try_from_blueprint(ctx, space_view_id, self, state)?; + ui.add_enabled_ui(matches!(view_query.mode, QueryMode::Range { .. }), |ui| { view_property_ui::( ctx, ui, @@ -152,9 +159,9 @@ mode sets the default time range to _everything_. You can override this in the s state, ); }); - }); - Ok(()) + Ok(()) + }) } fn ui( @@ -167,23 +174,60 @@ mode sets the default time range to _everything_. You can override this in the s ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - let settings = ViewProperty::from_archetype::( - ctx.blueprint_db(), - ctx.blueprint_query, - query.space_view_id, - ); - - let mode = - settings.component_or_fallback::(ctx, self, state)?; - - // update state - let state = state.downcast_mut::()?; - state.mode = mode; - - match mode { - components::DataframeViewMode::LatestAt => latest_at_table_ui(ctx, ui, query), + // let settings = ViewProperty::from_archetype::( + // ctx.blueprint_db(), + // ctx.blueprint_query, + // query.space_view_id, + // ); + // + // let mode = + // settings.component_or_fallback::(ctx, self, state)?; + // + // // update state + // let state = state.downcast_mut::()?; + // state.mode = mode; + // + // match mode { + // components::DataframeViewMode::LatestAt => latest_at_table_ui(ctx, ui, query), + // + // components::DataframeViewMode::TimeRange => { + // let time_range_table_order = + // ViewProperty::from_archetype::( + // ctx.blueprint_db(), + // ctx.blueprint_query, + // query.space_view_id, + // ); + // let sort_key = time_range_table_order + // .component_or_fallback::(ctx, self, state)?; + // let sort_order = time_range_table_order + // .component_or_fallback::(ctx, self, state)?; + // + // time_range_table_ui(ctx, ui, query, sort_key, sort_order); + // } + // }; + + let view_query = + super::view_query::Query::try_from_blueprint(ctx, query.space_view_id, self, state)?; + + let Some(timeline) = ctx + .recording() + .timelines() + .find(|t| t.name() == &view_query.timeline) + else { + //TODO: create dummy timeline instead? + re_log::warn_once!( + "Could not find timeline {:?}.", + view_query.timeline.as_str() + ); + //TODO(ab): we should have an error for that + return Ok(()); + }; - components::DataframeViewMode::TimeRange => { + match view_query.mode { + QueryMode::LatestAt { time } => { + latest_at_table_ui(ctx, ui, query, LatestAtQuery::new(*timeline, time)) + } + QueryMode::Range { from, to } => { let time_range_table_order = ViewProperty::from_archetype::( ctx.blueprint_db(), @@ -195,12 +239,51 @@ mode sets the default time range to _everything_. You can override this in the s let sort_order = time_range_table_order .component_or_fallback::(ctx, self, state)?; - time_range_table_ui(ctx, ui, query, sort_key, sort_order); + time_range_table_ui( + ctx, + ui, + query, + sort_key, + sort_order, + timeline, + ResolvedTimeRange::new(from, to), + ); } - }; + } Ok(()) } } -re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => []); +impl TypedComponentFallbackProvider for DataframeSpaceView { + fn fallback_for(&self, ctx: &re_viewer_context::QueryContext<'_>) -> Timeline { + //TODO: add helper to Timeline component + Timeline(Utf8::from( + ctx.viewer_ctx + .rec_cfg + .time_ctrl + .read() + .timeline() + .name() + .as_str(), + )) + } +} + +impl TypedComponentFallbackProvider for DataframeSpaceView { + fn fallback_for(&self, ctx: &QueryContext<'_>) -> LatestAtQueries { + let current_time = ctx.viewer_ctx.rec_cfg.time_ctrl.read(); + + let latest_at_query = datatypes::LatestAtQuery { + timeline: Utf8::from(current_time.timeline().name().as_str()), + time: re_types_core::datatypes::TimeInt::from( + current_time + .time_int() + .unwrap_or(re_log_types::TimeInt::MAX), + ), + }; + LatestAtQueries::from(vec![latest_at_query]) + } +} + +re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => [Timeline, LatestAtQueries]); diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index 7448ea0b0e57..190e4c4473b4 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -30,9 +30,12 @@ use crate::table_ui::{row_id_ui, table_ui}; pub(crate) fn time_range_table_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, + //TODO: remove that, pass space view id and BTreeSet instead query: &ViewQuery<'_>, sort_key: SortKey, sort_order: SortOrder, + timeline: &Timeline, + resolved_time_range: ResolvedTimeRange, ) { re_tracing::profile_function!(); @@ -51,7 +54,7 @@ pub(crate) fn time_range_table_ui( .filter(|data_result| data_result.is_visible(ctx)) .flat_map(|data_result| { ctx.recording_store() - .all_components_on_timeline(&query.timeline, &data_result.entity_path) + .all_components_on_timeline(timeline, &data_result.entity_path) .unwrap_or_default() }) // TODO(#4466): make showing/hiding indicators components an explicit optional @@ -119,20 +122,12 @@ pub(crate) fn time_range_table_ui( .iter_all_data_results() .filter(|data_result| data_result.is_visible(ctx)) .flat_map(|data_result| { - let time_range = match &data_result.property_overrides.query_range { - QueryRange::TimeRange(time_range) => time_range.clone(), - QueryRange::LatestAt => TimeRange::AT_CURSOR, - }; - - let resolved_time_range = - ResolvedTimeRange::from_relative_time_range(&time_range, ctx.current_query().at()); - sorted_components.iter().flat_map(move |component| { entity_components_to_key_value_iter( ctx, &data_result.entity_path, component, - query.timeline, + *timeline, resolved_time_range, ) }) @@ -218,6 +213,7 @@ pub(crate) fn time_range_table_ui( } }; + //TODO: why are these even needed?? let latest_at_query = query.latest_at_query(); let entity_ui = |ui: &mut egui::Ui, entity_path: &EntityPath| { entity_path_button( @@ -245,6 +241,7 @@ pub(crate) fn time_range_table_ui( }; // Draw a single line of the table. This is called for each _visible_ row. + //TODO: why are these even needed?? let latest_at_query = query.latest_at_query(); let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { let row_key = rows[row.index()]; diff --git a/crates/viewer/re_space_view_dataframe/src/utils.rs b/crates/viewer/re_space_view_dataframe/src/utils.rs index e622e2cb413a..de61cc5d80e5 100644 --- a/crates/viewer/re_space_view_dataframe/src/utils.rs +++ b/crates/viewer/re_space_view_dataframe/src/utils.rs @@ -19,10 +19,10 @@ pub(crate) fn sorted_visible_entity_path( } /// Returns a sorted, deduplicated iterator of all instance paths for a given entity. -pub(crate) fn sorted_instance_paths_for<'a>( +pub(crate) fn sorted_instance_paths_for<'a, 'b>( entity_path: &'a EntityPath, store: &'a ChunkStore, - timeline: &'a Timeline, + timeline: &'b Timeline, latest_at_query: &'a LatestAtQuery, ) -> impl Iterator + 'a { re_tracing::profile_function!(); diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs new file mode 100644 index 000000000000..961e5fd06bbb --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -0,0 +1,571 @@ +use egui::{NumExt, Response}; +use re_entity_db::TimeHistogram; +use re_log_types::{TimeInt, TimeType, TimeZone, TimelineName}; +use re_types::blueprint::components::DataframeViewMode; +use re_types::blueprint::datatypes::LatestAtQuery; +use re_types::blueprint::{archetypes, components, datatypes}; +use re_types_core::{Archetype as _, ComponentName, Loggable as _}; +use re_ui::{list_item, UiExt as _}; +use re_viewer_context::{ + ComponentFallbackProvider, QueryContext, SpaceViewId, SpaceViewState, + SpaceViewSystemExecutionError, ViewQuery, ViewerContext, +}; +use re_viewport_blueprint::{entity_path_for_view_property, ViewProperty}; +use std::ops::RangeInclusive; + +pub(crate) enum QueryMode { + LatestAt { + time: TimeInt, + }, + Range { + from: TimeInt, + to: TimeInt, + //TODO(ab): add PoV components + }, +} + +//TODO: fallback to the current timeline is nice but should be saved back to the blueprint such as +// to "freeze" the value + +pub(crate) struct Query { + pub(crate) timeline: TimelineName, + pub(crate) mode: QueryMode, +} + +impl Query { + pub(crate) fn try_from_blueprint( + ctx: &ViewerContext<'_>, + space_view_id: SpaceViewId, + fallback_provider: &dyn ComponentFallbackProvider, + state: &mut dyn SpaceViewState, + ) -> Result { + let property = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query, + space_view_id, + ); + + let timeline = TimelineName::from( + property + .component_or_fallback::(ctx, fallback_provider, state)? + .0 + .as_str(), + ); + + let mode = property.component_or_fallback::( + ctx, + fallback_provider, + state, + )?; + + let mode = match mode { + DataframeViewMode::LatestAt => { + let time = property + .component_or_fallback::( + ctx, + fallback_provider, + state, + )? + .0 + .into_iter() + .find(|q| q.timeline.as_str() == timeline) + .map(|q| q.time.into()) + .unwrap_or_else(|| { + ctx.rec_cfg + .time_ctrl + .read() + .time_int() + .unwrap_or(TimeInt::MAX) + }); + + QueryMode::LatestAt { time } + } + DataframeViewMode::TimeRange => { + let (from, to) = property + .component_or_fallback::( + ctx, + fallback_provider, + state, + )? + .0 + .into_iter() + .find(|q| q.timeline.as_str() == timeline) + .map(|q| (q.start.into(), q.end.into())) + .unwrap_or((TimeInt::MIN, TimeInt::MAX)); + + QueryMode::Range { from, to } + } + }; + + Ok(Self { timeline, mode }) + } + + pub(crate) fn ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + fallback_provider: &dyn ComponentFallbackProvider, + state: &mut dyn SpaceViewState, + space_view_id: SpaceViewId, + ) -> Result<(), SpaceViewSystemExecutionError> { + let name = archetypes::DataframeQuery::name(); + let Some(reflection) = ctx.reflection.archetypes.get(&name) else { + // The `ArchetypeReflectionMarker` bound should make this impossible. + re_log::warn_once!("Missing reflection data for archetype {name:?}."); + //TODO(ab): we should have an error for that + return Ok(()); + }; + + let blueprint_path = + entity_path_for_view_property(space_view_id, ctx.blueprint_db().tree(), name); + let query_context = QueryContext { + viewer_ctx: ctx, + target_entity_path: &blueprint_path, + archetype_name: Some(name), + query: ctx.blueprint_query, + view_state: state, + view_ctx: None, + }; + + let property = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query, + space_view_id, + ); + + let current_mode = property.component_or_fallback::( + ctx, + fallback_provider, + state, + )?; + + let timeline_name = property + .component_or_fallback::(ctx, fallback_provider, state) + .map(|t| t.timeline_name())?; + + let Some(timeline) = ctx + .recording() + .timelines() + .find(|t| t.name() == &timeline_name) + else { + re_log::warn_once!("Could not find timeline {:?}.", timeline_name.as_str()); + //TODO(ab): we should have an error for that + return Ok(()); + }; + + let inner_ui = |ui: &mut egui::Ui| -> Result<(), SpaceViewSystemExecutionError> { + let component_results = ctx.blueprint_db().latest_at( + ctx.blueprint_query, + &blueprint_path, + reflection.fields.iter().map(|field| field.component_name), + ); + + // + // Timeline + // + + let component_name = components::Timeline::name(); + ui.list_item_flat_noninteractive(list_item::PropertyContent::new("Timeline").value_fn( + |ui, _| { + ctx.component_ui_registry.singleline_edit_ui( + &query_context, + ui, + ctx.blueprint_db(), + &blueprint_path, + component_name, + component_results + .component_batch_raw(&component_name) + .as_deref(), + fallback_provider, + ); + }, + )); + + // + // Mode + // + + let component_name = components::DataframeViewMode::name(); + ui.list_item_flat_noninteractive(list_item::PropertyContent::new("Mode").value_fn( + |ui, _| { + ctx.component_ui_registry.singleline_edit_ui( + &query_context, + ui, + ctx.blueprint_db(), + &blueprint_path, + component_name, + component_results + .component_batch_raw(&component_name) + .as_deref(), + fallback_provider, + ); + }, + )); + + let time_spec = if let Some(time_histogram) = ctx.recording().time_histogram(&timeline) + { + TimelineSpec::from_time_histogram(time_histogram) + } else { + // shouldn't happen, `timeline` existence was already checked + TimelineSpec::from_time_range(0..=0) + }; + + match current_mode { + DataframeViewMode::LatestAt => { + // + // Latest At time + // TODO(ab): we can't use edit ui because we dont have the required context + // there, aka the currently chosen timeline. + // + + let mut latest_at_queries = property + .component_or_fallback::( + ctx, + fallback_provider, + state, + )?; + + let mut latest_at_query = latest_at_queries + .query_for_timeline(timeline_name.as_str()) + .cloned() + .unwrap_or_else(|| datatypes::LatestAtQuery { + timeline: timeline_name.as_str().into(), + time: TimeInt::MAX.into(), + }); + + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("At time").value_fn(|ui, _| { + let resp = match timeline.typ() { + TimeType::Time => { + time_spec + .temporal_drag_value( + ui, + &mut latest_at_query.time, + true, + None, + ctx.app_options.time_zone, + ) + .0 + } + TimeType::Sequence => time_spec.sequence_drag_value( + ui, + &mut latest_at_query.time, + true, + None, + ), + }; + + if resp.changed() { + latest_at_queries.set_query_for_timeline( + timeline_name.as_str(), + Some(latest_at_query), + ); + ctx.save_blueprint_component(&blueprint_path, &latest_at_queries); + } + }), + ); + } + DataframeViewMode::TimeRange => { + // + // Range times + + let mut time_range_queries = property + .component_or_fallback::( + ctx, + fallback_provider, + state, + )?; + + let mut time_range_query = time_range_queries + .query_for_timeline(timeline_name.as_str()) + .cloned() + .unwrap_or_else(|| datatypes::TimeRangeQuery { + timeline: timeline_name.as_str().into(), + start: TimeInt::MIN.into(), + end: TimeInt::MAX.into(), + }); + + let mut changed = false; + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("From").value_fn(|ui, _| { + let resp = match timeline.typ() { + TimeType::Time => { + time_spec + .temporal_drag_value( + ui, + &mut time_range_query.start, + true, + None, + ctx.app_options.time_zone, + ) + .0 + } + TimeType::Sequence => time_spec.sequence_drag_value( + ui, + &mut time_range_query.start, + true, + None, + ), + }; + + changed |= resp.changed(); + }), + ); + + let end_response = ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("To").value_fn(|ui, _| { + let resp = match timeline.typ() { + TimeType::Time => { + time_spec + .temporal_drag_value( + ui, + &mut time_range_query.end, + true, + None, + ctx.app_options.time_zone, + ) + .0 + } + TimeType::Sequence => time_spec.sequence_drag_value( + ui, + &mut time_range_query.end, + true, + None, + ), + }; + + changed |= resp.changed(); + }), + ); + + if changed { + time_range_queries + .set_query_for_timeline(timeline_name.as_str(), Some(time_range_query)); + ctx.save_blueprint_component(&blueprint_path, &time_range_queries); + } + } + } + + Ok(()) + }; + + let result = ui + .list_item() + .interactive(false) + .show_hierarchical_with_children( + ui, + ui.make_persistent_id("view_query"), + true, + list_item::LabelContent::new("Query"), + |ui| inner_ui(ui), + ); + + result.body_response.map(|r| r.inner).unwrap_or(Ok(())) + } +} + +// ================================================================================================= +// TODO: this is copied from visible_time_range_ui.rs. It should be extracted and cleaned-up. Also +// there is time histogram stuff here that is bound to be removed/fixed. + +/// Compute and store various information about a timeline related to how the UI should behave. +#[derive(Debug)] +struct TimelineSpec { + /// Actual range of logged data on the timelines (excluding timeless data). + range: RangeInclusive, + + /// For timelines with large offsets (e.g. `log_time`), this is a rounded time just before the + /// first logged data, which can be used as offset in the UI. + base_time: Option, + + // used only for temporal timelines + /// For temporal timelines, this is a nice unit factor to use. + unit_factor: i64, + + /// For temporal timelines, this is the unit symbol to display. + unit_symbol: &'static str, + + /// This is a nice range of absolute times to use when editing an absolute time. The boundaries + /// are extended to the nearest rounded unit to minimize glitches. + abs_range: RangeInclusive, + + /// This is a nice range of relative times to use when editing an absolute time. The boundaries + /// are extended to the nearest rounded unit to minimize glitches. + rel_range: RangeInclusive, +} + +impl TimelineSpec { + fn from_time_histogram(times: &TimeHistogram) -> Self { + Self::from_time_range( + times.min_key().unwrap_or_default()..=times.max_key().unwrap_or_default(), + ) + } + + fn from_time_range(range: RangeInclusive) -> Self { + let span = range.end() - range.start(); + let base_time = time_range_base_time(*range.start(), span); + let (unit_symbol, unit_factor) = unit_from_span(span); + + // `abs_range` is used by the DragValue when editing an absolute time, its bound expended to + // nearest unit to minimize glitches. + let abs_range = + round_down(*range.start(), unit_factor)..=round_up(*range.end(), unit_factor); + + // `rel_range` is used by the DragValue when editing a relative time offset. It must have + // enough margin either side to accommodate for all possible values of current time. + let rel_range = round_down(-span, unit_factor)..=round_up(2 * span, unit_factor); + + Self { + range, + base_time, + unit_factor, + unit_symbol, + abs_range, + rel_range, + } + } + + fn sequence_drag_value( + &self, + ui: &mut egui::Ui, + value: &mut re_types_core::datatypes::TimeInt, + absolute: bool, + low_bound_override: Option, + ) -> Response { + let mut time_range = if absolute { + self.abs_range.clone() + } else { + self.rel_range.clone() + }; + + // speed must be computed before messing with time_range for consistency + let span = time_range.end() - time_range.start(); + let speed = (span as f32 * 0.005).at_least(1.0); + + if let Some(low_bound_override) = low_bound_override { + time_range = low_bound_override.0.at_least(*time_range.start())..=*time_range.end(); + } + + ui.add( + egui::DragValue::new(&mut value.0) + .range(time_range) + .speed(speed), + ) + } + + /// Show a temporal drag value. + /// + /// Feature rich: + /// - scale to the proper units + /// - display the base time if any + /// - etc. + /// + /// Returns a tuple of the [`egui::DragValue`]'s [`egui::Response`], and the base time label's + /// [`egui::Response`], if any. + fn temporal_drag_value( + &self, + ui: &mut egui::Ui, + value: &mut re_types_core::datatypes::TimeInt, + absolute: bool, + low_bound_override: Option, + time_zone_for_timestamps: TimeZone, + ) -> (Response, Option) { + let mut time_range = if absolute { + self.abs_range.clone() + } else { + self.rel_range.clone() + }; + + let factor = self.unit_factor as f32; + let offset = if absolute { + self.base_time.unwrap_or(0) + } else { + 0 + }; + + // speed must be computed before messing with time_range for consistency + let speed = (time_range.end() - time_range.start()) as f32 / factor * 0.005; + + if let Some(low_bound_override) = low_bound_override { + time_range = low_bound_override.0.at_least(*time_range.start())..=*time_range.end(); + } + + let mut time_unit = (value.0 - offset) as f32 / factor; + + let time_range = (*time_range.start() - offset) as f32 / factor + ..=(*time_range.end() - offset) as f32 / factor; + + let base_time_response = if absolute { + self.base_time.map(|base_time| { + ui.label(format!( + "{} + ", + TimeType::Time.format( + re_types_core::datatypes::TimeInt(base_time), + time_zone_for_timestamps + ) + )) + }) + } else { + None + }; + + let drag_value_response = ui.add( + egui::DragValue::new(&mut time_unit) + .range(time_range) + .speed(speed) + .suffix(self.unit_symbol), + ); + + *value = re_types_core::datatypes::TimeInt((time_unit * factor).round() as i64 + offset); + + (drag_value_response, base_time_response) + } +} + +fn unit_from_span(span: i64) -> (&'static str, i64) { + if span / 1_000_000_000 > 0 { + ("s", 1_000_000_000) + } else if span / 1_000_000 > 0 { + ("ms", 1_000_000) + } else if span / 1_000 > 0 { + ("μs", 1_000) + } else { + ("ns", 1) + } +} + +/// Value of the start time over time span ratio above which an explicit offset is handled. +static SPAN_TO_START_TIME_OFFSET_THRESHOLD: i64 = 10; + +fn time_range_base_time(min_time: i64, span: i64) -> Option { + if min_time <= 0 { + return None; + } + + if span.saturating_mul(SPAN_TO_START_TIME_OFFSET_THRESHOLD) < min_time { + let factor = if span / 1_000_000 > 0 { + 1_000_000_000 + } else if span / 1_000 > 0 { + 1_000_000 + } else { + 1_000 + }; + + Some(min_time - (min_time % factor)) + } else { + None + } +} + +fn round_down(value: i64, factor: i64) -> i64 { + value - (value.rem_euclid(factor)) +} + +fn round_up(value: i64, factor: i64) -> i64 { + let val = round_down(value, factor); + + if val == value { + val + } else { + val + factor + } +} diff --git a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs index b81e71f7eb26..14618ca18010 100644 --- a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs @@ -8,6 +8,7 @@ pub use re_types::blueprint::components::Corner2D; pub use re_types::blueprint::components::DataframeViewMode; pub use re_types::blueprint::components::IncludedContent; pub use re_types::blueprint::components::Interactive; +pub use re_types::blueprint::components::LatestAtQueries; pub use re_types::blueprint::components::LockRangeDuringZoom; pub use re_types::blueprint::components::PanelState; pub use re_types::blueprint::components::QueryExpression; @@ -17,6 +18,8 @@ pub use re_types::blueprint::components::SortOrder; pub use re_types::blueprint::components::SpaceViewClass; pub use re_types::blueprint::components::SpaceViewOrigin; pub use re_types::blueprint::components::TensorDimensionIndexSlider; +pub use re_types::blueprint::components::TimeRangeQueries; +pub use re_types::blueprint::components::Timeline; pub use re_types::blueprint::components::ViewFit; pub use re_types::blueprint::components::ViewerRecommendationHash; pub use re_types::blueprint::components::Visible; @@ -47,6 +50,7 @@ pub fn is_valid_blueprint(blueprint: &EntityDb) -> bool { && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) @@ -58,6 +62,8 @@ pub fn is_valid_blueprint(blueprint: &EntityDb) -> bool { && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) + && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 5a7641ffeeb3..12a4c11bdcdd 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -118,6 +118,13 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "Component(s) used as point-of-view for a query.", + placeholder: Some(LatestAtQueries::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -195,6 +202,20 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "Component(s) used as point-of-view for a query.", + placeholder: Some(TimeRangeQueries::default().to_arrow()?), + }, + ), + ( + ::name(), + ComponentReflection { + docstring_md: "A timeline", + placeholder: Some(Timeline::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -746,6 +767,28 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { ], }, ), + ( + ArchetypeName::new("rerun.blueprint.archetypes.DataframeQuery"), + ArchetypeReflection { + display_name: "Dataframe query", + docstring_md: "Configuration for the dataframe view", + fields: vec![ + ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.Timeline".into(), display_name : + "Timeline", docstring_md : "Name of the timeline this applies to.", + }, ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.DataframeViewMode".into(), display_name : + "Mode", docstring_md : "Type of query: latest at or range", }, + ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.LatestAtQueries".into(), display_name : + "Latest at queries", docstring_md : + "Times (1 for latest at, 2 for range)", }, ArchetypeFieldReflection { + component_name : "rerun.blueprint.components.TimeRangeQueries" + .into(), display_name : "Time range queries", docstring_md : + "Times (1 for latest at, 2 for range)", }, + ], + }, + ), ( ArchetypeName::new("rerun.blueprint.archetypes.DataframeViewMode"), ArchetypeReflection { diff --git a/rerun_cpp/src/rerun/blueprint/archetypes.hpp b/rerun_cpp/src/rerun/blueprint/archetypes.hpp index cb7eb69e8012..6a31bb9502c2 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes.hpp @@ -4,6 +4,7 @@ #include "blueprint/archetypes/background.hpp" #include "blueprint/archetypes/container_blueprint.hpp" +#include "blueprint/archetypes/dataframe_query.hpp" #include "blueprint/archetypes/dataframe_view_mode.hpp" #include "blueprint/archetypes/panel_blueprint.hpp" #include "blueprint/archetypes/plot_legend.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes index a8d7bcacc964..db276da6126a 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes @@ -5,6 +5,8 @@ background.cpp linguist-generated=true background.hpp linguist-generated=true container_blueprint.cpp linguist-generated=true container_blueprint.hpp linguist-generated=true +dataframe_query.cpp linguist-generated=true +dataframe_query.hpp linguist-generated=true dataframe_view_mode.cpp linguist-generated=true dataframe_view_mode.hpp linguist-generated=true panel_blueprint.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp new file mode 100644 index 000000000000..545751fe7aa6 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp @@ -0,0 +1,48 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +#include "dataframe_query.hpp" + +#include "../../collection_adapter_builtins.hpp" + +namespace rerun::blueprint::archetypes {} + +namespace rerun { + + Result> AsComponents::serialize( + const blueprint::archetypes::DataframeQuery& archetype + ) { + using namespace blueprint::archetypes; + std::vector cells; + cells.reserve(5); + + if (archetype.timeline.has_value()) { + auto result = DataCell::from_loggable(archetype.timeline.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.mode.has_value()) { + auto result = DataCell::from_loggable(archetype.mode.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.latest_at_queries.has_value()) { + auto result = DataCell::from_loggable(archetype.latest_at_queries.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.time_range_queries.has_value()) { + auto result = DataCell::from_loggable(archetype.time_range_queries.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + { + auto indicator = DataframeQuery::IndicatorComponent(); + auto result = DataCell::from_loggable(indicator); + RR_RETURN_NOT_OK(result.error); + cells.emplace_back(std::move(result.value)); + } + + return cells; + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp new file mode 100644 index 000000000000..d9124b943041 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp @@ -0,0 +1,95 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +#pragma once + +#include "../../blueprint/components/dataframe_view_mode.hpp" +#include "../../blueprint/components/latest_at_queries.hpp" +#include "../../blueprint/components/time_range_queries.hpp" +#include "../../blueprint/components/timeline.hpp" +#include "../../collection.hpp" +#include "../../compiler_utils.hpp" +#include "../../data_cell.hpp" +#include "../../indicator_component.hpp" +#include "../../result.hpp" + +#include +#include +#include +#include + +namespace rerun::blueprint::archetypes { + /// **Archetype**: Configuration for the dataframe view + struct DataframeQuery { + /// Name of the timeline this applies to. + std::optional timeline; + + /// Type of query: latest at or range + std::optional mode; + + /// Times (1 for latest at, 2 for range) + std::optional latest_at_queries; + + /// Times (1 for latest at, 2 for range) + std::optional time_range_queries; + + public: + static constexpr const char IndicatorComponentName[] = + "rerun.blueprint.components.DataframeQueryIndicator"; + + /// Indicator component, used to identify the archetype when converting to a list of components. + using IndicatorComponent = rerun::components::IndicatorComponent; + + public: + DataframeQuery() = default; + DataframeQuery(DataframeQuery&& other) = default; + + /// Name of the timeline this applies to. + DataframeQuery with_timeline(rerun::blueprint::components::Timeline _timeline) && { + timeline = std::move(_timeline); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Type of query: latest at or range + DataframeQuery with_mode(rerun::blueprint::components::DataframeViewMode _mode) && { + mode = std::move(_mode); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Times (1 for latest at, 2 for range) + DataframeQuery with_latest_at_queries( + rerun::blueprint::components::LatestAtQueries _latest_at_queries + ) && { + latest_at_queries = std::move(_latest_at_queries); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Times (1 for latest at, 2 for range) + DataframeQuery with_time_range_queries( + rerun::blueprint::components::TimeRangeQueries _time_range_queries + ) && { + time_range_queries = std::move(_time_range_queries); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + }; + +} // namespace rerun::blueprint::archetypes + +namespace rerun { + /// \private + template + struct AsComponents; + + /// \private + template <> + struct AsComponents { + /// Serialize all set component batches. + static Result> serialize( + const blueprint::archetypes::DataframeQuery& archetype + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index f157b8a7db1f..c88962f3a5a7 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -14,6 +14,7 @@ #include "blueprint/components/included_content.hpp" #include "blueprint/components/included_space_view.hpp" #include "blueprint/components/interactive.hpp" +#include "blueprint/components/latest_at_queries.hpp" #include "blueprint/components/lock_range_during_zoom.hpp" #include "blueprint/components/panel_state.hpp" #include "blueprint/components/query_expression.hpp" @@ -25,6 +26,8 @@ #include "blueprint/components/space_view_maximized.hpp" #include "blueprint/components/space_view_origin.hpp" #include "blueprint/components/tensor_dimension_index_slider.hpp" +#include "blueprint/components/time_range_queries.hpp" +#include "blueprint/components/timeline.hpp" #include "blueprint/components/view_fit.hpp" #include "blueprint/components/viewer_recommendation_hash.hpp" #include "blueprint/components/visible.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/components/.gitattributes b/rerun_cpp/src/rerun/blueprint/components/.gitattributes index 62e282550cc4..2eae797a34ce 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -17,6 +17,8 @@ grid_columns.hpp linguist-generated=true included_content.hpp linguist-generated=true included_space_view.hpp linguist-generated=true interactive.hpp linguist-generated=true +latest_at_queries.cpp linguist-generated=true +latest_at_queries.hpp linguist-generated=true lock_range_during_zoom.hpp linguist-generated=true panel_state.cpp linguist-generated=true panel_state.hpp linguist-generated=true @@ -31,6 +33,9 @@ space_view_class.hpp linguist-generated=true space_view_maximized.hpp linguist-generated=true space_view_origin.hpp linguist-generated=true tensor_dimension_index_slider.hpp linguist-generated=true +time_range_queries.cpp linguist-generated=true +time_range_queries.hpp linguist-generated=true +timeline.hpp linguist-generated=true view_fit.cpp linguist-generated=true view_fit.hpp linguist-generated=true viewer_recommendation_hash.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp new file mode 100644 index 000000000000..9cc174cb71dc --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp @@ -0,0 +1,81 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +#include "latest_at_queries.hpp" + +#include "../../blueprint/datatypes/latest_at_query.hpp" + +#include +#include + +namespace rerun::blueprint::components {} + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::list(arrow::field( + "item", + Loggable::arrow_datatype(), + false + )); + return datatype; + } + + Result> + Loggable::to_arrow( + const blueprint::components::LatestAtQueries* instances, size_t num_instances + ) { + // TODO(andreas): Allow configuring the memory pool. + arrow::MemoryPool* pool = arrow::default_memory_pool(); + auto datatype = arrow_datatype(); + + ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) + if (instances && num_instances > 0) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + ) + ); + } + std::shared_ptr array; + ARROW_RETURN_NOT_OK(builder->Finish(&array)); + return array; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::LatestAtQueries* elements, + size_t num_elements + ) { + if (builder == nullptr) { + return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); + } + if (elements == nullptr) { + return rerun::Error( + ErrorCode::UnexpectedNullArgument, + "Cannot serialize null pointer to arrow array." + ); + } + + auto value_builder = static_cast(builder->value_builder()); + ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); + ARROW_RETURN_NOT_OK(value_builder->Reserve(static_cast(num_elements * 2))); + + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + const auto& element = elements[elem_idx]; + ARROW_RETURN_NOT_OK(builder->Append()); + if (element.value.data()) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + value_builder, + element.value.data(), + element.value.size() + ) + ); + } + } + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp new file mode 100644 index 000000000000..dc47e12460bc --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp @@ -0,0 +1,63 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +#pragma once + +#include "../../blueprint/datatypes/latest_at_query.hpp" +#include "../../collection.hpp" +#include "../../result.hpp" + +#include +#include +#include + +namespace arrow { + class Array; + class DataType; + class ListBuilder; +} // namespace arrow + +namespace rerun::blueprint::components { + /// **Component**: Component(s) used as point-of-view for a query. + struct LatestAtQueries { + rerun::Collection value; + + public: + LatestAtQueries() = default; + + LatestAtQueries(rerun::Collection value_) + : value(std::move(value_)) {} + + LatestAtQueries& operator=( + rerun::Collection value_ + ) { + value = std::move(value_); + return *this; + } + }; +} // namespace rerun::blueprint::components + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.LatestAtQueries"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: components::LatestAtQueries` into an arrow array. + static Result> to_arrow( + const blueprint::components::LatestAtQueries* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::LatestAtQueries* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp new file mode 100644 index 000000000000..da545e384f02 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp @@ -0,0 +1,81 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +#include "time_range_queries.hpp" + +#include "../../blueprint/datatypes/time_range_query.hpp" + +#include +#include + +namespace rerun::blueprint::components {} + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::list(arrow::field( + "item", + Loggable::arrow_datatype(), + false + )); + return datatype; + } + + Result> + Loggable::to_arrow( + const blueprint::components::TimeRangeQueries* instances, size_t num_instances + ) { + // TODO(andreas): Allow configuring the memory pool. + arrow::MemoryPool* pool = arrow::default_memory_pool(); + auto datatype = arrow_datatype(); + + ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) + if (instances && num_instances > 0) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + ) + ); + } + std::shared_ptr array; + ARROW_RETURN_NOT_OK(builder->Finish(&array)); + return array; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::TimeRangeQueries* elements, + size_t num_elements + ) { + if (builder == nullptr) { + return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); + } + if (elements == nullptr) { + return rerun::Error( + ErrorCode::UnexpectedNullArgument, + "Cannot serialize null pointer to arrow array." + ); + } + + auto value_builder = static_cast(builder->value_builder()); + ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); + ARROW_RETURN_NOT_OK(value_builder->Reserve(static_cast(num_elements * 2))); + + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + const auto& element = elements[elem_idx]; + ARROW_RETURN_NOT_OK(builder->Append()); + if (element.value.data()) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + value_builder, + element.value.data(), + element.value.size() + ) + ); + } + } + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp new file mode 100644 index 000000000000..fd409c65111a --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp @@ -0,0 +1,63 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +#pragma once + +#include "../../blueprint/datatypes/time_range_query.hpp" +#include "../../collection.hpp" +#include "../../result.hpp" + +#include +#include +#include + +namespace arrow { + class Array; + class DataType; + class ListBuilder; +} // namespace arrow + +namespace rerun::blueprint::components { + /// **Component**: Component(s) used as point-of-view for a query. + struct TimeRangeQueries { + rerun::Collection value; + + public: + TimeRangeQueries() = default; + + TimeRangeQueries(rerun::Collection value_) + : value(std::move(value_)) {} + + TimeRangeQueries& operator=( + rerun::Collection value_ + ) { + value = std::move(value_); + return *this; + } + }; +} // namespace rerun::blueprint::components + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.TimeRangeQueries"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: components::TimeRangeQueries` into an arrow array. + static Result> to_arrow( + const blueprint::components::TimeRangeQueries* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::TimeRangeQueries* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/timeline.hpp b/rerun_cpp/src/rerun/blueprint/components/timeline.hpp new file mode 100644 index 000000000000..10f6596fde27 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/timeline.hpp @@ -0,0 +1,63 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs". + +#pragma once + +#include "../../datatypes/utf8.hpp" +#include "../../result.hpp" + +#include +#include +#include +#include + +namespace rerun::blueprint::components { + /// **Component**: A timeline + struct Timeline { + rerun::datatypes::Utf8 value; + + public: + Timeline() = default; + + Timeline(rerun::datatypes::Utf8 value_) : value(std::move(value_)) {} + + Timeline& operator=(rerun::datatypes::Utf8 value_) { + value = std::move(value_); + return *this; + } + + Timeline(std::string value_) : value(std::move(value_)) {} + + Timeline& operator=(std::string value_) { + value = std::move(value_); + return *this; + } + + /// Cast to the underlying Utf8 datatype + operator rerun::datatypes::Utf8() const { + return value; + } + }; +} // namespace rerun::blueprint::components + +namespace rerun { + static_assert(sizeof(rerun::datatypes::Utf8) == sizeof(blueprint::components::Timeline)); + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.Timeline"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype() { + return Loggable::arrow_datatype(); + } + + /// Serializes an array of `rerun::blueprint:: components::Timeline` into an arrow array. + static Result> to_arrow( + const blueprint::components::Timeline* instances, size_t num_instances + ) { + return Loggable::to_arrow(&instances->value, num_instances); + } + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes.hpp b/rerun_cpp/src/rerun/blueprint/datatypes.hpp index 429e06dea010..0908c7ae3a56 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/datatypes.hpp @@ -2,5 +2,7 @@ #pragma once +#include "blueprint/datatypes/latest_at_query.hpp" #include "blueprint/datatypes/tensor_dimension_index_slider.hpp" +#include "blueprint/datatypes/time_range_query.hpp" #include "blueprint/datatypes/utf8list.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes index 914f011d695c..38ef06171ae0 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes @@ -1,7 +1,11 @@ # DO NOT EDIT! This file is generated by crates/build/re_types_builder/src/lib.rs .gitattributes linguist-generated=true +latest_at_query.cpp linguist-generated=true +latest_at_query.hpp linguist-generated=true tensor_dimension_index_slider.cpp linguist-generated=true tensor_dimension_index_slider.hpp linguist-generated=true +time_range_query.cpp linguist-generated=true +time_range_query.hpp linguist-generated=true utf8list.cpp linguist-generated=true utf8list.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp new file mode 100644 index 000000000000..490f5df72cd9 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp @@ -0,0 +1,86 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +#include "latest_at_query.hpp" + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" + +#include +#include + +namespace rerun::blueprint::datatypes {} + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::struct_({ + arrow::field("timeline", Loggable::arrow_datatype(), false), + arrow::field("time", Loggable::arrow_datatype(), false), + }); + return datatype; + } + + Result> Loggable::to_arrow( + const blueprint::datatypes::LatestAtQuery* instances, size_t num_instances + ) { + // TODO(andreas): Allow configuring the memory pool. + arrow::MemoryPool* pool = arrow::default_memory_pool(); + auto datatype = arrow_datatype(); + + ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) + if (instances && num_instances > 0) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + ) + ); + } + std::shared_ptr array; + ARROW_RETURN_NOT_OK(builder->Finish(&array)); + return array; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::LatestAtQuery* elements, + size_t num_elements + ) { + if (builder == nullptr) { + return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); + } + if (elements == nullptr) { + return rerun::Error( + ErrorCode::UnexpectedNullArgument, + "Cannot serialize null pointer to arrow array." + ); + } + + { + auto field_builder = static_cast(builder->field_builder(0)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].timeline, + 1 + )); + } + } + { + auto field_builder = static_cast(builder->field_builder(1)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].time, + 1 + )); + } + } + ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast(num_elements), nullptr)); + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp new file mode 100644 index 000000000000..01c7a7f6c7ec --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp @@ -0,0 +1,56 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +#pragma once + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" +#include "../../result.hpp" + +#include +#include + +namespace arrow { + class Array; + class DataType; + class StructBuilder; +} // namespace arrow + +namespace rerun::blueprint::datatypes { + /// **Datatype**: Visible time range bounds for a specific timeline. + struct LatestAtQuery { + /// Name of the timeline this applies to. + rerun::datatypes::Utf8 timeline; + + /// Time range to use for this timeline. + rerun::datatypes::TimeInt time; + + public: + LatestAtQuery() = default; + }; +} // namespace rerun::blueprint::datatypes + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.datatypes.LatestAtQuery"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: datatypes::LatestAtQuery` into an arrow array. + static Result> to_arrow( + const blueprint::datatypes::LatestAtQuery* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::LatestAtQuery* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp new file mode 100644 index 000000000000..1ce005eba6b8 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp @@ -0,0 +1,98 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +#include "time_range_query.hpp" + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" + +#include +#include + +namespace rerun::blueprint::datatypes {} + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::struct_({ + arrow::field("timeline", Loggable::arrow_datatype(), false), + arrow::field("start", Loggable::arrow_datatype(), false), + arrow::field("end", Loggable::arrow_datatype(), false), + }); + return datatype; + } + + Result> Loggable::to_arrow( + const blueprint::datatypes::TimeRangeQuery* instances, size_t num_instances + ) { + // TODO(andreas): Allow configuring the memory pool. + arrow::MemoryPool* pool = arrow::default_memory_pool(); + auto datatype = arrow_datatype(); + + ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) + if (instances && num_instances > 0) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + ) + ); + } + std::shared_ptr array; + ARROW_RETURN_NOT_OK(builder->Finish(&array)); + return array; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::TimeRangeQuery* elements, + size_t num_elements + ) { + if (builder == nullptr) { + return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); + } + if (elements == nullptr) { + return rerun::Error( + ErrorCode::UnexpectedNullArgument, + "Cannot serialize null pointer to arrow array." + ); + } + + { + auto field_builder = static_cast(builder->field_builder(0)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].timeline, + 1 + )); + } + } + { + auto field_builder = static_cast(builder->field_builder(1)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].start, + 1 + )); + } + } + { + auto field_builder = static_cast(builder->field_builder(2)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].end, + 1 + )); + } + } + ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast(num_elements), nullptr)); + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp new file mode 100644 index 000000000000..356e2fdcc52f --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp @@ -0,0 +1,59 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +#pragma once + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" +#include "../../result.hpp" + +#include +#include + +namespace arrow { + class Array; + class DataType; + class StructBuilder; +} // namespace arrow + +namespace rerun::blueprint::datatypes { + /// **Datatype**: Visible time range bounds for a specific timeline. + struct TimeRangeQuery { + /// Name of the timeline this applies to. + rerun::datatypes::Utf8 timeline; + + /// Start + rerun::datatypes::TimeInt start; + + /// End + rerun::datatypes::TimeInt end; + + public: + TimeRangeQuery() = default; + }; +} // namespace rerun::blueprint::datatypes + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.datatypes.TimeRangeQuery"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: datatypes::TimeRangeQuery` into an arrow array. + static Result> to_arrow( + const blueprint::datatypes::TimeRangeQuery* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::TimeRangeQuery* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes index 19180594d84a..01e3ac82b617 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes @@ -4,6 +4,7 @@ __init__.py linguist-generated=true background.py linguist-generated=true container_blueprint.py linguist-generated=true +dataframe_query.py linguist-generated=true dataframe_view_mode.py linguist-generated=true panel_blueprint.py linguist-generated=true plot_legend.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py index 61638524540e..fc973484e2ff 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py @@ -4,6 +4,7 @@ from .background import Background from .container_blueprint import ContainerBlueprint +from .dataframe_query import DataframeQuery from .dataframe_view_mode import DataframeViewMode from .panel_blueprint import PanelBlueprint from .plot_legend import PlotLegend @@ -21,6 +22,7 @@ __all__ = [ "Background", "ContainerBlueprint", + "DataframeQuery", "DataframeViewMode", "PanelBlueprint", "PlotLegend", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py new file mode 100644 index 000000000000..4b7cf8861aaf --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py @@ -0,0 +1,111 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +# You can extend this class by creating a "DataframeQueryExt" class in "dataframe_query_ext.py". + +from __future__ import annotations + +from typing import Any + +from attrs import define, field + +from ... import datatypes +from ..._baseclasses import ( + Archetype, +) +from ...blueprint import components as blueprint_components +from ...error_utils import catch_and_log_exceptions + +__all__ = ["DataframeQuery"] + + +@define(str=False, repr=False, init=False) +class DataframeQuery(Archetype): + """**Archetype**: Configuration for the dataframe view.""" + + def __init__( + self: Any, + *, + timeline: datatypes.Utf8Like | None = None, + mode: blueprint_components.DataframeViewModeLike | None = None, + latest_at_queries: blueprint_components.LatestAtQueriesLike | None = None, + time_range_queries: blueprint_components.TimeRangeQueriesLike | None = None, + ): + """ + Create a new instance of the DataframeQuery archetype. + + Parameters + ---------- + timeline: + Name of the timeline this applies to. + mode: + Type of query: latest at or range + latest_at_queries: + Times (1 for latest at, 2 for range) + time_range_queries: + Times (1 for latest at, 2 for range) + + """ + + # You can define your own __init__ function as a member of DataframeQueryExt in dataframe_query_ext.py + with catch_and_log_exceptions(context=self.__class__.__name__): + self.__attrs_init__( + timeline=timeline, mode=mode, latest_at_queries=latest_at_queries, time_range_queries=time_range_queries + ) + return + self.__attrs_clear__() + + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( + timeline=None, # type: ignore[arg-type] + mode=None, # type: ignore[arg-type] + latest_at_queries=None, # type: ignore[arg-type] + time_range_queries=None, # type: ignore[arg-type] + ) + + @classmethod + def _clear(cls) -> DataframeQuery: + """Produce an empty DataframeQuery, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + + timeline: blueprint_components.TimelineBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.TimelineBatch._optional, # type: ignore[misc] + ) + # Name of the timeline this applies to. + # + # (Docstring intentionally commented out to hide this field from the docs) + + mode: blueprint_components.DataframeViewModeBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.DataframeViewModeBatch._optional, # type: ignore[misc] + ) + # Type of query: latest at or range + # + # (Docstring intentionally commented out to hide this field from the docs) + + latest_at_queries: blueprint_components.LatestAtQueriesBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.LatestAtQueriesBatch._optional, # type: ignore[misc] + ) + # Times (1 for latest at, 2 for range) + # + # (Docstring intentionally commented out to hide this field from the docs) + + time_range_queries: blueprint_components.TimeRangeQueriesBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.TimeRangeQueriesBatch._optional, # type: ignore[misc] + ) + # Times (1 for latest at, 2 for range) + # + # (Docstring intentionally commented out to hide this field from the docs) + + __str__ = Archetype.__str__ + __repr__ = Archetype.__repr__ # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index cbbd0123a5e2..b486f77a6c53 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -14,6 +14,7 @@ grid_columns.py linguist-generated=true included_content.py linguist-generated=true included_space_view.py linguist-generated=true interactive.py linguist-generated=true +latest_at_queries.py linguist-generated=true lock_range_during_zoom.py linguist-generated=true panel_state.py linguist-generated=true query_expression.py linguist-generated=true @@ -25,6 +26,8 @@ space_view_class.py linguist-generated=true space_view_maximized.py linguist-generated=true space_view_origin.py linguist-generated=true tensor_dimension_index_slider.py linguist-generated=true +time_range_queries.py linguist-generated=true +timeline.py linguist-generated=true view_fit.py linguist-generated=true viewer_recommendation_hash.py linguist-generated=true visible.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py index 7e966a7394ec..afc495d5a565 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -32,6 +32,13 @@ from .included_content import IncludedContent, IncludedContentBatch, IncludedContentType from .included_space_view import IncludedSpaceView, IncludedSpaceViewBatch, IncludedSpaceViewType from .interactive import Interactive, InteractiveBatch, InteractiveType +from .latest_at_queries import ( + LatestAtQueries, + LatestAtQueriesArrayLike, + LatestAtQueriesBatch, + LatestAtQueriesLike, + LatestAtQueriesType, +) from .lock_range_during_zoom import LockRangeDuringZoom, LockRangeDuringZoomBatch, LockRangeDuringZoomType from .panel_state import PanelState, PanelStateArrayLike, PanelStateBatch, PanelStateLike, PanelStateType from .query_expression import QueryExpression, QueryExpressionBatch, QueryExpressionType @@ -47,6 +54,14 @@ TensorDimensionIndexSliderBatch, TensorDimensionIndexSliderType, ) +from .time_range_queries import ( + TimeRangeQueries, + TimeRangeQueriesArrayLike, + TimeRangeQueriesBatch, + TimeRangeQueriesLike, + TimeRangeQueriesType, +) +from .timeline import Timeline, TimelineBatch, TimelineType from .view_fit import ViewFit, ViewFitArrayLike, ViewFitBatch, ViewFitLike, ViewFitType from .viewer_recommendation_hash import ( ViewerRecommendationHash, @@ -103,6 +118,11 @@ "Interactive", "InteractiveBatch", "InteractiveType", + "LatestAtQueries", + "LatestAtQueriesArrayLike", + "LatestAtQueriesBatch", + "LatestAtQueriesLike", + "LatestAtQueriesType", "LockRangeDuringZoom", "LockRangeDuringZoomBatch", "LockRangeDuringZoomType", @@ -142,6 +162,14 @@ "TensorDimensionIndexSlider", "TensorDimensionIndexSliderBatch", "TensorDimensionIndexSliderType", + "TimeRangeQueries", + "TimeRangeQueriesArrayLike", + "TimeRangeQueriesBatch", + "TimeRangeQueriesLike", + "TimeRangeQueriesType", + "Timeline", + "TimelineBatch", + "TimelineType", "ViewFit", "ViewFitArrayLike", "ViewFitBatch", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py b/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py new file mode 100644 index 000000000000..8cd9b5f1ad67 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py @@ -0,0 +1,84 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +# You can extend this class by creating a "LatestAtQueriesExt" class in "latest_at_queries_ext.py". + +from __future__ import annotations + +from typing import Any, Sequence, Union + +import pyarrow as pa +from attrs import define, field + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, + ComponentMixin, +) +from ...blueprint import datatypes as blueprint_datatypes + +__all__ = [ + "LatestAtQueries", + "LatestAtQueriesArrayLike", + "LatestAtQueriesBatch", + "LatestAtQueriesLike", + "LatestAtQueriesType", +] + + +@define(init=False) +class LatestAtQueries(ComponentMixin): + """**Component**: Component(s) used as point-of-view for a query.""" + + _BATCH_TYPE = None + + def __init__(self: Any, value: LatestAtQueriesLike): + """Create a new instance of the LatestAtQueries component.""" + + # You can define your own __init__ function as a member of LatestAtQueriesExt in latest_at_queries_ext.py + self.__attrs_init__(value=value) + + value: list[blueprint_datatypes.LatestAtQuery] = field() + + +LatestAtQueriesLike = LatestAtQueries +LatestAtQueriesArrayLike = Union[ + LatestAtQueries, + Sequence[LatestAtQueriesLike], +] + + +class LatestAtQueriesType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.LatestAtQueries" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.list_( + pa.field( + "item", + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("time", pa.int64(), nullable=False, metadata={}), + ]), + nullable=False, + metadata={}, + ) + ), + self._TYPE_NAME, + ) + + +class LatestAtQueriesBatch(BaseBatch[LatestAtQueriesArrayLike], ComponentBatchMixin): + _ARROW_TYPE = LatestAtQueriesType() + + @staticmethod + def _native_to_pa_array(data: LatestAtQueriesArrayLike, data_type: pa.DataType) -> pa.Array: + raise NotImplementedError( + "Arrow serialization of LatestAtQueries not implemented: We lack codegen for arrow-serialization of general structs" + ) # You need to implement native_to_pa_array_override in latest_at_queries_ext.py + + +# This is patched in late to avoid circular dependencies. +LatestAtQueries._BATCH_TYPE = LatestAtQueriesBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py b/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py new file mode 100644 index 000000000000..b0266ccc0aff --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py @@ -0,0 +1,85 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +# You can extend this class by creating a "TimeRangeQueriesExt" class in "time_range_queries_ext.py". + +from __future__ import annotations + +from typing import Any, Sequence, Union + +import pyarrow as pa +from attrs import define, field + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, + ComponentMixin, +) +from ...blueprint import datatypes as blueprint_datatypes + +__all__ = [ + "TimeRangeQueries", + "TimeRangeQueriesArrayLike", + "TimeRangeQueriesBatch", + "TimeRangeQueriesLike", + "TimeRangeQueriesType", +] + + +@define(init=False) +class TimeRangeQueries(ComponentMixin): + """**Component**: Component(s) used as point-of-view for a query.""" + + _BATCH_TYPE = None + + def __init__(self: Any, value: TimeRangeQueriesLike): + """Create a new instance of the TimeRangeQueries component.""" + + # You can define your own __init__ function as a member of TimeRangeQueriesExt in time_range_queries_ext.py + self.__attrs_init__(value=value) + + value: list[blueprint_datatypes.TimeRangeQuery] = field() + + +TimeRangeQueriesLike = TimeRangeQueries +TimeRangeQueriesArrayLike = Union[ + TimeRangeQueries, + Sequence[TimeRangeQueriesLike], +] + + +class TimeRangeQueriesType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.TimeRangeQueries" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.list_( + pa.field( + "item", + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("start", pa.int64(), nullable=False, metadata={}), + pa.field("end", pa.int64(), nullable=False, metadata={}), + ]), + nullable=False, + metadata={}, + ) + ), + self._TYPE_NAME, + ) + + +class TimeRangeQueriesBatch(BaseBatch[TimeRangeQueriesArrayLike], ComponentBatchMixin): + _ARROW_TYPE = TimeRangeQueriesType() + + @staticmethod + def _native_to_pa_array(data: TimeRangeQueriesArrayLike, data_type: pa.DataType) -> pa.Array: + raise NotImplementedError( + "Arrow serialization of TimeRangeQueries not implemented: We lack codegen for arrow-serialization of general structs" + ) # You need to implement native_to_pa_array_override in time_range_queries_ext.py + + +# This is patched in late to avoid circular dependencies. +TimeRangeQueries._BATCH_TYPE = TimeRangeQueriesBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py new file mode 100644 index 000000000000..509cfac82829 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py @@ -0,0 +1,36 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs". + +# You can extend this class by creating a "TimelineExt" class in "timeline_ext.py". + +from __future__ import annotations + +from ... import datatypes +from ..._baseclasses import ( + ComponentBatchMixin, + ComponentMixin, +) + +__all__ = ["Timeline", "TimelineBatch", "TimelineType"] + + +class Timeline(datatypes.Utf8, ComponentMixin): + """**Component**: A timeline.""" + + _BATCH_TYPE = None + # You can define your own __init__ function as a member of TimelineExt in timeline_ext.py + + # Note: there are no fields here because Timeline delegates to datatypes.Utf8 + pass + + +class TimelineType(datatypes.Utf8Type): + _TYPE_NAME: str = "rerun.blueprint.components.Timeline" + + +class TimelineBatch(datatypes.Utf8Batch, ComponentBatchMixin): + _ARROW_TYPE = TimelineType() + + +# This is patched in late to avoid circular dependencies. +Timeline._BATCH_TYPE = TimelineBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes index 8ae92d95c142..71e16d43761e 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes @@ -2,5 +2,7 @@ .gitattributes linguist-generated=true __init__.py linguist-generated=true +latest_at_query.py linguist-generated=true tensor_dimension_index_slider.py linguist-generated=true +time_range_query.py linguist-generated=true utf8list.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py index 929fa1b8089b..709ee623a9e0 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py @@ -2,6 +2,13 @@ from __future__ import annotations +from .latest_at_query import ( + LatestAtQuery, + LatestAtQueryArrayLike, + LatestAtQueryBatch, + LatestAtQueryLike, + LatestAtQueryType, +) from .tensor_dimension_index_slider import ( TensorDimensionIndexSlider, TensorDimensionIndexSliderArrayLike, @@ -9,14 +16,31 @@ TensorDimensionIndexSliderLike, TensorDimensionIndexSliderType, ) +from .time_range_query import ( + TimeRangeQuery, + TimeRangeQueryArrayLike, + TimeRangeQueryBatch, + TimeRangeQueryLike, + TimeRangeQueryType, +) from .utf8list import Utf8List, Utf8ListArrayLike, Utf8ListBatch, Utf8ListLike, Utf8ListType __all__ = [ + "LatestAtQuery", + "LatestAtQueryArrayLike", + "LatestAtQueryBatch", + "LatestAtQueryLike", + "LatestAtQueryType", "TensorDimensionIndexSlider", "TensorDimensionIndexSliderArrayLike", "TensorDimensionIndexSliderBatch", "TensorDimensionIndexSliderLike", "TensorDimensionIndexSliderType", + "TimeRangeQuery", + "TimeRangeQueryArrayLike", + "TimeRangeQueryBatch", + "TimeRangeQueryLike", + "TimeRangeQueryType", "Utf8List", "Utf8ListArrayLike", "Utf8ListBatch", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py new file mode 100644 index 000000000000..06803336a4a4 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py @@ -0,0 +1,104 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +# You can extend this class by creating a "LatestAtQueryExt" class in "latest_at_query_ext.py". + +from __future__ import annotations + +from typing import Any, Sequence, Union + +import pyarrow as pa +from attrs import define, field + +from ... import datatypes +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, +) + +__all__ = ["LatestAtQuery", "LatestAtQueryArrayLike", "LatestAtQueryBatch", "LatestAtQueryLike", "LatestAtQueryType"] + + +def _latest_at_query__timeline__special_field_converter_override(x: datatypes.Utf8Like) -> datatypes.Utf8: + if isinstance(x, datatypes.Utf8): + return x + else: + return datatypes.Utf8(x) + + +def _latest_at_query__time__special_field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(x) + + +@define(init=False) +class LatestAtQuery: + """**Datatype**: Visible time range bounds for a specific timeline.""" + + def __init__(self: Any, timeline: datatypes.Utf8Like, time: datatypes.TimeIntLike): + """ + Create a new instance of the LatestAtQuery datatype. + + Parameters + ---------- + timeline: + Name of the timeline this applies to. + time: + Time range to use for this timeline. + + """ + + # You can define your own __init__ function as a member of LatestAtQueryExt in latest_at_query_ext.py + self.__attrs_init__(timeline=timeline, time=time) + + timeline: datatypes.Utf8 = field(converter=_latest_at_query__timeline__special_field_converter_override) + # Name of the timeline this applies to. + # + # (Docstring intentionally commented out to hide this field from the docs) + + time: datatypes.TimeInt = field(converter=_latest_at_query__time__special_field_converter_override) + # Time range to use for this timeline. + # + # (Docstring intentionally commented out to hide this field from the docs) + + +LatestAtQueryLike = LatestAtQuery +LatestAtQueryArrayLike = Union[ + LatestAtQuery, + Sequence[LatestAtQueryLike], +] + + +class LatestAtQueryType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.datatypes.LatestAtQuery" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("time", pa.int64(), nullable=False, metadata={}), + ]), + self._TYPE_NAME, + ) + + +class LatestAtQueryBatch(BaseBatch[LatestAtQueryArrayLike]): + _ARROW_TYPE = LatestAtQueryType() + + @staticmethod + def _native_to_pa_array(data: LatestAtQueryArrayLike, data_type: pa.DataType) -> pa.Array: + from rerun.datatypes import TimeIntBatch, Utf8Batch + + if isinstance(data, LatestAtQuery): + data = [data] + + return pa.StructArray.from_arrays( + [ + Utf8Batch([x.timeline for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + TimeIntBatch([x.time for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + ], + fields=list(data_type), + ) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py new file mode 100644 index 000000000000..cd43dc17e2ce --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py @@ -0,0 +1,126 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +# You can extend this class by creating a "TimeRangeQueryExt" class in "time_range_query_ext.py". + +from __future__ import annotations + +from typing import Any, Sequence, Union + +import pyarrow as pa +from attrs import define, field + +from ... import datatypes +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, +) + +__all__ = [ + "TimeRangeQuery", + "TimeRangeQueryArrayLike", + "TimeRangeQueryBatch", + "TimeRangeQueryLike", + "TimeRangeQueryType", +] + + +def _time_range_query__timeline__special_field_converter_override(x: datatypes.Utf8Like) -> datatypes.Utf8: + if isinstance(x, datatypes.Utf8): + return x + else: + return datatypes.Utf8(x) + + +def _time_range_query__start__special_field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(x) + + +def _time_range_query__end__special_field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(x) + + +@define(init=False) +class TimeRangeQuery: + """**Datatype**: Visible time range bounds for a specific timeline.""" + + def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLike, end: datatypes.TimeIntLike): + """ + Create a new instance of the TimeRangeQuery datatype. + + Parameters + ---------- + timeline: + Name of the timeline this applies to. + start: + Start + end: + End + + """ + + # You can define your own __init__ function as a member of TimeRangeQueryExt in time_range_query_ext.py + self.__attrs_init__(timeline=timeline, start=start, end=end) + + timeline: datatypes.Utf8 = field(converter=_time_range_query__timeline__special_field_converter_override) + # Name of the timeline this applies to. + # + # (Docstring intentionally commented out to hide this field from the docs) + + start: datatypes.TimeInt = field(converter=_time_range_query__start__special_field_converter_override) + # Start + # + # (Docstring intentionally commented out to hide this field from the docs) + + end: datatypes.TimeInt = field(converter=_time_range_query__end__special_field_converter_override) + # End + # + # (Docstring intentionally commented out to hide this field from the docs) + + +TimeRangeQueryLike = TimeRangeQuery +TimeRangeQueryArrayLike = Union[ + TimeRangeQuery, + Sequence[TimeRangeQueryLike], +] + + +class TimeRangeQueryType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.datatypes.TimeRangeQuery" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("start", pa.int64(), nullable=False, metadata={}), + pa.field("end", pa.int64(), nullable=False, metadata={}), + ]), + self._TYPE_NAME, + ) + + +class TimeRangeQueryBatch(BaseBatch[TimeRangeQueryArrayLike]): + _ARROW_TYPE = TimeRangeQueryType() + + @staticmethod + def _native_to_pa_array(data: TimeRangeQueryArrayLike, data_type: pa.DataType) -> pa.Array: + from rerun.datatypes import TimeIntBatch, Utf8Batch + + if isinstance(data, TimeRangeQuery): + data = [data] + + return pa.StructArray.from_arrays( + [ + Utf8Batch([x.timeline for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + TimeIntBatch([x.start for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + TimeIntBatch([x.end for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + ], + fields=list(data_type), + ) From 3d6024e1d8d3fcc0f1cfe7b195048e091db77ec8 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Tue, 6 Aug 2024 10:18:20 +0200 Subject: [PATCH 02/18] Cleaned-up fbs --- .../rerun/blueprint/archetypes.fbs | 1 - .../blueprint/archetypes/dataframe_query.fbs | 43 +++-- .../archetypes/dataframe_view_mode.fbs | 14 -- .../rerun/blueprint/components.fbs | 2 +- .../components/dataframe_view_mode.fbs | 21 --- .../components/latest_at_queries.fbs | 8 +- .../rerun/blueprint/components/query_kind.fbs | 13 ++ .../components/time_range_queries.fbs | 8 +- .../blueprint/datatypes/latest_at_query.fbs | 4 +- .../blueprint/datatypes/time_range_query.fbs | 6 +- .../src/blueprint/archetypes/.gitattributes | 1 - .../blueprint/archetypes/dataframe_query.rs | 45 +++-- .../archetypes/dataframe_view_mode.rs | 163 ------------------ .../re_types/src/blueprint/archetypes/mod.rs | 2 - .../src/blueprint/components/.gitattributes | 2 +- .../components/dataframe_view_mode.rs | 159 ----------------- .../blueprint/components/latest_at_queries.rs | 10 +- .../re_types/src/blueprint/components/mod.rs | 4 +- .../src/blueprint/components/query_kind.rs | 163 ++++++++++++++++++ .../components/time_range_queries.rs | 10 +- .../src/blueprint/components/timeline_ext.rs | 2 + .../blueprint/datatypes/latest_at_query.rs | 4 +- .../blueprint/datatypes/time_range_query.rs | 6 +- crates/viewer/re_edit_ui/src/lib.rs | 6 +- .../src/space_view_class.rs | 8 +- .../re_space_view_dataframe/src/view_query.rs | 16 +- .../src/blueprint/validation_gen/mod.rs | 4 +- crates/viewer/re_viewer/src/reflection/mod.rs | 49 +++--- rerun_cpp/src/rerun/blueprint/archetypes.hpp | 1 - .../rerun/blueprint/archetypes/.gitattributes | 2 - .../blueprint/archetypes/dataframe_query.hpp | 32 ++-- .../archetypes/dataframe_view_mode.cpp | 33 ---- .../archetypes/dataframe_view_mode.hpp | 58 ------- rerun_cpp/src/rerun/blueprint/components.hpp | 2 +- .../rerun/blueprint/components/.gitattributes | 4 +- .../components/latest_at_queries.cpp | 6 +- .../components/latest_at_queries.hpp | 14 +- ...dataframe_view_mode.cpp => query_kind.cpp} | 37 ++-- ...dataframe_view_mode.hpp => query_kind.hpp} | 32 ++-- .../components/time_range_queries.cpp | 6 +- .../components/time_range_queries.hpp | 14 +- .../blueprint/datatypes/latest_at_query.hpp | 4 +- .../blueprint/datatypes/time_range_query.hpp | 6 +- .../rerun/blueprint/archetypes/.gitattributes | 1 - .../rerun/blueprint/archetypes/__init__.py | 2 - .../blueprint/archetypes/dataframe_query.py | 32 ++-- .../archetypes/dataframe_view_mode.py | 65 ------- .../rerun/blueprint/components/.gitattributes | 2 +- .../rerun/blueprint/components/__init__.py | 18 +- .../components/dataframe_view_mode.py | 90 ---------- .../blueprint/components/latest_at_queries.py | 12 +- .../rerun/blueprint/components/query_kind.py | 102 +++++++++++ .../components/time_range_queries.py | 12 +- .../blueprint/datatypes/latest_at_query.py | 6 +- .../blueprint/datatypes/time_range_query.py | 10 +- 55 files changed, 539 insertions(+), 838 deletions(-) delete mode 100644 crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs delete mode 100644 crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs delete mode 100644 crates/store/re_types/src/blueprint/components/dataframe_view_mode.rs create mode 100644 crates/store/re_types/src/blueprint/components/query_kind.rs delete mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp delete mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp rename rerun_cpp/src/rerun/blueprint/components/{dataframe_view_mode.cpp => query_kind.cpp} (56%) rename rerun_cpp/src/rerun/blueprint/components/{dataframe_view_mode.hpp => query_kind.hpp} (50%) delete mode 100644 rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py delete mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs index deb19bd78a5a..f6e6710b96b3 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs @@ -3,7 +3,6 @@ include "./archetypes/background.fbs"; include "./archetypes/container_blueprint.fbs"; include "./archetypes/dataframe_query.fbs"; -include "./archetypes/dataframe_view_mode.fbs"; include "./archetypes/panel_blueprint.fbs"; include "./archetypes/plot_legend.fbs"; include "./archetypes/scalar_axis.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs index a43fa4dbdc10..90f8ede34b98 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs @@ -1,37 +1,50 @@ namespace rerun.blueprint.archetypes; -/// Configuration for the dataframe view // Rationale behind the present data modelling: // - Avoid using `union` at all cost. // - An explicit "mode" enum maps well with a UI toggle and API parameter, and enabled a hard disambiguation when // settings are present for both the latest at and range modes. // - Timestamps are hard-invalidated by a change of timeline. So we keep them on a per-timeline basis. -// - On the contrary, chances are high that the user prefers to have their pov components _not_ invalidated by a change -// of timeline. + +// TODO(ab): add visible components and (optional) PoV components, to be modelled as: +// +// component PovComponents { +// datatype ComponentNames { +// value: [string]; +// } +// } +// Motivation: +// - Chances are high that the user prefers to have their pov components _not_ invalidated by a changeof timeline. // - That is even though a component might _technically_ be soft-invalidated by a change of timeline (e.g. if it was // not logged on that particular timeline). But we have to deal regardless with potentially invalid component, so this // doesn't change the story much. -//TODO: docs + +// -- + +/// The query for the dataframe view. table DataframeQuery ( "attr.rerun.scope": "blueprint", "attr.rust.generate_field_info" ) { // --- Optional --- - /// Name of the timeline this applies to. - timeline: rerun.blueprint.components.Timeline ("attr.rerun.component_optional", nullable, order: 100); - - /// Type of query: latest at or range - //TODO(ab): rename component - mode: rerun.blueprint.components.DataframeViewMode ("attr.rerun.component_optional", nullable,order: 200); + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + timeline: rerun.blueprint.components.Timeline ("attr.rerun.component_optional", nullable, order: 100); - /// Times (1 for latest at, 2 for range) - latest_at_queries: rerun.blueprint.components.LatestAtQueries ("attr.rerun.component_optional", nullable,order: 400); + /// Type of query: latest at or range + mode: rerun.blueprint.components.QueryKind ("attr.rerun.component_optional", nullable,order: 200); - /// Times (1 for latest at, 2 for range) - time_range_queries: rerun.blueprint.components.TimeRangeQueries ("attr.rerun.component_optional", nullable,order: 500); + /// Configuration for latest at queries.attribute + /// + /// Note: configuration as saved on a per-timeline basis. + latest_at_queries: rerun.blueprint.components.LatestAtQueries ("attr.rerun.component_optional", nullable,order: 400); - //TODO(ab): add (optional) PoV components, which range query supports + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. + time_range_queries: rerun.blueprint.components.TimeRangeQueries ("attr.rerun.component_optional", nullable,order: 500); } diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs deleted file mode 100644 index 86dba394426f..000000000000 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs +++ /dev/null @@ -1,14 +0,0 @@ -namespace rerun.blueprint.archetypes; - - -/// Configuration for the dataframe view -table DataframeViewMode ( - "attr.rerun.scope": "blueprint", - "attr.rust.derive": "Copy", - "attr.rust.generate_field_info" -) { - // --- Optional --- - - /// The kind of table to display - mode: rerun.blueprint.components.DataframeViewMode ("attr.rerun.component_optional", nullable, order: 1000); -} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components.fbs b/crates/store/re_types/definitions/rerun/blueprint/components.fbs index cda76572484c..5fc26f32fd92 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components.fbs @@ -7,7 +7,6 @@ include "./components/background_kind.fbs"; include "./components/column_share.fbs"; include "./components/container_kind.fbs"; include "./components/corner_2d.fbs"; -include "./components/dataframe_view_mode.fbs"; include "./components/grid_columns.fbs"; include "./components/included_content.fbs"; include "./components/included_space_view.fbs"; @@ -16,6 +15,7 @@ include "./components/latest_at_queries.fbs"; include "./components/lock_range_during_zoom.fbs"; include "./components/panel_state.fbs"; include "./components/query_expression.fbs"; +include "./components/query_kind.fbs"; include "./components/root_container.fbs"; include "./components/row_share.fbs"; include "./components/sort_key.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs index 3482f0e9b163..e69de29bb2d1 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs @@ -1,21 +0,0 @@ -namespace rerun.blueprint.components; - - -/// The kind of table displayed by the dataframe view -enum DataframeViewMode: byte ( - "attr.rerun.scope": "blueprint" -) { - /// Invalid value. Won't show up in generated types. - Invalid = 0, - - /// Display the entity values at the current time. - /// - /// In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. - LatestAt (default), - - /// Display a temporal table of entity values. - /// - /// In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - /// timestamp shown are determined by each view entity's visible time range setting. - TimeRange, -} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs index a91b248f12c6..666913f8e68c 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs @@ -1,14 +1,14 @@ namespace rerun.blueprint.components; -// --- -//TODO: sane default -/// Component(s) used as point-of-view for a query. +/// Configuration for latest at queries. +/// +/// Note: configuration as saved on a per-timeline basis. table LatestAtQueries ( "attr.arrow.transparent", "attr.rust.derive": "Default, PartialEq, Eq", "attr.rust.repr": "transparent", "attr.rerun.scope": "blueprint" ) { - value: [rerun.blueprint.datatypes.LatestAtQuery] (order: 100); + queries: [rerun.blueprint.datatypes.LatestAtQuery] (order: 100); } \ No newline at end of file diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs new file mode 100644 index 000000000000..ee36cf14dcf9 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs @@ -0,0 +1,13 @@ +namespace rerun.blueprint.components; + + +/// The kind of query displayed by the dataframe view +enum QueryKind: byte ( + "attr.rerun.scope": "blueprint" +) { + /// Query + LatestAt (default), + + /// Time range query. + TimeRange, +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs index e93c325fd7dc..e22c75bce40f 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs @@ -1,14 +1,14 @@ namespace rerun.blueprint.components; -// --- -//TODO: sane default -/// Component(s) used as point-of-view for a query. +/// Configuration for time range queries. +/// +/// Note: configuration as saved on a per-timeline basis. table TimeRangeQueries ( "attr.arrow.transparent", "attr.rust.derive": "Default, PartialEq, Eq", "attr.rust.repr": "transparent", "attr.rerun.scope": "blueprint" ) { - value: [rerun.blueprint.datatypes.TimeRangeQuery] (order: 100); + queries: [rerun.blueprint.datatypes.TimeRangeQuery] (order: 100); } \ No newline at end of file diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs index 87673ca21d17..eb03f3361352 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs @@ -1,7 +1,7 @@ namespace rerun.blueprint.datatypes; -/// Visible time range bounds for a specific timeline. +/// Latest at query configuration for a specific timeline. // Has to be a table because flatbuffer doesn't support strings in structs. table LatestAtQuery ( "attr.rust.derive": "PartialEq, Eq", @@ -10,6 +10,6 @@ table LatestAtQuery ( /// Name of the timeline this applies to. timeline: rerun.datatypes.Utf8 (order: 100); - /// Time range to use for this timeline. + /// Time value to use for this query. time: rerun.datatypes.TimeInt (order: 200); } diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs index c736c5648f67..8387cda25070 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs @@ -1,7 +1,7 @@ namespace rerun.blueprint.datatypes; -/// Visible time range bounds for a specific timeline. +/// Time range query configuration for a specific timeline. // Has to be a table because flatbuffer doesn't support strings in structs. table TimeRangeQuery ( "attr.rust.derive": "PartialEq, Eq", @@ -10,9 +10,9 @@ table TimeRangeQuery ( /// Name of the timeline this applies to. timeline: rerun.datatypes.Utf8 (order: 100); - /// Start + /// Begining of the time range. start: rerun.datatypes.TimeInt (order: 200); - /// End + /// End of the time range. end: rerun.datatypes.TimeInt (order: 300); } diff --git a/crates/store/re_types/src/blueprint/archetypes/.gitattributes b/crates/store/re_types/src/blueprint/archetypes/.gitattributes index 3769b8b507be..51fc7263ee37 100644 --- a/crates/store/re_types/src/blueprint/archetypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/archetypes/.gitattributes @@ -3,7 +3,6 @@ .gitattributes linguist-generated=true background.rs linguist-generated=true dataframe_query.rs linguist-generated=true -dataframe_view_mode.rs linguist-generated=true mod.rs linguist-generated=true plot_legend.rs linguist-generated=true scalar_axis.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs index 7768a56cc5f2..551222d47594 100644 --- a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs +++ b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs @@ -18,19 +18,25 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Archetype**: Configuration for the dataframe view +/// **Archetype**: The query for the dataframe view. #[derive(Clone, Debug)] pub struct DataframeQuery { - /// Name of the timeline this applies to. + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. pub timeline: Option, /// Type of query: latest at or range - pub mode: Option, + pub mode: Option, - /// Times (1 for latest at, 2 for range) + /// Configuration for latest at queries.attribute + /// + /// Note: configuration as saved on a per-timeline basis. pub latest_at_queries: Option, - /// Times (1 for latest at, 2 for range) + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. pub time_range_queries: Option, } @@ -46,7 +52,7 @@ impl ::re_types_core::SizeBytes for DataframeQuery { #[inline] fn is_pod() -> bool { >::is_pod() - && >::is_pod() + && >::is_pod() && >::is_pod() && >::is_pod() } @@ -62,7 +68,7 @@ static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = once_cell::sync::Lazy::new(|| { [ "rerun.blueprint.components.Timeline".into(), - "rerun.blueprint.components.DataframeViewMode".into(), + "rerun.blueprint.components.QueryKind".into(), "rerun.blueprint.components.LatestAtQueries".into(), "rerun.blueprint.components.TimeRangeQueries".into(), ] @@ -73,7 +79,7 @@ static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 5usize]> = [ "rerun.blueprint.components.DataframeQueryIndicator".into(), "rerun.blueprint.components.Timeline".into(), - "rerun.blueprint.components.DataframeViewMode".into(), + "rerun.blueprint.components.QueryKind".into(), "rerun.blueprint.components.LatestAtQueries".into(), "rerun.blueprint.components.TimeRangeQueries".into(), ] @@ -146,10 +152,8 @@ impl ::re_types_core::Archetype for DataframeQuery { } else { None }; - let mode = if let Some(array) = - arrays_by_name.get("rerun.blueprint.components.DataframeViewMode") - { - ::from_arrow_opt(&**array) + let mode = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.QueryKind") { + ::from_arrow_opt(&**array) .with_context("rerun.blueprint.archetypes.DataframeQuery#mode")? .into_iter() .next() @@ -226,7 +230,9 @@ impl DataframeQuery { } } - /// Name of the timeline this applies to. + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. #[inline] pub fn with_timeline( mut self, @@ -238,15 +244,14 @@ impl DataframeQuery { /// Type of query: latest at or range #[inline] - pub fn with_mode( - mut self, - mode: impl Into, - ) -> Self { + pub fn with_mode(mut self, mode: impl Into) -> Self { self.mode = Some(mode.into()); self } - /// Times (1 for latest at, 2 for range) + /// Configuration for latest at queries.attribute + /// + /// Note: configuration as saved on a per-timeline basis. #[inline] pub fn with_latest_at_queries( mut self, @@ -256,7 +261,9 @@ impl DataframeQuery { self } - /// Times (1 for latest at, 2 for range) + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. #[inline] pub fn with_time_range_queries( mut self, diff --git a/crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs b/crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs deleted file mode 100644 index ec2fb4e9f008..000000000000 --- a/crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs +++ /dev/null @@ -1,163 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -#![allow(unused_imports)] -#![allow(unused_parens)] -#![allow(clippy::clone_on_copy)] -#![allow(clippy::cloned_instead_of_copied)] -#![allow(clippy::map_flatten)] -#![allow(clippy::needless_question_mark)] -#![allow(clippy::new_without_default)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::too_many_lines)] - -use ::re_types_core::external::arrow2; -use ::re_types_core::ComponentName; -use ::re_types_core::SerializationResult; -use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; -use ::re_types_core::{DeserializationError, DeserializationResult}; - -/// **Archetype**: Configuration for the dataframe view -#[derive(Clone, Debug, Copy)] -pub struct DataframeViewMode { - /// The kind of table to display - pub mode: Option, -} - -impl ::re_types_core::SizeBytes for DataframeViewMode { - #[inline] - fn heap_size_bytes(&self) -> u64 { - self.mode.heap_size_bytes() - } - - #[inline] - fn is_pod() -> bool { - >::is_pod() - } -} - -static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = - once_cell::sync::Lazy::new(|| []); - -static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = - once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.DataframeViewModeIndicator".into()]); - -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = - once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.DataframeViewMode".into()]); - -static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = - once_cell::sync::Lazy::new(|| { - [ - "rerun.blueprint.components.DataframeViewModeIndicator".into(), - "rerun.blueprint.components.DataframeViewMode".into(), - ] - }); - -impl DataframeViewMode { - /// The total number of components in the archetype: 0 required, 1 recommended, 1 optional - pub const NUM_COMPONENTS: usize = 2usize; -} - -/// Indicator component for the [`DataframeViewMode`] [`::re_types_core::Archetype`] -pub type DataframeViewModeIndicator = ::re_types_core::GenericIndicatorComponent; - -impl ::re_types_core::Archetype for DataframeViewMode { - type Indicator = DataframeViewModeIndicator; - - #[inline] - fn name() -> ::re_types_core::ArchetypeName { - "rerun.blueprint.archetypes.DataframeViewMode".into() - } - - #[inline] - fn display_name() -> &'static str { - "Dataframe view mode" - } - - #[inline] - fn indicator() -> MaybeOwnedComponentBatch<'static> { - static INDICATOR: DataframeViewModeIndicator = DataframeViewModeIndicator::DEFAULT; - MaybeOwnedComponentBatch::Ref(&INDICATOR) - } - - #[inline] - fn required_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - REQUIRED_COMPONENTS.as_slice().into() - } - - #[inline] - fn recommended_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - RECOMMENDED_COMPONENTS.as_slice().into() - } - - #[inline] - fn optional_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - OPTIONAL_COMPONENTS.as_slice().into() - } - - #[inline] - fn all_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - ALL_COMPONENTS.as_slice().into() - } - - #[inline] - fn from_arrow_components( - arrow_data: impl IntoIterator)>, - ) -> DeserializationResult { - re_tracing::profile_function!(); - use ::re_types_core::{Loggable as _, ResultExt as _}; - let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data - .into_iter() - .map(|(name, array)| (name.full_name(), array)) - .collect(); - let mode = if let Some(array) = - arrays_by_name.get("rerun.blueprint.components.DataframeViewMode") - { - ::from_arrow_opt(&**array) - .with_context("rerun.blueprint.archetypes.DataframeViewMode#mode")? - .into_iter() - .next() - .flatten() - } else { - None - }; - Ok(Self { mode }) - } -} - -impl ::re_types_core::AsComponents for DataframeViewMode { - fn as_component_batches(&self) -> Vec> { - re_tracing::profile_function!(); - use ::re_types_core::Archetype as _; - [ - Some(Self::indicator()), - self.mode - .as_ref() - .map(|comp| (comp as &dyn ComponentBatch).into()), - ] - .into_iter() - .flatten() - .collect() - } -} - -impl ::re_types_core::ArchetypeReflectionMarker for DataframeViewMode {} - -impl DataframeViewMode { - /// Create a new `DataframeViewMode`. - #[inline] - pub fn new() -> Self { - Self { mode: None } - } - - /// The kind of table to display - #[inline] - pub fn with_mode( - mut self, - mode: impl Into, - ) -> Self { - self.mode = Some(mode.into()); - self - } -} diff --git a/crates/store/re_types/src/blueprint/archetypes/mod.rs b/crates/store/re_types/src/blueprint/archetypes/mod.rs index ce7f3454cb5f..e0616353c032 100644 --- a/crates/store/re_types/src/blueprint/archetypes/mod.rs +++ b/crates/store/re_types/src/blueprint/archetypes/mod.rs @@ -2,7 +2,6 @@ mod background; mod dataframe_query; -mod dataframe_view_mode; mod plot_legend; mod scalar_axis; mod space_view_blueprint; @@ -17,7 +16,6 @@ mod visual_bounds2d; pub use self::background::Background; pub use self::dataframe_query::DataframeQuery; -pub use self::dataframe_view_mode::DataframeViewMode; pub use self::plot_legend::PlotLegend; pub use self::scalar_axis::ScalarAxis; pub use self::space_view_blueprint::SpaceViewBlueprint; diff --git a/crates/store/re_types/src/blueprint/components/.gitattributes b/crates/store/re_types/src/blueprint/components/.gitattributes index f2a0d54cc97d..5ec5bbf2c49a 100644 --- a/crates/store/re_types/src/blueprint/components/.gitattributes +++ b/crates/store/re_types/src/blueprint/components/.gitattributes @@ -5,7 +5,6 @@ active_tab.rs linguist-generated=true background_kind.rs linguist-generated=true column_share.rs linguist-generated=true corner2d.rs linguist-generated=true -dataframe_view_mode.rs linguist-generated=true included_content.rs linguist-generated=true interactive.rs linguist-generated=true latest_at_queries.rs linguist-generated=true @@ -13,6 +12,7 @@ lock_range_during_zoom.rs linguist-generated=true mod.rs linguist-generated=true panel_state.rs linguist-generated=true query_expression.rs linguist-generated=true +query_kind.rs linguist-generated=true row_share.rs linguist-generated=true sort_key.rs linguist-generated=true sort_order.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/components/dataframe_view_mode.rs b/crates/store/re_types/src/blueprint/components/dataframe_view_mode.rs deleted file mode 100644 index 9a38e47cddff..000000000000 --- a/crates/store/re_types/src/blueprint/components/dataframe_view_mode.rs +++ /dev/null @@ -1,159 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". - -#![allow(unused_imports)] -#![allow(unused_parens)] -#![allow(clippy::clone_on_copy)] -#![allow(clippy::cloned_instead_of_copied)] -#![allow(clippy::map_flatten)] -#![allow(clippy::needless_question_mark)] -#![allow(clippy::new_without_default)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::too_many_lines)] - -use ::re_types_core::external::arrow2; -use ::re_types_core::ComponentName; -use ::re_types_core::SerializationResult; -use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; -use ::re_types_core::{DeserializationError, DeserializationResult}; - -/// **Component**: The kind of table displayed by the dataframe view -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] -#[repr(u8)] -pub enum DataframeViewMode { - /// Display the entity values at the current time. - /// - /// In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. - #[default] - LatestAt = 1, - - /// Display a temporal table of entity values. - /// - /// In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - /// timestamp shown are determined by each view entity's visible time range setting. - TimeRange = 2, -} - -impl ::re_types_core::reflection::Enum for DataframeViewMode { - #[inline] - fn variants() -> &'static [Self] { - &[Self::LatestAt, Self::TimeRange] - } - - #[inline] - fn docstring_md(self) -> &'static str { - match self { - Self::LatestAt => { - "Display the entity values at the current time.\n\nIn this mode, rows are entity instances, and columns are components. The visible time range setting is ignored." - } - Self::TimeRange => { - "Display a temporal table of entity values.\n\nIn this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The\ntimestamp shown are determined by each view entity's visible time range setting." - } - } - } -} - -impl ::re_types_core::SizeBytes for DataframeViewMode { - #[inline] - fn heap_size_bytes(&self) -> u64 { - 0 - } - - #[inline] - fn is_pod() -> bool { - true - } -} - -impl std::fmt::Display for DataframeViewMode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::LatestAt => write!(f, "LatestAt"), - Self::TimeRange => write!(f, "TimeRange"), - } - } -} - -::re_types_core::macros::impl_into_cow!(DataframeViewMode); - -impl ::re_types_core::Loggable for DataframeViewMode { - type Name = ::re_types_core::ComponentName; - - #[inline] - fn name() -> Self::Name { - "rerun.blueprint.components.DataframeViewMode".into() - } - - #[inline] - fn arrow_datatype() -> arrow2::datatypes::DataType { - #![allow(clippy::wildcard_imports)] - use arrow2::datatypes::*; - DataType::UInt8 - } - - fn to_arrow_opt<'a>( - data: impl IntoIterator>>>, - ) -> SerializationResult> - where - Self: Clone + 'a, - { - #![allow(clippy::wildcard_imports)] - use ::re_types_core::{Loggable as _, ResultExt as _}; - use arrow2::{array::*, datatypes::*}; - Ok({ - let (somes, data0): (Vec<_>, Vec<_>) = data - .into_iter() - .map(|datum| { - let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); - let datum = datum.map(|datum| *datum as u8); - (datum.is_some(), datum) - }) - .unzip(); - let data0_bitmap: Option = { - let any_nones = somes.iter().any(|some| !*some); - any_nones.then(|| somes.into()) - }; - PrimitiveArray::new( - Self::arrow_datatype(), - data0.into_iter().map(|v| v.unwrap_or_default()).collect(), - data0_bitmap, - ) - .boxed() - }) - } - - fn from_arrow_opt( - arrow_data: &dyn arrow2::array::Array, - ) -> DeserializationResult>> - where - Self: Sized, - { - #![allow(clippy::wildcard_imports)] - use ::re_types_core::{Loggable as _, ResultExt as _}; - use arrow2::{array::*, buffer::*, datatypes::*}; - Ok(arrow_data - .as_any() - .downcast_ref::() - .ok_or_else(|| { - let expected = Self::arrow_datatype(); - let actual = arrow_data.data_type().clone(); - DeserializationError::datatype_mismatch(expected, actual) - }) - .with_context("rerun.blueprint.components.DataframeViewMode#enum")? - .into_iter() - .map(|opt| opt.copied()) - .map(|typ| match typ { - Some(1) => Ok(Some(Self::LatestAt)), - Some(2) => Ok(Some(Self::TimeRange)), - None => Ok(None), - Some(invalid) => Err(DeserializationError::missing_union_arm( - Self::arrow_datatype(), - "", - invalid as _, - )), - }) - .collect::>>>() - .with_context("rerun.blueprint.components.DataframeViewMode")?) - } -} diff --git a/crates/store/re_types/src/blueprint/components/latest_at_queries.rs b/crates/store/re_types/src/blueprint/components/latest_at_queries.rs index 40799a8a059b..50c87e763ba0 100644 --- a/crates/store/re_types/src/blueprint/components/latest_at_queries.rs +++ b/crates/store/re_types/src/blueprint/components/latest_at_queries.rs @@ -18,7 +18,9 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Component**: Component(s) used as point-of-view for a query. +/// **Component**: Configuration for latest at queries. +/// +/// Note: configuration as saved on a per-timeline basis. #[derive(Clone, Debug, Default, PartialEq, Eq)] #[repr(transparent)] pub struct LatestAtQueries(pub Vec); @@ -130,14 +132,14 @@ impl ::re_types_core::Loggable for LatestAtQueries { let actual = arrow_data.data_type().clone(); DeserializationError::datatype_mismatch(expected, actual) }) - .with_context("rerun.blueprint.components.LatestAtQueries#value")?; + .with_context("rerun.blueprint.components.LatestAtQueries#queries")?; if arrow_data.is_empty() { Vec::new() } else { let arrow_data_inner = { let arrow_data_inner = &**arrow_data.values(); crate::blueprint::datatypes::LatestAtQuery::from_arrow_opt(arrow_data_inner) - .with_context("rerun.blueprint.components.LatestAtQueries#value")? + .with_context("rerun.blueprint.components.LatestAtQueries#queries")? .into_iter() .collect::>() }; @@ -175,7 +177,7 @@ impl ::re_types_core::Loggable for LatestAtQueries { .map(|v| v.ok_or_else(DeserializationError::missing_data)) .map(|res| res.map(|v| Some(Self(v)))) .collect::>>>() - .with_context("rerun.blueprint.components.LatestAtQueries#value") + .with_context("rerun.blueprint.components.LatestAtQueries#queries") .with_context("rerun.blueprint.components.LatestAtQueries")?) } } diff --git a/crates/store/re_types/src/blueprint/components/mod.rs b/crates/store/re_types/src/blueprint/components/mod.rs index e66d5e398307..8ae5cec561e5 100644 --- a/crates/store/re_types/src/blueprint/components/mod.rs +++ b/crates/store/re_types/src/blueprint/components/mod.rs @@ -5,7 +5,6 @@ mod background_kind; mod column_share; mod corner2d; mod corner2d_ext; -mod dataframe_view_mode; mod included_content; mod interactive; mod interactive_ext; @@ -15,6 +14,7 @@ mod lock_range_during_zoom; mod panel_state; mod panel_state_ext; mod query_expression; +mod query_kind; mod row_share; mod sort_key; mod sort_order; @@ -41,13 +41,13 @@ pub use self::active_tab::ActiveTab; pub use self::background_kind::BackgroundKind; pub use self::column_share::ColumnShare; pub use self::corner2d::Corner2D; -pub use self::dataframe_view_mode::DataframeViewMode; pub use self::included_content::IncludedContent; pub use self::interactive::Interactive; pub use self::latest_at_queries::LatestAtQueries; pub use self::lock_range_during_zoom::LockRangeDuringZoom; pub use self::panel_state::PanelState; pub use self::query_expression::QueryExpression; +pub use self::query_kind::QueryKind; pub use self::row_share::RowShare; pub use self::sort_key::SortKey; pub use self::sort_order::SortOrder; diff --git a/crates/store/re_types/src/blueprint/components/query_kind.rs b/crates/store/re_types/src/blueprint/components/query_kind.rs new file mode 100644 index 000000000000..87d79eff06f4 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/query_kind.rs @@ -0,0 +1,163 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: The kind of query displayed by the dataframe view +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] +pub enum QueryKind { + /// Query + #[default] + LatestAt = 1, + + /// Time range query. + TimeRange = 2, +} + +impl ::re_types_core::reflection::Enum for QueryKind { + #[inline] + fn variants() -> &'static [Self] { + &[Self::LatestAt, Self::TimeRange] + } + + #[inline] + fn docstring_md(self) -> &'static str { + match self { + Self::LatestAt => "Query", + Self::TimeRange => "Time range query.", + } + } +} + +impl ::re_types_core::SizeBytes for QueryKind { + #[inline] + fn heap_size_bytes(&self) -> u64 { + 0 + } + + #[inline] + fn is_pod() -> bool { + true + } +} + +impl std::fmt::Display for QueryKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::LatestAt => write!(f, "LatestAt"), + Self::TimeRange => write!(f, "TimeRange"), + } + } +} + +::re_types_core::macros::impl_into_cow!(QueryKind); + +impl ::re_types_core::Loggable for QueryKind { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.QueryKind".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::Union( + std::sync::Arc::new(vec![ + Field::new("_null_markers", DataType::Null, true), + Field::new("LatestAt", DataType::Null, true), + Field::new("TimeRange", DataType::Null, true), + ]), + Some(std::sync::Arc::new(vec![0i32, 1i32, 2i32])), + UnionMode::Sparse, + ) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + // Sparse Arrow union + let data: Vec<_> = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + datum + }) + .collect(); + let num_variants = 2usize; + let types = data + .iter() + .map(|a| match a.as_deref() { + None => 0, + Some(value) => *value as i8, + }) + .collect(); + let fields: Vec<_> = + std::iter::repeat(NullArray::new(DataType::Null, data.len()).boxed()) + .take(1 + num_variants) + .collect(); + UnionArray::new(Self::arrow_datatype(), types, fields, None).boxed() + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.QueryKind")?; + let arrow_data_types = arrow_data.types(); + arrow_data_types + .iter() + .map(|typ| match typ { + 0 => Ok(None), + 1 => Ok(Some(Self::LatestAt)), + 2 => Ok(Some(Self::TimeRange)), + _ => Err(DeserializationError::missing_union_arm( + Self::arrow_datatype(), + "", + *typ as _, + )), + }) + .collect::>>() + .with_context("rerun.blueprint.components.QueryKind")? + }) + } +} diff --git a/crates/store/re_types/src/blueprint/components/time_range_queries.rs b/crates/store/re_types/src/blueprint/components/time_range_queries.rs index 205a6adcf937..34eecb5613e5 100644 --- a/crates/store/re_types/src/blueprint/components/time_range_queries.rs +++ b/crates/store/re_types/src/blueprint/components/time_range_queries.rs @@ -18,7 +18,9 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Component**: Component(s) used as point-of-view for a query. +/// **Component**: Configuration for time range queries. +/// +/// Note: configuration as saved on a per-timeline basis. #[derive(Clone, Debug, Default, PartialEq, Eq)] #[repr(transparent)] pub struct TimeRangeQueries(pub Vec); @@ -130,14 +132,14 @@ impl ::re_types_core::Loggable for TimeRangeQueries { let actual = arrow_data.data_type().clone(); DeserializationError::datatype_mismatch(expected, actual) }) - .with_context("rerun.blueprint.components.TimeRangeQueries#value")?; + .with_context("rerun.blueprint.components.TimeRangeQueries#queries")?; if arrow_data.is_empty() { Vec::new() } else { let arrow_data_inner = { let arrow_data_inner = &**arrow_data.values(); crate::blueprint::datatypes::TimeRangeQuery::from_arrow_opt(arrow_data_inner) - .with_context("rerun.blueprint.components.TimeRangeQueries#value")? + .with_context("rerun.blueprint.components.TimeRangeQueries#queries")? .into_iter() .collect::>() }; @@ -175,7 +177,7 @@ impl ::re_types_core::Loggable for TimeRangeQueries { .map(|v| v.ok_or_else(DeserializationError::missing_data)) .map(|res| res.map(|v| Some(Self(v)))) .collect::>>>() - .with_context("rerun.blueprint.components.TimeRangeQueries#value") + .with_context("rerun.blueprint.components.TimeRangeQueries#queries") .with_context("rerun.blueprint.components.TimeRangeQueries")?) } } diff --git a/crates/store/re_types/src/blueprint/components/timeline_ext.rs b/crates/store/re_types/src/blueprint/components/timeline_ext.rs index 04d91586be5e..fdb3cfdedd2f 100644 --- a/crates/store/re_types/src/blueprint/components/timeline_ext.rs +++ b/crates/store/re_types/src/blueprint/components/timeline_ext.rs @@ -3,10 +3,12 @@ use re_log_types::TimelineName; use super::Timeline; impl Timeline { + /// Return the name of the timeline. pub fn timeline_name(&self) -> TimelineName { TimelineName::from(self.0.as_str()) } + /// Set the name of the timeline. pub fn set_timeline_name(&mut self, timeline_name: TimelineName) { self.0 = timeline_name.as_str().into() } diff --git a/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs b/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs index d64d2f2e9518..e8a888f13f63 100644 --- a/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs +++ b/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs @@ -18,13 +18,13 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Datatype**: Visible time range bounds for a specific timeline. +/// **Datatype**: Latest at query configuration for a specific timeline. #[derive(Clone, Debug, PartialEq, Eq)] pub struct LatestAtQuery { /// Name of the timeline this applies to. pub timeline: crate::datatypes::Utf8, - /// Time range to use for this timeline. + /// Time value to use for this query. pub time: crate::datatypes::TimeInt, } diff --git a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs index b5eb7bed6fff..b8ce7bac9cf2 100644 --- a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs +++ b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs @@ -18,16 +18,16 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Datatype**: Visible time range bounds for a specific timeline. +/// **Datatype**: Time range query configuration for a specific timeline. #[derive(Clone, Debug, PartialEq, Eq)] pub struct TimeRangeQuery { /// Name of the timeline this applies to. pub timeline: crate::datatypes::Utf8, - /// Start + /// Begining of the time range. pub start: crate::datatypes::TimeInt, - /// End + /// End of the time range. pub end: crate::datatypes::TimeInt, } diff --git a/crates/viewer/re_edit_ui/src/lib.rs b/crates/viewer/re_edit_ui/src/lib.rs index d99d0eec86dd..98abbb9ed799 100644 --- a/crates/viewer/re_edit_ui/src/lib.rs +++ b/crates/viewer/re_edit_ui/src/lib.rs @@ -20,8 +20,8 @@ use datatype_editors::{ }; use re_types::{ blueprint::components::{ - BackgroundKind, Corner2D, DataframeViewMode, LockRangeDuringZoom, SortKey, SortOrder, - Timeline, ViewFit, Visible, + BackgroundKind, Corner2D, LockRangeDuringZoom, QueryKind, SortKey, SortOrder, Timeline, + ViewFit, Visible, }, components::{ AggregationPolicy, AlbedoFactor, AxisLength, ChannelDatatype, Color, ColorModel, Colormap, @@ -78,7 +78,7 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); - registry.add_singleline_edit_or_view::(edit_view_enum); + registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index 05812afd0dca..b43689ce5045 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -27,7 +27,7 @@ use crate::{ /// `https://github.com/rerun-io/rerun/issues/6918`. #[derive(Debug, Default)] struct DataframeViewState { - mode: components::DataframeViewMode, + mode: components::QueryKind, } impl SpaceViewState for DataframeViewState { @@ -109,10 +109,8 @@ mode sets the default time range to _everything_. You can override this in the s .unwrap_or_default(); match mode { - components::DataframeViewMode::LatestAt => QueryRange::LatestAt, - components::DataframeViewMode::TimeRange => { - QueryRange::TimeRange(TimeRange::EVERYTHING) - } + components::QueryKind::LatestAt => QueryRange::LatestAt, + components::QueryKind::TimeRange => QueryRange::TimeRange(TimeRange::EVERYTHING), } } diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index 961e5fd06bbb..e28bd6e5aa45 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -1,7 +1,7 @@ use egui::{NumExt, Response}; use re_entity_db::TimeHistogram; use re_log_types::{TimeInt, TimeType, TimeZone, TimelineName}; -use re_types::blueprint::components::DataframeViewMode; +use re_types::blueprint::components::QueryKind; use re_types::blueprint::datatypes::LatestAtQuery; use re_types::blueprint::{archetypes, components, datatypes}; use re_types_core::{Archetype as _, ComponentName, Loggable as _}; @@ -52,14 +52,14 @@ impl Query { .as_str(), ); - let mode = property.component_or_fallback::( + let mode = property.component_or_fallback::( ctx, fallback_provider, state, )?; let mode = match mode { - DataframeViewMode::LatestAt => { + QueryKind::LatestAt => { let time = property .component_or_fallback::( ctx, @@ -80,7 +80,7 @@ impl Query { QueryMode::LatestAt { time } } - DataframeViewMode::TimeRange => { + QueryKind::TimeRange => { let (from, to) = property .component_or_fallback::( ctx, @@ -132,7 +132,7 @@ impl Query { space_view_id, ); - let current_mode = property.component_or_fallback::( + let current_mode = property.component_or_fallback::( ctx, fallback_provider, state, @@ -184,7 +184,7 @@ impl Query { // Mode // - let component_name = components::DataframeViewMode::name(); + let component_name = components::QueryKind::name(); ui.list_item_flat_noninteractive(list_item::PropertyContent::new("Mode").value_fn( |ui, _| { ctx.component_ui_registry.singleline_edit_ui( @@ -210,7 +210,7 @@ impl Query { }; match current_mode { - DataframeViewMode::LatestAt => { + QueryKind::LatestAt => { // // Latest At time // TODO(ab): we can't use edit ui because we dont have the required context @@ -264,7 +264,7 @@ impl Query { }), ); } - DataframeViewMode::TimeRange => { + QueryKind::TimeRange => { // // Range times diff --git a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs index 14618ca18010..afdc23a80a25 100644 --- a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs @@ -5,13 +5,13 @@ pub use re_types::blueprint::components::ActiveTab; pub use re_types::blueprint::components::BackgroundKind; pub use re_types::blueprint::components::ColumnShare; pub use re_types::blueprint::components::Corner2D; -pub use re_types::blueprint::components::DataframeViewMode; pub use re_types::blueprint::components::IncludedContent; pub use re_types::blueprint::components::Interactive; pub use re_types::blueprint::components::LatestAtQueries; pub use re_types::blueprint::components::LockRangeDuringZoom; pub use re_types::blueprint::components::PanelState; pub use re_types::blueprint::components::QueryExpression; +pub use re_types::blueprint::components::QueryKind; pub use re_types::blueprint::components::RowShare; pub use re_types::blueprint::components::SortKey; pub use re_types::blueprint::components::SortOrder; @@ -45,7 +45,6 @@ pub fn is_valid_blueprint(blueprint: &EntityDb) -> bool { && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) - && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) @@ -54,6 +53,7 @@ pub fn is_valid_blueprint(blueprint: &EntityDb) -> bool { && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 12a4c11bdcdd..bdae166365e7 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -83,13 +83,6 @@ fn generate_component_reflection() -> Result::name(), - ComponentReflection { - docstring_md: "The kind of table displayed by the dataframe view", - placeholder: Some(DataframeViewMode::default().to_arrow()?), - }, - ), ( ::name(), ComponentReflection { @@ -121,7 +114,7 @@ fn generate_component_reflection() -> Result::name(), ComponentReflection { - docstring_md: "Component(s) used as point-of-view for a query.", + docstring_md: "Configuration for latest at queries.\n\nNote: configuration as saved on a per-timeline basis.", placeholder: Some(LatestAtQueries::default().to_arrow()?), }, ), @@ -146,6 +139,13 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "The kind of query displayed by the dataframe view", + placeholder: Some(QueryKind::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -205,7 +205,7 @@ fn generate_component_reflection() -> Result::name(), ComponentReflection { - docstring_md: "Component(s) used as point-of-view for a query.", + docstring_md: "Configuration for time range queries.\n\nNote: configuration as saved on a per-timeline basis.", placeholder: Some(TimeRangeQueries::default().to_arrow()?), }, ), @@ -771,33 +771,24 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { ArchetypeName::new("rerun.blueprint.archetypes.DataframeQuery"), ArchetypeReflection { display_name: "Dataframe query", - docstring_md: "Configuration for the dataframe view", + docstring_md: "The query for the dataframe view.", fields: vec![ ArchetypeFieldReflection { component_name : "rerun.blueprint.components.Timeline".into(), display_name : - "Timeline", docstring_md : "Name of the timeline this applies to.", + "Timeline", docstring_md : + "The timeline for this query.\n\nIf unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype.", }, ArchetypeFieldReflection { component_name : - "rerun.blueprint.components.DataframeViewMode".into(), display_name : - "Mode", docstring_md : "Type of query: latest at or range", }, + "rerun.blueprint.components.QueryKind".into(), display_name : "Mode", + docstring_md : "Type of query: latest at or range", }, ArchetypeFieldReflection { component_name : "rerun.blueprint.components.LatestAtQueries".into(), display_name : "Latest at queries", docstring_md : - "Times (1 for latest at, 2 for range)", }, ArchetypeFieldReflection { - component_name : "rerun.blueprint.components.TimeRangeQueries" - .into(), display_name : "Time range queries", docstring_md : - "Times (1 for latest at, 2 for range)", }, - ], - }, - ), - ( - ArchetypeName::new("rerun.blueprint.archetypes.DataframeViewMode"), - ArchetypeReflection { - display_name: "Dataframe view mode", - docstring_md: "Configuration for the dataframe view", - fields: vec![ - ArchetypeFieldReflection { component_name : - "rerun.blueprint.components.DataframeViewMode".into(), display_name : - "Mode", docstring_md : "The kind of table to display", }, + "Configuration for latest at queries.attribute\n\nNote: configuration as saved on a per-timeline basis.", + }, ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.TimeRangeQueries".into(), display_name : + "Time range queries", docstring_md : + "Configuration for the time range queries.\n\nNote: configuration as saved on a per-timeline basis.", + }, ], }, ), diff --git a/rerun_cpp/src/rerun/blueprint/archetypes.hpp b/rerun_cpp/src/rerun/blueprint/archetypes.hpp index 6a31bb9502c2..39a6b0f8053b 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes.hpp @@ -5,7 +5,6 @@ #include "blueprint/archetypes/background.hpp" #include "blueprint/archetypes/container_blueprint.hpp" #include "blueprint/archetypes/dataframe_query.hpp" -#include "blueprint/archetypes/dataframe_view_mode.hpp" #include "blueprint/archetypes/panel_blueprint.hpp" #include "blueprint/archetypes/plot_legend.hpp" #include "blueprint/archetypes/scalar_axis.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes index db276da6126a..eae6a969df5b 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes @@ -7,8 +7,6 @@ container_blueprint.cpp linguist-generated=true container_blueprint.hpp linguist-generated=true dataframe_query.cpp linguist-generated=true dataframe_query.hpp linguist-generated=true -dataframe_view_mode.cpp linguist-generated=true -dataframe_view_mode.hpp linguist-generated=true panel_blueprint.cpp linguist-generated=true panel_blueprint.hpp linguist-generated=true plot_legend.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp index d9124b943041..bc770be02a9d 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp @@ -3,8 +3,8 @@ #pragma once -#include "../../blueprint/components/dataframe_view_mode.hpp" #include "../../blueprint/components/latest_at_queries.hpp" +#include "../../blueprint/components/query_kind.hpp" #include "../../blueprint/components/time_range_queries.hpp" #include "../../blueprint/components/timeline.hpp" #include "../../collection.hpp" @@ -19,18 +19,24 @@ #include namespace rerun::blueprint::archetypes { - /// **Archetype**: Configuration for the dataframe view + /// **Archetype**: The query for the dataframe view. struct DataframeQuery { - /// Name of the timeline this applies to. + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. std::optional timeline; /// Type of query: latest at or range - std::optional mode; + std::optional mode; - /// Times (1 for latest at, 2 for range) + /// Configuration for latest at queries.attribute + /// + /// Note: configuration as saved on a per-timeline basis. std::optional latest_at_queries; - /// Times (1 for latest at, 2 for range) + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. std::optional time_range_queries; public: @@ -44,7 +50,9 @@ namespace rerun::blueprint::archetypes { DataframeQuery() = default; DataframeQuery(DataframeQuery&& other) = default; - /// Name of the timeline this applies to. + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. DataframeQuery with_timeline(rerun::blueprint::components::Timeline _timeline) && { timeline = std::move(_timeline); // See: https://github.com/rerun-io/rerun/issues/4027 @@ -52,13 +60,15 @@ namespace rerun::blueprint::archetypes { } /// Type of query: latest at or range - DataframeQuery with_mode(rerun::blueprint::components::DataframeViewMode _mode) && { + DataframeQuery with_mode(rerun::blueprint::components::QueryKind _mode) && { mode = std::move(_mode); // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } - /// Times (1 for latest at, 2 for range) + /// Configuration for latest at queries.attribute + /// + /// Note: configuration as saved on a per-timeline basis. DataframeQuery with_latest_at_queries( rerun::blueprint::components::LatestAtQueries _latest_at_queries ) && { @@ -67,7 +77,9 @@ namespace rerun::blueprint::archetypes { RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } - /// Times (1 for latest at, 2 for range) + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. DataframeQuery with_time_range_queries( rerun::blueprint::components::TimeRangeQueries _time_range_queries ) && { diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp deleted file mode 100644 index 49e147099167..000000000000 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -#include "dataframe_view_mode.hpp" - -#include "../../collection_adapter_builtins.hpp" - -namespace rerun::blueprint::archetypes {} - -namespace rerun { - - Result> AsComponents::serialize( - const blueprint::archetypes::DataframeViewMode& archetype - ) { - using namespace blueprint::archetypes; - std::vector cells; - cells.reserve(2); - - if (archetype.mode.has_value()) { - auto result = DataCell::from_loggable(archetype.mode.value()); - RR_RETURN_NOT_OK(result.error); - cells.push_back(std::move(result.value)); - } - { - auto indicator = DataframeViewMode::IndicatorComponent(); - auto result = DataCell::from_loggable(indicator); - RR_RETURN_NOT_OK(result.error); - cells.emplace_back(std::move(result.value)); - } - - return cells; - } -} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp deleted file mode 100644 index 82608e42be57..000000000000 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -#pragma once - -#include "../../blueprint/components/dataframe_view_mode.hpp" -#include "../../collection.hpp" -#include "../../compiler_utils.hpp" -#include "../../data_cell.hpp" -#include "../../indicator_component.hpp" -#include "../../result.hpp" - -#include -#include -#include -#include - -namespace rerun::blueprint::archetypes { - /// **Archetype**: Configuration for the dataframe view - struct DataframeViewMode { - /// The kind of table to display - std::optional mode; - - public: - static constexpr const char IndicatorComponentName[] = - "rerun.blueprint.components.DataframeViewModeIndicator"; - - /// Indicator component, used to identify the archetype when converting to a list of components. - using IndicatorComponent = rerun::components::IndicatorComponent; - - public: - DataframeViewMode() = default; - DataframeViewMode(DataframeViewMode&& other) = default; - - /// The kind of table to display - DataframeViewMode with_mode(rerun::blueprint::components::DataframeViewMode _mode) && { - mode = std::move(_mode); - // See: https://github.com/rerun-io/rerun/issues/4027 - RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) - } - }; - -} // namespace rerun::blueprint::archetypes - -namespace rerun { - /// \private - template - struct AsComponents; - - /// \private - template <> - struct AsComponents { - /// Serialize all set component batches. - static Result> serialize( - const blueprint::archetypes::DataframeViewMode& archetype - ); - }; -} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index c88962f3a5a7..1c872515fac3 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -9,7 +9,6 @@ #include "blueprint/components/column_share.hpp" #include "blueprint/components/container_kind.hpp" #include "blueprint/components/corner2d.hpp" -#include "blueprint/components/dataframe_view_mode.hpp" #include "blueprint/components/grid_columns.hpp" #include "blueprint/components/included_content.hpp" #include "blueprint/components/included_space_view.hpp" @@ -18,6 +17,7 @@ #include "blueprint/components/lock_range_during_zoom.hpp" #include "blueprint/components/panel_state.hpp" #include "blueprint/components/query_expression.hpp" +#include "blueprint/components/query_kind.hpp" #include "blueprint/components/root_container.hpp" #include "blueprint/components/row_share.hpp" #include "blueprint/components/sort_key.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/components/.gitattributes b/rerun_cpp/src/rerun/blueprint/components/.gitattributes index 2eae797a34ce..acd8d2a05176 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -11,8 +11,6 @@ container_kind.cpp linguist-generated=true container_kind.hpp linguist-generated=true corner2d.cpp linguist-generated=true corner2d.hpp linguist-generated=true -dataframe_view_mode.cpp linguist-generated=true -dataframe_view_mode.hpp linguist-generated=true grid_columns.hpp linguist-generated=true included_content.hpp linguist-generated=true included_space_view.hpp linguist-generated=true @@ -23,6 +21,8 @@ lock_range_during_zoom.hpp linguist-generated=true panel_state.cpp linguist-generated=true panel_state.hpp linguist-generated=true query_expression.hpp linguist-generated=true +query_kind.cpp linguist-generated=true +query_kind.hpp linguist-generated=true root_container.hpp linguist-generated=true row_share.hpp linguist-generated=true sort_key.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp index 9cc174cb71dc..6f951ad7fb76 100644 --- a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp @@ -65,12 +65,12 @@ namespace rerun { for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { const auto& element = elements[elem_idx]; ARROW_RETURN_NOT_OK(builder->Append()); - if (element.value.data()) { + if (element.queries.data()) { RR_RETURN_NOT_OK( Loggable::fill_arrow_array_builder( value_builder, - element.value.data(), - element.value.size() + element.queries.data(), + element.queries.size() ) ); } diff --git a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp index dc47e12460bc..d570ac94ba6a 100644 --- a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp @@ -18,20 +18,22 @@ namespace arrow { } // namespace arrow namespace rerun::blueprint::components { - /// **Component**: Component(s) used as point-of-view for a query. + /// **Component**: Configuration for latest at queries. + /// + /// Note: configuration as saved on a per-timeline basis. struct LatestAtQueries { - rerun::Collection value; + rerun::Collection queries; public: LatestAtQueries() = default; - LatestAtQueries(rerun::Collection value_) - : value(std::move(value_)) {} + LatestAtQueries(rerun::Collection queries_) + : queries(std::move(queries_)) {} LatestAtQueries& operator=( - rerun::Collection value_ + rerun::Collection queries_ ) { - value = std::move(value_); + queries = std::move(queries_); return *this; } }; diff --git a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.cpp b/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp similarity index 56% rename from rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.cpp rename to rerun_cpp/src/rerun/blueprint/components/query_kind.cpp index 575a0868bbe1..bfc9c8769356 100644 --- a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp @@ -1,43 +1,44 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". -#include "dataframe_view_mode.hpp" +#include "query_kind.hpp" #include #include namespace rerun { const std::shared_ptr& - Loggable::arrow_datatype() { - static const auto datatype = arrow::uint8(); + Loggable::arrow_datatype() { + static const auto datatype = arrow::sparse_union({ + arrow::field("_null_markers", arrow::null(), true, nullptr), + arrow::field("LatestAt", arrow::null(), true), + arrow::field("TimeRange", arrow::null(), true), + }); return datatype; } - Result> - Loggable::to_arrow( - const blueprint::components::DataframeViewMode* instances, size_t num_instances - ) { + Result> Loggable::to_arrow( + const blueprint::components::QueryKind* instances, size_t num_instances + ) { // TODO(andreas): Allow configuring the memory pool. arrow::MemoryPool* pool = arrow::default_memory_pool(); auto datatype = arrow_datatype(); ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) if (instances && num_instances > 0) { - RR_RETURN_NOT_OK( - Loggable::fill_arrow_array_builder( - static_cast(builder.get()), - instances, - num_instances - ) - ); + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + )); } std::shared_ptr array; ARROW_RETURN_NOT_OK(builder->Finish(&array)); return array; } - rerun::Error Loggable::fill_arrow_array_builder( - arrow::UInt8Builder* builder, const blueprint::components::DataframeViewMode* elements, + rerun::Error Loggable::fill_arrow_array_builder( + arrow::SparseUnionBuilder* builder, const blueprint::components::QueryKind* elements, size_t num_elements ) { if (builder == nullptr) { @@ -53,7 +54,7 @@ namespace rerun { ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { const auto variant = elements[elem_idx]; - ARROW_RETURN_NOT_OK(builder->Append(static_cast(variant))); + ARROW_RETURN_NOT_OK(builder->Append(static_cast(variant))); } return Error::ok(); diff --git a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.hpp b/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp similarity index 50% rename from rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.hpp rename to rerun_cpp/src/rerun/blueprint/components/query_kind.hpp index 7e03b018ab04..451775056b2c 100644 --- a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp @@ -1,5 +1,5 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". #pragma once @@ -9,29 +9,19 @@ #include namespace arrow { - /// \private - template - class NumericBuilder; - class Array; class DataType; - class UInt8Type; - using UInt8Builder = NumericBuilder; + class SparseUnionBuilder; } // namespace arrow namespace rerun::blueprint::components { - /// **Component**: The kind of table displayed by the dataframe view - enum class DataframeViewMode : uint8_t { + /// **Component**: The kind of query displayed by the dataframe view + enum class QueryKind : uint8_t { - /// Display the entity values at the current time. - /// - /// In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. + /// Query LatestAt = 1, - /// Display a temporal table of entity values. - /// - /// In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - /// timestamp shown are determined by each view entity's visible time range setting. + /// Time range query. TimeRange = 2, }; } // namespace rerun::blueprint::components @@ -42,20 +32,20 @@ namespace rerun { /// \private template <> - struct Loggable { - static constexpr const char Name[] = "rerun.blueprint.components.DataframeViewMode"; + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.QueryKind"; /// Returns the arrow data type this type corresponds to. static const std::shared_ptr& arrow_datatype(); - /// Serializes an array of `rerun::blueprint:: components::DataframeViewMode` into an arrow array. + /// Serializes an array of `rerun::blueprint:: components::QueryKind` into an arrow array. static Result> to_arrow( - const blueprint::components::DataframeViewMode* instances, size_t num_instances + const blueprint::components::QueryKind* instances, size_t num_instances ); /// Fills an arrow array builder with an array of this type. static rerun::Error fill_arrow_array_builder( - arrow::UInt8Builder* builder, const blueprint::components::DataframeViewMode* elements, + arrow::SparseUnionBuilder* builder, const blueprint::components::QueryKind* elements, size_t num_elements ); }; diff --git a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp index da545e384f02..924d17db7a1c 100644 --- a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp @@ -65,12 +65,12 @@ namespace rerun { for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { const auto& element = elements[elem_idx]; ARROW_RETURN_NOT_OK(builder->Append()); - if (element.value.data()) { + if (element.queries.data()) { RR_RETURN_NOT_OK( Loggable::fill_arrow_array_builder( value_builder, - element.value.data(), - element.value.size() + element.queries.data(), + element.queries.size() ) ); } diff --git a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp index fd409c65111a..4ecee518f49b 100644 --- a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp @@ -18,20 +18,22 @@ namespace arrow { } // namespace arrow namespace rerun::blueprint::components { - /// **Component**: Component(s) used as point-of-view for a query. + /// **Component**: Configuration for time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. struct TimeRangeQueries { - rerun::Collection value; + rerun::Collection queries; public: TimeRangeQueries() = default; - TimeRangeQueries(rerun::Collection value_) - : value(std::move(value_)) {} + TimeRangeQueries(rerun::Collection queries_) + : queries(std::move(queries_)) {} TimeRangeQueries& operator=( - rerun::Collection value_ + rerun::Collection queries_ ) { - value = std::move(value_); + queries = std::move(queries_); return *this; } }; diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp index 01c7a7f6c7ec..8538eeed7697 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp @@ -17,12 +17,12 @@ namespace arrow { } // namespace arrow namespace rerun::blueprint::datatypes { - /// **Datatype**: Visible time range bounds for a specific timeline. + /// **Datatype**: Latest at query configuration for a specific timeline. struct LatestAtQuery { /// Name of the timeline this applies to. rerun::datatypes::Utf8 timeline; - /// Time range to use for this timeline. + /// Time value to use for this query. rerun::datatypes::TimeInt time; public: diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp index 356e2fdcc52f..dd4dcce3ed4d 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp @@ -17,15 +17,15 @@ namespace arrow { } // namespace arrow namespace rerun::blueprint::datatypes { - /// **Datatype**: Visible time range bounds for a specific timeline. + /// **Datatype**: Time range query configuration for a specific timeline. struct TimeRangeQuery { /// Name of the timeline this applies to. rerun::datatypes::Utf8 timeline; - /// Start + /// Begining of the time range. rerun::datatypes::TimeInt start; - /// End + /// End of the time range. rerun::datatypes::TimeInt end; public: diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes index 01e3ac82b617..58d01529a89b 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes @@ -5,7 +5,6 @@ __init__.py linguist-generated=true background.py linguist-generated=true container_blueprint.py linguist-generated=true dataframe_query.py linguist-generated=true -dataframe_view_mode.py linguist-generated=true panel_blueprint.py linguist-generated=true plot_legend.py linguist-generated=true scalar_axis.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py index fc973484e2ff..c07e1563847d 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py @@ -5,7 +5,6 @@ from .background import Background from .container_blueprint import ContainerBlueprint from .dataframe_query import DataframeQuery -from .dataframe_view_mode import DataframeViewMode from .panel_blueprint import PanelBlueprint from .plot_legend import PlotLegend from .scalar_axis import ScalarAxis @@ -23,7 +22,6 @@ "Background", "ContainerBlueprint", "DataframeQuery", - "DataframeViewMode", "PanelBlueprint", "PlotLegend", "ScalarAxis", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py index 4b7cf8861aaf..a9f9417d4322 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py @@ -21,13 +21,13 @@ @define(str=False, repr=False, init=False) class DataframeQuery(Archetype): - """**Archetype**: Configuration for the dataframe view.""" + """**Archetype**: The query for the dataframe view.""" def __init__( self: Any, *, timeline: datatypes.Utf8Like | None = None, - mode: blueprint_components.DataframeViewModeLike | None = None, + mode: blueprint_components.QueryKindLike | None = None, latest_at_queries: blueprint_components.LatestAtQueriesLike | None = None, time_range_queries: blueprint_components.TimeRangeQueriesLike | None = None, ): @@ -37,13 +37,19 @@ def __init__( Parameters ---------- timeline: - Name of the timeline this applies to. + The timeline for this query. + + If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. mode: Type of query: latest at or range latest_at_queries: - Times (1 for latest at, 2 for range) + Configuration for latest at queries.attribute + + Note: configuration as saved on a per-timeline basis. time_range_queries: - Times (1 for latest at, 2 for range) + Configuration for the time range queries. + + Note: configuration as saved on a per-timeline basis. """ @@ -76,14 +82,16 @@ def _clear(cls) -> DataframeQuery: default=None, converter=blueprint_components.TimelineBatch._optional, # type: ignore[misc] ) - # Name of the timeline this applies to. + # The timeline for this query. + # + # If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. # # (Docstring intentionally commented out to hide this field from the docs) - mode: blueprint_components.DataframeViewModeBatch | None = field( + mode: blueprint_components.QueryKindBatch | None = field( metadata={"component": "optional"}, default=None, - converter=blueprint_components.DataframeViewModeBatch._optional, # type: ignore[misc] + converter=blueprint_components.QueryKindBatch._optional, # type: ignore[misc] ) # Type of query: latest at or range # @@ -94,7 +102,9 @@ def _clear(cls) -> DataframeQuery: default=None, converter=blueprint_components.LatestAtQueriesBatch._optional, # type: ignore[misc] ) - # Times (1 for latest at, 2 for range) + # Configuration for latest at queries.attribute + # + # Note: configuration as saved on a per-timeline basis. # # (Docstring intentionally commented out to hide this field from the docs) @@ -103,7 +113,9 @@ def _clear(cls) -> DataframeQuery: default=None, converter=blueprint_components.TimeRangeQueriesBatch._optional, # type: ignore[misc] ) - # Times (1 for latest at, 2 for range) + # Configuration for the time range queries. + # + # Note: configuration as saved on a per-timeline basis. # # (Docstring intentionally commented out to hide this field from the docs) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py deleted file mode 100644 index 475ac728ab00..000000000000 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py +++ /dev/null @@ -1,65 +0,0 @@ -# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs -# Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -# You can extend this class by creating a "DataframeViewModeExt" class in "dataframe_view_mode_ext.py". - -from __future__ import annotations - -from typing import Any - -from attrs import define, field - -from ..._baseclasses import ( - Archetype, -) -from ...blueprint import components as blueprint_components -from ...error_utils import catch_and_log_exceptions - -__all__ = ["DataframeViewMode"] - - -@define(str=False, repr=False, init=False) -class DataframeViewMode(Archetype): - """**Archetype**: Configuration for the dataframe view.""" - - def __init__(self: Any, *, mode: blueprint_components.DataframeViewModeLike | None = None): - """ - Create a new instance of the DataframeViewMode archetype. - - Parameters - ---------- - mode: - The kind of table to display - - """ - - # You can define your own __init__ function as a member of DataframeViewModeExt in dataframe_view_mode_ext.py - with catch_and_log_exceptions(context=self.__class__.__name__): - self.__attrs_init__(mode=mode) - return - self.__attrs_clear__() - - def __attrs_clear__(self) -> None: - """Convenience method for calling `__attrs_init__` with all `None`s.""" - self.__attrs_init__( - mode=None, # type: ignore[arg-type] - ) - - @classmethod - def _clear(cls) -> DataframeViewMode: - """Produce an empty DataframeViewMode, bypassing `__init__`.""" - inst = cls.__new__(cls) - inst.__attrs_clear__() - return inst - - mode: blueprint_components.DataframeViewModeBatch | None = field( - metadata={"component": "optional"}, - default=None, - converter=blueprint_components.DataframeViewModeBatch._optional, # type: ignore[misc] - ) - # The kind of table to display - # - # (Docstring intentionally commented out to hide this field from the docs) - - __str__ = Archetype.__str__ - __repr__ = Archetype.__repr__ # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index b486f77a6c53..9799e2d824ce 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -9,7 +9,6 @@ background_kind.py linguist-generated=true column_share.py linguist-generated=true container_kind.py linguist-generated=true corner2d.py linguist-generated=true -dataframe_view_mode.py linguist-generated=true grid_columns.py linguist-generated=true included_content.py linguist-generated=true included_space_view.py linguist-generated=true @@ -18,6 +17,7 @@ latest_at_queries.py linguist-generated=true lock_range_during_zoom.py linguist-generated=true panel_state.py linguist-generated=true query_expression.py linguist-generated=true +query_kind.py linguist-generated=true root_container.py linguist-generated=true row_share.py linguist-generated=true sort_key.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py index afc495d5a565..0de47cb349a7 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -21,13 +21,6 @@ ContainerKindType, ) from .corner2d import Corner2D, Corner2DArrayLike, Corner2DBatch, Corner2DLike, Corner2DType -from .dataframe_view_mode import ( - DataframeViewMode, - DataframeViewModeArrayLike, - DataframeViewModeBatch, - DataframeViewModeLike, - DataframeViewModeType, -) from .grid_columns import GridColumns, GridColumnsBatch, GridColumnsType from .included_content import IncludedContent, IncludedContentBatch, IncludedContentType from .included_space_view import IncludedSpaceView, IncludedSpaceViewBatch, IncludedSpaceViewType @@ -42,6 +35,7 @@ from .lock_range_during_zoom import LockRangeDuringZoom, LockRangeDuringZoomBatch, LockRangeDuringZoomType from .panel_state import PanelState, PanelStateArrayLike, PanelStateBatch, PanelStateLike, PanelStateType from .query_expression import QueryExpression, QueryExpressionBatch, QueryExpressionType +from .query_kind import QueryKind, QueryKindArrayLike, QueryKindBatch, QueryKindLike, QueryKindType from .root_container import RootContainer, RootContainerBatch, RootContainerType from .row_share import RowShare, RowShareBatch, RowShareType from .sort_key import SortKey, SortKeyArrayLike, SortKeyBatch, SortKeyLike, SortKeyType @@ -101,11 +95,6 @@ "Corner2DBatch", "Corner2DLike", "Corner2DType", - "DataframeViewMode", - "DataframeViewModeArrayLike", - "DataframeViewModeBatch", - "DataframeViewModeLike", - "DataframeViewModeType", "GridColumns", "GridColumnsBatch", "GridColumnsType", @@ -134,6 +123,11 @@ "QueryExpression", "QueryExpressionBatch", "QueryExpressionType", + "QueryKind", + "QueryKindArrayLike", + "QueryKindBatch", + "QueryKindLike", + "QueryKindType", "RootContainer", "RootContainerBatch", "RootContainerType", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py b/rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py deleted file mode 100644 index 9ce262636db5..000000000000 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py +++ /dev/null @@ -1,90 +0,0 @@ -# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs -# Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". - -# You can extend this class by creating a "DataframeViewModeExt" class in "dataframe_view_mode_ext.py". - -from __future__ import annotations - -from typing import Literal, Sequence, Union - -import pyarrow as pa - -from ..._baseclasses import ( - BaseBatch, - BaseExtensionType, - ComponentBatchMixin, -) - -__all__ = [ - "DataframeViewMode", - "DataframeViewModeArrayLike", - "DataframeViewModeBatch", - "DataframeViewModeLike", - "DataframeViewModeType", -] - - -from enum import Enum - - -class DataframeViewMode(Enum): - """**Component**: The kind of table displayed by the dataframe view.""" - - LatestAt = 1 - """ - Display the entity values at the current time. - - In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. - """ - - TimeRange = 2 - """ - Display a temporal table of entity values. - - In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - timestamp shown are determined by each view entity's visible time range setting. - """ - - @classmethod - def auto(cls, val: str | int | DataframeViewMode) -> DataframeViewMode: - """Best-effort converter, including a case-insensitive string matcher.""" - if isinstance(val, DataframeViewMode): - return val - if isinstance(val, int): - return cls(val) - try: - return cls[val] - except KeyError: - val_lower = val.lower() - for variant in cls: - if variant.name.lower() == val_lower: - return variant - raise ValueError(f"Cannot convert {val} to {cls.__name__}") - - def __str__(self) -> str: - """Returns the variant name.""" - return self.name - - -DataframeViewModeLike = Union[DataframeViewMode, Literal["LatestAt", "TimeRange", "latestat", "timerange"], int] -DataframeViewModeArrayLike = Union[DataframeViewModeLike, Sequence[DataframeViewModeLike]] - - -class DataframeViewModeType(BaseExtensionType): - _TYPE_NAME: str = "rerun.blueprint.components.DataframeViewMode" - - def __init__(self) -> None: - pa.ExtensionType.__init__(self, pa.uint8(), self._TYPE_NAME) - - -class DataframeViewModeBatch(BaseBatch[DataframeViewModeArrayLike], ComponentBatchMixin): - _ARROW_TYPE = DataframeViewModeType() - - @staticmethod - def _native_to_pa_array(data: DataframeViewModeArrayLike, data_type: pa.DataType) -> pa.Array: - if isinstance(data, (DataframeViewMode, int, str)): - data = [data] - - pa_data = [DataframeViewMode.auto(v).value if v is not None else None for v in data] # type: ignore[redundant-expr] - - return pa.array(pa_data, type=data_type) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py b/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py index 8cd9b5f1ad67..f4882af5f88d 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py @@ -29,17 +29,21 @@ @define(init=False) class LatestAtQueries(ComponentMixin): - """**Component**: Component(s) used as point-of-view for a query.""" + """ + **Component**: Configuration for latest at queries. + + Note: configuration as saved on a per-timeline basis. + """ _BATCH_TYPE = None - def __init__(self: Any, value: LatestAtQueriesLike): + def __init__(self: Any, queries: LatestAtQueriesLike): """Create a new instance of the LatestAtQueries component.""" # You can define your own __init__ function as a member of LatestAtQueriesExt in latest_at_queries_ext.py - self.__attrs_init__(value=value) + self.__attrs_init__(queries=queries) - value: list[blueprint_datatypes.LatestAtQuery] = field() + queries: list[blueprint_datatypes.LatestAtQuery] = field() LatestAtQueriesLike = LatestAtQueries diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py b/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py new file mode 100644 index 000000000000..ec1e5c469b8e --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py @@ -0,0 +1,102 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". + +# You can extend this class by creating a "QueryKindExt" class in "query_kind_ext.py". + +from __future__ import annotations + +from typing import Literal, Sequence, Union + +import pyarrow as pa + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, +) + +__all__ = ["QueryKind", "QueryKindArrayLike", "QueryKindBatch", "QueryKindLike", "QueryKindType"] + + +from enum import Enum + + +class QueryKind(Enum): + """**Component**: The kind of query displayed by the dataframe view.""" + + LatestAt = 1 + """Query""" + + TimeRange = 2 + """Time range query.""" + + def __str__(self) -> str: + """Returns the variant name.""" + if self == QueryKind.LatestAt: + return "LatestAt" + elif self == QueryKind.TimeRange: + return "TimeRange" + else: + raise ValueError("Unknown enum variant") + + +QueryKindLike = Union[QueryKind, Literal["LatestAt", "TimeRange", "latestat", "timerange"]] +QueryKindArrayLike = Union[QueryKindLike, Sequence[QueryKindLike]] + + +class QueryKindType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.QueryKind" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.sparse_union([ + pa.field("_null_markers", pa.null(), nullable=True, metadata={}), + pa.field("LatestAt", pa.null(), nullable=True, metadata={}), + pa.field("TimeRange", pa.null(), nullable=True, metadata={}), + ]), + self._TYPE_NAME, + ) + + +class QueryKindBatch(BaseBatch[QueryKindArrayLike], ComponentBatchMixin): + _ARROW_TYPE = QueryKindType() + + @staticmethod + def _native_to_pa_array(data: QueryKindArrayLike, data_type: pa.DataType) -> pa.Array: + if isinstance(data, (QueryKind, int, str)): + data = [data] + + types: list[int] = [] + + for value in data: + if value is None: + types.append(0) + elif isinstance(value, QueryKind): + types.append(value.value) # Actual enum value + elif isinstance(value, int): + types.append(value) # By number + elif isinstance(value, str): + if hasattr(QueryKind, value): + types.append(QueryKind[value].value) # fast path + elif value.lower() == "latestat": + types.append(QueryKind.LatestAt.value) + elif value.lower() == "timerange": + types.append(QueryKind.TimeRange.value) + else: + raise ValueError(f"Unknown QueryKind kind: {value}") + else: + raise ValueError(f"Unknown QueryKind kind: {value}") + + buffers = [ + None, + pa.array(types, type=pa.int8()).buffers()[1], + ] + children = (1 + 2) * [pa.nulls(len(data))] + + return pa.UnionArray.from_buffers( + type=data_type, + length=len(data), + buffers=buffers, + children=children, + ) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py b/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py index b0266ccc0aff..bb884758bc8b 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py @@ -29,17 +29,21 @@ @define(init=False) class TimeRangeQueries(ComponentMixin): - """**Component**: Component(s) used as point-of-view for a query.""" + """ + **Component**: Configuration for time range queries. + + Note: configuration as saved on a per-timeline basis. + """ _BATCH_TYPE = None - def __init__(self: Any, value: TimeRangeQueriesLike): + def __init__(self: Any, queries: TimeRangeQueriesLike): """Create a new instance of the TimeRangeQueries component.""" # You can define your own __init__ function as a member of TimeRangeQueriesExt in time_range_queries_ext.py - self.__attrs_init__(value=value) + self.__attrs_init__(queries=queries) - value: list[blueprint_datatypes.TimeRangeQuery] = field() + queries: list[blueprint_datatypes.TimeRangeQuery] = field() TimeRangeQueriesLike = TimeRangeQueries diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py index 06803336a4a4..03f8e155a418 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py @@ -35,7 +35,7 @@ def _latest_at_query__time__special_field_converter_override(x: datatypes.TimeIn @define(init=False) class LatestAtQuery: - """**Datatype**: Visible time range bounds for a specific timeline.""" + """**Datatype**: Latest at query configuration for a specific timeline.""" def __init__(self: Any, timeline: datatypes.Utf8Like, time: datatypes.TimeIntLike): """ @@ -46,7 +46,7 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, time: datatypes.TimeIntLik timeline: Name of the timeline this applies to. time: - Time range to use for this timeline. + Time value to use for this query. """ @@ -59,7 +59,7 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, time: datatypes.TimeIntLik # (Docstring intentionally commented out to hide this field from the docs) time: datatypes.TimeInt = field(converter=_latest_at_query__time__special_field_converter_override) - # Time range to use for this timeline. + # Time value to use for this query. # # (Docstring intentionally commented out to hide this field from the docs) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py index cd43dc17e2ce..c5d238e55190 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py @@ -48,7 +48,7 @@ def _time_range_query__end__special_field_converter_override(x: datatypes.TimeIn @define(init=False) class TimeRangeQuery: - """**Datatype**: Visible time range bounds for a specific timeline.""" + """**Datatype**: Time range query configuration for a specific timeline.""" def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLike, end: datatypes.TimeIntLike): """ @@ -59,9 +59,9 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLi timeline: Name of the timeline this applies to. start: - Start + Begining of the time range. end: - End + End of the time range. """ @@ -74,12 +74,12 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLi # (Docstring intentionally commented out to hide this field from the docs) start: datatypes.TimeInt = field(converter=_time_range_query__start__special_field_converter_override) - # Start + # Begining of the time range. # # (Docstring intentionally commented out to hide this field from the docs) end: datatypes.TimeInt = field(converter=_time_range_query__end__special_field_converter_override) - # End + # End of the time range. # # (Docstring intentionally commented out to hide this field from the docs) From 9192638c61c5b0ed19f45a738ee34a3a7022f2d9 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Tue, 6 Aug 2024 13:29:41 +0200 Subject: [PATCH 03/18] Cleaned some todos --- .../rerun/blueprint/archetypes/dataframe_query.fbs | 6 ++++-- crates/viewer/re_space_view_dataframe/src/view_query.rs | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs index 90f8ede34b98..18cf213abf0d 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs @@ -7,13 +7,15 @@ namespace rerun.blueprint.archetypes; // settings are present for both the latest at and range modes. // - Timestamps are hard-invalidated by a change of timeline. So we keep them on a per-timeline basis. -// TODO(ab): add visible components and (optional) PoV components, to be modelled as: -// +// TODO(#7067): add visible components (maybe in another archetype?) +// TODO(#7072): add (optional) PoV components +// Note: component list should be modelled as: // component PovComponents { // datatype ComponentNames { // value: [string]; // } // } +// // Motivation: // - Chances are high that the user prefers to have their pov components _not_ invalidated by a changeof timeline. // - That is even though a component might _technically_ be soft-invalidated by a change of timeline (e.g. if it was diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index e28bd6e5aa45..3eb46fa54947 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -20,13 +20,11 @@ pub(crate) enum QueryMode { Range { from: TimeInt, to: TimeInt, - //TODO(ab): add PoV components + //TODO(#7072): add PoV components }, + //TODO(#7067): add selected components } -//TODO: fallback to the current timeline is nice but should be saved back to the blueprint such as -// to "freeze" the value - pub(crate) struct Query { pub(crate) timeline: TimelineName, pub(crate) mode: QueryMode, @@ -394,6 +392,7 @@ struct TimelineSpec { } impl TimelineSpec { + //TODO: remove that fn from_time_histogram(times: &TimeHistogram) -> Self { Self::from_time_range( times.min_key().unwrap_or_default()..=times.max_key().unwrap_or_default(), From 46c188676680ea3739127234019b9614297cb10e Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 14:28:29 +0200 Subject: [PATCH 04/18] New UI and lots of clean-up --- .../src/space_view_class.rs | 152 ++-- .../src/time_range_table.rs | 3 +- .../re_space_view_dataframe/src/view_query.rs | 857 ++++++++---------- .../re_viewer_context/src/time_drag_value.rs | 2 +- 4 files changed, 452 insertions(+), 562 deletions(-) diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index b43689ce5045..a031effde836 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -130,33 +130,24 @@ mode sets the default time range to _everything_. You can override this in the s _space_origin: &EntityPath, space_view_id: SpaceViewId, ) -> Result<(), SpaceViewSystemExecutionError> { - // let settings = ViewProperty::from_archetype::( - // ctx.blueprint_db(), - // ctx.blueprint_query, - // space_view_id, - // ); - // - // let mode = - // settings.component_or_fallback::(ctx, self, state)?; + crate::view_query::query_ui(ctx, ui, state, space_view_id)?; list_item::list_item_scope(ui, "dataframe_view_selection_ui", |ui| { - //TODO(ab): ideally we'd drop the "Dataframe" part in the UI label - //view_property_ui::(ctx, ui, space_view_id, self, state); - - view_property_ui::(ctx, ui, space_view_id, self, state); - super::view_query::Query::ui(ctx, ui, self, state, space_view_id); - //TODO: fix this :scream: - let view_query = Query::try_from_blueprint(ctx, space_view_id, self, state)?; - ui.add_enabled_ui(matches!(view_query.mode, QueryMode::Range { .. }), |ui| { - view_property_ui::( - ctx, - ui, - space_view_id, - self, - state, - ); - }); + let view_query = Query::try_from_blueprint(ctx, space_view_id)?; + + ui.add_enabled_ui( + matches!(view_query.mode(ctx), QueryMode::Range { .. }), + |ui| { + view_property_ui::( + ctx, + ui, + space_view_id, + self, + state, + ); + }, + ); Ok(()) }) @@ -172,56 +163,21 @@ mode sets the default time range to _everything_. You can override this in the s ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - // let settings = ViewProperty::from_archetype::( - // ctx.blueprint_db(), - // ctx.blueprint_query, - // query.space_view_id, - // ); - // - // let mode = - // settings.component_or_fallback::(ctx, self, state)?; - // - // // update state - // let state = state.downcast_mut::()?; - // state.mode = mode; - // - // match mode { - // components::DataframeViewMode::LatestAt => latest_at_table_ui(ctx, ui, query), - // - // components::DataframeViewMode::TimeRange => { - // let time_range_table_order = - // ViewProperty::from_archetype::( - // ctx.blueprint_db(), - // ctx.blueprint_query, - // query.space_view_id, - // ); - // let sort_key = time_range_table_order - // .component_or_fallback::(ctx, self, state)?; - // let sort_order = time_range_table_order - // .component_or_fallback::(ctx, self, state)?; - // - // time_range_table_ui(ctx, ui, query, sort_key, sort_order); - // } - // }; - - let view_query = - super::view_query::Query::try_from_blueprint(ctx, query.space_view_id, self, state)?; + let view_query = super::view_query::Query::try_from_blueprint(ctx, query.space_view_id)?; + let timeline_name = view_query.timeline_name(ctx); + let query_mode = view_query.mode(ctx); let Some(timeline) = ctx .recording() .timelines() - .find(|t| t.name() == &view_query.timeline) + .find(|t| t.name() == &timeline_name) else { - //TODO: create dummy timeline instead? - re_log::warn_once!( - "Could not find timeline {:?}.", - view_query.timeline.as_str() - ); + re_log::warn_once!("Could not find timeline {:?}.", timeline_name.as_str()); //TODO(ab): we should have an error for that return Ok(()); }; - match view_query.mode { + match query_mode { QueryMode::LatestAt { time } => { latest_at_table_ui(ctx, ui, query, LatestAtQuery::new(*timeline, time)) } @@ -253,35 +209,37 @@ mode sets the default time range to _everything_. You can override this in the s } } -impl TypedComponentFallbackProvider for DataframeSpaceView { - fn fallback_for(&self, ctx: &re_viewer_context::QueryContext<'_>) -> Timeline { - //TODO: add helper to Timeline component - Timeline(Utf8::from( - ctx.viewer_ctx - .rec_cfg - .time_ctrl - .read() - .timeline() - .name() - .as_str(), - )) - } -} - -impl TypedComponentFallbackProvider for DataframeSpaceView { - fn fallback_for(&self, ctx: &QueryContext<'_>) -> LatestAtQueries { - let current_time = ctx.viewer_ctx.rec_cfg.time_ctrl.read(); - - let latest_at_query = datatypes::LatestAtQuery { - timeline: Utf8::from(current_time.timeline().name().as_str()), - time: re_types_core::datatypes::TimeInt::from( - current_time - .time_int() - .unwrap_or(re_log_types::TimeInt::MAX), - ), - }; - LatestAtQueries::from(vec![latest_at_query]) - } -} - -re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => [Timeline, LatestAtQueries]); +// //TODO: probably no longer needed +// impl TypedComponentFallbackProvider for DataframeSpaceView { +// fn fallback_for(&self, ctx: &re_viewer_context::QueryContext<'_>) -> Timeline { +// //TODO: add helper to Timeline component +// Timeline(Utf8::from( +// ctx.viewer_ctx +// .rec_cfg +// .time_ctrl +// .read() +// .timeline() +// .name() +// .as_str(), +// )) +// } +// } +// +// //TODO: probably no longer needed +// impl TypedComponentFallbackProvider for DataframeSpaceView { +// fn fallback_for(&self, ctx: &QueryContext<'_>) -> LatestAtQueries { +// let current_time = ctx.viewer_ctx.rec_cfg.time_ctrl.read(); +// +// let latest_at_query = datatypes::LatestAtQuery { +// timeline: Utf8::from(current_time.timeline().name().as_str()), +// time: re_types_core::datatypes::TimeInt::from( +// current_time +// .time_int() +// .unwrap_or(re_log_types::TimeInt::MAX), +// ), +// }; +// LatestAtQueries::from(vec![latest_at_query]) +// } +// } +// +// re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => [Timeline, LatestAtQueries]); diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index 190e4c4473b4..839d72cde17d 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -6,9 +6,8 @@ use re_data_ui::item_ui::entity_path_button; use re_entity_db::InstancePath; use re_log_types::{EntityPath, ResolvedTimeRange, TimeInt, Timeline}; use re_types::blueprint::components::{SortKey, SortOrder}; -use re_types_core::datatypes::TimeRange; use re_types_core::ComponentName; -use re_viewer_context::{Item, QueryRange, UiLayout, ViewQuery, ViewerContext}; +use re_viewer_context::{Item, UiLayout, ViewQuery, ViewerContext}; use crate::table_ui::{row_id_ui, table_ui}; diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index 3eb46fa54947..7825c9651368 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -1,18 +1,17 @@ -use egui::{NumExt, Response}; -use re_entity_db::TimeHistogram; -use re_log_types::{TimeInt, TimeType, TimeZone, TimelineName}; +use crate::visualizer_system::EmptySystem; +use re_log_types::{TimeInt, TimeType, TimelineName}; use re_types::blueprint::components::QueryKind; -use re_types::blueprint::datatypes::LatestAtQuery; use re_types::blueprint::{archetypes, components, datatypes}; -use re_types_core::{Archetype as _, ComponentName, Loggable as _}; +use re_types_core::{Archetype as _, Loggable as _}; use re_ui::{list_item, UiExt as _}; use re_viewer_context::{ - ComponentFallbackProvider, QueryContext, SpaceViewId, SpaceViewState, - SpaceViewSystemExecutionError, ViewQuery, ViewerContext, + QueryContext, SpaceViewId, SpaceViewState, SpaceViewSystemExecutionError, TimeDragValue, + ViewerContext, }; use re_viewport_blueprint::{entity_path_for_view_property, ViewProperty}; -use std::ops::RangeInclusive; +/// The query mode for the dataframe view. +#[derive(Debug, Clone, Copy)] pub(crate) enum QueryMode { LatestAt { time: TimeInt, @@ -25,17 +24,20 @@ pub(crate) enum QueryMode { //TODO(#7067): add selected components } -pub(crate) struct Query { - pub(crate) timeline: TimelineName, - pub(crate) mode: QueryMode, +/// Helper for handling the dataframe view query blueprint. +pub(crate) enum Query { + FollowTimeline, + + Override { + timeline: TimelineName, + mode: QueryMode, + }, } impl Query { pub(crate) fn try_from_blueprint( ctx: &ViewerContext<'_>, space_view_id: SpaceViewId, - fallback_provider: &dyn ComponentFallbackProvider, - state: &mut dyn SpaceViewState, ) -> Result { let property = ViewProperty::from_archetype::( ctx.blueprint_db(), @@ -43,48 +45,35 @@ impl Query { space_view_id, ); - let timeline = TimelineName::from( - property - .component_or_fallback::(ctx, fallback_provider, state)? - .0 - .as_str(), - ); + let Some(timeline) = property + .component_or_empty::()? + .map(|t| t.timeline_name()) + else { + // if the timeline is not set, it means that we must follow the time panel settings + return Ok(Self::FollowTimeline); + }; - let mode = property.component_or_fallback::( - ctx, - fallback_provider, - state, - )?; + let mode = property + .component_or_empty::()? + .unwrap_or(QueryKind::LatestAt); let mode = match mode { QueryKind::LatestAt => { let time = property - .component_or_fallback::( - ctx, - fallback_provider, - state, - )? + .component_or_empty::()? + .unwrap_or_default() .0 .into_iter() .find(|q| q.timeline.as_str() == timeline) .map(|q| q.time.into()) - .unwrap_or_else(|| { - ctx.rec_cfg - .time_ctrl - .read() - .time_int() - .unwrap_or(TimeInt::MAX) - }); + .unwrap_or(TimeInt::MAX); QueryMode::LatestAt { time } } QueryKind::TimeRange => { let (from, to) = property - .component_or_fallback::( - ctx, - fallback_provider, - state, - )? + .component_or_empty::()? + .unwrap_or_default() .0 .into_iter() .find(|q| q.timeline.as_str() == timeline) @@ -95,476 +84,420 @@ impl Query { } }; - Ok(Self { timeline, mode }) + Ok(Self::Override { timeline, mode }) + } + + /// Get the timeline name for the query + #[inline] + pub(crate) fn timeline_name(&self, ctx: &ViewerContext<'_>) -> TimelineName { + match self { + Query::FollowTimeline => *ctx.rec_cfg.time_ctrl.read().timeline().name(), + Query::Override { timeline, .. } => *timeline, + } + } + + /// Get the mode for the query + #[inline] + pub(crate) fn mode(&self, ctx: &ViewerContext<'_>) -> QueryMode { + match self { + Query::FollowTimeline => { + let time_ctrl = ctx.rec_cfg.time_ctrl.read(); + QueryMode::LatestAt { + time: time_ctrl.time_int().unwrap_or(TimeInt::MAX), + } + } + Query::Override { mode, .. } => *mode, + } } - pub(crate) fn ui( + /// Save the query mode for the given timeline to the blueprint. + pub(crate) fn save_mode_for_timeline( ctx: &ViewerContext<'_>, - ui: &mut egui::Ui, - fallback_provider: &dyn ComponentFallbackProvider, - state: &mut dyn SpaceViewState, space_view_id: SpaceViewId, + timeline_name: &TimelineName, + query_mode: &QueryMode, ) -> Result<(), SpaceViewSystemExecutionError> { - let name = archetypes::DataframeQuery::name(); - let Some(reflection) = ctx.reflection.archetypes.get(&name) else { - // The `ArchetypeReflectionMarker` bound should make this impossible. - re_log::warn_once!("Missing reflection data for archetype {name:?}."); - //TODO(ab): we should have an error for that - return Ok(()); - }; - - let blueprint_path = - entity_path_for_view_property(space_view_id, ctx.blueprint_db().tree(), name); - let query_context = QueryContext { - viewer_ctx: ctx, - target_entity_path: &blueprint_path, - archetype_name: Some(name), - query: ctx.blueprint_query, - view_state: state, - view_ctx: None, - }; - let property = ViewProperty::from_archetype::( ctx.blueprint_db(), ctx.blueprint_query, space_view_id, ); - let current_mode = property.component_or_fallback::( - ctx, - fallback_provider, - state, - )?; + match query_mode { + QueryMode::LatestAt { time } => { + let mut latest_at_queries = property + .component_or_empty::()? + .unwrap_or_default(); + + latest_at_queries.set_query_for_timeline( + timeline_name.as_str(), + Some(datatypes::LatestAtQuery { + timeline: timeline_name.as_str().into(), + time: (*time).into(), + }), + ); + + ctx.save_blueprint_component(&property.blueprint_store_path, &latest_at_queries); + ctx.save_blueprint_component(&property.blueprint_store_path, &QueryKind::LatestAt); + } + QueryMode::Range { from, to } => { + let mut time_range_queries = property + .component_or_empty::()? + .unwrap_or_default(); + + time_range_queries.set_query_for_timeline( + timeline_name.as_str(), + Some(datatypes::TimeRangeQuery { + timeline: timeline_name.as_str().into(), + start: (*from).into(), + end: (*to).into(), + }), + ); + + ctx.save_blueprint_component(&property.blueprint_store_path, &time_range_queries); + ctx.save_blueprint_component(&property.blueprint_store_path, &QueryKind::TimeRange); + } + }; - let timeline_name = property - .component_or_fallback::(ctx, fallback_provider, state) - .map(|t| t.timeline_name())?; + Ok(()) + } +} - let Some(timeline) = ctx - .recording() +pub(crate) fn query_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + state: &mut dyn SpaceViewState, + space_view_id: SpaceViewId, +) -> Result<(), SpaceViewSystemExecutionError> { + let property = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query, + space_view_id, + ); + + // The existence of a timeline component determines if we are in follow time panel or + // override mode. + let timeline_component = property.component_or_empty::()?; + let timeline_name = timeline_component.as_ref().map(|t| t.timeline_name()); + + let timeline = timeline_name.and_then(|timeline_name| { + ctx.recording() .timelines() .find(|t| t.name() == &timeline_name) - else { - re_log::warn_once!("Could not find timeline {:?}.", timeline_name.as_str()); - //TODO(ab): we should have an error for that - return Ok(()); - }; - - let inner_ui = |ui: &mut egui::Ui| -> Result<(), SpaceViewSystemExecutionError> { - let component_results = ctx.blueprint_db().latest_at( - ctx.blueprint_query, - &blueprint_path, - reflection.fields.iter().map(|field| field.component_name), + }); + + let mut override_query = timeline.is_some(); + let changed = ui.selectable_toggle(|ui| { + ui.selectable_value(&mut override_query, false, "Follow timeline") + .changed() + || ui + .selectable_value(&mut override_query, true, "Override") + .changed() + }); + + if changed { + if override_query { + let time_ctrl = ctx.rec_cfg.time_ctrl.read(); + let timeline = time_ctrl.timeline(); + + // UX least surprising behavior: when switching from "follow" to "override", we ensure + // that the override configuration defaults to the current timeline configuration, so + // the table content remains stable. + property.save_blueprint_component( + ctx, + &components::Timeline::from(timeline.name().as_str()), ); - - // - // Timeline - // - - let component_name = components::Timeline::name(); - ui.list_item_flat_noninteractive(list_item::PropertyContent::new("Timeline").value_fn( - |ui, _| { - ctx.component_ui_registry.singleline_edit_ui( - &query_context, - ui, - ctx.blueprint_db(), - &blueprint_path, - component_name, - component_results - .component_batch_raw(&component_name) - .as_deref(), - fallback_provider, - ); - }, - )); - - // - // Mode - // - - let component_name = components::QueryKind::name(); - ui.list_item_flat_noninteractive(list_item::PropertyContent::new("Mode").value_fn( - |ui, _| { - ctx.component_ui_registry.singleline_edit_ui( - &query_context, - ui, - ctx.blueprint_db(), - &blueprint_path, - component_name, - component_results - .component_batch_raw(&component_name) - .as_deref(), - fallback_provider, - ); + Query::save_mode_for_timeline( + ctx, + space_view_id, + timeline.name(), + &QueryMode::LatestAt { + time: time_ctrl.time_int().unwrap_or(TimeInt::MAX), }, - )); - - let time_spec = if let Some(time_histogram) = ctx.recording().time_histogram(&timeline) - { - TimelineSpec::from_time_histogram(time_histogram) - } else { - // shouldn't happen, `timeline` existence was already checked - TimelineSpec::from_time_range(0..=0) - }; + )?; + } else { + property.reset_blueprint_component::(ctx); + } + } - match current_mode { - QueryKind::LatestAt => { - // - // Latest At time - // TODO(ab): we can't use edit ui because we dont have the required context - // there, aka the currently chosen timeline. - // - - let mut latest_at_queries = property - .component_or_fallback::( - ctx, - fallback_provider, - state, - )?; - - let mut latest_at_query = latest_at_queries - .query_for_timeline(timeline_name.as_str()) - .cloned() - .unwrap_or_else(|| datatypes::LatestAtQuery { - timeline: timeline_name.as_str().into(), - time: TimeInt::MAX.into(), - }); + if override_query { + override_ui(ctx, ui, state, space_view_id, property) + } else { + Ok(()) + } +} - ui.list_item_flat_noninteractive( - list_item::PropertyContent::new("At time").value_fn(|ui, _| { - let resp = match timeline.typ() { - TimeType::Time => { - time_spec - .temporal_drag_value( - ui, - &mut latest_at_query.time, - true, - None, - ctx.app_options.time_zone, - ) - .0 - } - TimeType::Sequence => time_spec.sequence_drag_value( - ui, - &mut latest_at_query.time, - true, - None, - ), - }; +fn override_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + state: &mut dyn SpaceViewState, + space_view_id: SpaceViewId, + property: ViewProperty<'_>, +) -> Result<(), SpaceViewSystemExecutionError> { + let name = archetypes::DataframeQuery::name(); + let Some(reflection) = ctx.reflection.archetypes.get(&name) else { + // The `ArchetypeReflectionMarker` bound should make this impossible. + re_log::warn_once!("Missing reflection data for archetype {name:?}."); + return Ok(()); + }; + + let timeline = property + .component_or_empty::()? + .map(|t| t.timeline_name()) + .and_then(|timeline_name| { + ctx.recording() + .timelines() + .find(|t| t.name() == &timeline_name) + .cloned() + }) + .unwrap_or(ctx.rec_cfg.time_ctrl.read().timeline().clone()); + let timeline_name = timeline.name(); + + let blueprint_path = + entity_path_for_view_property(space_view_id, ctx.blueprint_db().tree(), name); + let query_context = QueryContext { + viewer_ctx: ctx, + target_entity_path: &blueprint_path, + archetype_name: Some(name), + query: ctx.blueprint_query, + view_state: state, + view_ctx: None, + }; + + let component_results = ctx.blueprint_db().latest_at( + ctx.blueprint_query, + &blueprint_path, + reflection.fields.iter().map(|field| field.component_name), + ); + + ui.selection_grid("dataframe_view_query_ui") + .show(ui, |ui| { + ui.grid_left_hand_label("Timeline"); - if resp.changed() { - latest_at_queries.set_query_for_timeline( - timeline_name.as_str(), - Some(latest_at_query), - ); - ctx.save_blueprint_component(&blueprint_path, &latest_at_queries); - } - }), - ); - } - QueryKind::TimeRange => { - // - // Range times - - let mut time_range_queries = property - .component_or_fallback::( - ctx, - fallback_provider, - state, - )?; - - let mut time_range_query = time_range_queries - .query_for_timeline(timeline_name.as_str()) - .cloned() - .unwrap_or_else(|| datatypes::TimeRangeQuery { - timeline: timeline_name.as_str().into(), - start: TimeInt::MIN.into(), - end: TimeInt::MAX.into(), - }); + let component_name = components::Timeline::name(); - let mut changed = false; - ui.list_item_flat_noninteractive( - list_item::PropertyContent::new("From").value_fn(|ui, _| { - let resp = match timeline.typ() { - TimeType::Time => { - time_spec - .temporal_drag_value( - ui, - &mut time_range_query.start, - true, - None, - ctx.app_options.time_zone, - ) - .0 - } - TimeType::Sequence => time_spec.sequence_drag_value( - ui, - &mut time_range_query.start, - true, - None, - ), - }; + //TODO(ab, andreas): ideally it would be _much_ easier to call if a fallback provider is not needed + ctx.component_ui_registry.singleline_edit_ui( + &query_context, + ui, + ctx.blueprint_db(), + &blueprint_path, + component_name, + component_results + .component_batch_raw(&component_name) + .as_deref(), + // we don't need to provide a fallback here as the timeline should be present by definition + &EmptySystem {}, + ); - changed |= resp.changed(); - }), - ); - - let end_response = ui.list_item_flat_noninteractive( - list_item::PropertyContent::new("To").value_fn(|ui, _| { - let resp = match timeline.typ() { - TimeType::Time => { - time_spec - .temporal_drag_value( - ui, - &mut time_range_query.end, - true, - None, - ctx.app_options.time_zone, - ) - .0 - } - TimeType::Sequence => time_spec.sequence_drag_value( - ui, - &mut time_range_query.end, - true, - None, - ), - }; + ui.end_row(); - changed |= resp.changed(); - }), - ); + ui.grid_left_hand_label("Showing"); - if changed { - time_range_queries - .set_query_for_timeline(timeline_name.as_str(), Some(time_range_query)); - ctx.save_blueprint_component(&blueprint_path, &time_range_queries); - } - } + let query = Query::try_from_blueprint(ctx, space_view_id)?; + let mut ui_query_mode: UiQueryMode = query.mode(ctx).into(); + let time_drag_value = if let Some(times) = ctx.recording().time_histogram(&timeline) { + TimeDragValue::from_time_histogram(times) + } else { + TimeDragValue::from_time_range(0..=0) + }; + let changed = ui_query_mode.ui(ctx, ui, time_drag_value, timeline.typ()); + if changed { + Query::save_mode_for_timeline( + ctx, + space_view_id, + &timeline_name, + &ui_query_mode.into(), + )?; } Ok(()) - }; - - let result = ui - .list_item() - .interactive(false) - .show_hierarchical_with_children( - ui, - ui.make_persistent_id("view_query"), - true, - list_item::LabelContent::new("Query"), - |ui| inner_ui(ui), - ); - - result.body_response.map(|r| r.inner).unwrap_or(Ok(())) - } + }) + .inner } -// ================================================================================================= -// TODO: this is copied from visible_time_range_ui.rs. It should be extracted and cleaned-up. Also -// there is time histogram stuff here that is bound to be removed/fixed. - -/// Compute and store various information about a timeline related to how the UI should behave. -#[derive(Debug)] -struct TimelineSpec { - /// Actual range of logged data on the timelines (excluding timeless data). - range: RangeInclusive, - - /// For timelines with large offsets (e.g. `log_time`), this is a rounded time just before the - /// first logged data, which can be used as offset in the UI. - base_time: Option, +// -- - // used only for temporal timelines - /// For temporal timelines, this is a nice unit factor to use. - unit_factor: i64, - - /// For temporal timelines, this is the unit symbol to display. - unit_symbol: &'static str, - - /// This is a nice range of absolute times to use when editing an absolute time. The boundaries - /// are extended to the nearest rounded unit to minimize glitches. - abs_range: RangeInclusive, - - /// This is a nice range of relative times to use when editing an absolute time. The boundaries - /// are extended to the nearest rounded unit to minimize glitches. - rel_range: RangeInclusive, +/// Helper to handle the various query modes as they are offered in the UI. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum UiQueryMode { + LatestAt { time: TimeInt }, + TimeRangeAll, + TimeRange { from: TimeInt, to: TimeInt }, } -impl TimelineSpec { - //TODO: remove that - fn from_time_histogram(times: &TimeHistogram) -> Self { - Self::from_time_range( - times.min_key().unwrap_or_default()..=times.max_key().unwrap_or_default(), - ) - } - - fn from_time_range(range: RangeInclusive) -> Self { - let span = range.end() - range.start(); - let base_time = time_range_base_time(*range.start(), span); - let (unit_symbol, unit_factor) = unit_from_span(span); - - // `abs_range` is used by the DragValue when editing an absolute time, its bound expended to - // nearest unit to minimize glitches. - let abs_range = - round_down(*range.start(), unit_factor)..=round_up(*range.end(), unit_factor); - - // `rel_range` is used by the DragValue when editing a relative time offset. It must have - // enough margin either side to accommodate for all possible values of current time. - let rel_range = round_down(-span, unit_factor)..=round_up(2 * span, unit_factor); - - Self { - range, - base_time, - unit_factor, - unit_symbol, - abs_range, - rel_range, - } - } - - fn sequence_drag_value( - &self, +impl UiQueryMode { + /// Show the UI for the query mode selector. + fn ui( + &mut self, + ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - value: &mut re_types_core::datatypes::TimeInt, - absolute: bool, - low_bound_override: Option, - ) -> Response { - let mut time_range = if absolute { - self.abs_range.clone() - } else { - self.rel_range.clone() - }; + time_drag_value: TimeDragValue, + time_type: TimeType, + ) -> bool { + let orig_self = self.clone(); - // speed must be computed before messing with time_range for consistency - let span = time_range.end() - time_range.start(); - let speed = (span as f32 * 0.005).at_least(1.0); + ui.vertical(|ui| { + // + // LATEST AT + // - if let Some(low_bound_override) = low_bound_override { - time_range = low_bound_override.0.at_least(*time_range.start())..=*time_range.end(); - } + ui.horizontal(|ui| { + let mut is_latest_at = matches!(self, Self::LatestAt { .. }); - ui.add( - egui::DragValue::new(&mut value.0) - .range(time_range) - .speed(speed), - ) - } + let mut changed = ui + .re_radio_value(&mut is_latest_at, true, "Latest at") + .changed(); - /// Show a temporal drag value. - /// - /// Feature rich: - /// - scale to the proper units - /// - display the base time if any - /// - etc. - /// - /// Returns a tuple of the [`egui::DragValue`]'s [`egui::Response`], and the base time label's - /// [`egui::Response`], if any. - fn temporal_drag_value( - &self, - ui: &mut egui::Ui, - value: &mut re_types_core::datatypes::TimeInt, - absolute: bool, - low_bound_override: Option, - time_zone_for_timestamps: TimeZone, - ) -> (Response, Option) { - let mut time_range = if absolute { - self.abs_range.clone() - } else { - self.rel_range.clone() - }; - - let factor = self.unit_factor as f32; - let offset = if absolute { - self.base_time.unwrap_or(0) - } else { - 0 - }; + if is_latest_at { + let mut time = if let Self::LatestAt { time } = self { + *time + } else { + TimeInt::MAX + } + .into(); + + changed |= match time_type { + TimeType::Time => time_drag_value + .temporal_drag_value_ui( + ui, + &mut time, + true, + None, + ctx.app_options.time_zone, + ) + .0 + .changed(), + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut time, true, None) + .changed(), + }; - // speed must be computed before messing with time_range for consistency - let speed = (time_range.end() - time_range.start()) as f32 / factor * 0.005; + if changed { + *self = Self::LatestAt { time: time.into() }; + } + } + }); - if let Some(low_bound_override) = low_bound_override { - time_range = low_bound_override.0.at_least(*time_range.start())..=*time_range.end(); - } + // + // TIME RANGE ALL + // - let mut time_unit = (value.0 - offset) as f32 / factor; - - let time_range = (*time_range.start() - offset) as f32 / factor - ..=(*time_range.end() - offset) as f32 / factor; - - let base_time_response = if absolute { - self.base_time.map(|base_time| { - ui.label(format!( - "{} + ", - TimeType::Time.format( - re_types_core::datatypes::TimeInt(base_time), - time_zone_for_timestamps - ) - )) - }) - } else { - None - }; + ui.horizontal(|ui| { + let mut is_time_range_all = matches!(self, Self::TimeRangeAll); + if ui + .re_radio_value(&mut is_time_range_all, true, "From –∞ to +∞") + .changed() + && is_time_range_all + { + *self = Self::TimeRangeAll; + } + }); - let drag_value_response = ui.add( - egui::DragValue::new(&mut time_unit) - .range(time_range) - .speed(speed) - .suffix(self.unit_symbol), - ); + // + // TIME RANGE CUSTOM + // - *value = re_types_core::datatypes::TimeInt((time_unit * factor).round() as i64 + offset); + ui.vertical(|ui| { + let mut is_time_range_custom = matches!(self, Self::TimeRange { .. }); + let mut changed = ui + .re_radio_value(&mut is_time_range_custom, true, "Define time range") + .changed(); + + if is_time_range_custom { + ui.spacing_mut().indent = ui.spacing().icon_width + ui.spacing().icon_spacing; + ui.indent("time_range_custom", |ui| { + let mut from = if let Self::TimeRange { from, .. } = self { + (*from).into() + } else { + (*time_drag_value.range.start()).into() + }; + + let mut to = if let Self::TimeRange { to, .. } = self { + (*to).into() + } else { + (*time_drag_value.range.end()).into() + }; + + list_item::list_item_scope(ui, "time_range_custom_scope", |ui| { + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("Start").value_fn(|ui, _| { + changed |= match time_type { + TimeType::Time => time_drag_value + .temporal_drag_value_ui( + ui, + &mut from, + true, + None, + ctx.app_options.time_zone, + ) + .0 + .changed(), + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut from, true, None) + .changed(), + }; + }), + ); + + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("End").value_fn(|ui, _| { + changed |= match time_type { + TimeType::Time => time_drag_value + .temporal_drag_value_ui( + ui, + &mut to, + true, + Some(from), + ctx.app_options.time_zone, + ) + .0 + .changed(), + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut to, true, Some(from)) + .changed(), + }; + }), + ); + }); - (drag_value_response, base_time_response) - } -} + if changed { + *self = Self::TimeRange { + from: from.into(), + to: to.into(), + }; + } + }); + } + }); + }); -fn unit_from_span(span: i64) -> (&'static str, i64) { - if span / 1_000_000_000 > 0 { - ("s", 1_000_000_000) - } else if span / 1_000_000 > 0 { - ("ms", 1_000_000) - } else if span / 1_000 > 0 { - ("μs", 1_000) - } else { - ("ns", 1) + *self != orig_self } } -/// Value of the start time over time span ratio above which an explicit offset is handled. -static SPAN_TO_START_TIME_OFFSET_THRESHOLD: i64 = 10; - -fn time_range_base_time(min_time: i64, span: i64) -> Option { - if min_time <= 0 { - return None; - } - - if span.saturating_mul(SPAN_TO_START_TIME_OFFSET_THRESHOLD) < min_time { - let factor = if span / 1_000_000 > 0 { - 1_000_000_000 - } else if span / 1_000 > 0 { - 1_000_000 - } else { - 1_000 - }; - - Some(min_time - (min_time % factor)) - } else { - None +impl From for UiQueryMode { + fn from(value: QueryMode) -> Self { + match value { + QueryMode::LatestAt { time } => Self::LatestAt { time }, + QueryMode::Range { + from: TimeInt::MIN, + to: TimeInt::MAX, + } => Self::TimeRangeAll, + QueryMode::Range { from, to } => Self::TimeRange { from, to }, + } } } -fn round_down(value: i64, factor: i64) -> i64 { - value - (value.rem_euclid(factor)) -} - -fn round_up(value: i64, factor: i64) -> i64 { - let val = round_down(value, factor); - - if val == value { - val - } else { - val + factor +impl From for QueryMode { + fn from(value: UiQueryMode) -> Self { + match value { + UiQueryMode::LatestAt { time } => QueryMode::LatestAt { time }, + UiQueryMode::TimeRangeAll => QueryMode::Range { + from: TimeInt::MIN, + to: TimeInt::MAX, + }, + UiQueryMode::TimeRange { from, to } => QueryMode::Range { from, to }, + } } } diff --git a/crates/viewer/re_viewer_context/src/time_drag_value.rs b/crates/viewer/re_viewer_context/src/time_drag_value.rs index e43143b92deb..84e834f9d324 100644 --- a/crates/viewer/re_viewer_context/src/time_drag_value.rs +++ b/crates/viewer/re_viewer_context/src/time_drag_value.rs @@ -130,7 +130,7 @@ impl TimeDragValue { time_range = low_bound_override.0.at_least(*time_range.start())..=*time_range.end(); } - let mut time_unit = (value.0 - offset) as f32 / factor; + let mut time_unit = (value.0.saturating_sub(offset)) as f32 / factor; let time_range = (*time_range.start() - offset) as f32 / factor ..=(*time_range.end() - offset) as f32 / factor; From e50794c1cfdc9c21a0cece04025327b0631b5b6b Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 14:44:53 +0200 Subject: [PATCH 05/18] Post rebase fixes --- .../components/dataframe_view_mode.fbs | 0 .../rerun/blueprint/components/query_kind.fbs | 3 + .../src/blueprint/components/query_kind.rs | 91 ++++++++----------- .../src/space_view_class.rs | 2 +- .../rerun/blueprint/components/query_kind.cpp | 12 +-- .../rerun/blueprint/components/query_kind.hpp | 9 +- .../rerun/blueprint/components/query_kind.py | 71 +++++---------- 7 files changed, 76 insertions(+), 112 deletions(-) delete mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs index ee36cf14dcf9..11270222d1ba 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs @@ -5,6 +5,9 @@ namespace rerun.blueprint.components; enum QueryKind: byte ( "attr.rerun.scope": "blueprint" ) { + /// Invalid value. Won't show up in generated types. + Invalid = 0, + /// Query LatestAt (default), diff --git a/crates/store/re_types/src/blueprint/components/query_kind.rs b/crates/store/re_types/src/blueprint/components/query_kind.rs index 87d79eff06f4..e473b5a5fbaf 100644 --- a/crates/store/re_types/src/blueprint/components/query_kind.rs +++ b/crates/store/re_types/src/blueprint/components/query_kind.rs @@ -20,6 +20,7 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// **Component**: The kind of query displayed by the dataframe view #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] +#[repr(u8)] pub enum QueryKind { /// Query #[default] @@ -79,15 +80,7 @@ impl ::re_types_core::Loggable for QueryKind { fn arrow_datatype() -> arrow2::datatypes::DataType { #![allow(clippy::wildcard_imports)] use arrow2::datatypes::*; - DataType::Union( - std::sync::Arc::new(vec![ - Field::new("_null_markers", DataType::Null, true), - Field::new("LatestAt", DataType::Null, true), - Field::new("TimeRange", DataType::Null, true), - ]), - Some(std::sync::Arc::new(vec![0i32, 1i32, 2i32])), - UnionMode::Sparse, - ) + DataType::UInt8 } fn to_arrow_opt<'a>( @@ -100,27 +93,24 @@ impl ::re_types_core::Loggable for QueryKind { use ::re_types_core::{Loggable as _, ResultExt as _}; use arrow2::{array::*, datatypes::*}; Ok({ - // Sparse Arrow union - let data: Vec<_> = data + let (somes, data0): (Vec<_>, Vec<_>) = data .into_iter() .map(|datum| { let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); - datum + let datum = datum.map(|datum| *datum as u8); + (datum.is_some(), datum) }) - .collect(); - let num_variants = 2usize; - let types = data - .iter() - .map(|a| match a.as_deref() { - None => 0, - Some(value) => *value as i8, - }) - .collect(); - let fields: Vec<_> = - std::iter::repeat(NullArray::new(DataType::Null, data.len()).boxed()) - .take(1 + num_variants) - .collect(); - UnionArray::new(Self::arrow_datatype(), types, fields, None).boxed() + .unzip(); + let data0_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + Self::arrow_datatype(), + data0.into_iter().map(|v| v.unwrap_or_default()).collect(), + data0_bitmap, + ) + .boxed() }) } @@ -133,31 +123,28 @@ impl ::re_types_core::Loggable for QueryKind { #![allow(clippy::wildcard_imports)] use ::re_types_core::{Loggable as _, ResultExt as _}; use arrow2::{array::*, buffer::*, datatypes::*}; - Ok({ - let arrow_data = arrow_data - .as_any() - .downcast_ref::() - .ok_or_else(|| { - let expected = Self::arrow_datatype(); - let actual = arrow_data.data_type().clone(); - DeserializationError::datatype_mismatch(expected, actual) - }) - .with_context("rerun.blueprint.components.QueryKind")?; - let arrow_data_types = arrow_data.types(); - arrow_data_types - .iter() - .map(|typ| match typ { - 0 => Ok(None), - 1 => Ok(Some(Self::LatestAt)), - 2 => Ok(Some(Self::TimeRange)), - _ => Err(DeserializationError::missing_union_arm( - Self::arrow_datatype(), - "", - *typ as _, - )), - }) - .collect::>>() - .with_context("rerun.blueprint.components.QueryKind")? - }) + Ok(arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.QueryKind#enum")? + .into_iter() + .map(|opt| opt.copied()) + .map(|typ| match typ { + Some(1) => Ok(Some(Self::LatestAt)), + Some(2) => Ok(Some(Self::TimeRange)), + None => Ok(None), + Some(invalid) => Err(DeserializationError::missing_union_arm( + Self::arrow_datatype(), + "", + invalid as _, + )), + }) + .collect::>>>() + .with_context("rerun.blueprint.components.QueryKind")?) } } diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index a031effde836..a7e45700f6a7 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -242,4 +242,4 @@ mode sets the default time range to _everything_. You can override this in the s // } // } // -// re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => [Timeline, LatestAtQueries]); +re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => []); diff --git a/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp b/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp index bfc9c8769356..a6e0297f884e 100644 --- a/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp @@ -9,11 +9,7 @@ namespace rerun { const std::shared_ptr& Loggable::arrow_datatype() { - static const auto datatype = arrow::sparse_union({ - arrow::field("_null_markers", arrow::null(), true, nullptr), - arrow::field("LatestAt", arrow::null(), true), - arrow::field("TimeRange", arrow::null(), true), - }); + static const auto datatype = arrow::uint8(); return datatype; } @@ -27,7 +23,7 @@ namespace rerun { ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) if (instances && num_instances > 0) { RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( - static_cast(builder.get()), + static_cast(builder.get()), instances, num_instances )); @@ -38,7 +34,7 @@ namespace rerun { } rerun::Error Loggable::fill_arrow_array_builder( - arrow::SparseUnionBuilder* builder, const blueprint::components::QueryKind* elements, + arrow::UInt8Builder* builder, const blueprint::components::QueryKind* elements, size_t num_elements ) { if (builder == nullptr) { @@ -54,7 +50,7 @@ namespace rerun { ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { const auto variant = elements[elem_idx]; - ARROW_RETURN_NOT_OK(builder->Append(static_cast(variant))); + ARROW_RETURN_NOT_OK(builder->Append(static_cast(variant))); } return Error::ok(); diff --git a/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp b/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp index 451775056b2c..83ada16ad531 100644 --- a/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp @@ -9,9 +9,14 @@ #include namespace arrow { + /// \private + template + class NumericBuilder; + class Array; class DataType; - class SparseUnionBuilder; + class UInt8Type; + using UInt8Builder = NumericBuilder; } // namespace arrow namespace rerun::blueprint::components { @@ -45,7 +50,7 @@ namespace rerun { /// Fills an arrow array builder with an array of this type. static rerun::Error fill_arrow_array_builder( - arrow::SparseUnionBuilder* builder, const blueprint::components::QueryKind* elements, + arrow::UInt8Builder* builder, const blueprint::components::QueryKind* elements, size_t num_elements ); }; diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py b/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py index ec1e5c469b8e..cd8e452fb9e2 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py @@ -30,17 +30,28 @@ class QueryKind(Enum): TimeRange = 2 """Time range query.""" + @classmethod + def auto(cls, val: str | int | QueryKind) -> QueryKind: + """Best-effort converter, including a case-insensitive string matcher.""" + if isinstance(val, QueryKind): + return val + if isinstance(val, int): + return cls(val) + try: + return cls[val] + except KeyError: + val_lower = val.lower() + for variant in cls: + if variant.name.lower() == val_lower: + return variant + raise ValueError(f"Cannot convert {val} to {cls.__name__}") + def __str__(self) -> str: """Returns the variant name.""" - if self == QueryKind.LatestAt: - return "LatestAt" - elif self == QueryKind.TimeRange: - return "TimeRange" - else: - raise ValueError("Unknown enum variant") + return self.name -QueryKindLike = Union[QueryKind, Literal["LatestAt", "TimeRange", "latestat", "timerange"]] +QueryKindLike = Union[QueryKind, Literal["LatestAt", "TimeRange", "latestat", "timerange"], int] QueryKindArrayLike = Union[QueryKindLike, Sequence[QueryKindLike]] @@ -48,15 +59,7 @@ class QueryKindType(BaseExtensionType): _TYPE_NAME: str = "rerun.blueprint.components.QueryKind" def __init__(self) -> None: - pa.ExtensionType.__init__( - self, - pa.sparse_union([ - pa.field("_null_markers", pa.null(), nullable=True, metadata={}), - pa.field("LatestAt", pa.null(), nullable=True, metadata={}), - pa.field("TimeRange", pa.null(), nullable=True, metadata={}), - ]), - self._TYPE_NAME, - ) + pa.ExtensionType.__init__(self, pa.uint8(), self._TYPE_NAME) class QueryKindBatch(BaseBatch[QueryKindArrayLike], ComponentBatchMixin): @@ -67,36 +70,6 @@ def _native_to_pa_array(data: QueryKindArrayLike, data_type: pa.DataType) -> pa. if isinstance(data, (QueryKind, int, str)): data = [data] - types: list[int] = [] - - for value in data: - if value is None: - types.append(0) - elif isinstance(value, QueryKind): - types.append(value.value) # Actual enum value - elif isinstance(value, int): - types.append(value) # By number - elif isinstance(value, str): - if hasattr(QueryKind, value): - types.append(QueryKind[value].value) # fast path - elif value.lower() == "latestat": - types.append(QueryKind.LatestAt.value) - elif value.lower() == "timerange": - types.append(QueryKind.TimeRange.value) - else: - raise ValueError(f"Unknown QueryKind kind: {value}") - else: - raise ValueError(f"Unknown QueryKind kind: {value}") - - buffers = [ - None, - pa.array(types, type=pa.int8()).buffers()[1], - ] - children = (1 + 2) * [pa.nulls(len(data))] - - return pa.UnionArray.from_buffers( - type=data_type, - length=len(data), - buffers=buffers, - children=children, - ) + pa_data = [QueryKind.auto(v).value if v is not None else None for v in data] # type: ignore[redundant-expr] + + return pa.array(pa_data, type=data_type) From c9fd2d308db6c626bd6cfa496243c964e7473584 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 15:12:45 +0200 Subject: [PATCH 06/18] Hide visible time range for dataframe view --- Cargo.lock | 1 - crates/viewer/re_selection_panel/Cargo.toml | 1 - .../src/visible_time_range_ui.rs | 2 -- .../src/space_view_class.rs | 20 ++++++++++--------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec05f3e144ca..7c1e5fc9d8cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4857,7 +4857,6 @@ dependencies = [ "re_log", "re_log_types", "re_space_view", - "re_space_view_dataframe", "re_space_view_spatial", "re_space_view_time_series", "re_tracing", diff --git a/crates/viewer/re_selection_panel/Cargo.toml b/crates/viewer/re_selection_panel/Cargo.toml index 1f03685f7f58..e67bfccc46ea 100644 --- a/crates/viewer/re_selection_panel/Cargo.toml +++ b/crates/viewer/re_selection_panel/Cargo.toml @@ -26,7 +26,6 @@ re_data_ui.workspace = true re_entity_db.workspace = true re_log_types.workspace = true re_log.workspace = true -re_space_view_dataframe.workspace = true re_space_view_spatial.workspace = true re_space_view_time_series.workspace = true re_space_view.workspace = true diff --git a/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs b/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs index 10ee88a60a2b..0fbb6afc57da 100644 --- a/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs +++ b/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs @@ -3,7 +3,6 @@ use std::collections::HashSet; use egui::{NumExt as _, Ui}; use re_log_types::{EntityPath, ResolvedTimeRange, TimeType, TimelineName}; -use re_space_view_dataframe::DataframeSpaceView; use re_space_view_spatial::{SpatialSpaceView2D, SpatialSpaceView3D}; use re_space_view_time_series::TimeSeriesSpaceView; use re_types::{ @@ -23,7 +22,6 @@ static VISIBLE_HISTORY_SUPPORTED_SPACE_VIEWS: once_cell::sync::Lazy< SpatialSpaceView3D::identifier(), SpatialSpaceView2D::identifier(), TimeSeriesSpaceView::identifier(), - DataframeSpaceView::identifier(), ] .map(Into::into) .into() diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index a7e45700f6a7..a23833675a60 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -1,23 +1,25 @@ +use std::any::Any; + use egui::Ui; + use re_chunk_store::LatestAtQuery; use re_log_types::{EntityPath, ResolvedTimeRange}; use re_space_view::view_property_ui; -use re_types::blueprint::components::{LatestAtQueries, Timeline}; -use re_types::blueprint::{archetypes, components, datatypes}; -use re_types_core::datatypes::{TimeRange, Utf8}; +use re_types::blueprint::{archetypes, components}; +use re_types_core::datatypes::TimeRange; use re_types_core::SpaceViewClassIdentifier; use re_ui::list_item; use re_viewer_context::{ - QueryContext, QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, - SpaceViewState, SpaceViewStateExt, SpaceViewSystemExecutionError, SystemExecutionOutput, - TypedComponentFallbackProvider, ViewQuery, ViewerContext, + QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, + SpaceViewStateExt, SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, + ViewerContext, }; use re_viewport_blueprint::ViewProperty; -use std::any::Any; -use crate::view_query::{Query, QueryMode}; use crate::{ - latest_at_table::latest_at_table_ui, time_range_table::time_range_table_ui, + latest_at_table::latest_at_table_ui, + time_range_table::time_range_table_ui, + view_query::{Query, QueryMode}, visualizer_system::EmptySystem, }; From 19ced7012f2ac0e53afdbeab97f89cf680614828 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 16:00:44 +0200 Subject: [PATCH 07/18] Cleaned comments --- .../src/space_view_class.rs | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index a23833675a60..76daca57997e 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -211,37 +211,4 @@ mode sets the default time range to _everything_. You can override this in the s } } -// //TODO: probably no longer needed -// impl TypedComponentFallbackProvider for DataframeSpaceView { -// fn fallback_for(&self, ctx: &re_viewer_context::QueryContext<'_>) -> Timeline { -// //TODO: add helper to Timeline component -// Timeline(Utf8::from( -// ctx.viewer_ctx -// .rec_cfg -// .time_ctrl -// .read() -// .timeline() -// .name() -// .as_str(), -// )) -// } -// } -// -// //TODO: probably no longer needed -// impl TypedComponentFallbackProvider for DataframeSpaceView { -// fn fallback_for(&self, ctx: &QueryContext<'_>) -> LatestAtQueries { -// let current_time = ctx.viewer_ctx.rec_cfg.time_ctrl.read(); -// -// let latest_at_query = datatypes::LatestAtQuery { -// timeline: Utf8::from(current_time.timeline().name().as_str()), -// time: re_types_core::datatypes::TimeInt::from( -// current_time -// .time_int() -// .unwrap_or(re_log_types::TimeInt::MAX), -// ), -// }; -// LatestAtQueries::from(vec![latest_at_query]) -// } -// } -// re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => []); From 7d2b88b1c52ba3d068910e4195b2670b61ca4496 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 16:51:53 +0200 Subject: [PATCH 08/18] Self review & lint --- .../components/latest_at_queries.fbs | 2 +- .../components/time_range_queries.fbs | 2 +- .../rerun/blueprint/components/timeline.fbs | 4 +- .../blueprint/datatypes/time_range_query.fbs | 2 +- .../components/latest_at_queries_ext.rs | 18 ++--- .../components/time_range_queries_ext.rs | 18 ++--- .../src/blueprint/components/timeline.rs | 2 +- .../src/blueprint/components/timeline_ext.rs | 2 +- .../blueprint/datatypes/time_range_query.rs | 2 +- crates/viewer/re_edit_ui/src/lib.rs | 5 +- .../src/latest_at_table.rs | 13 ++-- .../src/space_view_class.rs | 51 ++------------ .../src/time_range_table.rs | 35 +++++----- .../re_space_view_dataframe/src/utils.rs | 4 +- .../re_space_view_dataframe/src/view_query.rs | 66 +++++++++---------- crates/viewer/re_viewer/src/reflection/mod.rs | 2 +- .../rerun/blueprint/components/timeline.hpp | 2 +- .../blueprint/datatypes/time_range_query.hpp | 2 +- .../rerun/blueprint/components/timeline.py | 2 +- .../blueprint/datatypes/time_range_query.py | 4 +- 20 files changed, 83 insertions(+), 155 deletions(-) diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs index 666913f8e68c..2ae62a030694 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs @@ -11,4 +11,4 @@ table LatestAtQueries ( "attr.rerun.scope": "blueprint" ) { queries: [rerun.blueprint.datatypes.LatestAtQuery] (order: 100); -} \ No newline at end of file +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs index e22c75bce40f..cfa60cd84d57 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs @@ -11,4 +11,4 @@ table TimeRangeQueries ( "attr.rerun.scope": "blueprint" ) { queries: [rerun.blueprint.datatypes.TimeRangeQuery] (order: 100); -} \ No newline at end of file +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs index 1b5a4f3bec05..a2ed7cdc4562 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs @@ -1,9 +1,7 @@ namespace rerun.blueprint.components; -// --- -//TODO: sane default -/// A timeline +/// A timeline, identified by its name. table Timeline ( "attr.arrow.transparent", "attr.python.aliases": "str", diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs index 8387cda25070..811c20c14aee 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs @@ -10,7 +10,7 @@ table TimeRangeQuery ( /// Name of the timeline this applies to. timeline: rerun.datatypes.Utf8 (order: 100); - /// Begining of the time range. + /// Beginning of the time range. start: rerun.datatypes.TimeInt (order: 200); /// End of the time range. diff --git a/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs index 1eff72fd58ca..256433253f7e 100644 --- a/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs +++ b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs @@ -10,21 +10,11 @@ impl LatestAtQueries { } /// Sets the query for a given timeline. - /// - /// If the query is `None`, the timeline will be removed from the list of latest queries. - pub fn set_query_for_timeline(&mut self, timeline_name: &str, query: Option) { - if let Some(query) = query { - if let Some(existing_query) = self - .0 - .iter_mut() - .find(|query| query.timeline.as_str() == timeline_name) - { - *existing_query = query; - } else { - self.0.push(query); - } + pub fn set_query_for_timeline(&mut self, query: LatestAtQuery) { + if let Some(existing_query) = self.0.iter_mut().find(|q| q.timeline == query.timeline) { + *existing_query = query; } else { - self.0.retain(|q| q.timeline.as_str() != timeline_name); + self.0.push(query); } } } diff --git a/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs index 5c54fa06f4cb..50a5bf2b9381 100644 --- a/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs +++ b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs @@ -10,21 +10,11 @@ impl TimeRangeQueries { } /// Sets the query for a given timeline. - /// - /// If the query is `None`, the timeline will be removed from the list of time range queries. - pub fn set_query_for_timeline(&mut self, timeline_name: &str, query: Option) { - if let Some(query) = query { - if let Some(existing_query) = self - .0 - .iter_mut() - .find(|query| query.timeline.as_str() == timeline_name) - { - *existing_query = query; - } else { - self.0.push(query); - } + pub fn set_query_for_timeline(&mut self, query: TimeRangeQuery) { + if let Some(existing_query) = self.0.iter_mut().find(|q| q.timeline == query.timeline) { + *existing_query = query; } else { - self.0.retain(|q| q.timeline.as_str() != timeline_name); + self.0.push(query); } } } diff --git a/crates/store/re_types/src/blueprint/components/timeline.rs b/crates/store/re_types/src/blueprint/components/timeline.rs index 37301240be69..4945faf83064 100644 --- a/crates/store/re_types/src/blueprint/components/timeline.rs +++ b/crates/store/re_types/src/blueprint/components/timeline.rs @@ -18,7 +18,7 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Component**: A timeline +/// **Component**: A timeline, identified by its name. #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] pub struct Timeline(pub crate::datatypes::Utf8); diff --git a/crates/store/re_types/src/blueprint/components/timeline_ext.rs b/crates/store/re_types/src/blueprint/components/timeline_ext.rs index fdb3cfdedd2f..410cb491576a 100644 --- a/crates/store/re_types/src/blueprint/components/timeline_ext.rs +++ b/crates/store/re_types/src/blueprint/components/timeline_ext.rs @@ -10,6 +10,6 @@ impl Timeline { /// Set the name of the timeline. pub fn set_timeline_name(&mut self, timeline_name: TimelineName) { - self.0 = timeline_name.as_str().into() + self.0 = timeline_name.as_str().into(); } } diff --git a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs index b8ce7bac9cf2..21ebcadd1ba6 100644 --- a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs +++ b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs @@ -24,7 +24,7 @@ pub struct TimeRangeQuery { /// Name of the timeline this applies to. pub timeline: crate::datatypes::Utf8, - /// Begining of the time range. + /// Beginning of the time range. pub start: crate::datatypes::TimeInt, /// End of the time range. diff --git a/crates/viewer/re_edit_ui/src/lib.rs b/crates/viewer/re_edit_ui/src/lib.rs index 98abbb9ed799..448cb7bc0d5e 100644 --- a/crates/viewer/re_edit_ui/src/lib.rs +++ b/crates/viewer/re_edit_ui/src/lib.rs @@ -20,8 +20,8 @@ use datatype_editors::{ }; use re_types::{ blueprint::components::{ - BackgroundKind, Corner2D, LockRangeDuringZoom, QueryKind, SortKey, SortOrder, Timeline, - ViewFit, Visible, + BackgroundKind, Corner2D, LockRangeDuringZoom, SortKey, SortOrder, Timeline, ViewFit, + Visible, }, components::{ AggregationPolicy, AlbedoFactor, AxisLength, ChannelDatatype, Color, ColorModel, Colormap, @@ -78,7 +78,6 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); - registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); diff --git a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs index 567487bf9eb3..679dd30a896f 100644 --- a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs @@ -17,9 +17,8 @@ use crate::{ pub(crate) fn latest_at_table_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - //TODO: remove this parameter, pass space view id and BTreeSet instead query: &ViewQuery<'_>, - latest_at_query: LatestAtQuery, + latest_at_query: &LatestAtQuery, ) { re_tracing::profile_function!(); @@ -53,7 +52,7 @@ pub(crate) fn latest_at_table_ui( entity_path, ctx.recording_store(), &latest_at_query.timeline(), - &latest_at_query, + latest_at_query, ) }) .collect(); @@ -134,7 +133,7 @@ pub(crate) fn latest_at_table_ui( row.col(|ui| { instance_path_button( ctx, - &latest_at_query, + latest_at_query, ctx.recording(), ui, Some(query.space_view_id), @@ -151,14 +150,14 @@ pub(crate) fn latest_at_table_ui( let result = ctx .recording_store() .latest_at_relevant_chunks( - &latest_at_query, + latest_at_query, &instance_path.entity_path, *component_name, ) .into_iter() .filter_map(|chunk| { let (index, unit) = chunk - .latest_at(&latest_at_query, *component_name) + .latest_at(latest_at_query, *component_name) .into_unit() .and_then(|unit| { unit.index(&latest_at_query.timeline()) @@ -186,7 +185,7 @@ pub(crate) fn latest_at_table_ui( ctx, ui, UiLayout::List, - &latest_at_query, + latest_at_query, ctx.recording(), &instance_path.entity_path, *component_name, diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index 76daca57997e..b9f4d51e405a 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -1,18 +1,14 @@ -use std::any::Any; - use egui::Ui; use re_chunk_store::LatestAtQuery; use re_log_types::{EntityPath, ResolvedTimeRange}; use re_space_view::view_property_ui; use re_types::blueprint::{archetypes, components}; -use re_types_core::datatypes::TimeRange; use re_types_core::SpaceViewClassIdentifier; use re_ui::list_item; use re_viewer_context::{ - QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, - SpaceViewStateExt, SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, - ViewerContext, + SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, + SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, ViewerContext, }; use re_viewport_blueprint::ViewProperty; @@ -23,27 +19,6 @@ use crate::{ visualizer_system::EmptySystem, }; -/// State for the Dataframe view. -/// -/// We use this to carry information from `ui()` to `default_query_range()` as a workaround for -/// `https://github.com/rerun-io/rerun/issues/6918`. -#[derive(Debug, Default)] -struct DataframeViewState { - mode: components::QueryKind, -} - -impl SpaceViewState for DataframeViewState { - #[inline] - fn as_any(&self) -> &dyn Any { - self - } - - #[inline] - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - #[derive(Default)] pub struct DataframeSpaceView; @@ -90,7 +65,7 @@ mode sets the default time range to _everything_. You can override this in the s } fn new_state(&self) -> Box { - Box::::default() + Box::<()>::default() } fn preferred_tile_aspect_ratio(&self, _state: &dyn SpaceViewState) -> Option { @@ -101,21 +76,6 @@ mode sets the default time range to _everything_. You can override this in the s re_viewer_context::SpaceViewClassLayoutPriority::Low } - fn default_query_range(&self, state: &dyn SpaceViewState) -> QueryRange { - // TODO(#6918): passing the mode via view state is a hacky work-around, until we're able to - // pass more context to this function. - let mode = state - .downcast_ref::() - .map(|state| state.mode) - .inspect_err(|err| re_log::warn_once!("Unexpected view type: {err}")) - .unwrap_or_default(); - - match mode { - components::QueryKind::LatestAt => QueryRange::LatestAt, - components::QueryKind::TimeRange => QueryRange::TimeRange(TimeRange::EVERYTHING), - } - } - fn spawn_heuristics( &self, _ctx: &ViewerContext<'_>, @@ -135,9 +95,8 @@ mode sets the default time range to _everything_. You can override this in the s crate::view_query::query_ui(ctx, ui, state, space_view_id)?; list_item::list_item_scope(ui, "dataframe_view_selection_ui", |ui| { - //TODO: fix this :scream: let view_query = Query::try_from_blueprint(ctx, space_view_id)?; - + //TODO(#7070): column order and sorting needs much love ui.add_enabled_ui( matches!(view_query.mode(ctx), QueryMode::Range { .. }), |ui| { @@ -181,7 +140,7 @@ mode sets the default time range to _everything_. You can override this in the s match query_mode { QueryMode::LatestAt { time } => { - latest_at_table_ui(ctx, ui, query, LatestAtQuery::new(*timeline, time)) + latest_at_table_ui(ctx, ui, query, &LatestAtQuery::new(*timeline, time)); } QueryMode::Range { from, to } => { let time_range_table_order = diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index 839d72cde17d..abea5757a82f 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::sync::Arc; -use re_chunk_store::{Chunk, RangeQuery, RowId}; +use re_chunk_store::{Chunk, LatestAtQuery, RangeQuery, RowId}; use re_data_ui::item_ui::entity_path_button; use re_entity_db::InstancePath; use re_log_types::{EntityPath, ResolvedTimeRange, TimeInt, Timeline}; @@ -29,7 +29,6 @@ use crate::table_ui::{row_id_ui, table_ui}; pub(crate) fn time_range_table_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - //TODO: remove that, pass space view id and BTreeSet instead query: &ViewQuery<'_>, sort_key: SortKey, sort_order: SortOrder, @@ -212,18 +211,17 @@ pub(crate) fn time_range_table_ui( } }; - //TODO: why are these even needed?? - let latest_at_query = query.latest_at_query(); - let entity_ui = |ui: &mut egui::Ui, entity_path: &EntityPath| { - entity_path_button( - ctx, - &latest_at_query, - ctx.recording(), - ui, - Some(query.space_view_id), - entity_path, - ); - }; + let entity_ui = + |ui: &mut egui::Ui, entity_path: &EntityPath, latest_at_query: &LatestAtQuery| { + entity_path_button( + ctx, + latest_at_query, + ctx.recording(), + ui, + Some(query.space_view_id), + entity_path, + ); + }; let time_ui = |ui: &mut egui::Ui, time: &TimeInt| { if ui @@ -240,21 +238,22 @@ pub(crate) fn time_range_table_ui( }; // Draw a single line of the table. This is called for each _visible_ row. - //TODO: why are these even needed?? - let latest_at_query = query.latest_at_query(); let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { let row_key = rows[row.index()]; let row_chunk = &rows_to_chunk[row_key]; let (entity_path, time, row_id) = row_key; + // Latest at query corresponding to the current time + let latest_at_query = LatestAtQuery::new(*timeline, *time); + match sort_key { SortKey::Entity => { - row.col(|ui| entity_ui(ui, entity_path)); + row.col(|ui| entity_ui(ui, entity_path, &latest_at_query)); row.col(|ui| time_ui(ui, time)); } SortKey::Time => { row.col(|ui| time_ui(ui, time)); - row.col(|ui| entity_ui(ui, entity_path)); + row.col(|ui| entity_ui(ui, entity_path, &latest_at_query)); } }; diff --git a/crates/viewer/re_space_view_dataframe/src/utils.rs b/crates/viewer/re_space_view_dataframe/src/utils.rs index de61cc5d80e5..b5b2cc938ee9 100644 --- a/crates/viewer/re_space_view_dataframe/src/utils.rs +++ b/crates/viewer/re_space_view_dataframe/src/utils.rs @@ -19,10 +19,10 @@ pub(crate) fn sorted_visible_entity_path( } /// Returns a sorted, deduplicated iterator of all instance paths for a given entity. -pub(crate) fn sorted_instance_paths_for<'a, 'b>( +pub(crate) fn sorted_instance_paths_for<'a>( entity_path: &'a EntityPath, store: &'a ChunkStore, - timeline: &'b Timeline, + timeline: &Timeline, latest_at_query: &'a LatestAtQuery, ) -> impl Iterator + 'a { re_tracing::profile_function!(); diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index 7825c9651368..ab34e9b3b29c 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -65,8 +65,7 @@ impl Query { .0 .into_iter() .find(|q| q.timeline.as_str() == timeline) - .map(|q| q.time.into()) - .unwrap_or(TimeInt::MAX); + .map_or(TimeInt::MAX, |q| q.time.into()); QueryMode::LatestAt { time } } @@ -77,8 +76,9 @@ impl Query { .0 .into_iter() .find(|q| q.timeline.as_str() == timeline) - .map(|q| (q.start.into(), q.end.into())) - .unwrap_or((TimeInt::MIN, TimeInt::MAX)); + .map_or((TimeInt::MIN, TimeInt::MAX), |q| { + (q.start.into(), q.end.into()) + }); QueryMode::Range { from, to } } @@ -91,8 +91,8 @@ impl Query { #[inline] pub(crate) fn timeline_name(&self, ctx: &ViewerContext<'_>) -> TimelineName { match self { - Query::FollowTimeline => *ctx.rec_cfg.time_ctrl.read().timeline().name(), - Query::Override { timeline, .. } => *timeline, + Self::FollowTimeline => *ctx.rec_cfg.time_ctrl.read().timeline().name(), + Self::Override { timeline, .. } => *timeline, } } @@ -100,13 +100,13 @@ impl Query { #[inline] pub(crate) fn mode(&self, ctx: &ViewerContext<'_>) -> QueryMode { match self { - Query::FollowTimeline => { + Self::FollowTimeline => { let time_ctrl = ctx.rec_cfg.time_ctrl.read(); QueryMode::LatestAt { time: time_ctrl.time_int().unwrap_or(TimeInt::MAX), } } - Query::Override { mode, .. } => *mode, + Self::Override { mode, .. } => *mode, } } @@ -129,13 +129,10 @@ impl Query { .component_or_empty::()? .unwrap_or_default(); - latest_at_queries.set_query_for_timeline( - timeline_name.as_str(), - Some(datatypes::LatestAtQuery { - timeline: timeline_name.as_str().into(), - time: (*time).into(), - }), - ); + latest_at_queries.set_query_for_timeline(datatypes::LatestAtQuery { + timeline: timeline_name.as_str().into(), + time: (*time).into(), + }); ctx.save_blueprint_component(&property.blueprint_store_path, &latest_at_queries); ctx.save_blueprint_component(&property.blueprint_store_path, &QueryKind::LatestAt); @@ -145,14 +142,11 @@ impl Query { .component_or_empty::()? .unwrap_or_default(); - time_range_queries.set_query_for_timeline( - timeline_name.as_str(), - Some(datatypes::TimeRangeQuery { - timeline: timeline_name.as_str().into(), - start: (*from).into(), - end: (*to).into(), - }), - ); + time_range_queries.set_query_for_timeline(datatypes::TimeRangeQuery { + timeline: timeline_name.as_str().into(), + start: (*from).into(), + end: (*to).into(), + }); ctx.save_blueprint_component(&property.blueprint_store_path, &time_range_queries); ctx.save_blueprint_component(&property.blueprint_store_path, &QueryKind::TimeRange); @@ -166,7 +160,7 @@ impl Query { pub(crate) fn query_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - state: &mut dyn SpaceViewState, + state: &dyn SpaceViewState, space_view_id: SpaceViewId, ) -> Result<(), SpaceViewSystemExecutionError> { let property = ViewProperty::from_archetype::( @@ -221,7 +215,7 @@ pub(crate) fn query_ui( } if override_query { - override_ui(ctx, ui, state, space_view_id, property) + override_ui(ctx, ui, state, space_view_id, &property) } else { Ok(()) } @@ -230,9 +224,9 @@ pub(crate) fn query_ui( fn override_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - state: &mut dyn SpaceViewState, + state: &dyn SpaceViewState, space_view_id: SpaceViewId, - property: ViewProperty<'_>, + property: &ViewProperty<'_>, ) -> Result<(), SpaceViewSystemExecutionError> { let name = archetypes::DataframeQuery::name(); let Some(reflection) = ctx.reflection.archetypes.get(&name) else { @@ -248,9 +242,9 @@ fn override_ui( ctx.recording() .timelines() .find(|t| t.name() == &timeline_name) - .cloned() + .copied() }) - .unwrap_or(ctx.rec_cfg.time_ctrl.read().timeline().clone()); + .unwrap_or(*ctx.rec_cfg.time_ctrl.read().timeline()); let timeline_name = timeline.name(); let blueprint_path = @@ -301,12 +295,12 @@ fn override_ui( } else { TimeDragValue::from_time_range(0..=0) }; - let changed = ui_query_mode.ui(ctx, ui, time_drag_value, timeline.typ()); + let changed = ui_query_mode.ui(ctx, ui, &time_drag_value, timeline.typ()); if changed { Query::save_mode_for_timeline( ctx, space_view_id, - &timeline_name, + timeline_name, &ui_query_mode.into(), )?; } @@ -332,10 +326,10 @@ impl UiQueryMode { &mut self, ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - time_drag_value: TimeDragValue, + time_drag_value: &TimeDragValue, time_type: TimeType, ) -> bool { - let orig_self = self.clone(); + let orig_self = *self; ui.vertical(|ui| { // @@ -492,12 +486,12 @@ impl From for UiQueryMode { impl From for QueryMode { fn from(value: UiQueryMode) -> Self { match value { - UiQueryMode::LatestAt { time } => QueryMode::LatestAt { time }, - UiQueryMode::TimeRangeAll => QueryMode::Range { + UiQueryMode::LatestAt { time } => Self::LatestAt { time }, + UiQueryMode::TimeRangeAll => Self::Range { from: TimeInt::MIN, to: TimeInt::MAX, }, - UiQueryMode::TimeRange { from, to } => QueryMode::Range { from, to }, + UiQueryMode::TimeRange { from, to } => Self::Range { from, to }, } } } diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index bdae166365e7..a9fc74d3c8af 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -212,7 +212,7 @@ fn generate_component_reflection() -> Result::name(), ComponentReflection { - docstring_md: "A timeline", + docstring_md: "A timeline, identified by its name.", placeholder: Some(Timeline::default().to_arrow()?), }, ), diff --git a/rerun_cpp/src/rerun/blueprint/components/timeline.hpp b/rerun_cpp/src/rerun/blueprint/components/timeline.hpp index 10f6596fde27..b9c17bc30228 100644 --- a/rerun_cpp/src/rerun/blueprint/components/timeline.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/timeline.hpp @@ -12,7 +12,7 @@ #include namespace rerun::blueprint::components { - /// **Component**: A timeline + /// **Component**: A timeline, identified by its name. struct Timeline { rerun::datatypes::Utf8 value; diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp index dd4dcce3ed4d..5feab6b63125 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp @@ -22,7 +22,7 @@ namespace rerun::blueprint::datatypes { /// Name of the timeline this applies to. rerun::datatypes::Utf8 timeline; - /// Begining of the time range. + /// Beginning of the time range. rerun::datatypes::TimeInt start; /// End of the time range. diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py index 509cfac82829..e5e50f30f6fa 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py @@ -15,7 +15,7 @@ class Timeline(datatypes.Utf8, ComponentMixin): - """**Component**: A timeline.""" + """**Component**: A timeline, identified by its name.""" _BATCH_TYPE = None # You can define your own __init__ function as a member of TimelineExt in timeline_ext.py diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py index c5d238e55190..d80c50713411 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py @@ -59,7 +59,7 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLi timeline: Name of the timeline this applies to. start: - Begining of the time range. + Beginning of the time range. end: End of the time range. @@ -74,7 +74,7 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLi # (Docstring intentionally commented out to hide this field from the docs) start: datatypes.TimeInt = field(converter=_time_range_query__start__special_field_converter_override) - # Begining of the time range. + # Beginning of the time range. # # (Docstring intentionally commented out to hide this field from the docs) From 5f098f9726d694b700414b15cb7c0f67c5cc00a7 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 17:00:35 +0200 Subject: [PATCH 09/18] `use` order --- crates/viewer/re_space_view_dataframe/src/latest_at_table.rs | 3 ++- crates/viewer/re_space_view_dataframe/src/view_query.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs index 679dd30a896f..6c8c57dfcc3f 100644 --- a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs @@ -1,9 +1,10 @@ +use std::collections::BTreeSet; + use re_chunk_store::LatestAtQuery; use re_data_ui::item_ui::instance_path_button; use re_entity_db::InstancePath; use re_log_types::Instance; use re_viewer_context::{Item, UiLayout, ViewQuery, ViewerContext}; -use std::collections::BTreeSet; use crate::{ table_ui::table_ui, diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index ab34e9b3b29c..09aba292d6d1 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -1,4 +1,3 @@ -use crate::visualizer_system::EmptySystem; use re_log_types::{TimeInt, TimeType, TimelineName}; use re_types::blueprint::components::QueryKind; use re_types::blueprint::{archetypes, components, datatypes}; @@ -10,6 +9,8 @@ use re_viewer_context::{ }; use re_viewport_blueprint::{entity_path_for_view_property, ViewProperty}; +use crate::visualizer_system::EmptySystem; + /// The query mode for the dataframe view. #[derive(Debug, Clone, Copy)] pub(crate) enum QueryMode { From a4c4d1b7ee9aef5531d7156cc43787ddc1f2bf72 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 17:04:18 +0200 Subject: [PATCH 10/18] comment --- crates/viewer/re_space_view_dataframe/src/view_query.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index 09aba292d6d1..42c36eec4910 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -46,11 +46,12 @@ impl Query { space_view_id, ); + // The presence (or not) of the timeline component determines if the view should follow the + // time panel timeline/latest at query, or override it. let Some(timeline) = property .component_or_empty::()? .map(|t| t.timeline_name()) else { - // if the timeline is not set, it means that we must follow the time panel settings return Ok(Self::FollowTimeline); }; From d1d3ac32dda48541032c01e392f4e852e61018d0 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 17:08:25 +0200 Subject: [PATCH 11/18] code cleanup --- .../src/blueprint/components/latest_at_queries_ext.rs | 6 ++++-- .../src/blueprint/components/time_range_queries_ext.rs | 6 ++++-- crates/viewer/re_space_view_dataframe/src/view_query.rs | 8 ++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs index 256433253f7e..f5804cb488ab 100644 --- a/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs +++ b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs @@ -1,12 +1,14 @@ +use re_log_types::TimelineName; + use super::LatestAtQueries; use crate::blueprint::datatypes::LatestAtQuery; impl LatestAtQueries { /// Retrieves the query for a given timeline. - pub fn query_for_timeline(&self, timeline_name: &str) -> Option<&LatestAtQuery> { + pub fn query_for_timeline(&self, timeline_name: &TimelineName) -> Option<&LatestAtQuery> { self.0 .iter() - .find(|query| query.timeline.as_str() == timeline_name) + .find(|query| query.timeline.as_str() == timeline_name.as_str()) } /// Sets the query for a given timeline. diff --git a/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs index 50a5bf2b9381..5e43fea06fd8 100644 --- a/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs +++ b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs @@ -1,12 +1,14 @@ +use re_log_types::TimelineName; + use super::TimeRangeQueries; use crate::blueprint::datatypes::TimeRangeQuery; impl TimeRangeQueries { /// Retrieves the query for a given timeline. - pub fn query_for_timeline(&self, timeline_name: &str) -> Option<&TimeRangeQuery> { + pub fn query_for_timeline(&self, timeline_name: &TimelineName) -> Option<&TimeRangeQuery> { self.0 .iter() - .find(|query| query.timeline.as_str() == timeline_name) + .find(|query| query.timeline.as_str() == timeline_name.as_str()) } /// Sets the query for a given timeline. diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index 42c36eec4910..88b682b6a740 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -64,9 +64,7 @@ impl Query { let time = property .component_or_empty::()? .unwrap_or_default() - .0 - .into_iter() - .find(|q| q.timeline.as_str() == timeline) + .query_for_timeline(&timeline) .map_or(TimeInt::MAX, |q| q.time.into()); QueryMode::LatestAt { time } @@ -75,9 +73,7 @@ impl Query { let (from, to) = property .component_or_empty::()? .unwrap_or_default() - .0 - .into_iter() - .find(|q| q.timeline.as_str() == timeline) + .query_for_timeline(&timeline) .map_or((TimeInt::MIN, TimeInt::MAX), |q| { (q.start.into(), q.end.into()) }); From 1357059189717f4dd633c8db266432b85035be29 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 17:35:09 +0200 Subject: [PATCH 12/18] Fix codegen'd initialization of `TimeInt` in python --- .../blueprint/datatypes/latest_at_query.py | 14 ++++------- .../datatypes/latest_at_query_ext.py | 17 +++++++++++++ .../blueprint/datatypes/time_range_query.py | 25 ++++++------------- .../datatypes/time_range_query_ext.py | 24 ++++++++++++++++++ 4 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py index 03f8e155a418..58d7aa2a80a7 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py @@ -15,6 +15,7 @@ BaseBatch, BaseExtensionType, ) +from .latest_at_query_ext import LatestAtQueryExt __all__ = ["LatestAtQuery", "LatestAtQueryArrayLike", "LatestAtQueryBatch", "LatestAtQueryLike", "LatestAtQueryType"] @@ -26,15 +27,8 @@ def _latest_at_query__timeline__special_field_converter_override(x: datatypes.Ut return datatypes.Utf8(x) -def _latest_at_query__time__special_field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: - if isinstance(x, datatypes.TimeInt): - return x - else: - return datatypes.TimeInt(x) - - @define(init=False) -class LatestAtQuery: +class LatestAtQuery(LatestAtQueryExt): """**Datatype**: Latest at query configuration for a specific timeline.""" def __init__(self: Any, timeline: datatypes.Utf8Like, time: datatypes.TimeIntLike): @@ -58,7 +52,9 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, time: datatypes.TimeIntLik # # (Docstring intentionally commented out to hide this field from the docs) - time: datatypes.TimeInt = field(converter=_latest_at_query__time__special_field_converter_override) + time: datatypes.TimeInt = field( + converter=LatestAtQueryExt.time__field_converter_override, # type: ignore[misc] + ) # Time value to use for this query. # # (Docstring intentionally commented out to hide this field from the docs) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py new file mode 100644 index 000000000000..92805bd119e8 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from ... import datatypes + + +class LatestAtQueryExt: + """Extension for [LatestAtQuery][rerun.blueprint.datatypes.LatestAtQuery].""" + + # This override is required because otherwise the codegen uses `TimeInt(x)`, which is not valid with the custom + # `TimeInt.__init__` override. + + @staticmethod + def time__field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(seq=x) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py index d80c50713411..1edb469ba477 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py @@ -15,6 +15,7 @@ BaseBatch, BaseExtensionType, ) +from .time_range_query_ext import TimeRangeQueryExt __all__ = [ "TimeRangeQuery", @@ -32,22 +33,8 @@ def _time_range_query__timeline__special_field_converter_override(x: datatypes.U return datatypes.Utf8(x) -def _time_range_query__start__special_field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: - if isinstance(x, datatypes.TimeInt): - return x - else: - return datatypes.TimeInt(x) - - -def _time_range_query__end__special_field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: - if isinstance(x, datatypes.TimeInt): - return x - else: - return datatypes.TimeInt(x) - - @define(init=False) -class TimeRangeQuery: +class TimeRangeQuery(TimeRangeQueryExt): """**Datatype**: Time range query configuration for a specific timeline.""" def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLike, end: datatypes.TimeIntLike): @@ -73,12 +60,16 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLi # # (Docstring intentionally commented out to hide this field from the docs) - start: datatypes.TimeInt = field(converter=_time_range_query__start__special_field_converter_override) + start: datatypes.TimeInt = field( + converter=TimeRangeQueryExt.start__field_converter_override, # type: ignore[misc] + ) # Beginning of the time range. # # (Docstring intentionally commented out to hide this field from the docs) - end: datatypes.TimeInt = field(converter=_time_range_query__end__special_field_converter_override) + end: datatypes.TimeInt = field( + converter=TimeRangeQueryExt.end__field_converter_override, # type: ignore[misc] + ) # End of the time range. # # (Docstring intentionally commented out to hide this field from the docs) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py new file mode 100644 index 000000000000..6ddc984eb361 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from ... import datatypes + + +class TimeRangeQueryExt: + """Extension for [TimeRangeQuery][rerun.blueprint.datatypes.TimeRangeQuery].""" + + # These overrides are required because otherwise the codegen uses `TimeInt(x)`, which is not valid with the custom + # `TimeInt.__init__` override. + + @staticmethod + def start__field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(seq=x) + + @staticmethod + def end__field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(seq=x) From f7e686bfa3c6c188e87a376a1b64f79ad8c5d500 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Wed, 7 Aug 2024 18:14:18 +0200 Subject: [PATCH 13/18] Highlight range in timeline when possible. --- .../re_space_view_dataframe/src/view_query.rs | 78 ++++++++++++------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index 88b682b6a740..d18272243d84 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -1,4 +1,4 @@ -use re_log_types::{TimeInt, TimeType, TimelineName}; +use re_log_types::{ResolvedTimeRange, TimeInt, TimeType, TimelineName}; use re_types::blueprint::components::QueryKind; use re_types::blueprint::{archetypes, components, datatypes}; use re_types_core::{Archetype as _, Loggable as _}; @@ -293,7 +293,8 @@ fn override_ui( } else { TimeDragValue::from_time_range(0..=0) }; - let changed = ui_query_mode.ui(ctx, ui, &time_drag_value, timeline.typ()); + let changed = + ui_query_mode.ui(ctx, ui, &time_drag_value, timeline.name(), timeline.typ()); if changed { Query::save_mode_for_timeline( ctx, @@ -325,6 +326,7 @@ impl UiQueryMode { ctx: &ViewerContext<'_>, ui: &mut egui::Ui, time_drag_value: &TimeDragValue, + timeline_name: &TimelineName, time_type: TimeType, ) -> bool { let orig_self = *self; @@ -396,6 +398,8 @@ impl UiQueryMode { .re_radio_value(&mut is_time_range_custom, true, "Define time range") .changed(); + let mut should_display_time_range = false; + if is_time_range_custom { ui.spacing_mut().indent = ui.spacing().icon_width + ui.spacing().icon_spacing; ui.indent("time_range_custom", |ui| { @@ -414,41 +418,51 @@ impl UiQueryMode { list_item::list_item_scope(ui, "time_range_custom_scope", |ui| { ui.list_item_flat_noninteractive( list_item::PropertyContent::new("Start").value_fn(|ui, _| { - changed |= match time_type { - TimeType::Time => time_drag_value - .temporal_drag_value_ui( - ui, - &mut from, - true, - None, - ctx.app_options.time_zone, - ) - .0 - .changed(), + let response = match time_type { + TimeType::Time => { + time_drag_value + .temporal_drag_value_ui( + ui, + &mut from, + true, + None, + ctx.app_options.time_zone, + ) + .0 + } TimeType::Sequence => time_drag_value - .sequence_drag_value_ui(ui, &mut from, true, None) - .changed(), + .sequence_drag_value_ui(ui, &mut from, true, None), }; + + changed |= response.changed(); + should_display_time_range |= response.hovered() + || response.dragged() + || response.has_focus(); }), ); ui.list_item_flat_noninteractive( list_item::PropertyContent::new("End").value_fn(|ui, _| { - changed |= match time_type { - TimeType::Time => time_drag_value - .temporal_drag_value_ui( - ui, - &mut to, - true, - Some(from), - ctx.app_options.time_zone, - ) - .0 - .changed(), + let response = match time_type { + TimeType::Time => { + time_drag_value + .temporal_drag_value_ui( + ui, + &mut to, + true, + Some(from), + ctx.app_options.time_zone, + ) + .0 + } TimeType::Sequence => time_drag_value - .sequence_drag_value_ui(ui, &mut to, true, Some(from)) - .changed(), + .sequence_drag_value_ui(ui, &mut to, true, Some(from)), }; + + changed |= response.changed(); + should_display_time_range |= response.hovered() + || response.dragged() + || response.has_focus(); }), ); }); @@ -459,6 +473,14 @@ impl UiQueryMode { to: to.into(), }; } + + if should_display_time_range { + let mut time_ctrl = ctx.rec_cfg.time_ctrl.write(); + if time_ctrl.timeline().name() == timeline_name { + time_ctrl.highlighted_range = + Some(ResolvedTimeRange::new(from, to)); + } + } }); } }); From eaf5aaafded569091ad91f09947dd8d0ccdcfe59 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Thu, 8 Aug 2024 16:30:09 +0200 Subject: [PATCH 14/18] Changes as discussed with @Wumpf --- .../viewer/re_space_view_dataframe/src/lib.rs | 1 + .../src/query_mode_ui.rs | 212 +++++++++++++ .../re_space_view_dataframe/src/view_query.rs | 285 ++---------------- .../src/view_properties.rs | 10 +- 4 files changed, 247 insertions(+), 261 deletions(-) create mode 100644 crates/viewer/re_space_view_dataframe/src/query_mode_ui.rs diff --git a/crates/viewer/re_space_view_dataframe/src/lib.rs b/crates/viewer/re_space_view_dataframe/src/lib.rs index 525e98202e21..ad41e769a9e2 100644 --- a/crates/viewer/re_space_view_dataframe/src/lib.rs +++ b/crates/viewer/re_space_view_dataframe/src/lib.rs @@ -3,6 +3,7 @@ //! A Space View that shows the data contained in entities in a table. mod latest_at_table; +mod query_mode_ui; mod space_view_class; mod table_ui; mod time_range_table; diff --git a/crates/viewer/re_space_view_dataframe/src/query_mode_ui.rs b/crates/viewer/re_space_view_dataframe/src/query_mode_ui.rs new file mode 100644 index 000000000000..ffe0b60aff8f --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/query_mode_ui.rs @@ -0,0 +1,212 @@ +use re_log_types::{ResolvedTimeRange, TimeInt, TimeType, TimelineName}; +use re_ui::{list_item, UiExt}; +use re_viewer_context::{TimeDragValue, ViewerContext}; + +use crate::view_query::QueryMode; + +/// Helper to handle the UI for the various query modes are they are shown to the user. +/// +/// This struct is the "UI equivalent" of the [`QueryMode`] enum. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum UiQueryMode { + LatestAt { time: TimeInt }, + TimeRangeAll, + TimeRange { from: TimeInt, to: TimeInt }, +} + +impl UiQueryMode { + /// Show the UI for the query mode selector. + pub(crate) fn ui( + &mut self, + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + time_drag_value: &TimeDragValue, + timeline_name: &TimelineName, + time_type: TimeType, + ) -> bool { + let orig_self = *self; + + ui.vertical(|ui| { + // + // LATEST AT + // + + ui.horizontal(|ui| { + let mut is_latest_at = matches!(self, Self::LatestAt { .. }); + + let mut changed = ui + .re_radio_value(&mut is_latest_at, true, "Latest at") + .changed(); + + if is_latest_at { + let mut time = if let Self::LatestAt { time } = self { + *time + } else { + TimeInt::MAX + } + .into(); + + changed |= match time_type { + TimeType::Time => time_drag_value + .temporal_drag_value_ui( + ui, + &mut time, + true, + None, + ctx.app_options.time_zone, + ) + .0 + .changed(), + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut time, true, None) + .changed(), + }; + + if changed { + *self = Self::LatestAt { time: time.into() }; + } + } + }); + + // + // TIME RANGE ALL + // + + ui.horizontal(|ui| { + let mut is_time_range_all = matches!(self, Self::TimeRangeAll); + if ui + .re_radio_value(&mut is_time_range_all, true, "From –∞ to +∞") + .changed() + && is_time_range_all + { + *self = Self::TimeRangeAll; + } + }); + + // + // TIME RANGE CUSTOM + // + + ui.vertical(|ui| { + let mut is_time_range_custom = matches!(self, Self::TimeRange { .. }); + let mut changed = ui + .re_radio_value(&mut is_time_range_custom, true, "Define time range") + .changed(); + + let mut should_display_time_range = false; + + if is_time_range_custom { + ui.spacing_mut().indent = ui.spacing().icon_width + ui.spacing().icon_spacing; + ui.indent("time_range_custom", |ui| { + let mut from = if let Self::TimeRange { from, .. } = self { + (*from).into() + } else { + (*time_drag_value.range.start()).into() + }; + + let mut to = if let Self::TimeRange { to, .. } = self { + (*to).into() + } else { + (*time_drag_value.range.end()).into() + }; + + list_item::list_item_scope(ui, "time_range_custom_scope", |ui| { + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("Start").value_fn(|ui, _| { + let response = match time_type { + TimeType::Time => { + time_drag_value + .temporal_drag_value_ui( + ui, + &mut from, + true, + None, + ctx.app_options.time_zone, + ) + .0 + } + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut from, true, None), + }; + + changed |= response.changed(); + should_display_time_range |= response.hovered() + || response.dragged() + || response.has_focus(); + }), + ); + + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("End").value_fn(|ui, _| { + let response = match time_type { + TimeType::Time => { + time_drag_value + .temporal_drag_value_ui( + ui, + &mut to, + true, + Some(from), + ctx.app_options.time_zone, + ) + .0 + } + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut to, true, Some(from)), + }; + + changed |= response.changed(); + should_display_time_range |= response.hovered() + || response.dragged() + || response.has_focus(); + }), + ); + }); + + if changed { + *self = Self::TimeRange { + from: from.into(), + to: to.into(), + }; + } + + if should_display_time_range { + let mut time_ctrl = ctx.rec_cfg.time_ctrl.write(); + if time_ctrl.timeline().name() == timeline_name { + time_ctrl.highlighted_range = + Some(ResolvedTimeRange::new(from, to)); + } + } + }); + } + }); + }); + + *self != orig_self + } +} + +impl From for UiQueryMode { + fn from(value: QueryMode) -> Self { + match value { + QueryMode::LatestAt { time } => Self::LatestAt { time }, + QueryMode::Range { + from: TimeInt::MIN, + to: TimeInt::MAX, + } => Self::TimeRangeAll, + QueryMode::Range { from, to } => Self::TimeRange { from, to }, + } + } +} + +impl From for QueryMode { + fn from(value: UiQueryMode) -> Self { + match value { + UiQueryMode::LatestAt { time } => Self::LatestAt { time }, + UiQueryMode::TimeRangeAll => Self::Range { + from: TimeInt::MIN, + to: TimeInt::MAX, + }, + UiQueryMode::TimeRange { from, to } => Self::Range { from, to }, + } + } +} diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index d18272243d84..f80d28e24603 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -1,14 +1,14 @@ -use re_log_types::{ResolvedTimeRange, TimeInt, TimeType, TimelineName}; +use re_log_types::{TimeInt, TimelineName}; use re_types::blueprint::components::QueryKind; use re_types::blueprint::{archetypes, components, datatypes}; -use re_types_core::{Archetype as _, Loggable as _}; -use re_ui::{list_item, UiExt as _}; +use re_types_core::Loggable as _; +use re_ui::UiExt as _; use re_viewer_context::{ - QueryContext, SpaceViewId, SpaceViewState, SpaceViewSystemExecutionError, TimeDragValue, - ViewerContext, + SpaceViewId, SpaceViewState, SpaceViewSystemExecutionError, TimeDragValue, ViewerContext, }; -use re_viewport_blueprint::{entity_path_for_view_property, ViewProperty}; +use re_viewport_blueprint::ViewProperty; +use crate::query_mode_ui::UiQueryMode; use crate::visualizer_system::EmptySystem; /// The query mode for the dataframe view. @@ -132,8 +132,8 @@ impl Query { time: (*time).into(), }); - ctx.save_blueprint_component(&property.blueprint_store_path, &latest_at_queries); - ctx.save_blueprint_component(&property.blueprint_store_path, &QueryKind::LatestAt); + property.save_blueprint_component(ctx, &latest_at_queries); + property.save_blueprint_component(ctx, &QueryKind::LatestAt); } QueryMode::Range { from, to } => { let mut time_range_queries = property @@ -146,8 +146,8 @@ impl Query { end: (*to).into(), }); - ctx.save_blueprint_component(&property.blueprint_store_path, &time_range_queries); - ctx.save_blueprint_component(&property.blueprint_store_path, &QueryKind::TimeRange); + property.save_blueprint_component(ctx, &time_range_queries); + property.save_blueprint_component(ctx, &QueryKind::TimeRange); } }; @@ -226,58 +226,20 @@ fn override_ui( space_view_id: SpaceViewId, property: &ViewProperty<'_>, ) -> Result<(), SpaceViewSystemExecutionError> { - let name = archetypes::DataframeQuery::name(); - let Some(reflection) = ctx.reflection.archetypes.get(&name) else { - // The `ArchetypeReflectionMarker` bound should make this impossible. - re_log::warn_once!("Missing reflection data for archetype {name:?}."); - return Ok(()); - }; - - let timeline = property - .component_or_empty::()? - .map(|t| t.timeline_name()) - .and_then(|timeline_name| { - ctx.recording() - .timelines() - .find(|t| t.name() == &timeline_name) - .copied() - }) - .unwrap_or(*ctx.rec_cfg.time_ctrl.read().timeline()); - let timeline_name = timeline.name(); - - let blueprint_path = - entity_path_for_view_property(space_view_id, ctx.blueprint_db().tree(), name); - let query_context = QueryContext { - viewer_ctx: ctx, - target_entity_path: &blueprint_path, - archetype_name: Some(name), - query: ctx.blueprint_query, - view_state: state, - view_ctx: None, - }; - - let component_results = ctx.blueprint_db().latest_at( - ctx.blueprint_query, - &blueprint_path, - reflection.fields.iter().map(|field| field.component_name), - ); - ui.selection_grid("dataframe_view_query_ui") .show(ui, |ui| { ui.grid_left_hand_label("Timeline"); let component_name = components::Timeline::name(); - //TODO(ab, andreas): ideally it would be _much_ easier to call if a fallback provider is not needed + //TODO(ab, andreas): maybe have a `singleline_edit_ui` wrapper directly in `ViewProperty` ctx.component_ui_registry.singleline_edit_ui( - &query_context, + &property.query_context(ctx, state), ui, ctx.blueprint_db(), - &blueprint_path, + &property.blueprint_store_path, component_name, - component_results - .component_batch_raw(&component_name) - .as_deref(), + property.component_raw(component_name).as_deref(), // we don't need to provide a fallback here as the timeline should be present by definition &EmptySystem {}, ); @@ -286,6 +248,18 @@ fn override_ui( ui.grid_left_hand_label("Showing"); + let timeline = property + .component_or_empty::()? + .map(|t| t.timeline_name()) + .and_then(|timeline_name| { + ctx.recording() + .timelines() + .find(|t| t.name() == &timeline_name) + .copied() + }) + .unwrap_or(*ctx.rec_cfg.time_ctrl.read().timeline()); + let timeline_name = timeline.name(); + let query = Query::try_from_blueprint(ctx, space_view_id)?; let mut ui_query_mode: UiQueryMode = query.mode(ctx).into(); let time_drag_value = if let Some(times) = ctx.recording().time_histogram(&timeline) { @@ -308,210 +282,3 @@ fn override_ui( }) .inner } - -// -- - -/// Helper to handle the various query modes as they are offered in the UI. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum UiQueryMode { - LatestAt { time: TimeInt }, - TimeRangeAll, - TimeRange { from: TimeInt, to: TimeInt }, -} - -impl UiQueryMode { - /// Show the UI for the query mode selector. - fn ui( - &mut self, - ctx: &ViewerContext<'_>, - ui: &mut egui::Ui, - time_drag_value: &TimeDragValue, - timeline_name: &TimelineName, - time_type: TimeType, - ) -> bool { - let orig_self = *self; - - ui.vertical(|ui| { - // - // LATEST AT - // - - ui.horizontal(|ui| { - let mut is_latest_at = matches!(self, Self::LatestAt { .. }); - - let mut changed = ui - .re_radio_value(&mut is_latest_at, true, "Latest at") - .changed(); - - if is_latest_at { - let mut time = if let Self::LatestAt { time } = self { - *time - } else { - TimeInt::MAX - } - .into(); - - changed |= match time_type { - TimeType::Time => time_drag_value - .temporal_drag_value_ui( - ui, - &mut time, - true, - None, - ctx.app_options.time_zone, - ) - .0 - .changed(), - TimeType::Sequence => time_drag_value - .sequence_drag_value_ui(ui, &mut time, true, None) - .changed(), - }; - - if changed { - *self = Self::LatestAt { time: time.into() }; - } - } - }); - - // - // TIME RANGE ALL - // - - ui.horizontal(|ui| { - let mut is_time_range_all = matches!(self, Self::TimeRangeAll); - if ui - .re_radio_value(&mut is_time_range_all, true, "From –∞ to +∞") - .changed() - && is_time_range_all - { - *self = Self::TimeRangeAll; - } - }); - - // - // TIME RANGE CUSTOM - // - - ui.vertical(|ui| { - let mut is_time_range_custom = matches!(self, Self::TimeRange { .. }); - let mut changed = ui - .re_radio_value(&mut is_time_range_custom, true, "Define time range") - .changed(); - - let mut should_display_time_range = false; - - if is_time_range_custom { - ui.spacing_mut().indent = ui.spacing().icon_width + ui.spacing().icon_spacing; - ui.indent("time_range_custom", |ui| { - let mut from = if let Self::TimeRange { from, .. } = self { - (*from).into() - } else { - (*time_drag_value.range.start()).into() - }; - - let mut to = if let Self::TimeRange { to, .. } = self { - (*to).into() - } else { - (*time_drag_value.range.end()).into() - }; - - list_item::list_item_scope(ui, "time_range_custom_scope", |ui| { - ui.list_item_flat_noninteractive( - list_item::PropertyContent::new("Start").value_fn(|ui, _| { - let response = match time_type { - TimeType::Time => { - time_drag_value - .temporal_drag_value_ui( - ui, - &mut from, - true, - None, - ctx.app_options.time_zone, - ) - .0 - } - TimeType::Sequence => time_drag_value - .sequence_drag_value_ui(ui, &mut from, true, None), - }; - - changed |= response.changed(); - should_display_time_range |= response.hovered() - || response.dragged() - || response.has_focus(); - }), - ); - - ui.list_item_flat_noninteractive( - list_item::PropertyContent::new("End").value_fn(|ui, _| { - let response = match time_type { - TimeType::Time => { - time_drag_value - .temporal_drag_value_ui( - ui, - &mut to, - true, - Some(from), - ctx.app_options.time_zone, - ) - .0 - } - TimeType::Sequence => time_drag_value - .sequence_drag_value_ui(ui, &mut to, true, Some(from)), - }; - - changed |= response.changed(); - should_display_time_range |= response.hovered() - || response.dragged() - || response.has_focus(); - }), - ); - }); - - if changed { - *self = Self::TimeRange { - from: from.into(), - to: to.into(), - }; - } - - if should_display_time_range { - let mut time_ctrl = ctx.rec_cfg.time_ctrl.write(); - if time_ctrl.timeline().name() == timeline_name { - time_ctrl.highlighted_range = - Some(ResolvedTimeRange::new(from, to)); - } - } - }); - } - }); - }); - - *self != orig_self - } -} - -impl From for UiQueryMode { - fn from(value: QueryMode) -> Self { - match value { - QueryMode::LatestAt { time } => Self::LatestAt { time }, - QueryMode::Range { - from: TimeInt::MIN, - to: TimeInt::MAX, - } => Self::TimeRangeAll, - QueryMode::Range { from, to } => Self::TimeRange { from, to }, - } - } -} - -impl From for QueryMode { - fn from(value: UiQueryMode) -> Self { - match value { - UiQueryMode::LatestAt { time } => Self::LatestAt { time }, - UiQueryMode::TimeRangeAll => Self::Range { - from: TimeInt::MIN, - to: TimeInt::MAX, - }, - UiQueryMode::TimeRange { from, to } => Self::Range { from, to }, - } - } -} diff --git a/crates/viewer/re_viewport_blueprint/src/view_properties.rs b/crates/viewer/re_viewport_blueprint/src/view_properties.rs index a0b96f7d7dca..a5b04b71e835 100644 --- a/crates/viewer/re_viewport_blueprint/src/view_properties.rs +++ b/crates/viewer/re_viewport_blueprint/src/view_properties.rs @@ -29,7 +29,10 @@ impl From for SpaceViewSystemExecutionError { /// Utility for querying view properties. pub struct ViewProperty<'a> { + /// Entity path in the blueprint store where all components of this view property archetype are + /// stored. pub blueprint_store_path: EntityPath, + archetype_name: ArchetypeName, component_names: Vec, query_results: LatestAtResults, @@ -133,7 +136,7 @@ impl<'a> ViewProperty<'a> { .map(|value| value.unwrap_or_default()) } - fn component_raw( + pub fn component_raw( &self, component_name: ComponentName, ) -> Option> { @@ -194,7 +197,8 @@ impl<'a> ViewProperty<'a> { }) } - fn query_context( + /// Create a query context for this view property. + pub fn query_context( &self, viewer_ctx: &'a ViewerContext<'a>, view_state: &'a dyn re_viewer_context::SpaceViewState, @@ -210,6 +214,8 @@ impl<'a> ViewProperty<'a> { } } +/// Entity path in the blueprint store where all components of the given view property archetype are +/// stored. pub fn entity_path_for_view_property( space_view_id: SpaceViewId, _blueprint_entity_tree: &EntityTree, From 86073f0860d44f00f7ae28b0ed0183346e5de512 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Thu, 8 Aug 2024 16:33:53 +0200 Subject: [PATCH 15/18] Post-merge fixes --- .../rerun/blueprint/components/query_kind.fbs | 2 +- .../blueprint/archetypes/dataframe_query.cpp | 19 ++++++++++--------- .../blueprint/archetypes/dataframe_query.hpp | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs index 11270222d1ba..b4c91f52601a 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs @@ -2,7 +2,7 @@ namespace rerun.blueprint.components; /// The kind of query displayed by the dataframe view -enum QueryKind: byte ( +enum QueryKind: ubyte ( "attr.rerun.scope": "blueprint" ) { /// Invalid value. Won't show up in generated types. diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp index 545751fe7aa6..213350708ed0 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp @@ -9,36 +9,37 @@ namespace rerun::blueprint::archetypes {} namespace rerun { - Result> AsComponents::serialize( - const blueprint::archetypes::DataframeQuery& archetype - ) { + Result> + AsComponents::serialize( + const blueprint::archetypes::DataframeQuery& archetype + ) { using namespace blueprint::archetypes; - std::vector cells; + std::vector cells; cells.reserve(5); if (archetype.timeline.has_value()) { - auto result = DataCell::from_loggable(archetype.timeline.value()); + auto result = ComponentBatch::from_loggable(archetype.timeline.value()); RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } if (archetype.mode.has_value()) { - auto result = DataCell::from_loggable(archetype.mode.value()); + auto result = ComponentBatch::from_loggable(archetype.mode.value()); RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } if (archetype.latest_at_queries.has_value()) { - auto result = DataCell::from_loggable(archetype.latest_at_queries.value()); + auto result = ComponentBatch::from_loggable(archetype.latest_at_queries.value()); RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } if (archetype.time_range_queries.has_value()) { - auto result = DataCell::from_loggable(archetype.time_range_queries.value()); + auto result = ComponentBatch::from_loggable(archetype.time_range_queries.value()); RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } { auto indicator = DataframeQuery::IndicatorComponent(); - auto result = DataCell::from_loggable(indicator); + auto result = ComponentBatch::from_loggable(indicator); RR_RETURN_NOT_OK(result.error); cells.emplace_back(std::move(result.value)); } diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp index bc770be02a9d..36eab4a6fa98 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp @@ -9,7 +9,7 @@ #include "../../blueprint/components/timeline.hpp" #include "../../collection.hpp" #include "../../compiler_utils.hpp" -#include "../../data_cell.hpp" +#include "../../component_batch.hpp" #include "../../indicator_component.hpp" #include "../../result.hpp" @@ -100,7 +100,7 @@ namespace rerun { template <> struct AsComponents { /// Serialize all set component batches. - static Result> serialize( + static Result> serialize( const blueprint::archetypes::DataframeQuery& archetype ); }; From 0a700a4390b20c08c481cf62380ca394067250f2 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 9 Aug 2024 11:08:36 +0200 Subject: [PATCH 16/18] Use "query kind" everywhere --- .../blueprint/archetypes/dataframe_query.fbs | 6 +- .../blueprint/archetypes/dataframe_query.rs | 26 ++++---- .../viewer/re_space_view_dataframe/src/lib.rs | 2 +- .../{query_mode_ui.rs => query_kind_ui.rs} | 32 +++++----- .../src/space_view_class.rs | 10 +-- .../re_space_view_dataframe/src/view_query.rs | 61 +++++++++---------- crates/viewer/re_viewer/src/reflection/mod.rs | 6 +- .../blueprint/archetypes/dataframe_query.cpp | 4 +- .../blueprint/archetypes/dataframe_query.hpp | 14 ++--- .../blueprint/archetypes/dataframe_query.py | 18 +++--- 10 files changed, 89 insertions(+), 90 deletions(-) rename crates/viewer/re_space_view_dataframe/src/{query_mode_ui.rs => query_kind_ui.rs} (90%) diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs index 18cf213abf0d..b22b6191a21d 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs @@ -36,10 +36,10 @@ table DataframeQuery ( /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. timeline: rerun.blueprint.components.Timeline ("attr.rerun.component_optional", nullable, order: 100); - /// Type of query: latest at or range - mode: rerun.blueprint.components.QueryKind ("attr.rerun.component_optional", nullable,order: 200); + /// Kind of query: latest-at or range. + kind: rerun.blueprint.components.QueryKind ("attr.rerun.component_optional", nullable,order: 200); - /// Configuration for latest at queries.attribute + /// Configuration for latest-at queries. /// /// Note: configuration as saved on a per-timeline basis. latest_at_queries: rerun.blueprint.components.LatestAtQueries ("attr.rerun.component_optional", nullable,order: 400); diff --git a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs index 551222d47594..b0e2d314dfe7 100644 --- a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs +++ b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs @@ -26,10 +26,10 @@ pub struct DataframeQuery { /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. pub timeline: Option, - /// Type of query: latest at or range - pub mode: Option, + /// Kind of query: latest-at or range. + pub kind: Option, - /// Configuration for latest at queries.attribute + /// Configuration for latest-at queries. /// /// Note: configuration as saved on a per-timeline basis. pub latest_at_queries: Option, @@ -44,7 +44,7 @@ impl ::re_types_core::SizeBytes for DataframeQuery { #[inline] fn heap_size_bytes(&self) -> u64 { self.timeline.heap_size_bytes() - + self.mode.heap_size_bytes() + + self.kind.heap_size_bytes() + self.latest_at_queries.heap_size_bytes() + self.time_range_queries.heap_size_bytes() } @@ -152,9 +152,9 @@ impl ::re_types_core::Archetype for DataframeQuery { } else { None }; - let mode = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.QueryKind") { + let kind = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.QueryKind") { ::from_arrow_opt(&**array) - .with_context("rerun.blueprint.archetypes.DataframeQuery#mode")? + .with_context("rerun.blueprint.archetypes.DataframeQuery#kind")? .into_iter() .next() .flatten() @@ -184,7 +184,7 @@ impl ::re_types_core::Archetype for DataframeQuery { }; Ok(Self { timeline, - mode, + kind, latest_at_queries, time_range_queries, }) @@ -200,7 +200,7 @@ impl ::re_types_core::AsComponents for DataframeQuery { self.timeline .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), - self.mode + self.kind .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), self.latest_at_queries @@ -224,7 +224,7 @@ impl DataframeQuery { pub fn new() -> Self { Self { timeline: None, - mode: None, + kind: None, latest_at_queries: None, time_range_queries: None, } @@ -242,14 +242,14 @@ impl DataframeQuery { self } - /// Type of query: latest at or range + /// Kind of query: latest-at or range. #[inline] - pub fn with_mode(mut self, mode: impl Into) -> Self { - self.mode = Some(mode.into()); + pub fn with_kind(mut self, kind: impl Into) -> Self { + self.kind = Some(kind.into()); self } - /// Configuration for latest at queries.attribute + /// Configuration for latest-at queries. /// /// Note: configuration as saved on a per-timeline basis. #[inline] diff --git a/crates/viewer/re_space_view_dataframe/src/lib.rs b/crates/viewer/re_space_view_dataframe/src/lib.rs index ad41e769a9e2..b036b03577b4 100644 --- a/crates/viewer/re_space_view_dataframe/src/lib.rs +++ b/crates/viewer/re_space_view_dataframe/src/lib.rs @@ -3,7 +3,7 @@ //! A Space View that shows the data contained in entities in a table. mod latest_at_table; -mod query_mode_ui; +mod query_kind_ui; mod space_view_class; mod table_ui; mod time_range_table; diff --git a/crates/viewer/re_space_view_dataframe/src/query_mode_ui.rs b/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs similarity index 90% rename from crates/viewer/re_space_view_dataframe/src/query_mode_ui.rs rename to crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs index ffe0b60aff8f..35dabd65fafc 100644 --- a/crates/viewer/re_space_view_dataframe/src/query_mode_ui.rs +++ b/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs @@ -2,20 +2,20 @@ use re_log_types::{ResolvedTimeRange, TimeInt, TimeType, TimelineName}; use re_ui::{list_item, UiExt}; use re_viewer_context::{TimeDragValue, ViewerContext}; -use crate::view_query::QueryMode; +use crate::view_query::QueryKind; -/// Helper to handle the UI for the various query modes are they are shown to the user. +/// Helper to handle the UI for the various query kinds are they are shown to the user. /// -/// This struct is the "UI equivalent" of the [`QueryMode`] enum. +/// This struct is the "UI equivalent" of the [`QueryKind`] enum. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum UiQueryMode { +pub(crate) enum UiQueryKind { LatestAt { time: TimeInt }, TimeRangeAll, TimeRange { from: TimeInt, to: TimeInt }, } -impl UiQueryMode { - /// Show the UI for the query mode selector. +impl UiQueryKind { + /// Show the UI for the query kind selector. pub(crate) fn ui( &mut self, ctx: &ViewerContext<'_>, @@ -185,28 +185,28 @@ impl UiQueryMode { } } -impl From for UiQueryMode { - fn from(value: QueryMode) -> Self { +impl From for UiQueryKind { + fn from(value: QueryKind) -> Self { match value { - QueryMode::LatestAt { time } => Self::LatestAt { time }, - QueryMode::Range { + QueryKind::LatestAt { time } => Self::LatestAt { time }, + QueryKind::Range { from: TimeInt::MIN, to: TimeInt::MAX, } => Self::TimeRangeAll, - QueryMode::Range { from, to } => Self::TimeRange { from, to }, + QueryKind::Range { from, to } => Self::TimeRange { from, to }, } } } -impl From for QueryMode { - fn from(value: UiQueryMode) -> Self { +impl From for QueryKind { + fn from(value: UiQueryKind) -> Self { match value { - UiQueryMode::LatestAt { time } => Self::LatestAt { time }, - UiQueryMode::TimeRangeAll => Self::Range { + UiQueryKind::LatestAt { time } => Self::LatestAt { time }, + UiQueryKind::TimeRangeAll => Self::Range { from: TimeInt::MIN, to: TimeInt::MAX, }, - UiQueryMode::TimeRange { from, to } => Self::Range { from, to }, + UiQueryKind::TimeRange { from, to } => Self::Range { from, to }, } } } diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index b9f4d51e405a..b6c8aa660dd2 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -15,7 +15,7 @@ use re_viewport_blueprint::ViewProperty; use crate::{ latest_at_table::latest_at_table_ui, time_range_table::time_range_table_ui, - view_query::{Query, QueryMode}, + view_query::{Query, QueryKind}, visualizer_system::EmptySystem, }; @@ -98,7 +98,7 @@ mode sets the default time range to _everything_. You can override this in the s let view_query = Query::try_from_blueprint(ctx, space_view_id)?; //TODO(#7070): column order and sorting needs much love ui.add_enabled_ui( - matches!(view_query.mode(ctx), QueryMode::Range { .. }), + matches!(view_query.kind(ctx), QueryKind::Range { .. }), |ui| { view_property_ui::( ctx, @@ -126,7 +126,7 @@ mode sets the default time range to _everything_. You can override this in the s let view_query = super::view_query::Query::try_from_blueprint(ctx, query.space_view_id)?; let timeline_name = view_query.timeline_name(ctx); - let query_mode = view_query.mode(ctx); + let query_mode = view_query.kind(ctx); let Some(timeline) = ctx .recording() @@ -139,10 +139,10 @@ mode sets the default time range to _everything_. You can override this in the s }; match query_mode { - QueryMode::LatestAt { time } => { + QueryKind::LatestAt { time } => { latest_at_table_ui(ctx, ui, query, &LatestAtQuery::new(*timeline, time)); } - QueryMode::Range { from, to } => { + QueryKind::Range { from, to } => { let time_range_table_order = ViewProperty::from_archetype::( ctx.blueprint_db(), diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index f80d28e24603..753ce20f0187 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -1,5 +1,4 @@ use re_log_types::{TimeInt, TimelineName}; -use re_types::blueprint::components::QueryKind; use re_types::blueprint::{archetypes, components, datatypes}; use re_types_core::Loggable as _; use re_ui::UiExt as _; @@ -8,12 +7,12 @@ use re_viewer_context::{ }; use re_viewport_blueprint::ViewProperty; -use crate::query_mode_ui::UiQueryMode; +use crate::query_kind_ui::UiQueryKind; use crate::visualizer_system::EmptySystem; -/// The query mode for the dataframe view. +/// The query kind for the dataframe view. #[derive(Debug, Clone, Copy)] -pub(crate) enum QueryMode { +pub(crate) enum QueryKind { LatestAt { time: TimeInt, }, @@ -31,7 +30,7 @@ pub(crate) enum Query { Override { timeline: TimelineName, - mode: QueryMode, + kind: QueryKind, }, } @@ -55,21 +54,21 @@ impl Query { return Ok(Self::FollowTimeline); }; - let mode = property + let kind = property .component_or_empty::()? - .unwrap_or(QueryKind::LatestAt); + .unwrap_or(components::QueryKind::LatestAt); - let mode = match mode { - QueryKind::LatestAt => { + let kind = match kind { + components::QueryKind::LatestAt => { let time = property .component_or_empty::()? .unwrap_or_default() .query_for_timeline(&timeline) .map_or(TimeInt::MAX, |q| q.time.into()); - QueryMode::LatestAt { time } + QueryKind::LatestAt { time } } - QueryKind::TimeRange => { + components::QueryKind::TimeRange => { let (from, to) = property .component_or_empty::()? .unwrap_or_default() @@ -78,11 +77,11 @@ impl Query { (q.start.into(), q.end.into()) }); - QueryMode::Range { from, to } + QueryKind::Range { from, to } } }; - Ok(Self::Override { timeline, mode }) + Ok(Self::Override { timeline, kind }) } /// Get the timeline name for the query @@ -94,26 +93,26 @@ impl Query { } } - /// Get the mode for the query + /// Get the kind for the query #[inline] - pub(crate) fn mode(&self, ctx: &ViewerContext<'_>) -> QueryMode { + pub(crate) fn kind(&self, ctx: &ViewerContext<'_>) -> QueryKind { match self { Self::FollowTimeline => { let time_ctrl = ctx.rec_cfg.time_ctrl.read(); - QueryMode::LatestAt { + QueryKind::LatestAt { time: time_ctrl.time_int().unwrap_or(TimeInt::MAX), } } - Self::Override { mode, .. } => *mode, + Self::Override { kind, .. } => *kind, } } - /// Save the query mode for the given timeline to the blueprint. - pub(crate) fn save_mode_for_timeline( + /// Save the query kind for the given timeline to the blueprint. + pub(crate) fn save_kind_for_timeline( ctx: &ViewerContext<'_>, space_view_id: SpaceViewId, timeline_name: &TimelineName, - query_mode: &QueryMode, + query_kind: &QueryKind, ) -> Result<(), SpaceViewSystemExecutionError> { let property = ViewProperty::from_archetype::( ctx.blueprint_db(), @@ -121,8 +120,8 @@ impl Query { space_view_id, ); - match query_mode { - QueryMode::LatestAt { time } => { + match query_kind { + QueryKind::LatestAt { time } => { let mut latest_at_queries = property .component_or_empty::()? .unwrap_or_default(); @@ -133,9 +132,9 @@ impl Query { }); property.save_blueprint_component(ctx, &latest_at_queries); - property.save_blueprint_component(ctx, &QueryKind::LatestAt); + property.save_blueprint_component(ctx, &components::QueryKind::LatestAt); } - QueryMode::Range { from, to } => { + QueryKind::Range { from, to } => { let mut time_range_queries = property .component_or_empty::()? .unwrap_or_default(); @@ -147,7 +146,7 @@ impl Query { }); property.save_blueprint_component(ctx, &time_range_queries); - property.save_blueprint_component(ctx, &QueryKind::TimeRange); + property.save_blueprint_component(ctx, &components::QueryKind::TimeRange); } }; @@ -199,11 +198,11 @@ pub(crate) fn query_ui( ctx, &components::Timeline::from(timeline.name().as_str()), ); - Query::save_mode_for_timeline( + Query::save_kind_for_timeline( ctx, space_view_id, timeline.name(), - &QueryMode::LatestAt { + &QueryKind::LatestAt { time: time_ctrl.time_int().unwrap_or(TimeInt::MAX), }, )?; @@ -261,20 +260,20 @@ fn override_ui( let timeline_name = timeline.name(); let query = Query::try_from_blueprint(ctx, space_view_id)?; - let mut ui_query_mode: UiQueryMode = query.mode(ctx).into(); + let mut ui_query_kind: UiQueryKind = query.kind(ctx).into(); let time_drag_value = if let Some(times) = ctx.recording().time_histogram(&timeline) { TimeDragValue::from_time_histogram(times) } else { TimeDragValue::from_time_range(0..=0) }; let changed = - ui_query_mode.ui(ctx, ui, &time_drag_value, timeline.name(), timeline.typ()); + ui_query_kind.ui(ctx, ui, &time_drag_value, timeline.name(), timeline.typ()); if changed { - Query::save_mode_for_timeline( + Query::save_kind_for_timeline( ctx, space_view_id, timeline_name, - &ui_query_mode.into(), + &ui_query_kind.into(), )?; } diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index e2a3ee71c2a2..bc845a7cf272 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -764,12 +764,12 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { "Timeline", docstring_md : "The timeline for this query.\n\nIf unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype.", }, ArchetypeFieldReflection { component_name : - "rerun.blueprint.components.QueryKind".into(), display_name : "Mode", - docstring_md : "Type of query: latest at or range", }, + "rerun.blueprint.components.QueryKind".into(), display_name : "Kind", + docstring_md : "Kind of query: latest-at or range.", }, ArchetypeFieldReflection { component_name : "rerun.blueprint.components.LatestAtQueries".into(), display_name : "Latest at queries", docstring_md : - "Configuration for latest at queries.attribute\n\nNote: configuration as saved on a per-timeline basis.", + "Configuration for latest-at queries.\n\nNote: configuration as saved on a per-timeline basis.", }, ArchetypeFieldReflection { component_name : "rerun.blueprint.components.TimeRangeQueries".into(), display_name : "Time range queries", docstring_md : diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp index 213350708ed0..0bd53a79fd93 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp @@ -22,8 +22,8 @@ namespace rerun { RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } - if (archetype.mode.has_value()) { - auto result = ComponentBatch::from_loggable(archetype.mode.value()); + if (archetype.kind.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.kind.value()); RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp index 36eab4a6fa98..41c3d512b18a 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp @@ -26,10 +26,10 @@ namespace rerun::blueprint::archetypes { /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. std::optional timeline; - /// Type of query: latest at or range - std::optional mode; + /// Kind of query: latest-at or range. + std::optional kind; - /// Configuration for latest at queries.attribute + /// Configuration for latest-at queries. /// /// Note: configuration as saved on a per-timeline basis. std::optional latest_at_queries; @@ -59,14 +59,14 @@ namespace rerun::blueprint::archetypes { RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } - /// Type of query: latest at or range - DataframeQuery with_mode(rerun::blueprint::components::QueryKind _mode) && { - mode = std::move(_mode); + /// Kind of query: latest-at or range. + DataframeQuery with_kind(rerun::blueprint::components::QueryKind _kind) && { + kind = std::move(_kind); // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } - /// Configuration for latest at queries.attribute + /// Configuration for latest-at queries. /// /// Note: configuration as saved on a per-timeline basis. DataframeQuery with_latest_at_queries( diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py index a9f9417d4322..0802e515183d 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py @@ -27,7 +27,7 @@ def __init__( self: Any, *, timeline: datatypes.Utf8Like | None = None, - mode: blueprint_components.QueryKindLike | None = None, + kind: blueprint_components.QueryKindLike | None = None, latest_at_queries: blueprint_components.LatestAtQueriesLike | None = None, time_range_queries: blueprint_components.TimeRangeQueriesLike | None = None, ): @@ -40,10 +40,10 @@ def __init__( The timeline for this query. If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. - mode: - Type of query: latest at or range + kind: + Kind of query: latest-at or range. latest_at_queries: - Configuration for latest at queries.attribute + Configuration for latest-at queries. Note: configuration as saved on a per-timeline basis. time_range_queries: @@ -56,7 +56,7 @@ def __init__( # You can define your own __init__ function as a member of DataframeQueryExt in dataframe_query_ext.py with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( - timeline=timeline, mode=mode, latest_at_queries=latest_at_queries, time_range_queries=time_range_queries + timeline=timeline, kind=kind, latest_at_queries=latest_at_queries, time_range_queries=time_range_queries ) return self.__attrs_clear__() @@ -65,7 +65,7 @@ def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" self.__attrs_init__( timeline=None, # type: ignore[arg-type] - mode=None, # type: ignore[arg-type] + kind=None, # type: ignore[arg-type] latest_at_queries=None, # type: ignore[arg-type] time_range_queries=None, # type: ignore[arg-type] ) @@ -88,12 +88,12 @@ def _clear(cls) -> DataframeQuery: # # (Docstring intentionally commented out to hide this field from the docs) - mode: blueprint_components.QueryKindBatch | None = field( + kind: blueprint_components.QueryKindBatch | None = field( metadata={"component": "optional"}, default=None, converter=blueprint_components.QueryKindBatch._optional, # type: ignore[misc] ) - # Type of query: latest at or range + # Kind of query: latest-at or range. # # (Docstring intentionally commented out to hide this field from the docs) @@ -102,7 +102,7 @@ def _clear(cls) -> DataframeQuery: default=None, converter=blueprint_components.LatestAtQueriesBatch._optional, # type: ignore[misc] ) - # Configuration for latest at queries.attribute + # Configuration for latest-at queries. # # Note: configuration as saved on a per-timeline basis. # From 3d24b533e3f30bc68707c3094e9cb2f40a9bd2a4 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 9 Aug 2024 14:05:11 +0200 Subject: [PATCH 17/18] Rename Timeline component to TimelineName (+ other fixes) --- .../blueprint/archetypes/dataframe_query.fbs | 2 +- .../rerun/blueprint/components.fbs | 2 +- .../{timeline.fbs => timeline_name.fbs} | 6 ++-- .../blueprint/datatypes/time_range_query.fbs | 2 +- .../blueprint/archetypes/dataframe_query.rs | 14 ++++---- .../src/blueprint/components/.gitattributes | 2 +- .../re_types/src/blueprint/components/mod.rs | 6 ++-- .../src/blueprint/components/timeline_ext.rs | 15 -------- .../{timeline.rs => timeline_name.rs} | 24 ++++++------- .../blueprint/components/timeline_name_ext.rs | 22 ++++++++++++ .../blueprint/datatypes/time_range_query.rs | 2 +- crates/viewer/re_edit_ui/src/lib.rs | 4 +-- crates/viewer/re_edit_ui/src/timeline.rs | 11 +++--- .../re_space_view_dataframe/src/view_query.rs | 20 +++++------ .../src/blueprint/validation_gen/mod.rs | 4 +-- crates/viewer/re_viewer/src/reflection/mod.rs | 8 ++--- .../blueprint/archetypes/dataframe_query.hpp | 6 ++-- rerun_cpp/src/rerun/blueprint/components.hpp | 2 +- .../rerun/blueprint/components/.gitattributes | 2 +- .../{timeline.hpp => timeline_name.hpp} | 26 +++++++------- .../blueprint/datatypes/time_range_query.hpp | 2 +- .../blueprint/archetypes/dataframe_query.py | 4 +-- .../rerun/blueprint/components/.gitattributes | 2 +- .../rerun/blueprint/components/__init__.py | 8 ++--- .../rerun/blueprint/components/timeline.py | 36 ------------------- .../blueprint/components/timeline_name.py | 36 +++++++++++++++++++ .../blueprint/datatypes/time_range_query.py | 4 +-- 27 files changed, 140 insertions(+), 132 deletions(-) rename crates/store/re_types/definitions/rerun/blueprint/components/{timeline.fbs => timeline_name.fbs} (69%) delete mode 100644 crates/store/re_types/src/blueprint/components/timeline_ext.rs rename crates/store/re_types/src/blueprint/components/{timeline.rs => timeline_name.rs} (79%) create mode 100644 crates/store/re_types/src/blueprint/components/timeline_name_ext.rs rename rerun_cpp/src/rerun/blueprint/components/{timeline.hpp => timeline_name.hpp} (68%) delete mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs index b22b6191a21d..537da475465f 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs @@ -34,7 +34,7 @@ table DataframeQuery ( /// The timeline for this query. /// /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. - timeline: rerun.blueprint.components.Timeline ("attr.rerun.component_optional", nullable, order: 100); + timeline: rerun.blueprint.components.TimelineName ("attr.rerun.component_optional", nullable, order: 100); /// Kind of query: latest-at or range. kind: rerun.blueprint.components.QueryKind ("attr.rerun.component_optional", nullable,order: 200); diff --git a/crates/store/re_types/definitions/rerun/blueprint/components.fbs b/crates/store/re_types/definitions/rerun/blueprint/components.fbs index 5fc26f32fd92..95262a56a7e0 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components.fbs @@ -25,7 +25,7 @@ include "./components/space_view_maximized.fbs"; include "./components/space_view_origin.fbs"; include "./components/tensor_dimension_index_slider.fbs"; include "./components/time_range_queries.fbs"; -include "./components/timeline.fbs"; +include "./components/timeline_name.fbs"; include "./components/view_fit.fbs"; include "./components/viewer_recommendation_hash.fbs"; include "./components/visible.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs similarity index 69% rename from crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs rename to crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs index a2ed7cdc4562..ef03400d2a92 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs @@ -1,12 +1,12 @@ namespace rerun.blueprint.components; -/// A timeline, identified by its name. -table Timeline ( +/// A timeline identified by its name. +table TimelineName ( "attr.arrow.transparent", "attr.python.aliases": "str", "attr.python.array_aliases": "str, Sequence[str]", - "attr.rust.derive": "Default, PartialEq, Eq, PartialOrd, Ord", + "attr.rust.derive": "PartialEq, Eq, PartialOrd, Ord", "attr.rust.repr": "transparent", "attr.rerun.scope": "blueprint" ) { diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs index 811c20c14aee..6b467209e580 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs @@ -13,6 +13,6 @@ table TimeRangeQuery ( /// Beginning of the time range. start: rerun.datatypes.TimeInt (order: 200); - /// End of the time range. + /// End of the time range (inclusive). end: rerun.datatypes.TimeInt (order: 300); } diff --git a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs index b0e2d314dfe7..635e3ee6992d 100644 --- a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs +++ b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs @@ -24,7 +24,7 @@ pub struct DataframeQuery { /// The timeline for this query. /// /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. - pub timeline: Option, + pub timeline: Option, /// Kind of query: latest-at or range. pub kind: Option, @@ -51,7 +51,7 @@ impl ::re_types_core::SizeBytes for DataframeQuery { #[inline] fn is_pod() -> bool { - >::is_pod() + >::is_pod() && >::is_pod() && >::is_pod() && >::is_pod() @@ -67,7 +67,7 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = once_cell::sync::Lazy::new(|| { [ - "rerun.blueprint.components.Timeline".into(), + "rerun.blueprint.components.TimelineName".into(), "rerun.blueprint.components.QueryKind".into(), "rerun.blueprint.components.LatestAtQueries".into(), "rerun.blueprint.components.TimeRangeQueries".into(), @@ -78,7 +78,7 @@ static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 5usize]> = once_cell::sync::Lazy::new(|| { [ "rerun.blueprint.components.DataframeQueryIndicator".into(), - "rerun.blueprint.components.Timeline".into(), + "rerun.blueprint.components.TimelineName".into(), "rerun.blueprint.components.QueryKind".into(), "rerun.blueprint.components.LatestAtQueries".into(), "rerun.blueprint.components.TimeRangeQueries".into(), @@ -143,8 +143,8 @@ impl ::re_types_core::Archetype for DataframeQuery { .map(|(name, array)| (name.full_name(), array)) .collect(); let timeline = - if let Some(array) = arrays_by_name.get("rerun.blueprint.components.Timeline") { - ::from_arrow_opt(&**array) + if let Some(array) = arrays_by_name.get("rerun.blueprint.components.TimelineName") { + ::from_arrow_opt(&**array) .with_context("rerun.blueprint.archetypes.DataframeQuery#timeline")? .into_iter() .next() @@ -236,7 +236,7 @@ impl DataframeQuery { #[inline] pub fn with_timeline( mut self, - timeline: impl Into, + timeline: impl Into, ) -> Self { self.timeline = Some(timeline.into()); self diff --git a/crates/store/re_types/src/blueprint/components/.gitattributes b/crates/store/re_types/src/blueprint/components/.gitattributes index 5ec5bbf2c49a..93f783652817 100644 --- a/crates/store/re_types/src/blueprint/components/.gitattributes +++ b/crates/store/re_types/src/blueprint/components/.gitattributes @@ -20,7 +20,7 @@ space_view_class.rs linguist-generated=true space_view_origin.rs linguist-generated=true tensor_dimension_index_slider.rs linguist-generated=true time_range_queries.rs linguist-generated=true -timeline.rs linguist-generated=true +timeline_name.rs linguist-generated=true view_fit.rs linguist-generated=true viewer_recommendation_hash.rs linguist-generated=true visible.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/components/mod.rs b/crates/store/re_types/src/blueprint/components/mod.rs index 8ae5cec561e5..a54028c22654 100644 --- a/crates/store/re_types/src/blueprint/components/mod.rs +++ b/crates/store/re_types/src/blueprint/components/mod.rs @@ -26,8 +26,8 @@ mod tensor_dimension_index_slider; mod tensor_dimension_index_slider_ext; mod time_range_queries; mod time_range_queries_ext; -mod timeline; -mod timeline_ext; +mod timeline_name; +mod timeline_name_ext; mod view_fit; mod viewer_recommendation_hash; mod viewer_recommendation_hash_ext; @@ -55,7 +55,7 @@ pub use self::space_view_class::SpaceViewClass; pub use self::space_view_origin::SpaceViewOrigin; pub use self::tensor_dimension_index_slider::TensorDimensionIndexSlider; pub use self::time_range_queries::TimeRangeQueries; -pub use self::timeline::Timeline; +pub use self::timeline_name::TimelineName; pub use self::view_fit::ViewFit; pub use self::viewer_recommendation_hash::ViewerRecommendationHash; pub use self::visible::Visible; diff --git a/crates/store/re_types/src/blueprint/components/timeline_ext.rs b/crates/store/re_types/src/blueprint/components/timeline_ext.rs deleted file mode 100644 index 410cb491576a..000000000000 --- a/crates/store/re_types/src/blueprint/components/timeline_ext.rs +++ /dev/null @@ -1,15 +0,0 @@ -use re_log_types::TimelineName; - -use super::Timeline; - -impl Timeline { - /// Return the name of the timeline. - pub fn timeline_name(&self) -> TimelineName { - TimelineName::from(self.0.as_str()) - } - - /// Set the name of the timeline. - pub fn set_timeline_name(&mut self, timeline_name: TimelineName) { - self.0 = timeline_name.as_str().into(); - } -} diff --git a/crates/store/re_types/src/blueprint/components/timeline.rs b/crates/store/re_types/src/blueprint/components/timeline_name.rs similarity index 79% rename from crates/store/re_types/src/blueprint/components/timeline.rs rename to crates/store/re_types/src/blueprint/components/timeline_name.rs index 4945faf83064..f4cfbd0bdf33 100644 --- a/crates/store/re_types/src/blueprint/components/timeline.rs +++ b/crates/store/re_types/src/blueprint/components/timeline_name.rs @@ -1,5 +1,5 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs". #![allow(unused_imports)] #![allow(unused_parens)] @@ -18,12 +18,12 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Component**: A timeline, identified by its name. -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +/// **Component**: A timeline identified by its name. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] -pub struct Timeline(pub crate::datatypes::Utf8); +pub struct TimelineName(pub crate::datatypes::Utf8); -impl ::re_types_core::SizeBytes for Timeline { +impl ::re_types_core::SizeBytes for TimelineName { #[inline] fn heap_size_bytes(&self) -> u64 { self.0.heap_size_bytes() @@ -35,20 +35,20 @@ impl ::re_types_core::SizeBytes for Timeline { } } -impl> From for Timeline { +impl> From for TimelineName { fn from(v: T) -> Self { Self(v.into()) } } -impl std::borrow::Borrow for Timeline { +impl std::borrow::Borrow for TimelineName { #[inline] fn borrow(&self) -> &crate::datatypes::Utf8 { &self.0 } } -impl std::ops::Deref for Timeline { +impl std::ops::Deref for TimelineName { type Target = crate::datatypes::Utf8; #[inline] @@ -57,21 +57,21 @@ impl std::ops::Deref for Timeline { } } -impl std::ops::DerefMut for Timeline { +impl std::ops::DerefMut for TimelineName { #[inline] fn deref_mut(&mut self) -> &mut crate::datatypes::Utf8 { &mut self.0 } } -::re_types_core::macros::impl_into_cow!(Timeline); +::re_types_core::macros::impl_into_cow!(TimelineName); -impl ::re_types_core::Loggable for Timeline { +impl ::re_types_core::Loggable for TimelineName { type Name = ::re_types_core::ComponentName; #[inline] fn name() -> Self::Name { - "rerun.blueprint.components.Timeline".into() + "rerun.blueprint.components.TimelineName".into() } #[inline] diff --git a/crates/store/re_types/src/blueprint/components/timeline_name_ext.rs b/crates/store/re_types/src/blueprint/components/timeline_name_ext.rs new file mode 100644 index 000000000000..6ef93e92c4f1 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/timeline_name_ext.rs @@ -0,0 +1,22 @@ +use super::TimelineName; + +// Not needed as there is a blanket implementation for impl Into +// impl From for TimelineName {} + +impl From for re_log_types::TimelineName { + fn from(value: TimelineName) -> Self { + Self::from(value.as_str()) + } +} + +impl From<&TimelineName> for re_log_types::TimelineName { + fn from(value: &TimelineName) -> Self { + Self::from(value.as_str()) + } +} + +impl Default for TimelineName { + fn default() -> Self { + Self::from("log_time") + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs index 21ebcadd1ba6..59e581545bd7 100644 --- a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs +++ b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs @@ -27,7 +27,7 @@ pub struct TimeRangeQuery { /// Beginning of the time range. pub start: crate::datatypes::TimeInt, - /// End of the time range. + /// End of the time range (inclusive). pub end: crate::datatypes::TimeInt, } diff --git a/crates/viewer/re_edit_ui/src/lib.rs b/crates/viewer/re_edit_ui/src/lib.rs index 15e7f7260269..2d6fe01a28c6 100644 --- a/crates/viewer/re_edit_ui/src/lib.rs +++ b/crates/viewer/re_edit_ui/src/lib.rs @@ -20,7 +20,7 @@ use datatype_editors::{ }; use re_types::{ blueprint::components::{ - BackgroundKind, Corner2D, LockRangeDuringZoom, SortKey, SortOrder, Timeline, ViewFit, + BackgroundKind, Corner2D, LockRangeDuringZoom, SortKey, SortOrder, TimelineName, ViewFit, Visible, }, components::{ @@ -61,7 +61,7 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { registry.add_singleline_edit_or_view::(edit_bool); registry.add_singleline_edit_or_view::(edit_bool); - registry.add_singleline_edit_or_view::(timeline::edit_timeline); + registry.add_singleline_edit_or_view::(timeline::edit_timeline_name); registry.add_display_ui(Text::name(), Box::new(display_text_ui)); registry.add_singleline_edit_or_view::(edit_singleline_string); diff --git a/crates/viewer/re_edit_ui/src/timeline.rs b/crates/viewer/re_edit_ui/src/timeline.rs index 9f95bae29956..f64cee9435e8 100644 --- a/crates/viewer/re_edit_ui/src/timeline.rs +++ b/crates/viewer/re_edit_ui/src/timeline.rs @@ -1,14 +1,15 @@ use re_types::blueprint::components; use re_types_core::LoggableBatch as _; +use re_viewer_context::external::re_log_types::TimelineName; use re_viewer_context::{MaybeMutRef, ViewerContext}; -pub(crate) fn edit_timeline( +pub(crate) fn edit_timeline_name( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - value: &mut MaybeMutRef<'_, components::Timeline>, + value: &mut MaybeMutRef<'_, components::TimelineName>, ) -> egui::Response { if let Some(value) = value.as_mut() { - let mut current_value = value.timeline_name(); + let mut current_value: TimelineName = (&*value).into(); let id_source = value.name(); let mut changed = false; let mut combobox_response = egui::ComboBox::from_id_source(id_source) @@ -26,12 +27,12 @@ pub(crate) fn edit_timeline( }); if changed { - value.set_timeline_name(current_value); + *value = current_value.as_str().into(); combobox_response.response.mark_changed(); } combobox_response.response } else { - ui.label(value.timeline_name().as_str()) + ui.label(value.as_str()) } } diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index 753ce20f0187..c0a0c72080de 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -48,8 +48,8 @@ impl Query { // The presence (or not) of the timeline component determines if the view should follow the // time panel timeline/latest at query, or override it. let Some(timeline) = property - .component_or_empty::()? - .map(|t| t.timeline_name()) + .component_or_empty::()? + .map(|t| t.into()) else { return Ok(Self::FollowTimeline); }; @@ -168,8 +168,8 @@ pub(crate) fn query_ui( // The existence of a timeline component determines if we are in follow time panel or // override mode. - let timeline_component = property.component_or_empty::()?; - let timeline_name = timeline_component.as_ref().map(|t| t.timeline_name()); + let timeline_component = property.component_or_empty::()?; + let timeline_name: Option = timeline_component.as_ref().map(|t| t.into()); let timeline = timeline_name.and_then(|timeline_name| { ctx.recording() @@ -196,7 +196,7 @@ pub(crate) fn query_ui( // the table content remains stable. property.save_blueprint_component( ctx, - &components::Timeline::from(timeline.name().as_str()), + &components::TimelineName::from(timeline.name().as_str()), ); Query::save_kind_for_timeline( ctx, @@ -207,7 +207,7 @@ pub(crate) fn query_ui( }, )?; } else { - property.reset_blueprint_component::(ctx); + property.reset_blueprint_component::(ctx); } } @@ -229,7 +229,7 @@ fn override_ui( .show(ui, |ui| { ui.grid_left_hand_label("Timeline"); - let component_name = components::Timeline::name(); + let component_name = components::TimelineName::name(); //TODO(ab, andreas): maybe have a `singleline_edit_ui` wrapper directly in `ViewProperty` ctx.component_ui_registry.singleline_edit_ui( @@ -248,9 +248,9 @@ fn override_ui( ui.grid_left_hand_label("Showing"); let timeline = property - .component_or_empty::()? - .map(|t| t.timeline_name()) - .and_then(|timeline_name| { + .component_or_empty::()? + .map(|t| t.into()) + .and_then(|timeline_name: TimelineName| { ctx.recording() .timelines() .find(|t| t.name() == &timeline_name) diff --git a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs index afdc23a80a25..4dd334f2c5a7 100644 --- a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs @@ -19,7 +19,7 @@ pub use re_types::blueprint::components::SpaceViewClass; pub use re_types::blueprint::components::SpaceViewOrigin; pub use re_types::blueprint::components::TensorDimensionIndexSlider; pub use re_types::blueprint::components::TimeRangeQueries; -pub use re_types::blueprint::components::Timeline; +pub use re_types::blueprint::components::TimelineName; pub use re_types::blueprint::components::ViewFit; pub use re_types::blueprint::components::ViewerRecommendationHash; pub use re_types::blueprint::components::Visible; @@ -63,7 +63,7 @@ pub fn is_valid_blueprint(blueprint: &EntityDb) -> bool { && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) - && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index bc845a7cf272..a8eb9d1976f4 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -210,10 +210,10 @@ fn generate_component_reflection() -> Result::name(), + ::name(), ComponentReflection { - docstring_md: "A timeline, identified by its name.", - placeholder: Some(Timeline::default().to_arrow()?), + docstring_md: "A timeline identified by its name.", + placeholder: Some(TimelineName::default().to_arrow()?), }, ), ( @@ -760,7 +760,7 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { docstring_md: "The query for the dataframe view.", fields: vec![ ArchetypeFieldReflection { component_name : - "rerun.blueprint.components.Timeline".into(), display_name : + "rerun.blueprint.components.TimelineName".into(), display_name : "Timeline", docstring_md : "The timeline for this query.\n\nIf unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype.", }, ArchetypeFieldReflection { component_name : diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp index 41c3d512b18a..b5824179e677 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp @@ -6,7 +6,7 @@ #include "../../blueprint/components/latest_at_queries.hpp" #include "../../blueprint/components/query_kind.hpp" #include "../../blueprint/components/time_range_queries.hpp" -#include "../../blueprint/components/timeline.hpp" +#include "../../blueprint/components/timeline_name.hpp" #include "../../collection.hpp" #include "../../compiler_utils.hpp" #include "../../component_batch.hpp" @@ -24,7 +24,7 @@ namespace rerun::blueprint::archetypes { /// The timeline for this query. /// /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. - std::optional timeline; + std::optional timeline; /// Kind of query: latest-at or range. std::optional kind; @@ -53,7 +53,7 @@ namespace rerun::blueprint::archetypes { /// The timeline for this query. /// /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. - DataframeQuery with_timeline(rerun::blueprint::components::Timeline _timeline) && { + DataframeQuery with_timeline(rerun::blueprint::components::TimelineName _timeline) && { timeline = std::move(_timeline); // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index 1c872515fac3..19657a843547 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -27,7 +27,7 @@ #include "blueprint/components/space_view_origin.hpp" #include "blueprint/components/tensor_dimension_index_slider.hpp" #include "blueprint/components/time_range_queries.hpp" -#include "blueprint/components/timeline.hpp" +#include "blueprint/components/timeline_name.hpp" #include "blueprint/components/view_fit.hpp" #include "blueprint/components/viewer_recommendation_hash.hpp" #include "blueprint/components/visible.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/components/.gitattributes b/rerun_cpp/src/rerun/blueprint/components/.gitattributes index acd8d2a05176..96df82b452ea 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -35,7 +35,7 @@ space_view_origin.hpp linguist-generated=true tensor_dimension_index_slider.hpp linguist-generated=true time_range_queries.cpp linguist-generated=true time_range_queries.hpp linguist-generated=true -timeline.hpp linguist-generated=true +timeline_name.hpp linguist-generated=true view_fit.cpp linguist-generated=true view_fit.hpp linguist-generated=true viewer_recommendation_hash.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/components/timeline.hpp b/rerun_cpp/src/rerun/blueprint/components/timeline_name.hpp similarity index 68% rename from rerun_cpp/src/rerun/blueprint/components/timeline.hpp rename to rerun_cpp/src/rerun/blueprint/components/timeline_name.hpp index b9c17bc30228..7b068de8a301 100644 --- a/rerun_cpp/src/rerun/blueprint/components/timeline.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/timeline_name.hpp @@ -1,5 +1,5 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs". #pragma once @@ -12,23 +12,23 @@ #include namespace rerun::blueprint::components { - /// **Component**: A timeline, identified by its name. - struct Timeline { + /// **Component**: A timeline identified by its name. + struct TimelineName { rerun::datatypes::Utf8 value; public: - Timeline() = default; + TimelineName() = default; - Timeline(rerun::datatypes::Utf8 value_) : value(std::move(value_)) {} + TimelineName(rerun::datatypes::Utf8 value_) : value(std::move(value_)) {} - Timeline& operator=(rerun::datatypes::Utf8 value_) { + TimelineName& operator=(rerun::datatypes::Utf8 value_) { value = std::move(value_); return *this; } - Timeline(std::string value_) : value(std::move(value_)) {} + TimelineName(std::string value_) : value(std::move(value_)) {} - Timeline& operator=(std::string value_) { + TimelineName& operator=(std::string value_) { value = std::move(value_); return *this; } @@ -41,21 +41,21 @@ namespace rerun::blueprint::components { } // namespace rerun::blueprint::components namespace rerun { - static_assert(sizeof(rerun::datatypes::Utf8) == sizeof(blueprint::components::Timeline)); + static_assert(sizeof(rerun::datatypes::Utf8) == sizeof(blueprint::components::TimelineName)); /// \private template <> - struct Loggable { - static constexpr const char Name[] = "rerun.blueprint.components.Timeline"; + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.TimelineName"; /// Returns the arrow data type this type corresponds to. static const std::shared_ptr& arrow_datatype() { return Loggable::arrow_datatype(); } - /// Serializes an array of `rerun::blueprint:: components::Timeline` into an arrow array. + /// Serializes an array of `rerun::blueprint:: components::TimelineName` into an arrow array. static Result> to_arrow( - const blueprint::components::Timeline* instances, size_t num_instances + const blueprint::components::TimelineName* instances, size_t num_instances ) { return Loggable::to_arrow(&instances->value, num_instances); } diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp index 5feab6b63125..91e71a00acd2 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp +++ b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp @@ -25,7 +25,7 @@ namespace rerun::blueprint::datatypes { /// Beginning of the time range. rerun::datatypes::TimeInt start; - /// End of the time range. + /// End of the time range (inclusive). rerun::datatypes::TimeInt end; public: diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py index 0802e515183d..733490f56550 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py @@ -77,10 +77,10 @@ def _clear(cls) -> DataframeQuery: inst.__attrs_clear__() return inst - timeline: blueprint_components.TimelineBatch | None = field( + timeline: blueprint_components.TimelineNameBatch | None = field( metadata={"component": "optional"}, default=None, - converter=blueprint_components.TimelineBatch._optional, # type: ignore[misc] + converter=blueprint_components.TimelineNameBatch._optional, # type: ignore[misc] ) # The timeline for this query. # diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index 9799e2d824ce..201c9647727e 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -27,7 +27,7 @@ space_view_maximized.py linguist-generated=true space_view_origin.py linguist-generated=true tensor_dimension_index_slider.py linguist-generated=true time_range_queries.py linguist-generated=true -timeline.py linguist-generated=true +timeline_name.py linguist-generated=true view_fit.py linguist-generated=true viewer_recommendation_hash.py linguist-generated=true visible.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py index 0de47cb349a7..672894030dcb 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -55,7 +55,7 @@ TimeRangeQueriesLike, TimeRangeQueriesType, ) -from .timeline import Timeline, TimelineBatch, TimelineType +from .timeline_name import TimelineName, TimelineNameBatch, TimelineNameType from .view_fit import ViewFit, ViewFitArrayLike, ViewFitBatch, ViewFitLike, ViewFitType from .viewer_recommendation_hash import ( ViewerRecommendationHash, @@ -161,9 +161,9 @@ "TimeRangeQueriesBatch", "TimeRangeQueriesLike", "TimeRangeQueriesType", - "Timeline", - "TimelineBatch", - "TimelineType", + "TimelineName", + "TimelineNameBatch", + "TimelineNameType", "ViewFit", "ViewFitArrayLike", "ViewFitBatch", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py deleted file mode 100644 index e5e50f30f6fa..000000000000 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/timeline.py +++ /dev/null @@ -1,36 +0,0 @@ -# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs -# Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline.fbs". - -# You can extend this class by creating a "TimelineExt" class in "timeline_ext.py". - -from __future__ import annotations - -from ... import datatypes -from ..._baseclasses import ( - ComponentBatchMixin, - ComponentMixin, -) - -__all__ = ["Timeline", "TimelineBatch", "TimelineType"] - - -class Timeline(datatypes.Utf8, ComponentMixin): - """**Component**: A timeline, identified by its name.""" - - _BATCH_TYPE = None - # You can define your own __init__ function as a member of TimelineExt in timeline_ext.py - - # Note: there are no fields here because Timeline delegates to datatypes.Utf8 - pass - - -class TimelineType(datatypes.Utf8Type): - _TYPE_NAME: str = "rerun.blueprint.components.Timeline" - - -class TimelineBatch(datatypes.Utf8Batch, ComponentBatchMixin): - _ARROW_TYPE = TimelineType() - - -# This is patched in late to avoid circular dependencies. -Timeline._BATCH_TYPE = TimelineBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py new file mode 100644 index 000000000000..99c49ffee02e --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py @@ -0,0 +1,36 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs". + +# You can extend this class by creating a "TimelineNameExt" class in "timeline_name_ext.py". + +from __future__ import annotations + +from ... import datatypes +from ..._baseclasses import ( + ComponentBatchMixin, + ComponentMixin, +) + +__all__ = ["TimelineName", "TimelineNameBatch", "TimelineNameType"] + + +class TimelineName(datatypes.Utf8, ComponentMixin): + """**Component**: A timeline identified by its name.""" + + _BATCH_TYPE = None + # You can define your own __init__ function as a member of TimelineNameExt in timeline_name_ext.py + + # Note: there are no fields here because TimelineName delegates to datatypes.Utf8 + pass + + +class TimelineNameType(datatypes.Utf8Type): + _TYPE_NAME: str = "rerun.blueprint.components.TimelineName" + + +class TimelineNameBatch(datatypes.Utf8Batch, ComponentBatchMixin): + _ARROW_TYPE = TimelineNameType() + + +# This is patched in late to avoid circular dependencies. +TimelineName._BATCH_TYPE = TimelineNameBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py index 1edb469ba477..f8ab08cfee48 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py @@ -48,7 +48,7 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLi start: Beginning of the time range. end: - End of the time range. + End of the time range (inclusive). """ @@ -70,7 +70,7 @@ def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLi end: datatypes.TimeInt = field( converter=TimeRangeQueryExt.end__field_converter_override, # type: ignore[misc] ) - # End of the time range. + # End of the time range (inclusive). # # (Docstring intentionally commented out to hide this field from the docs) From 0c22cfaabe41f5fd44571718fc79db3e21c08d22 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 9 Aug 2024 15:38:36 +0200 Subject: [PATCH 18/18] Fixed UI spacing --- crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs | 2 ++ crates/viewer/re_space_view_dataframe/src/view_query.rs | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs b/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs index 35dabd65fafc..b02f7f18f025 100644 --- a/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs +++ b/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs @@ -98,6 +98,8 @@ impl UiQueryKind { if is_time_range_custom { ui.spacing_mut().indent = ui.spacing().icon_width + ui.spacing().icon_spacing; ui.indent("time_range_custom", |ui| { + ui.add_space(-4.0); + let mut from = if let Self::TimeRange { from, .. } = self { (*from).into() } else { diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs index c0a0c72080de..dcf716abe7e8 100644 --- a/crates/viewer/re_space_view_dataframe/src/view_query.rs +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -177,6 +177,8 @@ pub(crate) fn query_ui( .find(|t| t.name() == &timeline_name) }); + ui.add_space(5.0); + let mut override_query = timeline.is_some(); let changed = ui.selectable_toggle(|ui| { ui.selectable_value(&mut override_query, false, "Follow timeline") @@ -225,7 +227,9 @@ fn override_ui( space_view_id: SpaceViewId, property: &ViewProperty<'_>, ) -> Result<(), SpaceViewSystemExecutionError> { - ui.selection_grid("dataframe_view_query_ui") + egui::Grid::new("dataframe_view_query_ui") + .num_columns(2) + .spacing(egui::vec2(8.0, 10.0)) .show(ui, |ui| { ui.grid_left_hand_label("Timeline");