use std::collections::BTreeMap;
use itertools::Itertools as _;
use nohash_hasher::IntSet;
use re_chunk_store::MissingChunkReporter;
use re_log_types::EntityPath;
use re_sdk_types::ViewClassIdentifier;
use vec1::Vec1;
use super::ViewContext;
use crate::{
IndicatedEntities, PerVisualizerType, QueryRange, RecommendedMappings, SystemExecutionOutput,
ViewClassRegistryError, ViewId, ViewQuery, ViewSpawnHeuristics, ViewSystemExecutionError,
ViewSystemIdentifier, ViewSystemRegistrator, ViewerContext, VisualizableReason,
};
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Ord, Eq)]
pub enum ViewClassLayoutPriority {
Low,
#[default]
Medium,
High,
}
pub struct RecommendedVisualizers {
all_recommendations: BTreeMap<ViewSystemIdentifier, Vec1<RecommendedMappings>>,
auto_spawned: BTreeMap<ViewSystemIdentifier, Vec1<RecommendedMappings>>,
}
impl RecommendedVisualizers {
pub fn new(
recommended_and_auto_spawned: BTreeMap<ViewSystemIdentifier, Vec1<RecommendedMappings>>,
) -> Self {
Self {
auto_spawned: recommended_and_auto_spawned.clone(),
all_recommendations: recommended_and_auto_spawned,
}
}
pub fn empty() -> Self {
Self::new(Default::default())
}
pub fn default(visualizer: ViewSystemIdentifier) -> Self {
Self::new(std::iter::once((visualizer, Default::default())).collect())
}
pub fn default_many(visualizers: impl IntoIterator<Item = ViewSystemIdentifier>) -> Self {
let recommended = visualizers
.into_iter()
.map(|v| (v, Default::default()))
.collect();
Self::new(recommended)
}
pub fn insert(
&mut self,
visualizer: ViewSystemIdentifier,
mappings: Vec1<RecommendedMappings>,
auto_spawn: bool,
) {
if auto_spawn {
Self::extend_mappings_unique(&mut self.auto_spawned, visualizer, mappings.clone());
}
Self::extend_mappings_unique(&mut self.all_recommendations, visualizer, mappings);
}
pub fn all_recommendations(
&self,
) -> &BTreeMap<ViewSystemIdentifier, Vec1<RecommendedMappings>> {
&self.all_recommendations
}
pub fn into_auto_spawned(self) -> BTreeMap<ViewSystemIdentifier, Vec1<RecommendedMappings>> {
self.auto_spawned
}
fn extend_mappings_unique(
map: &mut BTreeMap<ViewSystemIdentifier, Vec1<RecommendedMappings>>,
visualizer: ViewSystemIdentifier,
mappings: Vec1<RecommendedMappings>,
) {
match map.entry(visualizer) {
std::collections::btree_map::Entry::Occupied(mut entry) => {
let existing = entry.get_mut();
existing.extend(mappings);
*existing = Vec1::try_from_vec(existing.iter().cloned().unique().collect())
.expect("There was already at least one mapping.");
}
std::collections::btree_map::Entry::Vacant(entry) => {
entry.insert(mappings);
}
}
}
}
pub type VisualizersSectionUi<'a> = Box<dyn Fn(&mut egui::Ui, &ViewContext<'_>) + 'a>;
pub struct VisualizersSectionOutput<'a> {
pub ui: VisualizersSectionUi<'a>,
pub add_options: Vec<(EntityPath, RecommendedVisualizers)>,
}
pub trait ViewClass: Send + Sync {
fn identifier() -> ViewClassIdentifier
where
Self: Sized;
fn recommendation_order(&self) -> i32 {
0
}
fn display_name(&self) -> &'static str;
fn icon(&self) -> &'static re_ui::Icon {
&re_ui::icons::VIEW_GENERIC
}
fn help(&self, os: egui::os::OperatingSystem) -> re_ui::Help;
fn on_register(
&self,
system_registry: &mut ViewSystemRegistrator<'_>,
) -> Result<(), ViewClassRegistryError>;
fn new_state(&self) -> Box<dyn ViewState>;
fn preferred_tile_aspect_ratio(&self, _state: &dyn ViewState) -> Option<f32> {
None
}
fn layout_priority(&self) -> ViewClassLayoutPriority;
fn supports_visible_time_range(&self) -> bool {
false
}
fn default_query_range(&self, _state: &dyn ViewState) -> QueryRange {
QueryRange::LatestAt
}
fn recommended_origin_for_entities(
&self,
entities: &IntSet<EntityPath>,
_entity_db: &re_entity_db::EntityDb,
) -> Option<EntityPath> {
Some(EntityPath::common_ancestor_of(entities.iter()))
}
fn recommended_visualizers_for_entity(
&self,
entity_path: &EntityPath,
visualizers_with_reason: &[(ViewSystemIdentifier, &VisualizableReason)],
indicated_entities_per_visualizer: &PerVisualizerType<&IndicatedEntities>,
) -> RecommendedVisualizers {
let recommended = visualizers_with_reason
.iter()
.filter_map(|(visualizer, _reason)| {
if indicated_entities_per_visualizer
.get(visualizer)
.is_some_and(|matching_list| matching_list.contains(entity_path))
{
Some((*visualizer, Default::default()))
} else {
None
}
})
.collect();
RecommendedVisualizers::new(recommended)
}
fn visualizers_section<'a>(
&'a self,
_ctx: &'a ViewContext<'a>,
) -> Option<VisualizersSectionOutput<'a>> {
None
}
fn spawn_heuristics(
&self,
ctx: &ViewerContext<'_>,
include_entity: &dyn Fn(&EntityPath) -> bool,
) -> ViewSpawnHeuristics;
#[doc(alias = "settings_ui")]
fn selection_ui(
&self,
_ctx: &ViewerContext<'_>,
_ui: &mut egui::Ui,
_state: &mut dyn ViewState,
_space_origin: &EntityPath,
_view_id: ViewId,
) -> Result<(), ViewSystemExecutionError> {
Ok(())
}
fn extra_title_bar_ui(
&self,
_ctx: &ViewerContext<'_>,
_ui: &mut egui::Ui,
_state: &mut dyn ViewState,
_space_origin: &EntityPath,
_view_id: ViewId,
) -> Result<(), ViewSystemExecutionError> {
Ok(())
}
#[doc(alias = "paint")]
#[doc(alias = "render")]
fn ui(
&self,
ctx: &ViewerContext<'_>,
missing_chunk_reporter: &MissingChunkReporter,
ui: &mut egui::Ui,
state: &mut dyn ViewState,
query: &ViewQuery<'_>,
system_output: SystemExecutionOutput,
) -> Result<(), ViewSystemExecutionError>;
}
pub trait ViewClassExt<'a>: ViewClass + 'a {
fn view_context<'b>(
&self,
viewer_ctx: &'b ViewerContext<'b>,
view_id: ViewId,
view_state: &'b dyn ViewState,
space_origin: &'b EntityPath,
) -> ViewContext<'b>;
}
impl<'a, T> ViewClassExt<'a> for T
where
T: ViewClass + 'a,
{
fn view_context<'b>(
&self,
viewer_ctx: &'b ViewerContext<'b>,
view_id: ViewId,
view_state: &'b dyn ViewState,
space_origin: &'b EntityPath,
) -> ViewContext<'b> {
ViewContext {
viewer_ctx,
view_id,
view_class_identifier: T::identifier(),
space_origin,
view_state,
query_result: viewer_ctx.lookup_query_result(view_id),
}
}
}
pub trait ViewState: std::any::Any + Sync + Send {
fn as_any(&self) -> &dyn std::any::Any;
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
fn size_bytes(&self) -> u64 {
0 }
}
impl ViewState for () {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
pub trait ViewStateExt: ViewState {
fn downcast_ref<T: ViewState>(&self) -> Result<&T, ViewSystemExecutionError> {
self.as_any()
.downcast_ref()
.ok_or(ViewSystemExecutionError::StateCastError(
std::any::type_name::<T>(),
))
}
fn downcast_mut<T: ViewState>(&mut self) -> Result<&mut T, ViewSystemExecutionError> {
self.as_any_mut()
.downcast_mut()
.ok_or(ViewSystemExecutionError::StateCastError(
std::any::type_name::<T>(),
))
}
}
impl ViewStateExt for dyn ViewState {}