diff options
| -rw-r--r-- | src/input.rs | 7 | ||||
| -rw-r--r-- | src/lib.rs | 101 | ||||
| -rw-r--r-- | src/ui.rs | 20 |
3 files changed, 90 insertions, 38 deletions
diff --git a/src/input.rs b/src/input.rs index f1431c5..dbfe763 100644 --- a/src/input.rs +++ b/src/input.rs @@ -20,6 +20,9 @@ impl Calculator { self.input_buffer = String::new(); } KeyCode::Char('C') => self.clear(), + KeyCode::Char('A') => { + self.angle_mode = self.angle_mode.toggle(); + } _ => {} }, KeyModifiers::NONE => match key.code { @@ -29,9 +32,7 @@ impl Calculator { } KeyCode::Enter => { if let Ok(func) = Function::parse(&self.input_buffer) { - if let Some(st) = self.stack.pop() { - self.stack.push(func.call_on(st)); - } + self.call_function(func); } else if let Ok(c) = Constant::parse(&self.input_buffer) { self.stack.push(c.value()); } else if let Ok(bu) = self.input_buffer.parse::<f64>() { @@ -1,4 +1,7 @@ -use std::f64::consts::{E, PI}; +use std::{ + f64::consts::{E, PI}, + fmt::{self, Display, Formatter}, +}; mod input; pub mod ui; @@ -7,6 +10,7 @@ pub mod ui; pub struct Calculator { stack: Vec<f64>, input_buffer: String, + angle_mode: AngleMode, } impl Calculator { @@ -31,6 +35,66 @@ impl Calculator { Operator::Exp => lhs.powf(rhs), }); } + + fn call_function(&mut self, func: Function) { + let mut val = match self.stack.pop() { + Some(v) => v, + None => { + return; + } + }; + self.stack.push(match func { + Function::Sin => { + if self.angle_mode == AngleMode::Degrees { + val = val.to_radians(); + } + val.sin() + } + Function::Cos => { + if self.angle_mode == AngleMode::Degrees { + val = val.to_radians(); + } + val.cos() + } + Function::Tan => { + if self.angle_mode == AngleMode::Degrees { + val = val.to_radians(); + } + val.tan() + } + Function::Deg => val.to_degrees(), + Function::Rad => val.to_radians(), + }); + } +} + +#[derive(Default, Copy, Clone, PartialEq)] +enum AngleMode { + #[default] + Degrees, + Radians, +} + +impl AngleMode { + fn toggle(&self) -> Self { + match self { + Self::Degrees => Self::Radians, + Self::Radians => Self::Degrees, + } + } +} + +impl Display for AngleMode { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Degrees => "deg", + Self::Radians => "rad", + } + ) + } } enum Operator { @@ -57,43 +121,24 @@ impl Operator { struct ParseOperatorError(char); enum Function { - DSin, // Sine (degrees) - DCos, // Cosine (degrees) - DTan, // Tangent (degrees) - RSin, // Sine (radians) - RCos, // Cosing (radians) - RTan, // Tangent (radians) - Deg, // Convert from radians to degrees - Rad, // Convert from degrees to radians + Sin, // Sine + Cos, // Cosine + Tan, // Tangent + Deg, // Convert from radians to degrees + Rad, // Convert from degrees to radians } impl Function { fn parse(s: &str) -> Result<Self, ParseFunctionError> { match s { - "dsin" => Ok(Self::DSin), - "dcos" => Ok(Self::DCos), - "dtan" => Ok(Self::DTan), - "rsin" => Ok(Self::RSin), - "rcos" => Ok(Self::RCos), - "rtan" => Ok(Self::RTan), + "sin" => Ok(Self::Sin), + "cos" => Ok(Self::Cos), + "tan" => Ok(Self::Tan), "deg" => Ok(Self::Deg), "rad" => Ok(Self::Rad), _ => Err(ParseFunctionError(s.to_string())), } } - - fn call_on(&self, f: f64) -> f64 { - match self { - Self::DSin => f.to_radians().sin(), - Self::DCos => f.to_radians().cos(), - Self::DTan => f.to_radians().tan(), - Self::RSin => f.sin(), - Self::RCos => f.cos(), - Self::RTan => f.tan(), - Self::Deg => f.to_degrees(), - Self::Rad => f.to_radians(), - } - } } struct ParseFunctionError(String); @@ -12,7 +12,7 @@ use tui::{ Frame, Terminal, }; -use crate::{Calculator, Constant, Function}; +use crate::{AngleMode, Calculator, Constant, Function}; const WIDTH: u16 = 32; @@ -20,8 +20,9 @@ impl Calculator { pub fn draw<B: Backend>(&self, f: &mut Frame<B>) { let chunks = layout(self.stack.len(), f.size()); f.render_widget(version_number_widget(), chunks[0]); - f.render_widget(stack_widget(&self.stack), chunks[2]); - f.render_widget(input_buffer_widget(&self.input_buffer), chunks[3]); + f.render_widget(angle_mode_widget(self.angle_mode), chunks[2]); + f.render_widget(stack_widget(&self.stack), chunks[3]); + f.render_widget(input_buffer_widget(&self.input_buffer), chunks[4]); } } @@ -53,16 +54,21 @@ fn layout(stack_size: usize, frame_size: Rect) -> Vec<Rect> { .direction(Direction::Vertical) .constraints( [ - Constraint::Length(1), - Constraint::Max(u16::MAX), - Constraint::Length(stack_size as u16 + 2), - Constraint::Length(3), + Constraint::Length(1), // Version number + Constraint::Max(u16::MAX), // Fill + Constraint::Length(1), // Angle mode + Constraint::Length(stack_size as u16 + 2), // Stack + Constraint::Length(3), // Input buffer ] .as_ref(), ) .split(columns[0]) } +fn angle_mode_widget(angle_mode: AngleMode) -> impl Widget { + Paragraph::new(format!("{}", angle_mode)).alignment(Alignment::Right) +} + fn stack_widget(stack: &Vec<f64>) -> impl Widget { List::new( stack |