Skip to main content

perspective_viewer/components/style_controls/
number_string_format.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
13mod digits_section;
14mod misc_section;
15mod style_section;
16mod types;
17
18use perspective_client::config::ColumnType;
19pub use types::*;
20use yew::{Callback, Component, Properties, html};
21
22use crate::components::style::LocalStyle;
23use crate::config::*;
24use crate::css;
25
26#[derive(Properties, PartialEq, Clone)]
27pub struct CustomNumberFormatProps {
28    pub restored_config: CustomNumberFormatConfig,
29    pub on_change: Callback<ColumnConfigValueUpdate>,
30    pub view_type: ColumnType,
31    pub column_name: String,
32}
33
34pub enum CustomNumberFormatMsg {
35    StyleChanged(Option<NumberStyle>),
36    NotationChanged(Option<NotationName>),
37    CurrencyCode(Option<CurrencyCode>),
38    CurrencyDisplay(Option<CurrencyDisplay>),
39    CompactDisplay(Option<CompactDisplay>),
40    CurrencySign(Option<CurrencySign>),
41    UseGrouping(Option<UseGrouping>),
42    SignDisplay(Option<SignDisplay>),
43    Unit(Option<Unit>),
44    UnitDisplay(Option<UnitDisplay>),
45    MinimumIntegerDigits(Option<f64>),
46    SigChange(Option<(f64, f64)>),
47    FracChange(Option<(f64, f64)>),
48    RoundingIncrement(RoundingIncrement),
49    TrailingZero(Option<TrailingZeroDisplay>),
50    RoundingMode(Option<RoundingMode>),
51    RoundingPriority(Option<RoundingPriority>),
52}
53
54#[derive(Default)]
55pub struct CustomNumberFormat {
56    config: CustomNumberFormatConfig,
57    style: NumberStyle,
58    notation: Option<NotationName>,
59    // show_frac: bool,
60    // show_sig: bool,
61    // disable_rounding_increment: bool,
62    // disable_rounding_priority: bool,
63}
64
65impl Component for CustomNumberFormat {
66    type Message = CustomNumberFormatMsg;
67    type Properties = CustomNumberFormatProps;
68
69    fn create(ctx: &yew::prelude::Context<Self>) -> Self {
70        Self::initialize(ctx)
71    }
72
73    fn changed(
74        &mut self,
75        ctx: &yew::prelude::Context<Self>,
76        _old_props: &Self::Properties,
77    ) -> bool {
78        *self = Self::initialize(ctx);
79        true
80    }
81
82    fn update(&mut self, ctx: &yew::prelude::Context<Self>, msg: Self::Message) -> bool {
83        match msg {
84            CustomNumberFormatMsg::StyleChanged(style) => {
85                let style = style.unwrap_or_default();
86                let new_style = match style {
87                    NumberStyle::Decimal => NumberFormatStyle::Decimal,
88                    NumberStyle::Percent => NumberFormatStyle::Percent,
89                    NumberStyle::Currency => {
90                        NumberFormatStyle::Currency(CurrencyNumberFormatStyle::default())
91                    },
92                    NumberStyle::Unit => NumberFormatStyle::Unit(UnitNumberFormatStyle {
93                        unit: Unit::default(),
94                        unit_display: None,
95                    }),
96                };
97                self.config._style = Some(new_style);
98                self.style = style;
99            },
100            CustomNumberFormatMsg::NotationChanged(notation) => {
101                self.notation = notation;
102                let new_notation = notation.map(|notation| match notation {
103                    NotationName::Standard => Notation::Standard,
104                    NotationName::Scientific => Notation::Scientific,
105                    NotationName::Engineering => Notation::Engineering,
106                    NotationName::Compact => Notation::Compact(CompactDisplay::default()),
107                });
108                self.config._notation = new_notation;
109            },
110            CustomNumberFormatMsg::CurrencyCode(val) => {
111                if let Some(NumberFormatStyle::Currency(currency)) = &mut self.config._style {
112                    currency.currency = val.unwrap_or_default();
113                }
114            },
115            CustomNumberFormatMsg::CurrencyDisplay(val) => {
116                if let Some(NumberFormatStyle::Currency(currency)) = &mut self.config._style {
117                    currency.currency_display = val;
118                }
119            },
120            CustomNumberFormatMsg::CurrencySign(val) => {
121                if let Some(NumberFormatStyle::Currency(currency)) = &mut self.config._style {
122                    currency.currency_sign = val;
123                }
124            },
125            CustomNumberFormatMsg::CompactDisplay(val) => {
126                if let Some(Notation::Compact(old)) = &mut self.config._notation {
127                    if let Some(val) = val {
128                        *old = val;
129                    }
130                } else {
131                    tracing::error!("Unreachable change in compact display!");
132                }
133            },
134            CustomNumberFormatMsg::UseGrouping(val) => {
135                self.config.use_grouping = val;
136            },
137            CustomNumberFormatMsg::SignDisplay(val) => {
138                self.config.sign_display = val;
139            },
140            CustomNumberFormatMsg::Unit(val) => {
141                if let Some(NumberFormatStyle::Unit(style)) = &mut self.config._style {
142                    style.unit = val.unwrap_or_default();
143                }
144            },
145            CustomNumberFormatMsg::UnitDisplay(val) => {
146                if let Some(NumberFormatStyle::Unit(style)) = &mut self.config._style {
147                    style.unit_display = val;
148                }
149            },
150            CustomNumberFormatMsg::MinimumIntegerDigits(val) => {
151                self.config.minimum_integer_digits = val;
152            },
153            CustomNumberFormatMsg::FracChange(val) => {
154                self.config.rounding_increment = None;
155                self.config.maximum_fraction_digits = val.map(|(_, val)| {
156                    let min = self.config.minimum_fraction_digits.unwrap_or(2.);
157                    val.max(min)
158                });
159
160                self.config.minimum_fraction_digits = val.map(|(val, _)| {
161                    let max = self.config.maximum_fraction_digits.unwrap_or(2.);
162                    val.min(max)
163                });
164            },
165            CustomNumberFormatMsg::SigChange(val) => {
166                self.config.maximum_significant_digits = val.map(|(_, val)| {
167                    let min = self.config.minimum_significant_digits.unwrap_or(1.);
168                    val.max(min)
169                });
170
171                self.config.minimum_significant_digits = val.map(|(val, _)| {
172                    let max = self.config.maximum_significant_digits.unwrap_or(21.);
173                    val.min(max)
174                });
175            },
176            CustomNumberFormatMsg::RoundingIncrement(val) => {
177                if let RoundingIncrement::Custom(val) = val {
178                    self.config.rounding_priority = None;
179                    self.config.rounding_increment = Some(val);
180                    self.config.maximum_fraction_digits = Some(0.);
181                    self.config.minimum_fraction_digits = Some(0.);
182                } else {
183                    self.config.rounding_increment = None;
184                }
185            },
186            CustomNumberFormatMsg::TrailingZero(val) => {
187                self.config.trailing_zero_display = val;
188            },
189            CustomNumberFormatMsg::RoundingMode(val) => {
190                self.config.rounding_mode = val;
191            },
192            CustomNumberFormatMsg::RoundingPriority(val) => {
193                self.config.rounding_increment = None;
194                self.config.rounding_priority = val;
195            },
196        };
197
198        let is_float = ctx.props().view_type == ColumnType::Float;
199        let filtered_config = self.config.clone().filter_default(is_float);
200        let value =
201            (filtered_config != CustomNumberFormatConfig::default()).then_some(filtered_config);
202
203        let update = ColumnConfigValueUpdate::CustomNumberStringFormat(value);
204        ctx.props().on_change.emit(update);
205        true
206    }
207
208    fn view(&self, ctx: &yew::prelude::Context<Self>) -> yew::prelude::Html {
209        html! {
210            <>
211                <LocalStyle href={css!("column-style")} />
212                { self.style_section(ctx) }
213                { self.digits_section(ctx) }
214                { self.misc_section(ctx) }
215            </>
216        }
217    }
218}
219
220impl CustomNumberFormat {
221    fn initialize(ctx: &yew::prelude::Context<Self>) -> Self {
222        let config = ctx.props().restored_config.clone();
223        // let show_frac = config
224        //     .minimum_fraction_digits
225        //     .or(config.maximum_fraction_digits)
226        //     .or(config.rounding_increment)
227        //     .is_some();
228        // let show_sig = config
229        //     .minimum_significant_digits
230        //     .or(config.maximum_significant_digits)
231        //     .is_some();
232        // let disable_rounding_increment = show_sig
233        //     || show_frac
234        //     || !matches!(
235        //         config.rounding_priority,
236        //         Some(RoundingPriority::Auto) | None
237        //     );
238        // let disable_rounding_priority = !(show_frac && show_sig);
239        Self {
240            style: config
241                ._style
242                .as_ref()
243                .map(|style| match style {
244                    NumberFormatStyle::Decimal => NumberStyle::Decimal,
245                    NumberFormatStyle::Currency(_) => NumberStyle::Currency,
246                    NumberFormatStyle::Percent => NumberStyle::Percent,
247                    NumberFormatStyle::Unit(_) => NumberStyle::Unit,
248                })
249                .unwrap_or_default(),
250            config,
251            // show_frac,
252            // show_sig,
253            // disable_rounding_increment,
254            // disable_rounding_priority,
255            notation: None,
256        }
257    }
258}