Skip to content

Commit

Permalink
Display location list when multiple locations are returned by Geocodi…
Browse files Browse the repository at this point in the history
…ng API

Refs: #56
  • Loading branch information
orontee committed Oct 9, 2023
1 parent d66d5ce commit 5515152
Show file tree
Hide file tree
Showing 20 changed files with 284 additions and 27 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Added

- Display location list when multiple locations are returned by
Geocoding API [#56](https://github.com/orontee/taranis/issues/56)

- Compile with O3 optimization and strip executable
[#25](https://github.com/orontee/taranis/issues/25)

Expand Down
Binary file added icons/icon_radio_button_checked.bmp
Binary file not shown.
Binary file added icons/icon_radio_button_unchecked.bmp
Binary file not shown.
2 changes: 2 additions & 0 deletions icons/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ icons = files(
'icon_50n_2x.bmp',
'icon_favorite.bmp',
'icon_menu.bmp',
'icon_radio_button_checked.bmp',
'icon_radio_button_unchecked.bmp',
'icon_warning.bmp'
)

Expand Down
31 changes: 24 additions & 7 deletions src/app.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "app.h"

#include <experimental/optional>

#include "config.h"
#include "errors.h"
#include "events.h"
Expand All @@ -21,12 +19,16 @@ int App::process_event(int event_type, int param_one, int param_two) {
return 1;
}

if (event_type == EVT_SHOW) {
if (event_type == EVT_SHOW or event_type == EVT_FOREGROUND) {
this->show();
return 1;
}

if ((event_type == EVT_EXIT) || (event_type == EVT_HIDE)) {
if (event_type == EVT_HIDE or event_type == EVT_BACKGROUND) {
return 1;
}

if (event_type == EVT_EXIT) {
this->exit();
return 1;
}
Expand Down Expand Up @@ -176,14 +178,27 @@ int App::handle_custom_event(int param_one, int param_two) {
return 1;
} else if (param_one == CustomEvent::select_location_from_history) {
const size_t history_index = param_two;
auto location = this->history->get_location(history_index);
const auto location = this->history->get_location(history_index);
if (location) {
this->set_model_location(*location);
} else {
DialogSynchro(ICON_WARNING, "Title", "Location not found!",
GetLangText("Ok"), nullptr, nullptr);
}
return 1;
} else if (param_one == CustomEvent::select_location_from_list) {
const size_t list_index = param_two;
if (this->ui) {
const auto location =
this->ui->get_location_from_location_list(list_index);
if (location) {
this->set_model_location(*location);
} else {
DialogSynchro(ICON_WARNING, "Title", "Location not found!",
GetLangText("Ok"), nullptr, nullptr);
}
return 1;
}
} else if (param_one == CustomEvent::show_about_dialog) {
this->open_about_dialog();
return 1;
Expand Down Expand Up @@ -301,7 +316,9 @@ void App::search_location(const std::string &location_description) {
if (found_locations.size() == 1) {
this->set_model_location(found_locations[0]);
} else if (found_locations.size() > 1) {
// TODO Open location list
if (this->ui) {
this->ui->open_location_list(found_locations);
}
}
} catch (const InvalidLocation &error) {
const auto event_handler = GetEventHandler();
Expand Down Expand Up @@ -336,7 +353,7 @@ void App::set_model_location(const Location &location) const {
BOOST_LOG_TRIVIAL(debug) << "Updating model location";

if (location == this->model->location) {
BOOST_LOG_TRIVIAL(debug) << "No need to update configured location";
BOOST_LOG_TRIVIAL(debug) << "No need to update model location";

return;
}
Expand Down
4 changes: 0 additions & 4 deletions src/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
using namespace std::placeholders;
using namespace std::string_literals;

namespace std {
template <class T> using optional = std::experimental::optional<T>;
}

namespace taranis {

std::string get_about_content();
Expand Down
5 changes: 5 additions & 0 deletions src/events.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ std::string taranis::format_custom_event_param(int param) {
if (param == CustomEvent::select_location_from_history) {
return "select_location_from_history";
}
if (param == CustomEvent::select_location_from_list) {
return "select_location_from_list";
}
if (param == CustomEvent::show_about_dialog) {
return "show_about_dialog";
}
Expand All @@ -39,6 +42,8 @@ std::string taranis::format_custom_event_param(int param) {
}

std::string taranis::format_event_type(int event_type) {
// Note that char *iv_evttype(int event_type) is not complete...

if (event_type == EVT_INIT) {
return "EVT_INIT";
}
Expand Down
1 change: 1 addition & 0 deletions src/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum CustomEvent {
display_alert,
refresh_data,
select_location_from_history,
select_location_from_list,
show_about_dialog,
toggle_current_location_favorite,

Expand Down
2 changes: 1 addition & 1 deletion src/hourlyforecastbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class HourlyForecastBox : public Widget {
for (int x_screen = this->bounding_box.x; x_screen < width; ++x_screen) {
const double x =
this->forecast_offset * step + (x_screen - this->bounding_box.x);
if (x < xa.front() || x > xa.back()) {
if (x < xa.front() or x > xa.back()) {
continue;
}
double y;
Expand Down
8 changes: 8 additions & 0 deletions src/icons.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ extern const ibitmap icon_13n_2x;
extern const ibitmap icon_50n_2x;
extern const ibitmap icon_favorite;
extern const ibitmap icon_menu;
extern const ibitmap icon_radio_button_checked;
extern const ibitmap icon_radio_button_unchecked;
extern const ibitmap icon_warning;
;

Expand Down Expand Up @@ -55,6 +57,12 @@ class Icons {
if (name == "menu") {
return const_cast<ibitmap *>(&icon_menu);
}
if (name == "radio-button-checked") {
return const_cast<ibitmap *>(&icon_radio_button_checked);
}
if (name == "radio-button-unchecked") {
return const_cast<ibitmap *>(&icon_radio_button_unchecked);
}
if (name == "warning") {
return const_cast<ibitmap *>(&icon_warning);
}
Expand Down
2 changes: 1 addition & 1 deletion src/locationbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class LocationBox : public Widget {
std::string elide_maybe(const std::string &text) const {
SetFont(this->font.get(), BLACK);
const auto text_width = StringWidth(text.c_str());
if (text_width <= this->bounding_box.w || text.size() <= 2) {
if (text_width <= this->bounding_box.w or text.size() <= 2) {
// the second case should not happen unless the default font is
// huge...
return text;
Expand Down
152 changes: 152 additions & 0 deletions src/locationlist.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#include "locationlist.h"

#include <algorithm>
#include <boost/log/trivial.hpp>
#include <inkview.h>

#include "events.h"
#include "util.h"

namespace {
taranis::LocationList *that;

iv_handler application_event_handler;

int last_selected_item_index;
} // namespace

namespace taranis {

LocationList::LocationList(const int icon_size, std::shared_ptr<Fonts> fonts,
std::shared_ptr<Icons> icons)
: font{fonts->get_normal_font()},
radio_button_unchecked{BitmapStretchProportionally(
icons->get("radio-button-unchecked"), icon_size, icon_size)},
radio_button_checked{BitmapStretchProportionally(
icons->get("radio-button-checked"), icon_size, icon_size)} {}

std::optional<Location> LocationList::get_location(size_t index) const {
if (index < this->locations.size()) {
return this->locations.at(index);
}
return std::experimental::nullopt;
}

void LocationList::set_locations(const std::vector<Location> &locations) {
this->locations = locations;

this->item_names.clear();
this->item_names.reserve(this->locations.size());

for (const auto &location : this->locations) {
this->item_names.push_back(format_location(location, true));
}
}

void LocationList::show() {
if (this->locations.size() == 0) {
return;
}
that = this;
application_event_handler = GetEventHandler();

OpenList(GetLangText("Locations"), nullptr, this->get_item_width(),
this->get_item_height(), this->locations.size(), 0,
&handle_list_action);
}

int LocationList::get_item_width() const {
return ScreenWidth() - 2 * LocationList::horizontal_padding;
}

int LocationList::get_item_height() const {
return std::max(static_cast<int>(this->radio_button_unchecked->height),
this->font->height) +
LocationList::vertical_padding;
}

int LocationList::get_icon_vertical_offset() const {
return (get_item_height() - this->radio_button_checked->height) / 2;
}

int LocationList::handle_list_action(int action, int x, int y, int item_index,
int state) {
if (that == nullptr) {
BOOST_LOG_TRIVIAL(debug)
<< "Skipping action received by uninitialized list " << action;
return 1;
}
if (action == LIST_BEGINPAINT) {
BOOST_LOG_TRIVIAL(debug) << "Starting to paint location list";
return 1;
} else if (action == LIST_PAINT) {
if (0 <= item_index and item_index < that->item_names.size()) {
BOOST_LOG_TRIVIAL(debug)
<< "Drawing list item with index " << item_index << " and state "
<< state << " at " << x << ", " << y;

const ibitmap *icon = that->radio_button_unchecked;
if (state) {
if (last_selected_item_index != -1) {
that->item_names[last_selected_item_index] =
format_location(that->locations[last_selected_item_index], true);
}
last_selected_item_index = item_index;
icon = that->radio_button_checked;

DrawSelection(
x, y, ScreenWidth() - 2 * LocationList::horizontal_padding,
that->font->height + +LocationList::vertical_padding, BLACK);
}
DrawBitmap(x + LocationList::horizontal_padding / 2,
y + that->get_icon_vertical_offset(), icon);

DrawTextRect(
x + 2 * LocationList::horizontal_padding + icon->width, y,
ScreenWidth() - 4 * LocationList::horizontal_padding - icon->width,
that->get_item_height(), that->item_names.at(item_index).c_str(),
ALIGN_LEFT | VALIGN_MIDDLE);
return 1;
}
} else if (action == LIST_ENDPAINT) {
BOOST_LOG_TRIVIAL(debug) << "Finished to paint location list";
return 1;
} else if (action == LIST_OPEN) {
if (0 <= item_index and item_index < that->item_names.size()) {
BOOST_LOG_TRIVIAL(debug)
<< "Will select location from item with index " << item_index;

SetEventHandler(application_event_handler);

SendEvent(application_event_handler, EVT_CUSTOM,
CustomEvent::select_location_from_list,
static_cast<size_t>(last_selected_item_index));

return 1;
}
} else if (action == LIST_MENU) {
BOOST_LOG_TRIVIAL(debug) << "Received list menu action";
} else if (action == LIST_DELETE) {
BOOST_LOG_TRIVIAL(debug) << "Received list delete action";
} else if (action == LIST_EXIT) {
BOOST_LOG_TRIVIAL(debug) << "Received list exit action";

SetEventHandler(application_event_handler);

that = nullptr;
return 1;
} else if (action == LIST_ORIENTATION) {
BOOST_LOG_TRIVIAL(debug) << "Changing list orientation is not supported";
} else if (action == LIST_POINTER) {
BOOST_LOG_TRIVIAL(debug) << "Received list pointer action";
} else if (action == LIST_INFO) {
BOOST_LOG_TRIVIAL(debug) << "Received list info action";
last_selected_item_index = -1;
} else if (action == LIST_SCROLL) {
BOOST_LOG_TRIVIAL(debug) << "Received list scroll action";
} else {
BOOST_LOG_TRIVIAL(warning) << "Unexpected list action " << action;
}
return 0;
}
} // namespace taranis
51 changes: 51 additions & 0 deletions src/locationlist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

#include <experimental/optional>
#include <inkview.h>
#include <memory>
#include <string>
#include <vector>

#include "fonts.h"
#include "icons.h"
#include "model.h"

namespace std {
template <class T> using optional = std::experimental::optional<T>;
}

namespace taranis {

class LocationList {
public:
LocationList(int icon_size, std::shared_ptr<Fonts> fonts,
std::shared_ptr<Icons> icons);

std::optional<Location> get_location(size_t index) const;

void set_locations(const std::vector<Location> &locations);

void show();

private:
static constexpr int horizontal_padding{25};
static constexpr int vertical_padding{25};

std::vector<Location> locations;

std::vector<std::string> item_names;

std::shared_ptr<ifont> font;
const ibitmap *const radio_button_unchecked;
const ibitmap *const radio_button_checked;

int get_item_width() const;

int get_item_height() const;

int get_icon_vertical_offset() const;

static int handle_list_action(int action, int x, int y, int item_index,
int state);
};
} // namespace taranis
Loading

0 comments on commit 5515152

Please sign in to comment.