perspective_viewer/components/containers/
scroll_panel_item.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

// Forked from https://github.com/AircastDev/yew-virtual-scroller (Apache 2.0)
// Adds support for Yew 0.19, auto-width and a simplified message structure.

#[cfg(debug_assertions)]
use std::cell::Cell;
#[cfg(debug_assertions)]
use std::rc::Rc;

use yew::prelude::*;

#[derive(PartialEq, Properties)]
pub struct ScrollPanelItemProps {
    /// The expected size of this component in pixels. Calculating this value
    /// ahead of time makes it easier to implement a high-performance virtual
    /// renderer without resorting to weird tricks, _but_ checking that this
    /// hint is correct is nearly as expensive. So, we only generate the
    /// validation code in debug builds.
    pub size_hint: f64,
    pub children: Children,

    #[cfg(debug_assertions)]
    #[prop_or_default]
    measured_size: Rc<Cell<Option<f64>>>,
}

impl ScrollPanelItemProps {
    #[cfg(debug_assertions)]
    pub fn get_size(&self) -> f64 {
        self.measured_size.get().unwrap_or(self.size_hint)
    }

    #[cfg(not(debug_assertions))]
    pub fn get_size(&self) -> f64 {
        self.size_hint
    }
}

#[cfg(debug_assertions)]
pub struct ScrollPanelItem {
    node: NodeRef,
}

#[cfg(not(debug_assertions))]
pub struct ScrollPanelItem {}

impl Component for ScrollPanelItem {
    type Message = ();
    type Properties = ScrollPanelItemProps;

    #[cfg(debug_assertions)]
    fn create(ctx: &Context<Self>) -> Self {
        ctx.props().measured_size.set(Some(ctx.props().size_hint));
        Self {
            node: NodeRef::default(),
        }
    }

    #[cfg(not(debug_assertions))]
    fn create(_ctx: &Context<Self>) -> Self {
        Self {}
    }

    #[cfg(debug_assertions)]
    fn view(&self, ctx: &Context<Self>) -> Html {
        html! {
            <div class="debug-size-wrapper" style="display:flow-root" ref={self.node.clone()}>
                { for ctx.props().children.iter() }
            </div>
        }
    }

    #[cfg(not(debug_assertions))]
    fn view(&self, ctx: &Context<Self>) -> Html {
        html! { { for ctx.props().children.iter() } }
    }

    #[cfg(debug_assertions)]
    fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
        ctx.props().measured_size.set(Some(ctx.props().size_hint));
        true
    }

    #[cfg(debug_assertions)]
    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
        if first_render {
            let elem = self.node.cast::<web_sys::HtmlElement>().unwrap();
            let new_height = elem.get_bounding_client_rect().height();
            if ctx.props().measured_size.get() != Some(new_height) {
                tracing::warn!(
                    "ScrollPanel size_hint does not match element size: {} != {}",
                    ctx.props().size_hint,
                    new_height
                );
                web_sys::console::warn_1(&elem);
                ctx.props().measured_size.set(Some(new_height));
            }
        }
    }
}