1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! The `calc` crate contains all the drawing and button-press logic
//! for the `calc-rs` project.
//!
//! You can think of the `calc-rs` crate as a crate that runs `calc` on
//! the physical calculator, and you can think of the `calc-simulator`
//! crate as a crate that runs `calc` on linux/windows
//!
//! This crates main external interface is the [`CalculatorState`] object.
//! More specifically, it provides the
//! [`on_button_press`](CalculatorState::on_button_press) and the
//! [draw](CalculatorState::draw) methods.

#![warn(clippy::complexity, clippy::pedantic)]
#![deny(
    clippy::manual_let_else,
    clippy::manual_clamp,
    clippy::manual_assert,
    clippy::manual_ok_or,
    clippy::manual_string_new
)]
#![allow(
    clippy::semicolon_if_nothing_returned,
    clippy::default_trait_access,
    clippy::cast_possible_truncation,
    clippy::module_name_repetitions,
    clippy::must_use_candidate,
    clippy::inline_always,
    clippy::cast_possible_truncation,
    clippy::match_wildcard_for_single_variants,
    clippy::cast_sign_loss,
    clippy::unused_self
)]
#![no_std]
extern crate alloc;

use alloc::vec::Vec;

use calc_common::Button;
use calc_common::Character;
use calc_common::MetaButton;
use calc_common::NUM_CHARS;

use evaluation_menu::EvaluationMenuPersistentData;
use evaluation_menu::EvaluationMenuState;
pub use math::number_to_chars;
use meta_menu::MetaMenuState;
use settings_menu::SettingsMenuState;

pub mod drawing;
pub mod evaluation_menu;
pub mod math;
mod meta_menu;
mod settings_menu;
mod util;

enum CalcMenuState {
    EvaluationMenu(EvaluationMenuState),
    Settings(SettingsMenuState),
    Meta(MetaMenuState),
}

/// Represents the state of the calculator
pub struct CalculatorState {
    pub screen: drawing::ScreenBuffer,
    pub msg: Vec<Character>,
    menu: CalcMenuState,
    evaluation_menu_persistent_data: EvaluationMenuPersistentData,
}

impl CalculatorState {
    pub fn draw(&mut self) {
        match &mut self.menu {
            CalcMenuState::Meta(state) => state.draw(&mut self.screen),
            CalcMenuState::EvaluationMenu(state) => {
                state.draw(&mut self.screen, &self.evaluation_menu_persistent_data)
            }
            CalcMenuState::Settings(state) => state.draw(&mut self.screen),
        }
    }
    pub fn on_button_press(&mut self, button: Button) {
        if button == MetaButton::Menu.into() {
            self.menu = CalcMenuState::Meta(Default::default());
            self.draw();
            return;
        }

        match &mut self.menu {
            CalcMenuState::Meta(state) => {
                if let Some(new_menu_state) = state.on_button_press(&mut self.screen, button) {
                    self.menu = new_menu_state;
                    self.draw();
                }
            }
            CalcMenuState::EvaluationMenu(state) => state.on_button_press(
                &mut self.screen,
                button,
                &mut self.evaluation_menu_persistent_data,
            ),
            CalcMenuState::Settings(state) => state.on_button_press(&mut self.screen, button),
        }
    }
}

impl Default for CalculatorState {
    fn default() -> Self {
        let mut state = Self {
            screen: Default::default(),
            menu: CalcMenuState::EvaluationMenu(Default::default()),
            msg: Vec::new(),
            evaluation_menu_persistent_data: Default::default(),
        };

        state.draw();

        state
    }
}