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<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 }
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 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 notation: None,
256 }
257 }
258}