Skip to content

Commit

Permalink
Add scrollable view to alert viewer
Browse files Browse the repository at this point in the history
Refs: #66
  • Loading branch information
orontee committed Nov 13, 2023
1 parent b66f3f0 commit eff05b7
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 57 deletions.
188 changes: 141 additions & 47 deletions src/alerts.cc
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#include "alerts.h"

#include <cstdint>
#include <inkview.h>
#include <iomanip>
#include <memory>
#include <sstream>
#include <string>

#include "inkview.h"
#include "model.h"
#include "util.h"

Expand All @@ -15,78 +16,118 @@ void AlertsButton::on_clicked() { this->viewer->open(); }

AlertViewer::AlertViewer(std::shared_ptr<Model> model,
std::shared_ptr<Fonts> 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()) {
this->hide();
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();
SendEvent(event_handler, EVT_SHOW, 0, 0);
}

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) + "/" +
std::to_string(this->alert_count()));
}
}

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
Expand All @@ -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<irect *>(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
35 changes: 26 additions & 9 deletions src/alerts.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class AlertsButton : public Button {
std::shared_ptr<AlertViewer> viewer;
};

class AlertViewer : public Widget {
class AlertViewer : public ModalWidget {
public:
AlertViewer(std::shared_ptr<Model> model, std::shared_ptr<Fonts> fonts);

Expand All @@ -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:
Expand All @@ -53,21 +49,42 @@ class AlertViewer : public Widget {
std::shared_ptr<Model> model;
std::shared_ptr<Fonts> 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
2 changes: 1 addition & 1 deletion src/app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down

0 comments on commit eff05b7

Please sign in to comment.