use itertools::izip;
use re_chunk_store::AbsoluteTimeRange;
use re_entity_db::EntityPath;
use re_log_types::{TimeInt, TimePoint};
use re_query::{clamped_zip_1x2, range_zip_1x2};
use re_sdk_types::Archetype as _;
use re_sdk_types::archetypes::TextLog;
use re_sdk_types::components::{Color, Text, TextLogLevel};
use re_view::range_with_blueprint_resolved_data;
use re_viewer_context::{
IdentifiedViewSystem, ViewContext, ViewContextCollection, ViewQuery, ViewSystemExecutionError,
VisualizerExecutionOutput, VisualizerQueryInfo, VisualizerSystem,
};
#[derive(Debug, Clone)]
pub struct Entry {
pub entity_path: EntityPath,
pub time: TimeInt,
pub timepoint: TimePoint,
pub color: Option<Color>,
pub body: Text,
pub level: Option<TextLogLevel>,
}
#[derive(Default)]
pub struct TextLogSystem {
pub entries: Vec<Entry>,
}
impl IdentifiedViewSystem for TextLogSystem {
fn identifier() -> re_viewer_context::ViewSystemIdentifier {
"TextLog".into()
}
}
impl VisualizerSystem for TextLogSystem {
fn visualizer_query_info(
&self,
_app_options: &re_viewer_context::AppOptions,
) -> VisualizerQueryInfo {
VisualizerQueryInfo::single_required_component::<Text>(
&TextLog::descriptor_text(),
&TextLog::all_components(),
)
}
fn execute(
&mut self,
ctx: &ViewContext<'_>,
view_query: &ViewQuery<'_>,
_context_systems: &ViewContextCollection,
) -> Result<VisualizerExecutionOutput, ViewSystemExecutionError> {
re_tracing::profile_function!();
let output = VisualizerExecutionOutput::default();
let query =
re_chunk_store::RangeQuery::new(view_query.timeline, AbsoluteTimeRange::EVERYTHING)
.keep_extra_timelines(true);
for (data_result, instruction) in
view_query.iter_visualizer_instruction_for(Self::identifier())
{
self.process_visualizer_instruction(ctx, &query, data_result, instruction, &output);
}
{
re_tracing::profile_scope!("sort");
self.entries.sort_by_key(|e| e.time);
}
Ok(output)
}
}
impl TextLogSystem {
fn process_visualizer_instruction(
&mut self,
ctx: &ViewContext<'_>,
query: &re_chunk_store::RangeQuery,
data_result: &re_viewer_context::DataResult,
instruction: &re_viewer_context::VisualizerInstruction,
output: &VisualizerExecutionOutput,
) {
re_tracing::profile_function!();
let range_results = range_with_blueprint_resolved_data(
ctx,
None,
query,
data_result,
TextLog::all_component_identifiers(),
instruction,
);
let results = re_view::BlueprintResolvedResults::from((query.clone(), range_results));
let results =
re_view::VisualizerInstructionQueryResults::new(instruction, &results, output);
let all_texts = results.iter_required(TextLog::descriptor_text().component);
if all_texts.is_empty() {
return;
}
let all_timepoints = all_texts
.chunks()
.iter()
.flat_map(|chunk| chunk.iter_component_timepoints());
let all_levels = results.iter_optional(TextLog::descriptor_level().component);
let all_colors = results.iter_optional(TextLog::descriptor_color().component);
let all_frames = range_zip_1x2(
all_texts.slice::<String>(),
all_levels.slice::<String>(),
all_colors.slice::<u32>(),
);
let all_frames = izip!(all_timepoints, all_frames);
for (timepoint, ((data_time, _row_id), bodies, levels, colors)) in all_frames {
let levels = levels.as_deref().unwrap_or(&[]).iter().cloned().map(Some);
let colors = colors
.unwrap_or(&[])
.iter()
.copied()
.map(Into::into)
.map(Some);
let level_default_fn = || None;
let color_default_fn = || None;
let results =
clamped_zip_1x2(bodies, levels, level_default_fn, colors, color_default_fn);
for (text, level, color) in results {
self.entries.push(Entry {
entity_path: data_result.entity_path.clone(),
time: data_time,
timepoint: timepoint.clone(),
color,
body: text.clone().into(),
level: level.clone().map(Into::into),
});
}
}
}
}