rosace_widgets/tree/
transform_layer.rs1use rosace_core::types::{Point, Rect, Size};
2use rosace_layout::Constraints;
3use rosace_render::PictureRecorder;
4use rosace_state::Atom;
5use super::{Widget, LayoutCtx, PaintCtx, TransformLayerEntry};
6
7pub struct TransformLayer<W: Widget + Send + Sync + 'static> {
15 pub child: W,
16 pub scroll_y: Atom<f32>,
18 pub scroll_x: Atom<f32>,
20 pub viewport_h: f32,
22}
23
24pub const MAX_TRANSFORM_DIM: u32 = 4096;
26
27impl<W: Widget + Send + Sync + 'static> TransformLayer<W> {
28 pub fn new(child: W, viewport_h: f32, scroll_y: Atom<f32>) -> Self {
29 Self {
30 child,
31 scroll_y,
32 scroll_x: rosace_state::use_atom(0.0_f32),
33 viewport_h,
34 }
35 }
36}
37
38impl<W: Widget + Send + Sync + 'static> Widget for TransformLayer<W> {
39 fn layout(&self, ctx: &LayoutCtx) -> Size {
40 let unconstrained = Constraints::loose(ctx.constraints.max_width_f32(), f32::INFINITY);
42 let child_lctx = LayoutCtx::new(unconstrained, ctx.font, ctx.theme);
43 let child_size = self.child.layout(&child_lctx);
44 Size {
45 width: child_size.width,
46 height: self.viewport_h.min(child_size.height),
47 }
48 }
49
50 fn paint(&self, ctx: &mut PaintCtx) {
51 let scroll_y = self.scroll_y.get();
52 let scroll_x = self.scroll_x.get();
53 let vp_rect = ctx.rect;
54
55 let child_lctx = ctx.layout_ctx(Constraints::loose(vp_rect.size.width, f32::INFINITY));
57 let child_size = self.child.layout(&child_lctx);
58
59 let mut sub_rec = PictureRecorder::new();
62 let child_origin = Point { x: 0.0, y: 0.0 };
63 let child_rect = Rect { origin: child_origin, size: child_size };
64
65 let sub_node = ctx.tree.borrow_mut().slot(ctx.node, true);
66 let mut sub_ctx = PaintCtx {
67 recorder: &mut sub_rec,
68 rect: child_rect,
69 font: ctx.font,
70 theme: ctx.theme.clone(),
71 tree: ctx.tree.clone(),
72 node: sub_node,
73 owner: ctx.owner,
74 clip_rect: None,
75 };
76 self.child.paint(&mut sub_ctx);
77 let picture = sub_rec.finish();
78
79 ctx.attach_transform(TransformLayerEntry {
82 picture,
83 child_size,
84 viewport_rect: vp_rect,
85 zoom: 1.0,
86 scroll_x,
87 scroll_y,
88 });
89
90 let node_id = ctx.node as u64;
96 let max_x = (child_size.width - vp_rect.size.width).max(0.0);
97 let max_y = (child_size.height - self.viewport_h).max(0.0);
98 ctx.register_scroll_target(
99 vp_rect,
100 super::render_tree::ScrollAxes::BOTH,
101 std::sync::Arc::new(move |dx, dy| {
102 rosace_state::scroll_offset_by(node_id, -dx, -dy, max_x, max_y);
103 }),
104 );
105
106 ctx.rect = Rect {
108 origin: vp_rect.origin,
109 size: Size {
110 width: vp_rect.size.width,
111 height: self.viewport_h.min(vp_rect.size.height),
112 },
113 };
114 }
115}