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