use ratatui::layout::Position;
use crate::widgets::InputNumberState;
#[derive(Debug)]
pub(crate) enum InputCurrencyFocus
{
Integral,
Decimal,
}
#[derive(Debug)]
pub struct InputCurrencyState
{
pub(crate) label: Option<String>,
pub(crate) input_mode: InputCurrencyFocus,
pub(crate) is_negative: bool,
pub(crate) input_integral: InputNumberState,
pub(crate) input_decimal: InputNumberState,
pub(crate) min_value: Option<i32>,
pub(crate) max_value: Option<i32>,
}
impl std::default::Default for InputCurrencyState
{
fn default() -> Self
{
Self::new()
}
}
impl InputCurrencyState
{
pub fn new() -> Self
{
Self {
label: None,
input_mode: InputCurrencyFocus::Integral,
is_negative: false,
input_integral: InputNumberState::new()
.right_aligned()
.with_max_length(8),
input_decimal: InputNumberState::new().with_max_length(2),
min_value: None,
max_value: None,
}
}
pub fn input(&self) -> Option<i32>
{
let integral = match self
.input_integral
.input()
.and_then(|i| i.checked_mul(100))
{
Some(value) => value,
None => return None,
};
let decimal = match self
.input_decimal
.input()
.filter(|i| *i <= 99)
{
Some(value) => value,
None => return None,
};
let mut value: i32 = match integral
.checked_add(decimal)
.and_then(
|i| {
i.try_into()
.ok()
},
)
{
Some(value) => value,
None => return None,
};
if self.is_negative
{
value *= -1;
}
if let Some(min) = self.min_value
{
if value < min
{
return None;
}
}
if let Some(max) = self.max_value
{
if value > max
{
return None;
}
}
Some(value)
}
pub fn set_label<S>(
&mut self,
label: S,
) where
S: AsRef<str>,
{
self.label = Some(
label
.as_ref()
.to_string(),
);
}
pub fn remove_label(&mut self)
{
self.label
.take();
}
pub fn with_label<S>(
mut self,
label: S,
) -> Self
where
S: AsRef<str>,
{
self.set_label(label);
self
}
pub fn max(
mut self,
value: i32,
) -> Self
{
self.max_value = Some(value);
self
}
pub fn min(
mut self,
value: i32,
) -> Self
{
self.min_value = Some(value);
self
}
pub fn set(
&mut self,
value: i32,
)
{
let integral = (value / 100).unsigned_abs();
let decimal = value.unsigned_abs() - (integral * 100);
let is_negative = value < 0;
self.is_negative = is_negative;
self.input_mode = InputCurrencyFocus::Integral;
self.input_integral
.set(integral);
self.input_decimal
.set_str(format!("{decimal:02}"));
if integral == 0
{
self.input_integral
.set_str("");
}
if decimal == 0
{
self.input_decimal
.set_str("");
}
}
pub fn reset_cursor(&mut self)
{
self.input_integral
.reset_cursor();
self.input_decimal
.reset_cursor();
}
pub fn with_default(
mut self,
value: i32,
) -> Self
{
self.set(value);
self
}
pub fn cursor(&self) -> Position
{
match self.input_mode
{
InputCurrencyFocus::Integral => self
.input_integral
.cursor(),
InputCurrencyFocus::Decimal => self
.input_decimal
.cursor(),
}
}
pub fn clear(&mut self)
{
self.input_integral
.clear();
self.input_decimal
.clear();
}
}