use cranpose_core::{MemoryApplier, NodeId, collections::map::HashMap};
use cranpose_ui::{Point, Rect};
use cranpose_ui_graphics::GraphicsLayer;
use super::{
AbsOrigin, LowerContext, TranslateAncestorContext, inline_leaf::retext_kept_inline,
placed_transform, publish_retained_window_geometry, text_node, translate_layer::PlacedChild,
};
use crate::{
NodeUpdate,
graph::{LayerNode, ProjectiveTransform, RenderNode},
layer_transform::layer_transform_to_window,
};
#[derive(Clone, Copy)]
pub(super) struct TranslateGeometry {
pub(super) content_offset: Point,
pub(super) window_transform: ProjectiveTransform,
pub(super) top_left: Point,
child_origin: Point,
}
impl TranslateGeometry {
pub(super) fn new(
layout_state: &cranpose_ui::widgets::LayoutState,
graphics_layer: &GraphicsLayer,
local_bounds: Rect,
parent_abs: AbsOrigin,
) -> Self {
let content_offset = layout_state.content_offset();
let top_left = Point {
x: parent_abs.content_origin.x + layout_state.position().x,
y: parent_abs.content_origin.y + layout_state.position().y,
};
let window_transform = layer_transform_to_window(
parent_abs.window_transform,
top_left,
local_bounds,
graphics_layer,
);
Self {
content_offset,
window_transform,
top_left,
child_origin: Point {
x: top_left.x + content_offset.x,
y: top_left.y + content_offset.y,
},
}
}
pub(super) fn children_context(
self,
container: &LayerNode,
ancestors: TranslateAncestorContext,
) -> TranslateAncestorContext {
TranslateAncestorContext {
inherited_motion_context_animated: container.motion_context_animated,
update: ancestors.update,
inherited_translated_content_context: ancestors.inherited_translated_content_context
|| container.translated_content_context,
parent_content_offset: self.content_offset,
parent_abs: self.child_abs(),
}
}
pub(super) fn child_abs(self) -> AbsOrigin {
AbsOrigin {
content_origin: self.child_origin,
window_transform: self.window_transform,
}
}
}
pub(super) fn translate_retained_child(
layer: &mut LayerNode,
position: Point,
content_offset: Point,
) {
layer.transform_to_parent = placed_transform(
layer.local_bounds,
position,
layer.graphics_layer.get(),
content_offset,
);
layer.origin_in_parent = position;
}
#[derive(Clone, Copy)]
pub(super) enum KeptChild {
Left,
Moved,
Retexted,
}
#[inline]
pub(super) fn move_kept_child(
applier: &MemoryApplier,
node: &mut RenderNode,
placed: &PlacedChild,
children: TranslateAncestorContext,
dirty_nodes: &mut HashMap<NodeId, NodeUpdate>,
) {
let position = placed.geometry.position;
match (placed.kept, node) {
(KeptChild::Left, _) | (_, RenderNode::Primitive(_) | RenderNode::DrawRun(_)) => {}
(KeptChild::Moved, RenderNode::Layer(layer)) => {
translate_retained_child(layer, position, children.parent_content_offset);
if layer.has_origin_sinks {
publish_retained_window_geometry(applier, layer, children.parent_abs);
}
}
(KeptChild::Moved, RenderNode::Inline(inline)) => {
let offset = children.parent_content_offset;
inline.origin = Point::new(position.x + offset.x, position.y + offset.y);
}
(KeptChild::Retexted, node) => {
write_kept_label(applier, node, placed, children, dirty_nodes);
}
}
}
#[inline(never)]
fn write_kept_label(
applier: &MemoryApplier,
node: &mut RenderNode,
placed: &PlacedChild,
children: TranslateAncestorContext,
dirty_nodes: &mut HashMap<NodeId, NodeUpdate>,
) {
let written = match node {
RenderNode::Layer(layer) => {
text_node::retext_kept_leaf(applier, layer, children) == Some(true)
}
RenderNode::Inline(inline) => {
retext_kept_inline(applier, inline, LowerContext::beneath(children))
}
RenderNode::Primitive(_) | RenderNode::DrawRun(_) => false,
};
if written {
dirty_nodes.remove(&placed.id);
}
}