Skip to main content

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 IntoUiNode, enabled: impl IntoVar<bool>) -> 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 } if enabled.get() => {
38            let s = SCROLL_SCALE_VAR.get();
39            if s != 1.fct() {
40                // return the unscaled size to not affect the parent layout,
41                // ideally the scaled parent will fit around the resized child.
42                *final_size = c.measure(&mut wl.to_measure(None));
43                let scaled_size = *final_size * s;
44                LAYOUT.with_constraints(PxConstraints2d::new_exact_size(scaled_size), || c.layout(wl));
45                if scale != s {
46                    scale = s;
47                    WIDGET.render_update();
48                }
49            }
50        }
51        UiNodeOp::Render { frame } => {
52            if frame.is_outer() {
53                if scale != 1.fct()
54                    && let Some(t) = PxTransform::scale(scale.0, scale.0).inverse()
55                {
56                    frame.push_inner_transform(&t, |frame| c.render(frame));
57                }
58            } else {
59                tracing::error!("zoom_size_only must render outside NestGroup::WIDGET_INNER")
60            }
61        }
62        UiNodeOp::RenderUpdate { update } => {
63            if update.is_outer() {
64                if scale != 1.fct()
65                    && let Some(t) = PxTransform::scale(scale.0, scale.0).inverse()
66                {
67                    update.with_inner_transform(&t, |update| c.render_update(update));
68                }
69            } else {
70                tracing::error!("zoom_size_only must render outside NestGroup::WIDGET_INNER")
71            }
72        }
73        _ => {}
74    })
75}