Skip to main content

perspective_viewer/components/
render_warning.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 yew::prelude::*;
14
15use super::style::LocalStyle;
16use crate::model::*;
17use crate::renderer::*;
18use crate::session::*;
19use crate::*;
20
21#[derive(Properties, PerspectiveProperties!)]
22pub struct RenderWarningProps {
23    // Current dimensions
24    pub dimensions: Option<(usize, usize, Option<usize>, Option<usize>)>,
25
26    // State
27    pub renderer: Renderer,
28    pub session: Session,
29}
30
31impl PartialEq for RenderWarningProps {
32    fn eq(&self, other: &Self) -> bool {
33        self.dimensions == other.dimensions
34    }
35}
36
37pub enum RenderWarningMsg {
38    DismissWarning,
39}
40
41pub struct RenderWarning {
42    col_warn: Option<(usize, usize)>,
43    row_warn: Option<(usize, usize)>,
44}
45
46impl RenderWarning {
47    fn update_warnings(&mut self, ctx: &Context<Self>) {
48        if let Some((num_cols, num_rows, max_cols, max_rows)) = ctx.props().dimensions {
49            let count = num_cols * num_rows;
50            if max_cols.is_some_and(|x| x < num_cols) {
51                self.col_warn = Some((max_cols.unwrap(), num_cols));
52            } else {
53                self.col_warn = None;
54            }
55
56            if max_rows.is_some_and(|x| x < num_rows) {
57                self.row_warn = Some((num_cols * max_rows.unwrap(), count));
58            } else {
59                self.row_warn = None;
60            }
61        } else {
62            self.col_warn = None;
63            self.row_warn = None;
64        }
65    }
66}
67
68impl Component for RenderWarning {
69    type Message = RenderWarningMsg;
70    type Properties = RenderWarningProps;
71
72    fn create(ctx: &Context<Self>) -> Self {
73        let mut elem = Self {
74            col_warn: None,
75            row_warn: None,
76        };
77
78        elem.update_warnings(ctx);
79        elem
80    }
81
82    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
83        match msg {
84            RenderWarningMsg::DismissWarning => {
85                let state = ctx.props().clone_state();
86                ApiFuture::spawn(async move {
87                    state.renderer().disable_active_plugin_render_warning();
88                    let view_task = state.session().get_view();
89                    state.renderer().update(view_task).await
90                });
91            },
92        };
93        true
94    }
95
96    fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
97        self.update_warnings(ctx);
98        true
99    }
100
101    fn view(&self, ctx: &Context<Self>) -> Html {
102        if self.col_warn.is_some() || self.row_warn.is_some() {
103            let warning = match (self.col_warn, self.row_warn) {
104                (Some((x, y)), Some((a, b))) => html! {
105                    <span style="white-space: nowrap">
106                        { "Rendering" }
107                        { render_pair(x, y) }
108                        { "of columns and" }
109                        { render_pair(a, b) }
110                        { "of points." }
111                    </span>
112                },
113                (Some((x, y)), None) => html! {
114                    <span style="white-space: nowrap">
115                        { "Rendering" }
116                        { render_pair(x, y) }
117                        { "of columns." }
118                    </span>
119                },
120                (None, Some((x, y))) => html! {
121                    <span style="white-space: nowrap">
122                        { "Rendering" }
123                        { render_pair(x, y) }
124                        { "of points." }
125                    </span>
126                },
127                _ => html! { <div /> },
128            };
129
130            let onclick = ctx.link().callback(|_| RenderWarningMsg::DismissWarning);
131
132            html! {
133                <>
134                    <LocalStyle href={css!("render-warning")} />
135                    <div
136                        class="plugin_information plugin_information--warning"
137                        id="plugin_information--size"
138                    >
139                        <span class="plugin_information__icon" />
140                        <span class="plugin_information__text" id="plugin_information_count">
141                            { warning }
142                        </span>
143                        <span class="plugin_information__actions">
144                            <span class="plugin_information__action" onmousedown={onclick}>
145                                { "Render all points" }
146                            </span>
147                        </span>
148                    </div>
149                </>
150            }
151        } else {
152            html! {}
153        }
154    }
155}
156
157fn pretty_print_int(i: usize) -> String {
158    let mut s = String::new();
159    let i_str = i.to_string();
160    let a = i_str.chars().rev().enumerate();
161    for (idx, val) in a {
162        if idx != 0 && idx % 3 == 0 {
163            s.insert(0, ',');
164        }
165        s.insert(0, val);
166    }
167    s
168}
169
170fn render_pair(n: usize, d: usize) -> Html {
171    let x = pretty_print_int(n);
172    let y = pretty_print_int(d);
173    let total = ((n as f64 / d as f64) * 100_f64).floor() as usize;
174    html! {
175        <span title={format!("${x} / ${y}")} class="plugin_information--overflow-hint">
176            { "\u{00a0}" }
177            <span class="plugin_information--overflow-hint-percent">{ format!("{}%", total) }</span>
178            { "\u{00a0}" }
179        </span>
180    }
181}