#include #include #include #include #include #include #include #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: /* * 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); } /* * 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 set_clear_reset_button_disabled(bool disabled) { set_button_disabled("clear-reset-btn", disabled); } 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); }); }); } private: static void set_inner_text_by_id(std::string const & id, std::string const & text) { emval timer_display = document.call("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("getElementById", emval(id.c_str())); timer_display.set("disabled", disabled); } }; class TimerController { public: TimerController() : _counters { FreqCounter(_timer), FreqCounter(_timer) } , _alarm_sound_triggered(false) { } void handle_inc_time(uint32_t amount) { _timer.increment_preset_ms(amount * 1000); _update_labels(); } void handle_start_stop() { _timer.toggleStart(); _update_labels(); } void handle_clear_reset() { if(_clear_reset_btn_clears()) { clear(); } else { reset(); } _update_labels(); } /* * Counter */ void handle_inc_counter(uint32_t counter_num) { _counters[counter_num].inc(); // Effects _update_labels(); _update_counter(counter_num); } void handle_timer_update() { _view.timer_display_text(_timer.counter_display_value()); _view.timer_record_floor(_timer.record_floor_display()); for(size_t i = 0; i < _counters.size(); i++) _update_counter(i); if(_timer.overtime() && !_alarm_sound_triggered) { _view.play_alarm(); _alarm_sound_triggered = true; } } private: FreqTimer _timer; TimerView _view; std::array _counters; bool _alarm_sound_triggered; void _update_counter(uint32_t counter_num) { FreqCounter & counter = _counters[counter_num]; std::string count = counter.display_value(); std::string rate = counter.rate_display(); _view.counter_display_text(counter_num, count, rate); } bool _clear_reset_btn_clears() const { return ( _timer.has_preset() and !_timer.started() and (_counters[0].cnt() == 0 && _counters[1].cnt() == 0) ); } void _update_labels() { // Start / Stop Label if(_timer.running()) { _view.timer_start_stop_button_label("Stop"); } else { _view.timer_start_stop_button_label("Start"); } // Clear / Reset Button Label if(_clear_reset_btn_clears()) { _view.timer_clear_reset_button_label("Clear"); } else { _view.timer_clear_reset_button_label("Reset"); } // Disable the clear / reset button when the timer is running _view.set_clear_reset_button_disabled(_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_controller) { emscripten::class_("TimerController") .constructor() .function("handle_start_stop", &TimerController::handle_start_stop ) .function("handle_clear_reset", &TimerController::handle_clear_reset ) .function("handle_inc_counter", &TimerController::handle_inc_counter ) .function("handle_inc_time", &TimerController::handle_inc_time ) .function("handle_timer_update", &TimerController::handle_timer_update ); }