Skip to main content

perspective_viewer/components/
main_panel.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use wasm_bindgen::prelude::*;
14use yew::prelude::*;
15
16use super::render_warning::RenderWarning;
17use super::status_bar::StatusBar;
18use crate::presentation::{Presentation, PresentationProps};
19use crate::renderer::*;
20use crate::session::{Session, SessionProps};
21use crate::tasks::dismiss_render_warning_callback;
22
23#[derive(Clone, Properties)]
24pub struct MainPanelProps {
25    pub on_settings: Callback<()>,
26
27    /// Reset callback forwarded from the root component.  Fired when the user
28    /// clicks the reset button; `bool` is `true` for a full reset (expressions
29    /// + column configs), `false` for config-only.
30    pub on_reset: Callback<bool>,
31
32    /// Snapshots threaded from root.  Read for `has_table`, `title` here in
33    /// the panel itself; threaded wholesale to `StatusBar`/`StatusIndicator`.
34    pub session_props: SessionProps,
35    pub renderer_props: RendererProps,
36    pub presentation_props: PresentationProps,
37
38    /// Derived from root: `settings_open && has_table_loaded`.
39    pub is_settings_open: bool,
40
41    /// Root-managed in-flight render counter (not engine state).
42    pub update_count: u32,
43
44    /// State
45    pub session: Session,
46    pub renderer: Renderer,
47    pub presentation: Presentation,
48}
49
50impl PartialEq for MainPanelProps {
51    fn eq(&self, rhs: &Self) -> bool {
52        self.session_props == rhs.session_props
53            && self.renderer_props == rhs.renderer_props
54            && self.presentation_props == rhs.presentation_props
55            && self.is_settings_open == rhs.is_settings_open
56            && self.update_count == rhs.update_count
57    }
58}
59
60impl MainPanelProps {
61    fn is_title(&self) -> bool {
62        self.session_props.title.is_some()
63    }
64}
65
66#[derive(Debug)]
67pub enum MainPanelMsg {
68    PointerEvent(web_sys::PointerEvent),
69}
70
71pub struct MainPanel {
72    main_panel_ref: NodeRef,
73}
74
75impl Component for MainPanel {
76    type Message = MainPanelMsg;
77    type Properties = MainPanelProps;
78
79    fn create(_ctx: &Context<Self>) -> Self {
80        Self {
81            main_panel_ref: NodeRef::default(),
82        }
83    }
84
85    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
86        match msg {
87            MainPanelMsg::PointerEvent(event) => {
88                if event.target().map(JsValue::from)
89                    == self
90                        .main_panel_ref
91                        .cast::<web_sys::HtmlElement>()
92                        .map(JsValue::from)
93                {
94                    ctx.props().presentation.statusbar_pointer_event.emit(event);
95                }
96
97                false
98            },
99        }
100    }
101
102    fn changed(&mut self, _ctx: &Context<Self>, _old: &Self::Properties) -> bool {
103        true
104    }
105
106    fn view(&self, ctx: &Context<Self>) -> Html {
107        let Self::Properties {
108            presentation,
109            renderer,
110            session,
111            ..
112        } = ctx.props();
113
114        let is_settings_open = ctx.props().is_settings_open;
115        let on_settings = (!is_settings_open).then(|| ctx.props().on_settings.clone());
116
117        let mut class = classes!();
118        if !is_settings_open {
119            class.push("settings-closed");
120        }
121
122        if ctx.props().is_title() {
123            class.push("titled");
124        }
125
126        let pointerdown = ctx.link().callback(MainPanelMsg::PointerEvent);
127        let on_dismiss_warning = dismiss_render_warning_callback(session, renderer);
128
129        html! {
130            <div id="main_column">
131                <StatusBar
132                    id="status_bar"
133                    {on_settings}
134                    on_reset={ctx.props().on_reset.clone()}
135                    session_props={ctx.props().session_props.clone()}
136                    presentation_props={ctx.props().presentation_props.clone()}
137                    is_settings_open={ctx.props().is_settings_open}
138                    update_count={ctx.props().update_count}
139                    {presentation}
140                    {renderer}
141                    {session}
142                />
143                <div
144                    id="main_panel_container"
145                    ref={self.main_panel_ref.clone()}
146                    {class}
147                    onpointerdown={pointerdown}
148                >
149                    <RenderWarning
150                        on_dismiss={on_dismiss_warning}
151                        dimensions={ctx.props().renderer_props.render_limits}
152                    />
153                    <slot />
154                </div>
155            </div>
156        }
157    }
158
159    fn destroy(&mut self, _ctx: &Context<Self>) {}
160}