From eff05b7a467cfc25ee737750ca0dc1785284feb7 Mon Sep 17 00:00:00 2001 From: Matthias Meulien Date: Mon, 13 Nov 2023 14:08:13 +0100 Subject: [PATCH] Add scrollable view to alert viewer Refs: #66 --- src/alerts.cc | 188 +++++++++++++++++++++++++++++++++++++------------- src/alerts.h | 35 +++++++--- src/app.cc | 2 +- 3 files changed, 168 insertions(+), 57 deletions(-) diff --git a/src/alerts.cc b/src/alerts.cc index cde1dec..162afa0 100644 --- a/src/alerts.cc +++ b/src/alerts.cc @@ -1,11 +1,12 @@ #include "alerts.h" +#include +#include #include #include #include #include -#include "inkview.h" #include "model.h" #include "util.h" @@ -15,7 +16,17 @@ void AlertsButton::on_clicked() { this->viewer->open(); } AlertViewer::AlertViewer(std::shared_ptr model, std::shared_ptr fonts) - : Widget{0, 0, ScreenWidth(), ScreenHeight()}, model{model}, fonts{fonts} {} + : ModalWidget{}, model{model}, fonts{fonts} { + this->content_width = + (this->bounding_box.w - 2 * AlertViewer::horizontal_padding); + + this->title_height = this->compute_title_height(); + + this->alert_title_start_y = + (this->title_height + AlertViewer::vertical_padding); + + this->scrollable_view_rectangle = this->compute_scrollable_view_rectangle(); +} void AlertViewer::open() { if (this->alert_count() == 0 or this->alert_index >= this->alert_count()) { @@ -23,12 +34,25 @@ void AlertViewer::open() { return; } this->visible = true; + + const auto &alert = this->model->alerts.at(this->alert_index); + this->update_title_text(); + this->update_alert_title_text(alert); + this->update_description_text(alert); + + this->scrollable_view_offset = 0; + this->min_scrollable_view_offset = this->compute_min_scrollable_view_offset(); + + AddScrolledArea(&this->scrollable_view_rectangle, true); + const auto event_handler = GetEventHandler(); SendEvent(event_handler, EVT_SHOW, 0, 0); } void AlertViewer::hide() { this->visible = false; + RemoveScrolledArea(&this->scrollable_view_rectangle); + this->alert_index = 0; const auto event_handler = GetEventHandler(); @@ -36,49 +60,62 @@ void AlertViewer::hide() { } void AlertViewer::do_paint() { - const auto &alert = this->model->alerts.at(this->alert_index); - - this->update_title(); - this->update_description(alert); - const auto default_font = this->fonts->get_small_font(); SetFont(default_font.get(), BLACK); - const auto content_width = - (this->bounding_box.w - 2 * AlertViewer::horizontal_padding); - const auto title_height = - std::max(TextRectHeight(content_width, this->title.c_str(), ALIGN_CENTER), - 2 * default_font->height); DrawTextRect(AlertViewer::horizontal_padding, AlertViewer::vertical_padding, - content_width, title_height, this->title.c_str(), ALIGN_CENTER); + this->content_width, this->title_height, this->title.c_str(), + ALIGN_CENTER); + + DrawHorizontalSeparator(0, this->title_height, ScreenWidth(), + HORIZONTAL_SEPARATOR_SOLID); - DrawLine(0, title_height, ScreenWidth(), title_height, BLACK); + const auto bold_font = this->fonts->get_small_bold_font(); + SetFont(bold_font.get(), BLACK); - const auto alert_title_start_y = title_height + AlertViewer::vertical_padding; - auto description_start_y = alert_title_start_y; + const auto alert_title_height = TextRectHeight( + this->content_width, this->alert_title.c_str(), ALIGN_LEFT); + DrawTextRect(AlertViewer::horizontal_padding, alert_title_start_y, + this->content_width, alert_title_height, + this->alert_title.c_str(), ALIGN_LEFT); - if (not alert.event.empty()) { - const auto bold_font = this->fonts->get_small_bold_font(); - SetFont(bold_font.get(), BLACK); + SetFont(default_font.get(), BLACK); - const auto alert_title = alert.event; - const auto alert_title_height = - TextRectHeight(content_width, alert_title.c_str(), ALIGN_LEFT); - DrawTextRect(AlertViewer::horizontal_padding, alert_title_start_y, - content_width, alert_title_height, alert_title.c_str(), - ALIGN_LEFT); + SetClipRect(&this->scrollable_view_rectangle); - SetFont(default_font.get(), BLACK); - description_start_y += alert_title_height + AlertViewer::vertical_padding; - } - const auto description_height = - TextRectHeight(content_width, this->description.c_str(), ALIGN_LEFT); - DrawTextRect(AlertViewer::horizontal_padding, description_start_y, - content_width, description_height, this->description.c_str(), - ALIGN_LEFT); + const auto description_height = TextRectHeight( + this->content_width, this->description.c_str(), ALIGN_LEFT); + DrawTextRect(AlertViewer::horizontal_padding, + this->scrollable_view_rectangle.y + this->scrollable_view_offset, + this->content_width, description_height, + this->description.c_str(), ALIGN_LEFT); + + SetClip(0, 0, ScreenWidth(), ScreenHeight()); +} + +int AlertViewer::compute_title_height() const { + const auto default_font = this->fonts->get_small_font(); + return 2 * default_font->height; +} + +irect AlertViewer::compute_scrollable_view_rectangle() const { + const auto default_font = this->fonts->get_small_font(); + const auto view_start_y = this->alert_title_start_y + default_font->height + + AlertViewer::vertical_padding; + return iRect(AlertViewer::horizontal_padding, view_start_y, + ScreenWidth() - 2 * AlertViewer::horizontal_padding, + ScreenHeight() - view_start_y - AlertViewer::vertical_padding, + 0); +} + +int AlertViewer::compute_min_scrollable_view_offset() const { + const auto default_font = this->fonts->get_small_font(); + const auto description_height = TextRectHeight( + this->content_width, this->description.c_str(), ALIGN_LEFT); + return -std::max(0, description_height - this->scrollable_view_rectangle.h); } -void AlertViewer::update_title() { +void AlertViewer::update_title_text() { this->title = std::string{GetLangText("ALERT")}; if (this->alert_count() > 1) { this->title += (" " + std::to_string(this->alert_index + 1) + "/" + @@ -86,7 +123,11 @@ void AlertViewer::update_title() { } } -void AlertViewer::update_description(const Alert &alert) { +void AlertViewer::update_alert_title_text(const Alert &alert) { + this->alert_title = alert.event; +} + +void AlertViewer::update_description_text(const Alert &alert) { std::stringstream description_text; description_text << alert.description << std::endl << std::endl @@ -102,29 +143,82 @@ void AlertViewer::update_description(const Alert &alert) { this->description = description_text.str(); } +void AlertViewer::display_previous_alert_maybe() { + if (this->alert_index != 0) { + --this->alert_index; + + const auto &alert = this->model->alerts.at(this->alert_index); + this->update_title_text(); + this->update_alert_title_text(alert); + this->update_description_text(alert); + + this->scrollable_view_offset = 0; + this->min_scrollable_view_offset = + this->compute_min_scrollable_view_offset(); + + this->paint_and_update_screen(); + } else { + this->hide(); + } +} + +void AlertViewer::display_next_alert_maybe() { + if (this->alert_index + 1 < this->alert_count()) { + ++this->alert_index; + + const auto &alert = this->model->alerts.at(this->alert_index); + this->update_title_text(); + this->update_alert_title_text(alert); + this->update_description_text(alert); + + this->scrollable_view_offset = 0; + this->min_scrollable_view_offset = + this->compute_min_scrollable_view_offset(); + + this->paint_and_update_screen(); + } else { + this->hide(); + } +} + bool AlertViewer::handle_key_press(int key) { return (key == IV_KEY_PREV) or (key == IV_KEY_NEXT); } bool AlertViewer::handle_key_release(int key) { if (key == IV_KEY_PREV) { - if (this->alert_index != 0) { - --this->alert_index; - this->paint_and_update_screen(); - } else { - this->hide(); - } + this->display_previous_alert_maybe(); return true; } else if (key == IV_KEY_NEXT) { - if (this->alert_index + 1 < this->alert_count()) { - ++this->alert_index; - this->paint_and_update_screen(); - } else { - this->hide(); - } + this->display_next_alert_maybe(); return true; } return false; } +int AlertViewer::handle_pointer_event(int event_type, int pointer_pos_x, + int pointer_pos_y) { + if (event_type == EVT_SCROLL) { + auto *const scroll_area = reinterpret_cast(pointer_pos_x); + if (scroll_area == &this->scrollable_view_rectangle) { + const int delta_x = pointer_pos_y >> 16; + const int delta_y = (pointer_pos_y << 16) >> 16; + BOOST_LOG_TRIVIAL(debug) + << "Alert viewer received a scrolling event " + << "delta: " << delta_x << " " << delta_y + << " current offset: " << this->scrollable_view_offset + << " min. offset: " << this->min_scrollable_view_offset; + + this->scrollable_view_offset = + std::min(0, std::max(this->scrollable_view_offset + delta_y, + this->min_scrollable_view_offset)); + + this->paint_and_update_screen(); + + return 1; + } + } + return 0; +} + } // namespace taranis diff --git a/src/alerts.h b/src/alerts.h index 820f6b7..d7120e7 100644 --- a/src/alerts.h +++ b/src/alerts.h @@ -31,7 +31,7 @@ class AlertsButton : public Button { std::shared_ptr viewer; }; -class AlertViewer : public Widget { +class AlertViewer : public ModalWidget { public: AlertViewer(std::shared_ptr model, std::shared_ptr fonts); @@ -40,10 +40,6 @@ class AlertViewer : public Widget { void hide(); protected: - bool is_modal() const override { return true; } - - bool is_visible() const override { return this->visible; } - void do_paint() override; private: @@ -53,21 +49,42 @@ class AlertViewer : public Widget { std::shared_ptr model; std::shared_ptr fonts; - bool visible{false}; - size_t alert_index{0}; + int scrollable_view_offset{0}; + int min_scrollable_view_offset{0}; + + int content_width; + int title_height; + int alert_title_start_y; + irect scrollable_view_rectangle; std::string title; + std::string alert_title; std::string description; inline size_t alert_count() const { return this->model->alerts.size(); } - void update_title(); + int compute_title_height() const; + + irect compute_scrollable_view_rectangle() const; + + int compute_min_scrollable_view_offset() const; - void update_description(const Alert &alert); + void update_title_text(); + + void update_alert_title_text(const Alert &alert); + + void update_description_text(const Alert &alert); + + void display_previous_alert_maybe(); + + void display_next_alert_maybe(); bool handle_key_press(int key) override; bool handle_key_release(int key) override; + + int handle_pointer_event(int event_type, int pointer_pos_x, + int pointer_pos_y) override; }; } // namespace taranis diff --git a/src/app.cc b/src/app.cc index 4d410fe..4540e04 100644 --- a/src/app.cc +++ b/src/app.cc @@ -44,7 +44,7 @@ int App::process_event(int event_type, int param_one, int param_two) { } if (this->ui) { - if (ISPOINTEREVENT(event_type)) { + if (ISPOINTEREVENT(event_type) || event_type == EVT_SCROLL) { return this->ui->handle_pointer_event(event_type, param_one, param_two); } if (ISKEYEVENT(event_type)) {