Skip to content

Commit f2ba861

Browse files
IsseWWumpf
authored andcommitted
Make transform frame edit not experimental (#12057)
### Related * Closes RR-3044 ### What Improves the frame id edit in the selection panel, and makes it not experimental. ### Preview When the frame hasn't been overridden the text is subdued. <img width="376" height="31" alt="Screenshot 2025-12-02 at 17 31 01" src="https://github.com/user-attachments/assets/51436fdd-fa99-4f09-b386-4927e4383fa9" /> When starting to edit the frame it shows suggestions <img width="376" height="107" alt="Screenshot 2025-12-02 at 17 31 13" src="https://github.com/user-attachments/assets/ec4779d0-f2a7-4863-b82c-e3b74f1a547f" /> When editing the frame it keeps showing suggestion that match what you've written so far. The text is also red if the current value doesn't match an existing frame. <img width="376" height="66" alt="Screenshot 2025-12-02 at 17 31 28" src="https://github.com/user-attachments/assets/b2101ca6-ef06-42e0-b882-9b76aa5a143f" /> When overridden it uses the default text color. <img width="376" height="31" alt="Screenshot 2025-12-02 at 17 31 48" src="https://github.com/user-attachments/assets/d46447cc-88e3-4422-9cd3-dc01bc5e63a4" />
1 parent 64beb85 commit f2ba861

File tree

5 files changed

+147
-60
lines changed

5 files changed

+147
-60
lines changed

crates/viewer/re_selection_panel/src/selection_panel.rs

Lines changed: 141 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use re_data_ui::{
88
};
99
use re_entity_db::{EntityPath, InstancePath};
1010
use re_log_types::{ComponentPath, EntityPathFilter, EntityPathSubs, ResolvedEntityPathFilter};
11-
use re_types::ComponentDescriptor;
11+
use re_types::{ComponentDescriptor, TransformFrameIdHash};
1212
use re_ui::list_item::ListItemContentButtonsExt as _;
1313
use re_ui::{
1414
SyntaxHighlighting as _, UiExt as _, icons,
@@ -346,15 +346,9 @@ impl SelectionPanel {
346346
let view_ctx = view.bundle_context_with_states(ctx, view_states);
347347
visible_interactive_toggle_ui(&view_ctx, ui, query_result, data_result);
348348

349-
// TODO(RR-2700): Come up with something non-experimental.
350349
let is_spatial_view =
351350
view.class_identifier() == "3D" || view.class_identifier() == "2D";
352-
if ctx
353-
.global_context
354-
.app_options
355-
.experimental_coordinate_frame_display_and_override
356-
&& is_spatial_view
357-
{
351+
if is_spatial_view {
358352
coordinate_frame_ui(ui, &view_ctx, data_result);
359353
}
360354
}
@@ -521,7 +515,7 @@ The last rule matching `/world/house` is `+ /world/**`, so it is included.
521515
}
522516
}
523517

524-
/// Shows the active coordinate frame.
518+
/// Shows the active coordinate frame if it isn't the fallback frame.
525519
///
526520
/// This is not technically a visualizer, but it affects visualization, so we show it alongside.
527521
fn coordinate_frame_ui(ui: &mut egui::Ui, ctx: &ViewContext<'_>, data_result: &DataResult) {
@@ -543,29 +537,46 @@ fn coordinate_frame_ui(ui: &mut egui::Ui, ctx: &ViewContext<'_>, data_result: &D
543537

544538
let override_path = data_result.override_path();
545539

546-
let frame_id_before = query_result
547-
.get_mono_with_fallback::<TransformFrameId>(component)
548-
.to_string();
549-
let mut frame_id = frame_id_before.clone();
540+
let result_override = query_result.overrides.get(component);
541+
let raw_override = result_override
542+
.and_then(|c| c.non_empty_component_batch_raw(component))
543+
.map(|(_, array)| array);
544+
545+
let Some(frame_id_before) = query_result
546+
.get_mono::<TransformFrameId>(component)
547+
.map(|f| f.to_string())
548+
.or_else(|| {
549+
if raw_override.is_some() {
550+
Some(String::new())
551+
} else {
552+
None
553+
}
554+
})
555+
else {
556+
return;
557+
};
550558

551-
ui.list_item_flat_noninteractive(
552-
list_item::PropertyContent::new("Coordinate frame")
553-
.value_text_mut(&mut frame_id)
554-
.with_menu_button(&re_ui::icons::MORE, "More options", |ui: &mut egui::Ui| {
555-
let result_override = query_result.overrides.get(component);
556-
let raw_override = result_override
557-
.and_then(|c| c.non_empty_component_batch_raw(component))
558-
.map(|(_, array)| array);
559-
560-
crate::visualizer_ui::remove_and_reset_override_buttons(
561-
ctx,
562-
ui,
563-
component_descr.clone(),
564-
override_path,
565-
&raw_override,
566-
);
567-
}),
568-
)
559+
let mut frame_id = if raw_override.is_some() {
560+
frame_id_before.clone()
561+
} else {
562+
String::new()
563+
};
564+
565+
let property_content = list_item::PropertyContent::new("Coordinate frame")
566+
.value_fn(|ui, _| {
567+
frame_id_edit(ctx, ui, &mut frame_id, &frame_id_before);
568+
})
569+
.with_menu_button(&re_ui::icons::MORE, "More options", |ui: &mut egui::Ui| {
570+
crate::visualizer_ui::remove_and_reset_override_buttons(
571+
ctx,
572+
ui,
573+
component_descr.clone(),
574+
override_path,
575+
&raw_override,
576+
);
577+
});
578+
579+
ui.list_item_flat_noninteractive(property_content)
569580
.on_hover_ui(|ui| {
570581
ui.markdown_ui(
571582
"The coordinate frame this entity is associated with.
@@ -574,7 +585,18 @@ To learn more about coordinate frames, see the [Spaces & Transforms](https://rer
574585
);
575586
});
576587

577-
if frame_id_before != frame_id {
588+
if raw_override.is_some() {
589+
if frame_id.is_empty() {
590+
ctx.clear_blueprint_component(override_path.clone(), component_descr);
591+
} else if frame_id_before != frame_id {
592+
// Save as blueprint override.
593+
ctx.save_blueprint_component(
594+
override_path.clone(),
595+
&component_descr,
596+
&TransformFrameId::new(&frame_id),
597+
);
598+
}
599+
} else if !frame_id.is_empty() {
578600
// Save as blueprint override.
579601
ctx.save_blueprint_component(
580602
override_path.clone(),
@@ -584,6 +606,93 @@ To learn more about coordinate frames, see the [Spaces & Transforms](https://rer
584606
}
585607
}
586608

609+
fn frame_id_edit(
610+
ctx: &ViewContext<'_>,
611+
ui: &mut egui::Ui,
612+
frame_id: &mut String,
613+
frame_id_before: &String,
614+
) {
615+
let (frame_exists, mut suggestions) = {
616+
// In a scope to not hold the lock for longer than needed.
617+
let caches = ctx.viewer_ctx.store_context.caches;
618+
let transform_cache =
619+
caches.entry(|c: &mut re_viewer_context::TransformDatabaseStoreCache| {
620+
c.lock_transform_cache(ctx.recording())
621+
});
622+
623+
let frame_exists = transform_cache
624+
.frame_id_registry()
625+
.lookup_frame_id(TransformFrameIdHash::from_str(&*frame_id))
626+
.is_some();
627+
628+
let suggestions = transform_cache
629+
.frame_id_registry()
630+
.iter_frame_ids()
631+
// Only show named frames.
632+
.filter(|(_, id)| !id.is_entity_path_derived())
633+
.filter_map(|(_, id)| id.strip_prefix(&*frame_id))
634+
.filter(|rest| !rest.is_empty())
635+
.map(|rest| rest.to_owned())
636+
.collect::<Vec<_>>();
637+
638+
(frame_exists, suggestions)
639+
};
640+
641+
suggestions.sort_unstable();
642+
643+
let mut text_edit = egui::TextEdit::singleline(frame_id).hint_text(frame_id_before);
644+
if !frame_exists {
645+
text_edit = text_edit.text_color(ui.tokens().error_fg_color);
646+
}
647+
let response = ui.add(text_edit);
648+
649+
let suggestions_open =
650+
(response.has_focus() || response.lost_focus()) && !suggestions.is_empty();
651+
652+
let width = response.rect.width();
653+
654+
let suggestions_ui = |ui: &mut egui::Ui| {
655+
for rest in suggestions {
656+
let mut layout_job = egui::text::LayoutJob::default();
657+
layout_job.append(
658+
&*frame_id,
659+
0.0,
660+
egui::TextFormat::simple(
661+
ui.style().text_styles[&egui::TextStyle::Body].clone(),
662+
ui.tokens().text_default,
663+
),
664+
);
665+
layout_job.append(
666+
&rest,
667+
0.0,
668+
egui::TextFormat::simple(
669+
ui.style().text_styles[&egui::TextStyle::Body].clone(),
670+
ui.tokens().text_subdued,
671+
),
672+
);
673+
674+
if ui
675+
.add(egui::Button::new(layout_job).min_size(egui::vec2(width, 0.0)))
676+
.clicked()
677+
{
678+
frame_id.push_str(&rest);
679+
}
680+
}
681+
};
682+
683+
egui::Popup::from_response(&response)
684+
.style(re_ui::menu::menu_style())
685+
.open(suggestions_open)
686+
.show(|ui: &mut egui::Ui| {
687+
ui.set_width(width);
688+
689+
egui::ScrollArea::vertical()
690+
.min_scrolled_height(350.0)
691+
.max_height(350.0)
692+
.show(ui, suggestions_ui);
693+
});
694+
}
695+
587696
fn show_recording_properties(
588697
ctx: &ViewerContext<'_>,
589698
db: &re_entity_db::EntityDb,

crates/viewer/re_viewer/src/ui/settings_screen.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -176,26 +176,6 @@ fn settings_screen_ui_impl(ui: &mut egui::Ui, app_options: &mut AppOptions, keep
176176
separator_with_some_space(ui);
177177
ui.strong("Video");
178178
video_section_ui(ui, app_options);
179-
180-
//
181-
// Experimental features
182-
//
183-
184-
//#[cfg(not(target_arch = "wasm32"))]
185-
if true {
186-
separator_with_some_space(ui);
187-
ui.strong("Experimental features");
188-
189-
ui.re_checkbox(
190-
&mut app_options.experimental_coordinate_frame_display_and_override,
191-
"Display coordinate frames",
192-
)
193-
.on_hover_ui(|ui| {
194-
ui.markdown_ui(
195-
"Every entity is associated with a coordinate frame id. Enabling this shows them in 2D & 3D views and allows blueprint overrides for them.",
196-
);
197-
});
198-
}
199179
}
200180

201181
fn video_section_ui(ui: &mut Ui, app_options: &mut AppOptions) {
Lines changed: 2 additions & 2 deletions
Loading

crates/viewer/re_viewer_context/src/app_options.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ pub struct AppOptions {
6363
/// see [`AppOptions::cache_subdirectory`].
6464
#[cfg(not(target_arch = "wasm32"))]
6565
pub cache_directory: Option<std::path::PathBuf>,
66-
67-
/// Enables experimental coordinate frame id overrides.
68-
// TODO(RR-2700): Come up with something non-experimental.
69-
pub experimental_coordinate_frame_display_and_override: bool,
7066
}
7167

7268
impl Default for AppOptions {
@@ -94,8 +90,6 @@ impl Default for AppOptions {
9490

9591
#[cfg(not(target_arch = "wasm32"))]
9692
cache_directory: Self::default_cache_directory(),
97-
98-
experimental_coordinate_frame_display_and_override: false,
9993
}
10094
}
10195
}

docs/snippets/snippets.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ backwards_check = [
200200
"cpp", # Blueprint API doesn't exist for C++/Rust
201201
"rust", # Blueprint API doesn't exist for C++/Rust
202202
]
203+
"archetypes/pinhole_projections" = [
204+
"cpp", # Blueprint API doesn't exist for C++/Rust
205+
"rust", # Blueprint API doesn't exist for C++/Rust
206+
]
203207
"archetypes/video_stream_synthetic" = [
204208
"cpp", # Not implemented
205209
"rust", # Not implemented

0 commit comments

Comments
 (0)