Skip to content

Commit

Permalink
Merge c953bfd into bc0b00c
Browse files Browse the repository at this point in the history
  • Loading branch information
DataTriny committed Jan 2, 2019
2 parents bc0b00c + c953bfd commit 91728cc
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 41 deletions.
10 changes: 10 additions & 0 deletions examples/calculator.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
#expression {
max-height: 50pt;
background-color: #444;
color: white;
flex-direction: row;
text-align: right;
padding-right: 40pt;
justify-content: flex-end;
}

#result {
max-height: 81pt;
background: linear-gradient(to top, #111, #444);
Expand Down
192 changes: 151 additions & 41 deletions examples/calculator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,27 @@ use azul::prelude::*;

const FONT: &[u8] = include_bytes!("../assets/fonts/KoHo-Light.ttf");

#[derive(Clone, Debug)]
enum Event {
Clear,
InvertSign,
Percent,
Divide,
Multiply,
Subtract,
Plus,
EqualSign,
Dot,
Number(u8),
}

#[derive(Default)]
struct Calculator {
current_operator: Option<OperandStack>,
result: Option<f32>,
current_operand_stack: OperandStack,
division_by_zero: bool,
expression: String,
last_event: Option<Event>,
}

impl Layout for Calculator {
Expand All @@ -29,9 +45,15 @@ impl Layout for Calculator {
.with_child(numpad_btn(labels[3], "orange"))
}

let result = self.result.and_then(|r| Some(r.to_string())).unwrap_or(self.current_operand_stack.get_display());
let result = if self.division_by_zero {
String::from("Cannot divide by zero.")
}
else {
self.current_operand_stack.get_display()
};

Dom::div()
.with_child(Dom::label(self.expression.to_string()).with_id("expression"))
.with_child(Dom::label(result).with_id("result"))
.with_child(Dom::div().with_id("numpad-container")
.with_child(render_row(&["C", "+/-", "%", "/"]))
Expand All @@ -53,6 +75,24 @@ struct OperandStack {
negative_number: bool,
}

impl From<f32> for OperandStack {
fn from(value: f32) -> OperandStack {
let mut result = OperandStack::default();
for c in value.to_string().chars() {
if c == '-' {
result.negative_number = true;
}
else if c == '.' {
result.stack.push(Number::Dot);
}
else {
result.stack.push(Number::Value((c as u8 - 48) as u8))
}
}
result
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Number {
Value(u8),
Expand Down Expand Up @@ -92,9 +132,13 @@ impl OperandStack {
/// Returns the number which you can use to calculate things with
pub fn get_number(&self) -> f32 {

let stack_size = self.stack.len();
if stack_size == 0 {
return 0.0;
}

// Iterate the stack until the first Dot is found
let stack_size = self.stack.len();
let first_dot_position = self.stack.iter().position(|x| *x == Number::Dot).unwrap_or(stack_size - 1) as i32;
let first_dot_position = self.stack.iter().position(|x| *x == Number::Dot).and_then(|x| Some(x - 1)).unwrap_or(stack_size - 1) as i32;

let mut final_number = 0.0;

Expand Down Expand Up @@ -129,20 +173,6 @@ fn handle_mouseclick_numpad_btn(app_state: &mut AppState<Calculator>, event: Win
None => return UpdateScreen::DontRedraw,
};

#[derive(Debug)]
enum Event {
Clear,
InvertSign,
Percent,
Divide,
Multiply,
Subtract,
Plus,
EqualSign,
Dot,
Number(u8),
}

// Figure out what button was clicked from the given row and column, filter bad events
let event = match (clicked_row_idx, clicked_col_idx) {
(0, 0) => Event::Clear,
Expand Down Expand Up @@ -178,65 +208,145 @@ fn handle_mouseclick_numpad_btn(app_state: &mut AppState<Calculator>, event: Win
match event {
Event::Clear => {
app_state.data.modify(|state| {
state.current_operator = None;
state.result = None;
state.current_operand_stack = OperandStack::default();
*state = Calculator::default();
});
UpdateScreen::Redraw
},
Event::InvertSign => {
app_state.data.modify(|state| {
state.current_operand_stack.negative_number = !state.current_operand_stack.negative_number;
if !state.division_by_zero {
state.current_operand_stack.negative_number = !state.current_operand_stack.negative_number;
}
});

UpdateScreen::Redraw
},
Event::Percent => {
// TODO: not sure what this button does...
UpdateScreen::DontRedraw
app_state.data.modify(|state| {
if !state.division_by_zero {
state.current_operand_stack.negative_number = !state.current_operand_stack.negative_number;
}
if let Some(operation) = &state.last_event.clone() {
if let Some(operand) = state.current_operator.clone() {
let num = state.current_operand_stack.get_number();
let op = operand.get_number();
let result = match operation {
Event::Plus | Event::Subtract => op / 100.0 * num,
Event::Multiply | Event::Divide => num / 100.0,
_ => unreachable!(),
};
state.current_operand_stack = OperandStack::from(result);
}
}
});
UpdateScreen::Redraw
},
Event::EqualSign => {
app_state.data.modify(|state| {
if state.current_operator.is_none() {
state.current_operator = Some(state.current_operand_stack.clone());
state.current_operand_stack = OperandStack::default();
}
if !state.division_by_zero {
state.current_operand_stack.negative_number = !state.current_operand_stack.negative_number;
}
if let Some(Event::EqualSign) = state.last_event {
state.expression = format!("{} =", state.current_operand_stack.get_display());
}
else {
state.expression.push_str(&format!("{} =", state.current_operand_stack.get_display()));
if let Some(operation) = &state.last_event.clone() {
if let Some(operand) = state.current_operator.clone() {
let num = state.current_operand_stack.get_number();
let op = operand.get_number();
match perform_operation(op, &operation, num) {
Some(r) => state.current_operand_stack = OperandStack::from(r),
None => state.division_by_zero = true,
}
}
}
}
state.current_operator = None;
state.last_event = Some(Event::EqualSign);
});
UpdateScreen::Redraw
},
Event::Dot => {
app_state.data.modify(|state| {
state.current_operand_stack.stack.push(Number::Dot);
if !state.division_by_zero {
state.current_operand_stack.negative_number = !state.current_operand_stack.negative_number;
}
if state.current_operand_stack.stack.iter().position(|x| *x == Number::Dot).is_none() {
if state.current_operand_stack.stack.len() == 0 {
state.current_operand_stack.stack.push(Number::Value(0));
}
state.current_operand_stack.stack.push(Number::Dot);
}
});
UpdateScreen::Redraw
},
Event::Number(v) => {
app_state.data.modify(|state| {
if let Some(Event::EqualSign) = state.last_event {
*state = Calculator::default();
}
state.current_operand_stack.stack.push(Number::Value(v));
});
UpdateScreen::Redraw
},
operation => {
app_state.data.modify(|state| {
if let Some(operand) = &state.current_operator {
let num = state.current_operand_stack.get_number();
let op = operand.get_number();
let result = match operation {
Event::Multiply => op * num,
Event::Subtract => op - num,
Event::Plus => op + num,
Event::Divide => op / num,
_ => return,
};
state.result = Some(result);
}
if !state.division_by_zero {
state.current_operand_stack.negative_number = !state.current_operand_stack.negative_number;
}
if let Some(Event::EqualSign) = state.last_event {
state.expression = String::new();
}
state.expression.push_str(&state.current_operand_stack.get_display());
if let Some(Event::EqualSign) = state.last_event {
state.current_operator = Some(state.current_operand_stack.clone());
}
else if let Some(last_operation) = &state.last_event.clone() {
if let Some(operand) = state.current_operator.clone() {
let num = state.current_operand_stack.get_number();
let op = operand.get_number();
match perform_operation(op, last_operation, num) {
Some(r) => state.current_operator = Some(OperandStack::from(r)),
None => state.division_by_zero = true,
}
}
}
else {
state.current_operator = Some(state.current_operand_stack.clone());
}
state.current_operand_stack = OperandStack::default();
state.expression.push_str(match operation {
Event::Plus => " + ",
Event::Subtract => " - ",
Event::Multiply => " x ",
Event::Divide => " / ",
_ => unreachable!()
});
state.last_event = Some(operation);
});

UpdateScreen::Redraw
},
}
}

/// Performs an arithmetic operation. Returns None when trying to divide by zero.
fn perform_operation(left_operand: f32, operation: &Event, right_operand: f32) -> Option<f32> {
match operation {
Event::Multiply => Some(left_operand * right_operand),
Event::Subtract => Some(left_operand - right_operand),
Event::Plus => Some(left_operand + right_operand),
Event::Divide => if right_operand == 0.0 {
None
}
else {
Some(left_operand / right_operand)
},
_ => unreachable!(),
}
}

fn main() {
macro_rules! CSS_PATH { () => (concat!(env!("CARGO_MANIFEST_DIR"), "/../examples/calculator.css")) }

Expand Down

0 comments on commit 91728cc

Please sign in to comment.