use crate::dynamic_item_tree::{DynamicComponentVRc, ItemTreeBox};
use i_slint_compiler::object_tree::{Component, Element, ElementRc};
use i_slint_core::items::ItemRc;
use i_slint_core::lengths::LogicalRect;
use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::Rc;
use vtable::VRc;
pub enum ComponentKind {
Layout,
Element,
}
#[derive(Default)]
pub struct ComponentPositions {
pub kind: Option<ComponentKind>,
pub geometries: Vec<i_slint_core::lengths::LogicalRect>,
}
fn collect_highlight_data(
component: &DynamicComponentVRc,
elements: &[std::rc::Weak<RefCell<Element>>],
) -> ComponentPositions {
let component_instance = VRc::downgrade(component);
let component_instance = component_instance.upgrade().unwrap();
generativity::make_guard!(guard);
let c = component_instance.unerase(guard);
let mut values = ComponentPositions::default();
for element in elements.iter().filter_map(|e| e.upgrade()) {
if let Some(repeater_path) = repeater_path(&element) {
fill_highlight_data(&repeater_path, &element, &c, &c, &mut values);
}
}
values
}
pub(crate) fn component_positions(
component_instance: &DynamicComponentVRc,
path: PathBuf,
offset: u32,
) -> ComponentPositions {
generativity::make_guard!(guard);
let c = component_instance.unerase(guard);
let elements = find_element_at_offset(&c.description().original, path, offset.into());
collect_highlight_data(
component_instance,
&elements.into_iter().map(|e| Rc::downgrade(&e)).collect::<Vec<_>>(),
)
}
pub(crate) fn element_position(
component_instance: &DynamicComponentVRc,
element: &ElementRc,
) -> Vec<LogicalRect> {
generativity::make_guard!(guard);
let c = component_instance.unerase(guard);
let mut values = ComponentPositions::default();
if let Some(repeater_path) = repeater_path(element) {
fill_highlight_data(&repeater_path, &element, &c, &c, &mut values);
}
values.geometries
}
fn fill_highlight_data(
repeater_path: &[String],
element: &ElementRc,
component_instance: &ItemTreeBox,
root_component_instance: &ItemTreeBox,
values: &mut ComponentPositions,
) {
if let [first, rest @ ..] = repeater_path {
generativity::make_guard!(guard);
let rep = crate::dynamic_item_tree::get_repeater_by_name(
component_instance.borrow_instance(),
first.as_str(),
guard,
);
for idx in rep.0.range() {
if let Some(c) = rep.0.instance_at(idx) {
generativity::make_guard!(guard);
fill_highlight_data(
rest,
element,
&c.unerase(guard),
root_component_instance,
values,
);
}
}
} else {
let vrc = VRc::into_dyn(
component_instance.borrow_instance().self_weak().get().unwrap().upgrade().unwrap(),
);
let root_vrc = VRc::into_dyn(
root_component_instance.borrow_instance().self_weak().get().unwrap().upgrade().unwrap(),
);
let index = element.borrow().item_index.get().copied().unwrap();
let item_rc = ItemRc::new(vrc.clone(), index);
let geometry = item_rc.geometry();
let origin = item_rc.map_to_item_tree(geometry.origin, &root_vrc);
let size = geometry.size;
if values.kind.is_none() {
values.kind = if element.borrow().layout.is_some() {
Some(ComponentKind::Layout)
} else {
Some(ComponentKind::Element)
};
}
values.geometries.push(LogicalRect { origin, size });
}
}
fn find_element_at_offset(component: &Rc<Component>, path: PathBuf, offset: u32) -> Vec<ElementRc> {
let mut result = Vec::<ElementRc>::new();
i_slint_compiler::object_tree::recurse_elem_including_sub_components(
component,
&(),
&mut |elem, &()| {
if elem.borrow().repeated.is_some() {
return;
}
for node in elem.borrow().node.iter().filter_map(|n| n.QualifiedName()) {
if node.source_file.path() == path && node.text_range().contains(offset.into()) {
result.push(elem.clone());
}
}
},
);
result
}
fn repeater_path(elem: &ElementRc) -> Option<Vec<String>> {
let enclosing = elem.borrow().enclosing_component.upgrade().unwrap();
if let Some(parent) = enclosing.parent_element.upgrade() {
parent.borrow().repeated.as_ref()?;
let mut r = repeater_path(&parent)?;
r.push(parent.borrow().id.clone());
Some(r)
} else {
Some(vec![])
}
}