Properly implement interface

This commit is contained in:
Austen Adler 2021-04-28 21:07:38 -04:00
parent 4600f5d31e
commit fbedb044c5
3 changed files with 47 additions and 153 deletions

View File

@ -143,7 +143,7 @@ impl<'a> Calculator<'a> {
Ok(())
}
'R' => {
self.state = CalculatorState::WaitingForRegister(RegisterState::Load);
self.state = CalculatorState::WaitingForRegister(RegisterState::Save);
Ok(())
}
_ => {
@ -215,7 +215,24 @@ impl<'a> Calculator<'a> {
self.state = CalculatorState::Normal;
self.active_macros.clear();
}
pub fn backspace(&mut self) -> CalculatorResult<()> {
self.l.pop();
Ok(())
}
pub fn edit(&mut self) -> CalculatorResult<()> {
if self.l.len() > 0 {
return Ok(());
}
self.l = self
.pop()
.or(Err(CalculatorError::NotEnoughStackEntries))?
.to_string();
Ok(())
}
pub fn get_l(&mut self) -> &str {
self.l.as_ref()
}
fn entry(&mut self, c: char) -> CalculatorResult<()> {
match c {
'0'..='9' => {
@ -245,6 +262,9 @@ impl<'a> Calculator<'a> {
}
}
pub fn get_state(&self) -> &CalculatorState {
&self.state
}
pub fn get_constants_iter(&'a self) -> CalculatorConstantsIter<'a> {
self.constants.iter()
}

View File

@ -8,7 +8,6 @@ pub enum RegisterState {
pub enum CalculatorState {
Normal,
//Macro,
WaitingForConstant,
WaitingForMacro,
WaitingForRegister(RegisterState),

View File

@ -4,12 +4,11 @@
mod calc;
mod util;
use calc::errors::{CalculatorError, CalculatorResult};
use calc::constants::{CalculatorState, RegisterState};
use calc::errors::CalculatorResult;
use calc::Calculator;
use std::cmp;
use std::convert::TryFrom;
use util::event::{Event, Events};
//use util::event::T;
use std::{error::Error, io};
use termion::{event::Key, raw::IntoRawMode, screen::AlternateScreen};
use tui::{
@ -21,27 +20,19 @@ use tui::{
widgets::{Block, Borders, Clear, List, ListItem, Paragraph},
Terminal,
};
use util::event::{Event, Events};
struct Dimensions {
width: u16,
height: u16,
}
enum RegisterState {
Save,
Load,
}
enum AppState {
Calculator,
Help,
Constants,
Macros,
Registers(RegisterState),
}
struct App<'a> {
input: String,
calculator: Calculator<'a>,
error_msg: Option<String>,
state: AppState,
@ -51,7 +42,6 @@ struct App<'a> {
impl<'a> Default for App<'a> {
fn default() -> App<'a> {
App {
input: String::new(),
calculator: Calculator::default(),
error_msg: None,
state: AppState::Calculator,
@ -121,11 +111,6 @@ fn main() -> Result<(), Box<dyn Error>> {
})
.collect();
// stack.insert(
// 0,
// ListItem::new(Span::raw(format!("dbg: {}", chunks[2].height))),
// );
for _ in 0..(chunks[1]
.height
.saturating_sub(stack.len() as u16)
@ -138,15 +123,18 @@ fn main() -> Result<(), Box<dyn Error>> {
List::new(stack).block(Block::default().borders(Borders::ALL).title("Stack"));
f.render_widget(stack, chunks[1]);
let input = Paragraph::new(app.input.as_ref())
let input = Paragraph::new(app.calculator.get_l().as_ref())
.style(Style::default())
.block(Block::default().borders(Borders::ALL).title("Input"));
f.render_widget(input, chunks[2]);
f.set_cursor(chunks[2].x + app.input.len() as u16 + 1, chunks[2].y + 1);
f.set_cursor(
chunks[2].x + app.calculator.get_l().len() as u16 + 1,
chunks[2].y + 1,
);
match &app.state {
AppState::Help => {
match (&app.state, app.calculator.get_state()) {
(AppState::Help, _) => {
draw_clippy_rect(
ClippyRectangle {
title: "Help",
@ -171,7 +159,7 @@ fn main() -> Result<(), Box<dyn Error>> {
f,
);
}
AppState::Constants => {
(AppState::Calculator, CalculatorState::WaitingForConstant) => {
draw_clippy_rect(
ClippyRectangle {
title: "Constants",
@ -187,8 +175,8 @@ fn main() -> Result<(), Box<dyn Error>> {
f,
);
}
AppState::Registers(state) => {
let title = match state {
(AppState::Calculator, CalculatorState::WaitingForRegister(register_state)) => {
let title = match register_state {
RegisterState::Save => "Registers (press char to save)",
RegisterState::Load => "Registers",
};
@ -205,7 +193,7 @@ fn main() -> Result<(), Box<dyn Error>> {
f,
);
}
AppState::Macros => {
(AppState::Calculator, CalculatorState::WaitingForMacro) => {
draw_clippy_rect(
ClippyRectangle {
title: "Macros",
@ -252,167 +240,54 @@ fn main() -> Result<(), Box<dyn Error>> {
}
fn handle_key(app: &mut App, events: &Events, key: Key) -> CalculatorResult<bool> {
match &app.state {
AppState::Calculator => match key {
match (&app.state, app.calculator.get_state()) {
(AppState::Calculator, CalculatorState::Normal) => match key {
Key::Char('q') => {
return Ok(true);
}
// Key::Ctrl('c') => {
// app.state = AppState::Constants;
// }
// Key::Char('r') => {
// app.state = AppState::Registers(RegisterState::Load);
// }
// Key::Char('R') => {
// app.state = AppState::Registers(RegisterState::Save);
// }
// Key::Char('m') => {
// app.state = AppState::Macros;
// }
Key::Char('h') => {
app.state = AppState::Help;
}
Key::Char(c @ '0'..='9') => {
app.input.push(c);
}
Key::Char('e') => {
if app.input.is_empty() {
let f = app
.calculator
.pop()
.or(Err(CalculatorError::NotEnoughStackEntries))?;
app.input = f.to_string();
}
if !app.input.contains('e') {
app.input.push('e');
}
}
Key::Char('.') => {
if !app.input.contains('.') {
app.input.push('.');
}
}
Key::Char('\n') | Key::Char(' ') => {
if app.input.is_empty() {
calc_operation(app, ' ')?;
} else {
let mut tmp_input = app.input.clone();
if tmp_input.ends_with('e') {
let tmp_input = tmp_input.push('0');
}
if let Ok(f) = tmp_input.parse::<f64>() {
if app.calculator.push(f).is_ok() {
app.input.clear();
}
}
}
app.calculator.take_input(' ')?;
}
Key::Right => {
calc_operation(app, '>')?;
app.calculator.take_input('>')?;
}
Key::Down => {
// TODO: Internal calculator function
if let Ok(x) = app.calculator.pop() {
app.input = x.to_string();
}
app.calculator.edit()?;
}
Key::Backspace => {
app.input.pop();
}
Key::Delete => {
app.input.clear();
app.calculator.backspace()?;
}
Key::Char(c) => {
calc_operation(app, c)?;
app.calculator.take_input(c)?;
}
_ => {}
},
AppState::Help => match key {
(AppState::Help, _) => match key {
Key::Esc | Key::Char('q') => {
app.state = AppState::Calculator;
app.calculator.cancel();
}
_ => {}
},
AppState::Constants => match key {
(AppState::Calculator, CalculatorState::WaitingForConstant)
| (AppState::Calculator, CalculatorState::WaitingForRegister(_))
| (AppState::Calculator, CalculatorState::WaitingForMacro) => match key {
Key::Esc => {
app.state = AppState::Calculator;
app.calculator.cancel();
}
Key::Char(c) => {
app.calculator.push_constant(c)?;
app.input.clear();
app.state = AppState::Calculator;
app.calculator.cancel();
app.calculator.take_input(c)?;
}
_ => {}
},
AppState::Registers(task) => match key {
Key::Esc => {
app.state = AppState::Calculator;
app.calculator.cancel();
}
// Key::Char(c) => {
// match task {
// RegisterState::Save => {
// app.calculator.save_register(c)?;
// }
// RegisterState::Load => {
// app.calculator.push_register(c)?;
// }
// }
// app.input.clear();
// app.state = AppState::Calculator;
// }
_ => {}
},
AppState::Macros => match key {
Key::Esc => {
app.state = AppState::Calculator;
app.calculator.cancel();
}
// Key::Char(c) => {
// if !app.input.is_empty() {
// //TODO: A better way to do this
// //Can use calc_operation in the future. Already performs this check
// let f = app
// .input
// .parse::<f64>()
// .or(Err(CalculatorError::ParseError))?;
// app.calculator.push(f).and_then(|()| {
// app.input.clear();
// Ok(())
// })?;
// }
// // TODO: Handle macros internally to the calculator
// let mac = app.calculator.get_macro(c)?;
// events.fill_event_buf(mac.value);
// app.state = AppState::Calculator;
// }
_ => {}
},
}
return Ok(false);
}
fn calc_operation(app: &mut App, c: char) -> CalculatorResult<()> {
if !app.input.is_empty() {
let f = app
.input
.parse::<f64>()
.or(Err(CalculatorError::ParseError))?;
app.calculator.push(f)?;
app.input.clear();
}
//let op = CalculatorOperation::from_char(c)?;
app.calculator.take_input(c)
//app.calculator.op(op)
}
struct ClippyRectangle<'a> {
title: &'a str,
msg: &'a str,