aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/input.rs7
-rw-r--r--src/lib.rs101
-rw-r--r--src/ui.rs20
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>() {
diff --git a/src/lib.rs b/src/lib.rs
index 00163b1..039258c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
diff --git a/src/ui.rs b/src/ui.rs
index 3d09221..76ecaf5 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -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