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