use std::vec::IntoIter;
use dioxus_native_core::prelude::ElementNode;
use dioxus_native_core::real_dom::NodeImmutable;
use dioxus_native_core::tree::TreeRef;
use dioxus_native_core::{node::NodeType, NodeId};
use freya_common::NodeReferenceLayout;
use freya_dom::dom::DioxusNode;
use freya_dom::prelude::{DioxusDOM, FreyaDOM};
use itertools::sorted;
use freya_engine::prelude::*;
use freya_node_state::{CursorMode, CursorSettings, LayoutState, References, Style};
use rustc_hash::FxHashMap;
use torin::torin::Torin;
use uuid::Uuid;
use crate::layout::*;
fn traverse_dom(rdom: &DioxusDOM, mut f: impl FnMut(DioxusNode) -> bool) {
let mut stack = vec![rdom.root_id()];
let tree = rdom.tree_ref();
while let Some(id) = stack.pop() {
if let Some(node) = rdom.get(id) {
let traverse_children = f(node);
if traverse_children {
let children = tree.children_ids_advanced(id, true);
stack.extend(children.iter().copied().rev());
}
}
}
}
#[derive(Default, Clone)]
pub struct Layers {
pub layers: FxHashMap<i16, Vec<NodeId>>,
pub paragraph_elements: FxHashMap<Uuid, Vec<NodeId>>,
}
impl Layers {
pub fn new(
rdom: &DioxusDOM,
layout: &Torin<NodeId>,
font_collection: &FontCollection,
scale_factor: f32,
) -> Self {
let mut layers = Layers::default();
let mut inherit_layers = FxHashMap::default();
traverse_dom(rdom, |node| {
let areas = layout.get(node.id());
if let Some(areas) = areas {
let node_style = node.get::<Style>().unwrap();
let inherited_relative_layer = node
.parent_id()
.map(|p| *inherit_layers.get(&p).unwrap())
.unwrap_or(0);
let (node_layer, node_relative_layer) = Layers::calculate_layer(
node_style.relative_layer,
node.height() as i16,
inherited_relative_layer,
);
inherit_layers.insert(node.id(), node_relative_layer);
layers.add_element(node.id(), node_layer);
let traverse_inner_children =
if let NodeType::Element(ElementNode { tag, .. }) = &*node.node_type() {
let is_paragraph = tag == "paragraph";
if is_paragraph {
let cursor_settings = node.get::<CursorSettings>().unwrap();
let is_editable = CursorMode::Editable == cursor_settings.mode;
let references = node.get::<References>().unwrap();
if is_editable {
if let Some(cursor_ref) = &references.cursor_ref {
let text_group = layers
.paragraph_elements
.entry(cursor_ref.text_id)
.or_default();
text_group.push(node.id());
}
}
}
!is_paragraph
} else {
false
};
let size_state = &*node.get::<LayoutState>().unwrap();
if let Some(reference) = &size_state.node_ref {
let mut node_layout = NodeReferenceLayout {
area: areas.area,
inner: areas.inner_sizes,
};
node_layout.div(scale_factor);
reference.0.send(node_layout).ok();
}
traverse_inner_children
} else {
false
}
});
layers.measure_all_paragraph_elements(rdom, layout, font_collection, scale_factor);
layers
}
pub fn layers(&self) -> IntoIter<(&i16, &Vec<NodeId>)> {
sorted(self.layers.iter())
}
pub fn len_paragraph_elements(&self) -> usize {
self.paragraph_elements.len()
}
pub fn len_layers(&self) -> usize {
self.layers.len()
}
pub fn measure_all_paragraph_elements(
&self,
rdom: &DioxusDOM,
layout: &Torin<NodeId>,
font_collection: &FontCollection,
scale_factor: f32,
) {
for group in self.paragraph_elements.values() {
for node_id in group {
let node = rdom.get(*node_id);
let areas = layout.get(*node_id);
if let Some((node, areas)) = node.zip(areas) {
measure_paragraph(&node, &areas.area, font_collection, true, scale_factor);
}
}
}
}
pub fn measure_paragraph_elements(
&self,
text_id: &Uuid,
dom: &FreyaDOM,
font_collection: &FontCollection,
scale_factor: f32,
) {
let group = self.paragraph_elements.get(text_id);
let layout = dom.layout();
if let Some(group) = group {
for node_id in group {
let node = dom.rdom().get(*node_id);
let areas = layout.get(*node_id);
if let Some((node, areas)) = node.zip(areas) {
measure_paragraph(&node, &areas.area, font_collection, true, scale_factor);
}
}
}
}
pub fn calculate_layer(
relative_layer: i16,
height: i16,
inherited_relative_layer: i16,
) -> (i16, i16) {
let element_layer = -relative_layer + height - inherited_relative_layer;
(element_layer, relative_layer + inherited_relative_layer)
}
pub fn add_element(&mut self, node_id: NodeId, node_layer: i16) {
let layer = self.layers.entry(node_layer).or_default();
layer.push(node_id);
}
}