re_viewer_context/view/
highlights.rs1use nohash_hasher::IntMap;
2use re_entity_db::InstancePath;
3use re_log_types::{EntityPathHash, Instance};
4use re_renderer::OutlineMaskPreference;
5use re_sdk_types::blueprint::components::VisualizerInstructionId;
6
7use crate::{HoverHighlight, InteractionHighlight, SelectionHighlight};
8
9#[derive(Debug)]
13pub struct ViewEntityHighlight {
14 overall: InteractionHighlight,
15 instances: ahash::HashMap<Instance, InteractionHighlight>,
16
17 visualizer_instruction: Option<VisualizerInstructionId>,
19}
20
21impl ViewEntityHighlight {
22 pub fn new(visualizer_instruction: Option<VisualizerInstructionId>) -> Self {
23 Self {
24 overall: InteractionHighlight::default(),
25 instances: ahash::HashMap::default(),
26 visualizer_instruction,
27 }
28 }
29
30 #[inline]
32 pub fn add(&mut self, instance: &InstancePath, highlight: InteractionHighlight) {
33 let highlight_target = if let Some(selected_index) = instance.instance.specific_index() {
34 self.instances.entry(selected_index).or_default()
35 } else {
36 &mut self.overall
37 };
38 *highlight_target = (*highlight_target).max(highlight);
39 }
40
41 #[inline]
43 pub fn add_selection(&mut self, instance: &InstancePath, selection: SelectionHighlight) {
44 self.add(
45 instance,
46 InteractionHighlight {
47 selection,
48 hover: HoverHighlight::None,
49 },
50 );
51 }
52
53 #[inline]
55 pub fn add_hover(&mut self, instance: &InstancePath, hover: HoverHighlight) {
56 self.add(
57 instance,
58 InteractionHighlight {
59 selection: SelectionHighlight::None,
60 hover,
61 },
62 );
63 }
64}
65
66#[derive(Copy, Clone)]
67pub struct OptionalViewEntityHighlight<'a>(Option<&'a ViewEntityHighlight>);
68
69impl OptionalViewEntityHighlight<'_> {
70 #[inline]
71 pub fn index_highlight(
72 &self,
73 instance: Instance,
74 visualizer: VisualizerInstructionId,
75 ) -> InteractionHighlight {
76 match self.0 {
77 Some(entity_highlight) => {
78 if entity_highlight
79 .visualizer_instruction
80 .is_some_and(|v| v != visualizer)
81 {
82 InteractionHighlight::default()
84 } else {
85 entity_highlight
86 .instances
87 .get(&instance)
88 .copied()
89 .unwrap_or_default()
90 .max(entity_highlight.overall)
91 }
92 }
93 None => InteractionHighlight::default(),
94 }
95 }
96}
97
98#[derive(Default, Debug)]
99pub struct ViewOutlineMasks {
100 pub overall: OutlineMaskPreference,
101 pub instances: ahash::HashMap<Instance, OutlineMaskPreference>,
102}
103
104impl ViewOutlineMasks {
105 pub fn index_outline_mask(&self, instance: Instance) -> OutlineMaskPreference {
106 self.instances
107 .get(&instance)
108 .copied()
109 .unwrap_or_default()
110 .with_fallback_to(self.overall)
111 }
112
113 pub fn add(&mut self, instance: &InstancePath, preference: OutlineMaskPreference) {
115 let outline_mask_target = if let Some(selected_index) = instance.instance.specific_index() {
116 self.instances.entry(selected_index).or_default()
117 } else {
118 &mut self.overall
119 };
120 *outline_mask_target = preference.with_fallback_to(*outline_mask_target);
121 }
122}
123
124#[derive(Default, Debug)]
128pub struct ViewHighlights {
129 pub highlighted_entity_paths: IntMap<EntityPathHash, ViewEntityHighlight>,
130 pub outlines_masks: IntMap<EntityPathHash, ViewOutlineMasks>,
131}
132
133impl ViewHighlights {
134 #[inline]
135 pub fn entity_highlight(
136 &self,
137 entity_path_hash: EntityPathHash,
138 ) -> OptionalViewEntityHighlight<'_> {
139 OptionalViewEntityHighlight(self.highlighted_entity_paths.get(&entity_path_hash))
140 }
141
142 #[inline]
143 pub fn entity_outline_mask(&self, entity_path_hash: EntityPathHash) -> &ViewOutlineMasks {
144 use std::sync::OnceLock;
145 static CELL: OnceLock<ViewOutlineMasks> = OnceLock::new();
146
147 self.outlines_masks
148 .get(&entity_path_hash)
149 .unwrap_or_else(|| CELL.get_or_init(ViewOutlineMasks::default))
150 }
151
152 #[inline]
153 pub fn any_outlines(&self) -> bool {
154 !self.outlines_masks.is_empty()
155 }
156}