use re_data_ui::item_ui::table_id_button_ui;
use re_log_types::LogMsg;
use re_redap_browser::{
dataset_and_its_recordings_ui, EntryKind, RedapServers, EXAMPLES_ORIGIN, LOCAL_ORIGIN,
};
use re_smart_channel::{ReceiveSet, SmartChannelSource};
use re_ui::list_item::ItemMenuButton;
use re_ui::{list_item, UiExt as _, UiLayout};
use re_viewer_context::{
DisplayMode, Item, SystemCommand, SystemCommandSender as _, ViewerContext,
};
use crate::app_state::WelcomeScreenState;
pub fn recordings_panel_ui(
ctx: &ViewerContext<'_>,
rx: &ReceiveSet<LogMsg>,
ui: &mut egui::Ui,
welcome_screen_state: &WelcomeScreenState,
servers: &RedapServers,
) {
ui.panel_content(|ui| {
ui.panel_title_bar_with_buttons(
"Recordings",
Some(
"These are the Recordings currently loaded in the Viewer, organized by application",
),
|ui| {
add_button_ui(ctx, ui);
},
);
});
egui::ScrollArea::both()
.id_salt("recordings_scroll_area")
.auto_shrink([false, true])
.show(ui, |ui| {
ui.panel_content(|ui| {
re_ui::list_item::list_item_scope(ui, "recording panel", |ui| {
recording_list_ui(ctx, ui, welcome_screen_state, servers);
loading_receivers_ui(ctx, rx, ui);
});
});
});
}
fn loading_receivers_ui(ctx: &ViewerContext<'_>, rx: &ReceiveSet<LogMsg>, ui: &mut egui::Ui) {
let sources_with_stores: ahash::HashSet<SmartChannelSource> = ctx
.storage_context
.bundle
.recordings()
.filter_map(|store| store.data_source.clone())
.collect();
for source in rx.sources() {
let string = match source.as_ref() {
SmartChannelSource::File(path) => format!("Loading {}…", path.display()),
SmartChannelSource::RrdHttpStream { url, .. } => format!("Loading {url}…"),
SmartChannelSource::RedapGrpcStream(uri) => format!("Loading {uri}…"),
SmartChannelSource::RrdWebEventListener
| SmartChannelSource::JsChannel { .. }
| SmartChannelSource::MessageProxy { .. }
| SmartChannelSource::Sdk
| SmartChannelSource::Stdin => {
continue;
}
};
if !sources_with_stores.contains(&source) {
let response = ui.list_item().show_flat(
ui,
re_ui::list_item::LabelContent::new(string).with_buttons(|ui| {
let resp = ui
.small_icon_button(&re_ui::icons::REMOVE)
.on_hover_text("Disconnect from this source");
if resp.clicked() {
rx.remove(&source);
}
resp
}),
);
if let SmartChannelSource::MessageProxy { .. } = source.as_ref() {
response.on_hover_text("You can connect to this viewer from a Rerun SDK");
}
}
}
}
fn recording_list_ui(
ctx: &ViewerContext<'_>,
ui: &mut egui::Ui,
welcome_screen_state: &WelcomeScreenState,
servers: &RedapServers,
) {
let re_redap_browser::SortDatasetsResults {
remote_recordings,
example_recordings,
local_recordings,
} = re_redap_browser::sort_datasets(ctx);
servers.server_list_ui(ctx, ui, remote_recordings);
if ctx.storage_context.tables.is_empty()
&& servers.is_empty()
&& local_recordings.is_empty()
&& welcome_screen_state.hide
{
ui.list_item().interactive(false).show_flat(
ui,
re_ui::list_item::LabelContent::new("No recordings loaded")
.weak(true)
.italics(true),
);
}
if (!local_recordings.is_empty() || !ctx.storage_context.tables.is_empty())
&& ui
.list_item()
.header()
.show_hierarchical_with_children(
ui,
egui::Id::new("local items"),
true,
list_item::LabelContent::header("Local"),
|ui| {
for (app_id, entity_dbs) in local_recordings {
dataset_and_its_recordings_ui(
ui,
ctx,
&EntryKind::Local(app_id.clone()),
entity_dbs,
);
}
for table_id in ctx.storage_context.tables.keys() {
table_id_button_ui(ctx, ui, table_id, UiLayout::SelectionPanel);
}
},
)
.item_response
.clicked()
{
ctx.command_sender()
.send_system(SystemCommand::ChangeDisplayMode(DisplayMode::RedapServer(
LOCAL_ORIGIN.clone(),
)));
}
if (ctx
.app_options()
.include_welcome_screen_button_in_recordings_panel
&& !welcome_screen_state.hide)
|| !example_recordings.is_empty()
{
let item = Item::RedapServer(EXAMPLES_ORIGIN.clone());
let selected = ctx.selection().contains_item(&item);
let list_item = ui.list_item().header().selected(selected);
let title = list_item::LabelContent::header("Rerun examples");
let response = if example_recordings.is_empty() {
list_item.show_flat(ui, title)
} else {
list_item
.show_hierarchical_with_children(
ui,
egui::Id::new("example items"),
true,
title,
|ui| {
for (app_id, entity_dbs) in example_recordings {
dataset_and_its_recordings_ui(
ui,
ctx,
&EntryKind::Local(app_id.clone()),
entity_dbs,
);
}
},
)
.item_response
};
if response.clicked() {
ctx.command_sender()
.send_system(SystemCommand::ChangeDisplayMode(DisplayMode::RedapServer(
EXAMPLES_ORIGIN.clone(),
)));
ctx.command_sender()
.send_system(SystemCommand::SetSelection(Item::RedapServer(
EXAMPLES_ORIGIN.clone(),
)));
}
}
}
fn add_button_ui(ctx: &ViewerContext<'_>, ui: &mut egui::Ui) {
use re_ui::list_item::ItemButton as _;
Box::new(ItemMenuButton::new(&re_ui::icons::ADD, |ui| {
if re_ui::UICommand::Open
.menu_button_ui(ui, ctx.command_sender())
.clicked()
{
ui.close_menu();
};
if re_ui::UICommand::AddRedapServer
.menu_button_ui(ui, ctx.command_sender())
.clicked()
{
ui.close_menu();
};
}))
.ui(ui)
.on_hover_text("Open a file or connect to a server");
}