Properly implement interface
This commit is contained in:
parent
4600f5d31e
commit
fbedb044c5
22
src/calc.rs
22
src/calc.rs
@ -143,7 +143,7 @@ impl<'a> Calculator<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
'R' => {
|
'R' => {
|
||||||
self.state = CalculatorState::WaitingForRegister(RegisterState::Load);
|
self.state = CalculatorState::WaitingForRegister(RegisterState::Save);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -215,7 +215,24 @@ impl<'a> Calculator<'a> {
|
|||||||
self.state = CalculatorState::Normal;
|
self.state = CalculatorState::Normal;
|
||||||
self.active_macros.clear();
|
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<()> {
|
fn entry(&mut self, c: char) -> CalculatorResult<()> {
|
||||||
match c {
|
match c {
|
||||||
'0'..='9' => {
|
'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> {
|
pub fn get_constants_iter(&'a self) -> CalculatorConstantsIter<'a> {
|
||||||
self.constants.iter()
|
self.constants.iter()
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ pub enum RegisterState {
|
|||||||
|
|
||||||
pub enum CalculatorState {
|
pub enum CalculatorState {
|
||||||
Normal,
|
Normal,
|
||||||
//Macro,
|
|
||||||
WaitingForConstant,
|
WaitingForConstant,
|
||||||
WaitingForMacro,
|
WaitingForMacro,
|
||||||
WaitingForRegister(RegisterState),
|
WaitingForRegister(RegisterState),
|
||||||
|
177
src/main.rs
177
src/main.rs
@ -4,12 +4,11 @@
|
|||||||
mod calc;
|
mod calc;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
use calc::errors::{CalculatorError, CalculatorResult};
|
use calc::constants::{CalculatorState, RegisterState};
|
||||||
|
use calc::errors::CalculatorResult;
|
||||||
use calc::Calculator;
|
use calc::Calculator;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use util::event::{Event, Events};
|
|
||||||
//use util::event::T;
|
|
||||||
use std::{error::Error, io};
|
use std::{error::Error, io};
|
||||||
use termion::{event::Key, raw::IntoRawMode, screen::AlternateScreen};
|
use termion::{event::Key, raw::IntoRawMode, screen::AlternateScreen};
|
||||||
use tui::{
|
use tui::{
|
||||||
@ -21,27 +20,19 @@ use tui::{
|
|||||||
widgets::{Block, Borders, Clear, List, ListItem, Paragraph},
|
widgets::{Block, Borders, Clear, List, ListItem, Paragraph},
|
||||||
Terminal,
|
Terminal,
|
||||||
};
|
};
|
||||||
|
use util::event::{Event, Events};
|
||||||
|
|
||||||
struct Dimensions {
|
struct Dimensions {
|
||||||
width: u16,
|
width: u16,
|
||||||
height: u16,
|
height: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RegisterState {
|
|
||||||
Save,
|
|
||||||
Load,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AppState {
|
enum AppState {
|
||||||
Calculator,
|
Calculator,
|
||||||
Help,
|
Help,
|
||||||
Constants,
|
|
||||||
Macros,
|
|
||||||
Registers(RegisterState),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App<'a> {
|
struct App<'a> {
|
||||||
input: String,
|
|
||||||
calculator: Calculator<'a>,
|
calculator: Calculator<'a>,
|
||||||
error_msg: Option<String>,
|
error_msg: Option<String>,
|
||||||
state: AppState,
|
state: AppState,
|
||||||
@ -51,7 +42,6 @@ struct App<'a> {
|
|||||||
impl<'a> Default for App<'a> {
|
impl<'a> Default for App<'a> {
|
||||||
fn default() -> App<'a> {
|
fn default() -> App<'a> {
|
||||||
App {
|
App {
|
||||||
input: String::new(),
|
|
||||||
calculator: Calculator::default(),
|
calculator: Calculator::default(),
|
||||||
error_msg: None,
|
error_msg: None,
|
||||||
state: AppState::Calculator,
|
state: AppState::Calculator,
|
||||||
@ -121,11 +111,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// stack.insert(
|
|
||||||
// 0,
|
|
||||||
// ListItem::new(Span::raw(format!("dbg: {}", chunks[2].height))),
|
|
||||||
// );
|
|
||||||
|
|
||||||
for _ in 0..(chunks[1]
|
for _ in 0..(chunks[1]
|
||||||
.height
|
.height
|
||||||
.saturating_sub(stack.len() as u16)
|
.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"));
|
List::new(stack).block(Block::default().borders(Borders::ALL).title("Stack"));
|
||||||
f.render_widget(stack, chunks[1]);
|
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())
|
.style(Style::default())
|
||||||
.block(Block::default().borders(Borders::ALL).title("Input"));
|
.block(Block::default().borders(Borders::ALL).title("Input"));
|
||||||
f.render_widget(input, chunks[2]);
|
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 {
|
match (&app.state, app.calculator.get_state()) {
|
||||||
AppState::Help => {
|
(AppState::Help, _) => {
|
||||||
draw_clippy_rect(
|
draw_clippy_rect(
|
||||||
ClippyRectangle {
|
ClippyRectangle {
|
||||||
title: "Help",
|
title: "Help",
|
||||||
@ -171,7 +159,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
f,
|
f,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AppState::Constants => {
|
(AppState::Calculator, CalculatorState::WaitingForConstant) => {
|
||||||
draw_clippy_rect(
|
draw_clippy_rect(
|
||||||
ClippyRectangle {
|
ClippyRectangle {
|
||||||
title: "Constants",
|
title: "Constants",
|
||||||
@ -187,8 +175,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
f,
|
f,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AppState::Registers(state) => {
|
(AppState::Calculator, CalculatorState::WaitingForRegister(register_state)) => {
|
||||||
let title = match state {
|
let title = match register_state {
|
||||||
RegisterState::Save => "Registers (press char to save)",
|
RegisterState::Save => "Registers (press char to save)",
|
||||||
RegisterState::Load => "Registers",
|
RegisterState::Load => "Registers",
|
||||||
};
|
};
|
||||||
@ -205,7 +193,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
f,
|
f,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AppState::Macros => {
|
(AppState::Calculator, CalculatorState::WaitingForMacro) => {
|
||||||
draw_clippy_rect(
|
draw_clippy_rect(
|
||||||
ClippyRectangle {
|
ClippyRectangle {
|
||||||
title: "Macros",
|
title: "Macros",
|
||||||
@ -252,167 +240,54 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_key(app: &mut App, events: &Events, key: Key) -> CalculatorResult<bool> {
|
fn handle_key(app: &mut App, events: &Events, key: Key) -> CalculatorResult<bool> {
|
||||||
match &app.state {
|
match (&app.state, app.calculator.get_state()) {
|
||||||
AppState::Calculator => match key {
|
(AppState::Calculator, CalculatorState::Normal) => match key {
|
||||||
Key::Char('q') => {
|
Key::Char('q') => {
|
||||||
return Ok(true);
|
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') => {
|
Key::Char('h') => {
|
||||||
app.state = AppState::Help;
|
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(' ') => {
|
Key::Char('\n') | Key::Char(' ') => {
|
||||||
if app.input.is_empty() {
|
app.calculator.take_input(' ')?;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Key::Right => {
|
Key::Right => {
|
||||||
calc_operation(app, '>')?;
|
app.calculator.take_input('>')?;
|
||||||
}
|
}
|
||||||
Key::Down => {
|
Key::Down => {
|
||||||
// TODO: Internal calculator function
|
app.calculator.edit()?;
|
||||||
if let Ok(x) = app.calculator.pop() {
|
|
||||||
app.input = x.to_string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Key::Backspace => {
|
Key::Backspace => {
|
||||||
app.input.pop();
|
app.calculator.backspace()?;
|
||||||
}
|
|
||||||
Key::Delete => {
|
|
||||||
app.input.clear();
|
|
||||||
}
|
}
|
||||||
Key::Char(c) => {
|
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') => {
|
Key::Esc | Key::Char('q') => {
|
||||||
app.state = AppState::Calculator;
|
app.state = AppState::Calculator;
|
||||||
app.calculator.cancel();
|
app.calculator.cancel();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
AppState::Constants => match key {
|
(AppState::Calculator, CalculatorState::WaitingForConstant)
|
||||||
|
| (AppState::Calculator, CalculatorState::WaitingForRegister(_))
|
||||||
|
| (AppState::Calculator, CalculatorState::WaitingForMacro) => match key {
|
||||||
Key::Esc => {
|
Key::Esc => {
|
||||||
app.state = AppState::Calculator;
|
app.state = AppState::Calculator;
|
||||||
app.calculator.cancel();
|
app.calculator.cancel();
|
||||||
}
|
}
|
||||||
Key::Char(c) => {
|
Key::Char(c) => {
|
||||||
app.calculator.push_constant(c)?;
|
app.calculator.take_input(c)?;
|
||||||
app.input.clear();
|
|
||||||
app.state = AppState::Calculator;
|
|
||||||
app.calculator.cancel();
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
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);
|
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> {
|
struct ClippyRectangle<'a> {
|
||||||
title: &'a str,
|
title: &'a str,
|
||||||
msg: &'a str,
|
msg: &'a str,
|
||||||
|
Loading…
Reference in New Issue
Block a user