zng_wgt_scroll/
zoom_size.rs

1use zng_wgt::prelude::*;
2
3use crate::SCROLL_SCALE_VAR;
4
5/// Set on an descendant of `Scroll!` to resize the widget instead of scaling it with the scroll zoom.
6///
7/// This property disables inline layout for the widget.
8#[property(SIZE+1, default(false))]
9pub fn zoom_size_only(child: impl UiNode, enabled: impl IntoVar<bool>) -> impl UiNode {
10    let enabled = enabled.into_var();
11    let mut scale = 1.fct();
12    let mut _zoom_sub = VarHandle::dummy();
13    match_node(child, move |c, op| match op {
14        UiNodeOp::Init => {
15            WIDGET.sub_var(&enabled);
16            if enabled.get() {
17                _zoom_sub = SCROLL_SCALE_VAR.subscribe(UpdateOp::Layout, WIDGET.id());
18            }
19        }
20        UiNodeOp::Deinit => {
21            _zoom_sub = VarHandle::dummy();
22        }
23        UiNodeOp::Measure { wm, .. } => {
24            wm.disable_inline();
25        }
26        UiNodeOp::Update { .. } => {
27            if let Some(e) = enabled.get_new() {
28                if e {
29                    _zoom_sub = SCROLL_SCALE_VAR.subscribe(UpdateOp::Layout, WIDGET.id());
30                } else {
31                    _zoom_sub = VarHandle::dummy();
32                    scale = 1.fct();
33                }
34                WIDGET.layout();
35            }
36        }
37        UiNodeOp::Layout { wl, final_size } => {
38            if enabled.get() {
39                let s = SCROLL_SCALE_VAR.get();
40                if s != 1.fct() {
41                    // return the unscaled size to not affect the parent layout,
42                    // ideally the scaled parent will fit around the resized child.
43                    *final_size = c.measure(&mut wl.to_measure(None));
44                    let scaled_size = *final_size * s;
45                    LAYOUT.with_constraints(PxConstraints2d::new_exact_size(scaled_size), || c.layout(wl));
46                    if scale != s {
47                        scale = s;
48                        WIDGET.render_update();
49                    }
50                }
51            }
52        }
53        UiNodeOp::Render { frame } => {
54            if frame.is_outer() {
55                if scale != 1.fct() {
56                    if let Some(t) = PxTransform::scale(scale.0, scale.0).inverse() {
57                        frame.push_inner_transform(&t, |frame| c.render(frame));
58                    }
59                }
60            } else {
61                tracing::error!("zoom_size_only must render outside NestGroup::WIDGET_INNER")
62            }
63        }
64        UiNodeOp::RenderUpdate { update } => {
65            if update.is_outer() {
66                if scale != 1.fct() {
67                    if let Some(t) = PxTransform::scale(scale.0, scale.0).inverse() {
68                        update.with_inner_transform(&t, |update| c.render_update(update));
69                    }
70                }
71            } else {
72                tracing::error!("zoom_size_only must render outside NestGroup::WIDGET_INNER")
73            }
74        }
75        _ => {}
76    })
77}