|
|
@ -6,6 +6,9 @@ |
|
|
|
#include "constants.hpp" |
|
|
|
#include "constants.hpp" |
|
|
|
#include <fmt/xchar.h> |
|
|
|
#include <fmt/xchar.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define FSM_DEBUG 1 |
|
|
|
|
|
|
|
#include "fsm.hpp" |
|
|
|
|
|
|
|
|
|
|
|
constexpr const int WINDOW_WIDTH=300; |
|
|
|
constexpr const int WINDOW_WIDTH=300; |
|
|
|
constexpr const int WINDOW_HEIGHT=400; |
|
|
|
constexpr const int WINDOW_HEIGHT=400; |
|
|
|
|
|
|
|
|
|
|
@ -17,22 +20,85 @@ const std::unordered_map<string, wstring> LABELS { |
|
|
|
{"btn5", L"5"}, {"btn6", L"6"}, {"btn7", L"7"}, |
|
|
|
{"btn5", L"5"}, {"btn6", L"6"}, {"btn7", L"7"}, |
|
|
|
{"btn8", L"8"}, {"btn9", L"9"}, {"mult", L"*"}, |
|
|
|
{"btn8", L"8"}, {"btn9", L"9"}, {"mult", L"*"}, |
|
|
|
{"minus", L"-"}, {"plus", L"+"}, {"neg", L"!"}, |
|
|
|
{"minus", L"-"}, {"plus", L"+"}, {"neg", L"!"}, |
|
|
|
{"dot", L"."}, {"eq", L"="} |
|
|
|
{"div", L"/"}, {"eq", L"="} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct Calculator { |
|
|
|
enum class Event { |
|
|
|
|
|
|
|
NUMBER=0, |
|
|
|
|
|
|
|
OP=1, |
|
|
|
|
|
|
|
CLR=2, |
|
|
|
|
|
|
|
NOT=3, |
|
|
|
|
|
|
|
EQ=4 |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum class State { |
|
|
|
|
|
|
|
START=0, |
|
|
|
|
|
|
|
CALCULATING=1, |
|
|
|
|
|
|
|
CLEARED=3, |
|
|
|
|
|
|
|
DISPLAYED=4 |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Calculator : DeadSimpleFSM<State, Event> { |
|
|
|
|
|
|
|
wstring input; |
|
|
|
|
|
|
|
double value = 0.0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void event(Event ev, wchar_t op) { |
|
|
|
|
|
|
|
switch($state) { |
|
|
|
|
|
|
|
FSM_STATE(State, START, ev, op); |
|
|
|
|
|
|
|
FSM_STATE(State, CALCULATING, ev, op); |
|
|
|
|
|
|
|
FSM_STATE(State, CLEARED, ev, op); |
|
|
|
|
|
|
|
FSM_STATE(State, DISPLAYED, ev, op); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void START(Event ev, wchar_t op) { |
|
|
|
|
|
|
|
if(ev == Event::NUMBER) { |
|
|
|
|
|
|
|
input += op; |
|
|
|
|
|
|
|
state(State::CALCULATING); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CALCULATING(Event ev, wchar_t op) { |
|
|
|
|
|
|
|
if(ev == Event::NUMBER) { |
|
|
|
|
|
|
|
input += op; |
|
|
|
|
|
|
|
} else if(ev == Event::OP) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if(ev == Event::NOT) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if(ev == Event::EQ) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if(ev == Event::CLR) { |
|
|
|
|
|
|
|
input = L""; |
|
|
|
|
|
|
|
state(State::CLEARED); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CLEARED(Event ev, wchar_t op) { |
|
|
|
|
|
|
|
if(ev == Event::NUMBER) { |
|
|
|
|
|
|
|
input += op; |
|
|
|
|
|
|
|
state(State::CALCULATING); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DISPLAYED(Event ev, wchar_t op) { |
|
|
|
|
|
|
|
fmt::println(L"ev={}, op={}", (int)ev, op); |
|
|
|
|
|
|
|
state(State::CALCULATING); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct CalculatorUI { |
|
|
|
guecs::UI $gui; |
|
|
|
guecs::UI $gui; |
|
|
|
wstring $input; |
|
|
|
Calculator $fsm; |
|
|
|
double $value = 0.0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Calculator() { |
|
|
|
CalculatorUI() { |
|
|
|
$gui.position(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); |
|
|
|
$gui.position(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); |
|
|
|
$gui.layout( |
|
|
|
$gui.layout( |
|
|
|
"[*%(400)readout|_|_|_|clear]" |
|
|
|
"[*%(400)readout|_|_|_|clear]" |
|
|
|
"[btn7|btn8|btn9|mult]" |
|
|
|
"[btn7|btn8|btn9|mult]" |
|
|
|
"[btn4|btn5|btn6|minus]" |
|
|
|
"[btn4|btn5|btn6|minus]" |
|
|
|
"[btn1|btn2|btn3|plus]" |
|
|
|
"[btn1|btn2|btn3|plus]" |
|
|
|
"[neg|btn0|dot|eq]"); |
|
|
|
"[neg|btn0|eq|div]"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void init() { |
|
|
|
void init() { |
|
|
@ -79,39 +145,26 @@ struct Calculator { |
|
|
|
case L'7': |
|
|
|
case L'7': |
|
|
|
case L'8': |
|
|
|
case L'8': |
|
|
|
case L'9': |
|
|
|
case L'9': |
|
|
|
case L'.': |
|
|
|
$fsm.event(Event::NUMBER, op); |
|
|
|
if($input.size() <= 10) { |
|
|
|
|
|
|
|
$input += op; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
case L'*': |
|
|
|
case L'*': |
|
|
|
$value = $value * std::stof($input); |
|
|
|
|
|
|
|
$input = L""; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case L'-': |
|
|
|
case L'-': |
|
|
|
$value = $value - std::stof($input); |
|
|
|
|
|
|
|
$input = L""; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case L'+': |
|
|
|
case L'+': |
|
|
|
$value = $value + std::stof($input); |
|
|
|
case L'/': |
|
|
|
$input = L""; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case L'!': |
|
|
|
case L'!': |
|
|
|
$value = $value * -1.0; |
|
|
|
$fsm.event(Event::OP, op); |
|
|
|
$input = L""; |
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
case L'=': |
|
|
|
case L'=': |
|
|
|
$input = fmt::format(L"{}", $value); |
|
|
|
$fsm.event(Event::EQ, op); |
|
|
|
$value = 0.0; |
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
case L'C': |
|
|
|
case L'C': |
|
|
|
$input = L""; |
|
|
|
$fsm.event(Event::CLR, op); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto readout = $gui.entity("readout"); |
|
|
|
auto readout = $gui.entity("readout"); |
|
|
|
auto& label = $gui.get<guecs::Textual>(readout); |
|
|
|
auto& label = $gui.get<guecs::Textual>(readout); |
|
|
|
label.update($input); |
|
|
|
label.update($fsm.input); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -126,7 +179,7 @@ int main() { |
|
|
|
window.setFramerateLimit(FRAME_LIMIT); |
|
|
|
window.setFramerateLimit(FRAME_LIMIT); |
|
|
|
window.setVerticalSyncEnabled(VSYNC); |
|
|
|
window.setVerticalSyncEnabled(VSYNC); |
|
|
|
|
|
|
|
|
|
|
|
Calculator calc; |
|
|
|
CalculatorUI calc; |
|
|
|
calc.init(); |
|
|
|
calc.init(); |
|
|
|
|
|
|
|
|
|
|
|
while(window.isOpen()) { |
|
|
|
while(window.isOpen()) { |
|
|
|