Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show all loaded applications in recordings panel #5766

Merged
merged 15 commits into from
Apr 4, 2024
Merged
54 changes: 54 additions & 0 deletions crates/re_data_ui/src/app_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use re_entity_db::EntityDb;
use re_log_types::ApplicationId;
use re_viewer_context::{UiVerbosity, ViewerContext};

use crate::item_ui::entity_db_button_ui;

impl crate::DataUi for ApplicationId {
fn data_ui(
&self,
ctx: &ViewerContext<'_>,
ui: &mut egui::Ui,
verbosity: UiVerbosity,
_query: &re_data_store::LatestAtQuery,
_store: &re_data_store::DataStore,
) {
egui::Grid::new("application_id")
.num_columns(2)
.show(ui, |ui| {
ui.label("Application ID");
ui.label(self.to_string());
if self == &ctx.store_context.app_id {
ui.label("(active)");
}
ui.end_row();
});

if verbosity == UiVerbosity::Small {
return;
}

// Find all recordings with this app id
let recordings: Vec<&EntityDb> = ctx
Comment on lines +33 to +34
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to have the blueprints here as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but could also be very confusing. Do we show all the blueprints? Or just the active and default ones? What if the active and default are the same? Etc. I opted to keep it simple for now.

.store_context
.bundle
.recordings()
.filter(|db| db.app_id() == Some(self))
.collect();

if !recordings.is_empty() {
ui.scope(|ui| {
ui.set_clip_rect(ui.max_rect()); // TODO(#5740): Hack required because `entity_db_button_ui` uses `ListItem`, which fills the full width until the clip rect.

ui.add_space(8.0);
ui.strong("Loaded recordings for this app");
ui.indent("recordings", |ui| {
ui.spacing_mut().item_spacing.y = 0.0;
for entity_db in recordings {
entity_db_button_ui(ctx, ui, entity_db, true);
}
});
});
}
}
}
51 changes: 26 additions & 25 deletions crates/re_data_ui/src/data_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ impl crate::DataUi for re_smart_channel::SmartChannelSource {
for other in ctx
.store_context
.bundle
.entity_dbs_from_channel_source(self)
.entity_dbs()
.filter(|db| db.data_source.as_ref() == Some(self))
{
let is_clone = other.cloned_from().is_some();
if is_clone {
Expand All @@ -46,30 +47,30 @@ impl crate::DataUi for re_smart_channel::SmartChannelSource {
}
}

if !recordings.is_empty() {
ui.add_space(8.0);
ui.strong("Recordings from this data source");
let max_rect = ui.max_rect();
ui.indent("recordings", |ui| {
ui.set_clip_rect(max_rect); // TODO(#5740): Hack required because `entity_db_button_ui` uses `ListItem`, which fills the full width until the clip rect.
ui.spacing_mut().item_spacing.y = 0.0;
for entity_db in recordings {
entity_db_button_ui(ctx, ui, entity_db, true);
}
});
}
ui.scope(|ui| {
ui.set_clip_rect(ui.max_rect()); // TODO(#5740): Hack required because `entity_db_button_ui` uses `ListItem`, which fills the full width until the clip rect.

if !blueprints.is_empty() {
ui.add_space(8.0);
ui.strong("Blueprints from this data source");
let max_rect = ui.max_rect();
ui.indent("blueprints", |ui| {
ui.set_clip_rect(max_rect); // TODO(#5740): Hack required because `entity_db_button_ui` uses `ListItem`, which fills the full width until the clip rect.
ui.spacing_mut().item_spacing.y = 0.0;
for entity_db in blueprints {
entity_db_button_ui(ctx, ui, entity_db, true);
}
});
}
if !recordings.is_empty() {
ui.add_space(8.0);
ui.strong("Recordings from this data source");
ui.indent("recordings", |ui| {
ui.spacing_mut().item_spacing.y = 0.0;
for entity_db in recordings {
entity_db_button_ui(ctx, ui, entity_db, true);
}
});
}

if !blueprints.is_empty() {
ui.add_space(8.0);
ui.strong("Blueprints from this data source");
ui.indent("blueprints", |ui| {
ui.spacing_mut().item_spacing.y = 0.0;
for entity_db in blueprints {
entity_db_button_ui(ctx, ui, entity_db, true);
}
});
}
});
}
}
4 changes: 2 additions & 2 deletions crates/re_data_ui/src/entity_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use re_log_types::StoreKind;
use re_types::SizeBytes;
use re_viewer_context::{UiVerbosity, ViewerContext};

use crate::item_ui::data_source_button_ui;
use crate::item_ui::{app_id_button_ui, data_source_button_ui};

impl crate::DataUi for EntityDb {
fn data_ui(
Expand Down Expand Up @@ -54,7 +54,7 @@ impl crate::DataUi for EntityDb {
}

re_ui.grid_left_hand_label(ui, "Application ID");
ui.label(application_id.to_string());
app_id_button_ui(ctx, ui, application_id);
ui.end_row();

re_ui.grid_left_hand_label(ui, "Source");
Expand Down
30 changes: 29 additions & 1 deletion crates/re_data_ui/src/item_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! TODO(andreas): This is not a `data_ui`, can this go somewhere else, shouldn't be in `re_data_ui`.

use re_entity_db::{EntityTree, InstancePath};
use re_log_types::{ComponentPath, EntityPath, TimeInt, Timeline};
use re_log_types::{ApplicationId, ComponentPath, EntityPath, TimeInt, Timeline};
use re_ui::{icons, SyntaxHighlighting};
use re_viewer_context::{HoverHighlight, Item, SpaceViewId, UiVerbosity, ViewerContext};

Expand Down Expand Up @@ -551,6 +551,34 @@ pub fn entity_hover_card_ui(
instance_hover_card_ui(ui, ctx, query, store, &instance_path);
}

pub fn app_id_button_ui(
ctx: &ViewerContext<'_>,
ui: &mut egui::Ui,
app_id: &ApplicationId,
) -> egui::Response {
let item = Item::AppId(app_id.clone());

let response = ctx.re_ui.selectable_label_with_icon(
ui,
&icons::APPLICATION,
app_id.to_string(),
ctx.selection().contains_item(&item),
re_ui::LabelStyle::Normal,
);

let response = response.on_hover_ui(|ui| {
app_id.data_ui(
ctx,
ui,
re_viewer_context::UiVerbosity::Reduced,
&ctx.current_query(), // unused
ctx.recording_store(), // unused
);
});

cursor_interact_with_selectable(ctx, response, item)
}

pub fn data_source_button_ui(
ctx: &ViewerContext<'_>,
ui: &mut egui::Ui,
Expand Down
1 change: 1 addition & 0 deletions crates/re_data_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use re_types::ComponentName;
use re_viewer_context::{UiVerbosity, ViewerContext};

mod annotation_context;
mod app_id;
mod blueprint_data;
mod component;
mod component_path;
Expand Down
14 changes: 2 additions & 12 deletions crates/re_entity_db/src/store_bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ impl StoreBundle {
}
}

pub fn remove(&mut self, id: &StoreId) {
self.entity_dbs.remove(id);
pub fn remove(&mut self, id: &StoreId) -> Option<EntityDb> {
self.entity_dbs.remove(id)
}

// --
Expand Down Expand Up @@ -134,16 +134,6 @@ impl StoreBundle {
.filter(|log| log.store_kind() == StoreKind::Blueprint)
}

/// All stores that came from the given source
pub fn entity_dbs_from_channel_source<'a>(
&'a self,
source: &'a re_smart_channel::SmartChannelSource,
) -> impl Iterator<Item = &EntityDb> + 'a {
self.entity_dbs
.values()
.filter(move |db| db.data_source.as_ref() == Some(source))
}

// --

pub fn retain(&mut self, mut f: impl FnMut(&EntityDb) -> bool) {
Expand Down
2 changes: 1 addition & 1 deletion crates/re_space_view_spatial/src/ui_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ pub fn view_3d(
// Track focused entity if any.
if let Some(focused_item) = ctx.focused_item {
let focused_entity = match focused_item {
Item::DataSource(_) | Item::StoreId(_) | Item::Container(_) => None,
Item::AppId(_) | Item::DataSource(_) | Item::StoreId(_) | Item::Container(_) => None,

Item::SpaceView(space_view_id) => {
if space_view_id == &query.space_view_id {
Expand Down
Binary file added crates/re_ui/data/icons/application.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions crates/re_ui/src/icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ pub const ENTITY_EMPTY: Icon = Icon::new(
pub const LINK: Icon = Icon::new("link", include_bytes!("../data/icons/link.png"));
pub const COMPONENT: Icon = Icon::new("component", include_bytes!("../data/icons/component.png"));

pub const APPLICATION: Icon = Icon::new(
"application",
include_bytes!("../data/icons/application.png"),
);
pub const DATA_SOURCE: Icon = Icon::new(
"data_source",
include_bytes!("../data/icons/data_source.png"),
Expand Down
2 changes: 2 additions & 0 deletions crates/re_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,8 @@ impl ReUi {
}

/// Workaround for putting a label into a grid at the top left of its row.
///
/// You only need to use this if you expect the right side to have multi-line entries.
#[allow(clippy::unused_self)]
pub fn grid_left_hand_label(&self, ui: &mut egui::Ui, label: &str) -> egui::Response {
ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
Expand Down
16 changes: 15 additions & 1 deletion crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,14 @@ impl App {
egui_ctx: &egui::Context,
) {
match cmd {
SystemCommand::ActivateApp(app_id) => {
store_hub.set_active_app(app_id);
}

SystemCommand::CloseApp(app_id) => {
store_hub.close_app(&app_id);
}

SystemCommand::ActivateRecording(store_id) => {
store_hub.set_activate_recording(store_id);
}
Expand Down Expand Up @@ -971,6 +979,11 @@ impl App {
StoreKind::Recording => {
re_log::debug!("Opening a new recording: {store_id}");
store_hub.set_active_recording_id(store_id.clone());

// Also select the new recording:
self.command_sender.send_system(SystemCommand::SetSelection(
re_viewer_context::Item::StoreId(store_id.clone()),
));
}
StoreKind::Blueprint => {
// We wait with activating blueprints until they are fully loaded,
Expand All @@ -983,7 +996,7 @@ impl App {
}

LogMsg::ArrowMsg(_, _) => {
// Andled by EntityDb::add
// Handled by `EntityDb::add`
}

LogMsg::BlueprintActivationCommand(cmd) => match store_id.kind {
Expand All @@ -1007,6 +1020,7 @@ impl App {
.unwrap_or_else(|err| {
re_log::warn!("Failed to make blueprint active: {err}");
});
store_hub.set_active_app(app_id); // Switch to this app, e.g. on drag-and-drop of a blueprint file
}
} else {
re_log::warn!(
Expand Down
8 changes: 5 additions & 3 deletions crates/re_viewer/src/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl AppState {
}
}

viewport.is_item_valid(item)
viewport.is_item_valid(store_context, item)
},
re_viewer_context::Item::StoreId(store_context.recording.store_id().clone()),
);
Expand Down Expand Up @@ -354,9 +354,11 @@ impl AppState {
// before drawing the blueprint panel.
ui.spacing_mut().item_spacing.y = 0.0;

let recording_shown = recordings_panel_ui(&ctx, rx, ui);
let pre_cursor = ui.cursor();
recordings_panel_ui(&ctx, rx, ui);
let any_recording_shows = pre_cursor == ui.cursor();

if recording_shown {
if any_recording_shows {
ui.add_space(4.0);
}

Expand Down
Loading
Loading