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