use std::collections::HashMap;
use super::registry::{AnnotationRegistry, RegionInfo, SerializableRect};
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct AnnotatedOutput {
pub visual: String,
pub annotations: Vec<WidgetAnnotation>,
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct WidgetAnnotation {
pub widget_type: String,
pub id: Option<String>,
pub label: Option<String>,
pub area: AnnotationArea,
pub focused: bool,
pub disabled: bool,
pub selected: bool,
pub expanded: Option<bool>,
pub value: Option<String>,
pub parent_index: Option<usize>,
pub depth: usize,
#[cfg_attr(
feature = "serialization",
serde(default, skip_serializing_if = "HashMap::is_empty")
)]
pub metadata: HashMap<String, String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct AnnotationArea {
pub x: u16,
pub y: u16,
pub width: u16,
pub height: u16,
}
impl From<SerializableRect> for AnnotationArea {
fn from(rect: SerializableRect) -> Self {
Self {
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
}
}
}
impl WidgetAnnotation {
fn from_region(region: &RegionInfo) -> Self {
Self {
widget_type: format!("{}", region.annotation.widget_type),
id: region.annotation.id.clone(),
label: region.annotation.label.clone(),
area: region.area.into(),
focused: region.annotation.focused,
disabled: region.annotation.disabled,
selected: region.annotation.selected,
expanded: region.annotation.expanded,
value: region.annotation.value.clone(),
parent_index: region.parent,
depth: region.depth,
metadata: region.annotation.metadata.clone(),
}
}
}
impl AnnotatedOutput {
pub fn from_backend_and_registry(
backend: &crate::backend::CaptureBackend,
registry: &AnnotationRegistry,
) -> Self {
let visual = backend.to_string();
let annotations = registry
.regions()
.iter()
.map(WidgetAnnotation::from_region)
.collect();
Self {
visual,
annotations,
}
}
pub fn from_visual_and_registry(visual: String, registry: &AnnotationRegistry) -> Self {
let annotations = registry
.regions()
.iter()
.map(WidgetAnnotation::from_region)
.collect();
Self {
visual,
annotations,
}
}
pub fn annotation_count(&self) -> usize {
self.annotations.len()
}
pub fn is_empty(&self) -> bool {
self.annotations.is_empty()
}
pub fn find_by_type(&self, widget_type: &str) -> Vec<&WidgetAnnotation> {
self.annotations
.iter()
.filter(|a| a.widget_type == widget_type)
.collect()
}
pub fn find_by_id(&self, id: &str) -> Option<&WidgetAnnotation> {
self.annotations
.iter()
.find(|a| a.id.as_deref() == Some(id))
}
pub fn focused_annotations(&self) -> Vec<&WidgetAnnotation> {
self.annotations.iter().filter(|a| a.focused).collect()
}
#[cfg(feature = "serialization")]
pub fn to_json(&self) -> Option<String> {
serde_json::to_string(self).ok()
}
#[cfg(feature = "serialization")]
pub fn to_json_pretty(&self) -> Option<String> {
serde_json::to_string_pretty(self).ok()
}
}
#[cfg(test)]
mod tests;