Skip to content

Commit

Permalink
Daily forecast can be used as power off logo
Browse files Browse the repository at this point in the history
Refs: #28
  • Loading branch information
orontee committed Nov 14, 2023
1 parent 5dda0d9 commit eb9d36a
Show file tree
Hide file tree
Showing 19 changed files with 162 additions and 20 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

- Daily forecast can be used as power off logo
[#28](https://github.com/orontee/taranis/issues/28)

- Menu item to edit location
[#68](https://github.com/orontee/taranis/issues/68)

Expand Down
Binary file added icons/icon_wallpaper.bmp
Binary file not shown.
1 change: 1 addition & 0 deletions icons/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ icons = files(
'icon_radio_button_checked.bmp',
'icon_radio_button_unchecked.bmp',
'icon_taranis.bmp',
'icon_wallpaper.bmp',
'icon_warning.bmp'
)

Expand Down
1 change: 0 additions & 1 deletion src/alerts.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class AlertViewer : public ModalWidget {

void hide();

protected:
void do_paint() override;

private:
Expand Down
6 changes: 5 additions & 1 deletion src/app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,11 @@ int App::handle_custom_event(int param_one, int param_two) {
this->model->refresh_date = std::chrono::system_clock::now();
this->history->update_history_maybe();
this->show();

if (this->ui) {
this->ui->generate_logo_maybe();
}

} else if (param_one == CustomEvent::warning_emitted) {
if (param_two == CustomEventParam::invalid_location) {
DialogSynchro(
Expand Down Expand Up @@ -360,7 +365,6 @@ void App::refresh_data(CallContext context) {

void App::open_about_dialog() {
BOOST_LOG_TRIVIAL(debug) << "Opening about dialog";

const auto about_content = get_about_content();
Dialog(ICON_INFORMATION, GetLangText("About"), about_content.c_str(),
GetLangText("Ok"), nullptr, &handle_about_dialog_button_clicked);
Expand Down
2 changes: 1 addition & 1 deletion src/button.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ class Button : public Widget, Activatable {
return {pos_x, pos_y};
}

protected:
void do_paint() override {
const auto [pos_x, pos_y] = this->get_icon_top_left_position();
DrawBitmap(pos_x, pos_y, this->icon);
}

protected:
virtual void on_clicked(){};

private:
Expand Down
12 changes: 9 additions & 3 deletions src/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ char *start_with_daily_forecast_values[] = {

char *custom_api_key_value[] = {const_cast<char *>(""), nullptr};

char *yes_no_values[] = {"@Yes", "@No", nullptr};

// Note that translating is handled by the configuration editor but
// translations must be provided as usual

Expand All @@ -38,6 +40,10 @@ static iconfigedit config_template[] = {
{CFG_TEXT, &icon_key, const_cast<char *>(GetLangText("Custom API key")),
nullptr, const_cast<char *>("api_key"), const_cast<char *>(""),
custom_api_key_value, nullptr},
{CFG_CHOICE, &icon_wallpaper,
const_cast<char *>(GetLangText("Generate shutdown logo")), nullptr,
const_cast<char *>("generate_shutdown_logo"), "@Yes", yes_no_values,
nullptr},
{0}};

// Don't use hints since failed to find a way to change their font
Expand All @@ -51,12 +57,12 @@ Config::Config() {

bool Config::read_bool(const std::string &name, bool default_value) {
return std::strcmp(
ReadString(config, name.c_str(), default_value ? "1" : "0"),
"1") == 0;
ReadString(config, name.c_str(), default_value ? "@Yes" : "@No"),
"@Yes") == 0;
}

void Config::write_bool(const std::string &name, bool value) {
WriteString(config, name.c_str(), value ? "1" : "0");
WriteString(config, name.c_str(), value ? "@Yes" : "@No");
}

int Config::read_int(const std::string &name, int default_value) {
Expand Down
1 change: 0 additions & 1 deletion src/currentconditionbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class CurrentConditionBox : public Widget {
this->bottom_padding);
}

protected:
void do_paint() override {
const auto condition = this->model->current_condition;
if (not condition) {
Expand Down
1 change: 0 additions & 1 deletion src/dailyforecastbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class DailyForecastBox : public Widget {
this->row_height = this->bounding_box.h / DailyForecastBox::row_count;
}

protected:
void do_paint() override {
this->draw_values();
this->draw_frame();
Expand Down
1 change: 0 additions & 1 deletion src/hourlyforecastbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class HourlyForecastBox : public Widget {

void decrease_forecast_offset();

protected:
void do_paint() override;

private:
Expand Down
4 changes: 4 additions & 0 deletions src/icons.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern const ibitmap icon_menu;
extern const ibitmap icon_radio_button_checked;
extern const ibitmap icon_radio_button_unchecked;
extern const ibitmap icon_taranis;
extern const ibitmap icon_wallpaper;
extern const ibitmap icon_warning;
;

Expand Down Expand Up @@ -71,6 +72,9 @@ class Icons {
if (name == "radio-button-unchecked") {
return const_cast<ibitmap *>(&icon_radio_button_unchecked);
}
if (name == "wallpaper") {
return const_cast<ibitmap *>(&icon_wallpaper);
}
if (name == "warning") {
return const_cast<ibitmap *>(&icon_warning);
}
Expand Down
1 change: 0 additions & 1 deletion src/locationbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class LocationBox : public Widget {

void edit_location();

protected:
void do_paint() override {
std::string location_text = format_location(this->model->location);
location_text = elide_maybe(location_text);
Expand Down
74 changes: 74 additions & 0 deletions src/logo.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "logo.h"

#include <boost/log/trivial.hpp>

#include "config.h"
#include "dailyforecastbox.h"
#include "inkview.h"
#include "statusbar.h"

namespace taranis {

Logo::Logo(std::shared_ptr<Model> model, std::shared_ptr<Icons> icons,
std::shared_ptr<Fonts> fonts)
: Widget{0, 0, ScreenWidth(), ScreenHeight()},
location_box{0, 0, model, fonts}, status_bar{model, fonts},
forecast_box{0,
this->location_box.get_height() + Logo::vertical_padding,
ScreenWidth(),
ScreenHeight() - 2 * Logo::vertical_padding -
this->location_box.get_height() -
this->status_bar.get_height(),
model,
icons,
fonts} {}

void Logo::do_paint() {
this->location_box.do_paint();
this->status_bar.do_paint();
this->forecast_box.do_paint();
}

void LogoGenerator::generate_maybe() const {
Config config;
const auto must_generate = config.read_bool("generate_shutdown_logo", false);
if (must_generate) {
this->generate();
} else {
BOOST_LOG_TRIVIAL(debug) << "Skipping logo generation";
}
}

void LogoGenerator::generate() const {
BOOST_LOG_TRIVIAL(debug) << "Generating new logo";

auto *const original_canvas = GetCanvas();
if (not original_canvas) {
return;
}
std::vector<unsigned char> data;
data.resize(ScreenHeight() * ScreenWidth());

icanvas canvas{ScreenWidth(),
ScreenHeight(),
ScreenWidth(),
original_canvas->depth,
0,
ScreenWidth(),
0,
ScreenHeight(),
data.data()};
SetCanvas(&canvas);

Logo logo{this->model, this->icons, this->fonts};
logo.paint();

const auto bitmap =
BitmapFromCanvas(0, 0, ScreenWidth(), ScreenHeight(), 0, &canvas);
const auto filename =
std::string{USEROFFLOGOPATH} + "/taranis_weather_forecast.bmp";
SaveBitmap(filename.data(), bitmap);

SetCanvas(original_canvas);
}
} // namespace taranis
46 changes: 46 additions & 0 deletions src/logo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include <inkview.h>
#include <memory>

#include "dailyforecastbox.h"
#include "fonts.h"
#include "icons.h"
#include "locationbox.h"
#include "model.h"
#include "statusbar.h"
#include "widget.h"

namespace taranis {

class Logo : public Widget {
public:
Logo(std::shared_ptr<Model> model, std::shared_ptr<Icons> icons,
std::shared_ptr<Fonts> fonts);

void do_paint() override;

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

LocationBox location_box;
StatusBar status_bar;
DailyForecastBox forecast_box;
};

struct LogoGenerator {
LogoGenerator(std::shared_ptr<Model> model, std::shared_ptr<Icons> icons,
std::shared_ptr<Fonts> fonts)
: model{model}, icons{icons}, fonts{fonts} {}

void generate_maybe() const;

private:
std::shared_ptr<Model> model;
std::shared_ptr<Icons> icons;
std::shared_ptr<Fonts> fonts;

void generate() const;
};
} // namespace taranis
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ sources = [about_cc, icons_cc, l10n_cc] + files(
'locationbox.cc',
'locationselector.cc',
'logging.cc',
'logo.cc',
'main.cc',
'menu.cc',
'service.cc',
Expand Down
11 changes: 5 additions & 6 deletions src/statusbar.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

#include <ctime>
#include <experimental/optional>
#include <inkview.h>
#include <memory>
#include <sstream>

#include "experimental/optional"
#include "fonts.h"
#include "model.h"
#include "util.h"
Expand All @@ -25,7 +25,6 @@ class StatusBar : public Widget {
this->set_bounding_box(pos_x, pos_y, width, height);
}

protected:
void do_paint() override {
std::stringstream first_row_text;
if (this->model->refresh_date == std::experimental::nullopt) {
Expand All @@ -51,12 +50,12 @@ class StatusBar : public Widget {
}

private:
static constexpr int left_padding{50};
static constexpr int top_padding{50};
static constexpr int bottom_padding{25};

std::shared_ptr<Model> model;
std::shared_ptr<ifont> font;

const int left_padding{50};
const int top_padding{50};
const int bottom_padding{25};
};

} // namespace taranis
7 changes: 7 additions & 0 deletions src/ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "keys.h"
#include "locationbox.h"
#include "locationselector.h"
#include "logo.h"
#include "menu.h"
#include "model.h"
#include "statusbar.h"
Expand Down Expand Up @@ -87,6 +88,7 @@ Ui::Ui(std::shared_ptr<Model> model)

void Ui::paint() {
ClearScreen();
// Will justify to call do_paint() on children and not paint()

this->check_modal_visibility();

Expand Down Expand Up @@ -140,6 +142,11 @@ Ui::get_location_from_location_list(size_t index) const {
return this->location_selector->get_location(index);
}

void Ui::generate_logo_maybe() const {
LogoGenerator generator{this->model, this->icons, this->fonts};
generator.generate_maybe();
}

bool Ui::is_consumer_active(std::shared_ptr<KeyEventConsumer> consumer) {
return ((consumer == this->visible_modal) or not this->visible_modal);
// modals expected to register / unregister on visibility change
Expand Down
6 changes: 4 additions & 2 deletions src/ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,18 @@ class Ui : public KeyEventDispatcher {
int handle_pointer_event(int event_type, int pointer_pos_x,
int pointer_pos_y);

void edit_location() { this->location_box->edit_location(); }

void display_alert() { this->alert_viewer->open(); }

void switch_forecast_widget();

void edit_location() { this->location_box->edit_location(); }

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

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

void generate_logo_maybe() const;

protected:
bool is_consumer_active(std::shared_ptr<KeyEventConsumer> consumer) override;

Expand Down
4 changes: 2 additions & 2 deletions src/widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ struct Widget : public KeyEventConsumer {
// screen could be outdated after a visibility update
}

virtual void do_paint() = 0;

bool is_in_bouding_box(int pos_x, int pos_y) const {
return IsInRect(pos_x, pos_y, &this->bounding_box);
}
Expand All @@ -76,8 +78,6 @@ struct Widget : public KeyEventConsumer {

void fill_bounding_box() const { FillAreaRect(&this->bounding_box, WHITE); }

virtual void do_paint() = 0;

void set_bounding_box(int pos_x, int pos_y, int width, int height) {
this->bounding_box.x = pos_x;
this->bounding_box.y = pos_y;
Expand Down

0 comments on commit eb9d36a

Please sign in to comment.