aboutsummaryrefslogtreecommitdiff
path: root/src/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'src/controllers')
-rw-r--r--src/controllers/timer_view.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/controllers/timer_view.cpp b/src/controllers/timer_view.cpp
new file mode 100644
index 0000000..28abd5c
--- /dev/null
+++ b/src/controllers/timer_view.cpp
@@ -0,0 +1,238 @@
+#include <emscripten/bind.h>
+#include <emscripten/val.h>
+#include <emscripten.h>
+
+#include <cstdio>
+#include <string>
+#include <memory>
+#include <array>
+
+#include "models/timer.hpp"
+#include "models/counter.hpp"
+#include "utils/utils.hpp"
+
+using emval = emscripten::val;
+
+thread_local const emval document = emval::global("document");
+
+class TimerView {
+
+ public:
+
+ TimerView()
+ : _counters { FreqCounter(_timer), FreqCounter(_timer) }
+ , _alarm_sound_triggered(false)
+ { }
+
+ /*
+ * Timer
+ */
+
+ void timer_display_text(std::string const & text) {
+ set_inner_text_by_id("time-display", text);
+ }
+
+ void timer_record_floor(std::string const & text) {
+ set_inner_text_by_id("record-floor", text);
+ }
+
+ void timer_start_stop_button_label(std::string const & text) {
+ set_inner_text_by_id("start-stop-btn", text);
+ }
+
+ void timer_clear_reset_button_label(std::string const & text) {
+ set_inner_text_by_id("clear-reset-btn", text);
+ }
+
+ void handle_inc_time(uint32_t amount) {
+ _timer.increment_preset_ms(amount * 1000);
+
+ _update_start_stop_label();
+ _update_clear_reset_btn_label();
+ _update_clear_reset_btn();
+ }
+
+ void handle_start_stop() {
+ _timer.toggleStart();
+
+ _update_start_stop_label();
+ _update_clear_reset_btn_label();
+ _update_clear_reset_btn();
+ }
+
+ void handle_clear_reset() {
+ if(_clear_reset_btn_clears()) {
+ clear();
+ } else {
+ reset();
+ }
+
+ _update_clear_reset_btn_label();
+ }
+
+ /*
+ * Counter
+ */
+
+ void counter_display_text(uint32_t counter_num, std::string const & counter_text, std::string const & rate_text) {
+ std::string counter_id = "counter-";
+ counter_id.append(std::to_string(counter_num));
+
+ std::string rate_id = "rate-";
+ rate_id.append(std::to_string(counter_num));
+
+ set_inner_text_by_id(counter_id, counter_text);
+ set_inner_text_by_id(rate_id, rate_text);
+ }
+
+ void handle_inc_counter(uint32_t counter_num) {
+ _counters[counter_num].inc();
+
+ _update_counter(counter_num);
+ }
+
+ void handle_timer_update() {
+
+ std::string value = _timer.counter_display_value();
+
+ timer_display_text(value);
+
+ double record_floor = _timer.record_floor();
+
+ std::string rec_floor_text;
+ format_rate(rec_floor_text, record_floor);
+
+ if(_timer.overtime()) {
+ std::string rec_floor_overtime;
+ format_rate(rec_floor_overtime, _timer.overtime_record_floor());
+ rec_floor_text.append(", ");
+ rec_floor_text.append(rec_floor_overtime);
+ }
+
+ timer_record_floor(rec_floor_text);
+
+ for(size_t i = 0; i < _counters.size(); i++)
+ _update_counter(i);
+
+ if(_timer.overtime() && !_alarm_sound_triggered) {
+ _play_alarm();
+ _alarm_sound_triggered = true;
+ }
+ }
+
+ private:
+
+ FreqTimer _timer;
+ std::array<FreqCounter, 2> _counters;
+ bool _alarm_sound_triggered;
+
+ static void set_inner_text_by_id(std::string const & id, std::string const & text) {
+ emval timer_display = document.call<emval>("getElementById", emval(id.c_str()));
+ timer_display.set("innerText", text.c_str());
+ }
+
+ static void set_button_disabled(std::string const & id, bool disabled) {
+ emval timer_display = document.call<emval>("getElementById", emval(id.c_str()));
+ timer_display.set("disabled", disabled);
+ }
+
+ void _update_counter(uint32_t counter_num) {
+ FreqCounter & counter = _counters[counter_num];
+
+ std::string text = counter.display_value();
+ double rate = counter.rate();
+
+ std::string rate_val;
+ format_rate(rate_val, rate);
+
+ if(_timer.overtime()) {
+ std::string rate_overtime;
+ format_rate(rate_overtime, counter.overtime_rate());
+ rate_val.append(", ");
+ rate_val.append(rate_overtime);
+ }
+
+ counter_display_text(counter_num, text, rate_val);
+ }
+
+ static void _play_alarm() {
+
+ EM_ASM({
+ const handle = document.getElementById("sound-handle");
+
+ const duration = Math.round(handle.duration * 1000.0);
+
+ handle.currentTime = 0;
+ handle.play().then(() => {
+ setTimeout(() => {
+ handle.pause();
+ }, duration);
+ });
+ });
+
+ }
+
+ void _update_start_stop_label() {
+ if(_timer.running()) {
+ timer_start_stop_button_label("Stop");
+ } else {
+ timer_start_stop_button_label("Start");
+ }
+ }
+
+ bool _clear_reset_btn_clears() const {
+ return _timer.has_preset() and !_timer.started();
+ }
+
+ void _update_clear_reset_btn_label() {
+ if(_clear_reset_btn_clears()) {
+ timer_clear_reset_button_label("Clear");
+ } else {
+ timer_clear_reset_button_label("Reset");
+ }
+ }
+
+ void _update_clear_reset_btn() {
+ set_button_disabled("clear-reset-btn", _timer.running());
+ }
+
+ void clear() {
+ _timer.clear();
+
+ for(FreqCounter & counter : _counters)
+ counter.reset();
+
+ _alarm_sound_triggered = false;
+ }
+
+ void reset() {
+ _timer.reset();
+
+ for(FreqCounter & counter : _counters)
+ counter.reset();
+
+ _alarm_sound_triggered = false;
+ }
+
+};
+
+
+EMSCRIPTEN_BINDINGS(timer_view) {
+ emscripten::class_<TimerView>("TimerView")
+ .constructor()
+ .function("handle_start_stop",
+ &TimerView::handle_start_stop
+ )
+ .function("handle_clear_reset",
+ &TimerView::handle_clear_reset
+ )
+ .function("handle_inc_counter",
+ &TimerView::handle_inc_counter
+ )
+ .function("handle_inc_time",
+ &TimerView::handle_inc_time
+ )
+ .function("handle_timer_update",
+ &TimerView::handle_timer_update
+ );
+}