Compare commits

..

7 Commits

9 changed files with 389 additions and 1 deletions

View File

@ -432,6 +432,7 @@ list(APPEND SOURCE_FILES
displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFaceTerminal.cpp
displayapp/screens/WatchFacePineTimeStyle.cpp displayapp/screens/WatchFacePineTimeStyle.cpp
displayapp/screens/WatchFaceCasioStyleG7710.cpp displayapp/screens/WatchFaceCasioStyleG7710.cpp
displayapp/screens/WatchFaceHorizon.cpp
## ##

View File

@ -15,6 +15,7 @@
#include "displayapp/screens/WatchFaceInfineat.h" #include "displayapp/screens/WatchFaceInfineat.h"
#include "displayapp/screens/WatchFacePineTimeStyle.h" #include "displayapp/screens/WatchFacePineTimeStyle.h"
#include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/WatchFaceTerminal.h"
#include "displayapp/screens/WatchFaceHorizon.h"
namespace Pinetime { namespace Pinetime {
namespace Applications { namespace Applications {

View File

@ -57,6 +57,7 @@ namespace Pinetime {
Terminal, Terminal,
Infineat, Infineat,
CasioStyleG7710, CasioStyleG7710,
Horizon
}; };
template <Apps> template <Apps>

View File

@ -30,6 +30,7 @@ else()
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Horizon")
set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware") set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware")
endif() endif()

View File

@ -0,0 +1,250 @@
#include "displayapp/screens/WatchFaceHorizon.h"
#include <lvgl/lvgl.h>
#include <cstdio>
#include "components/settings/Settings.h"
#include "components/battery/BatteryController.h"
#include "components/motion/MotionController.h"
#include "utility/DirtyValue.h"
using namespace Pinetime::Applications::Screens;
WatchFaceHorizon::WatchFaceHorizon(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController,
Controllers::FS& filesystem)
: currentDateTime {{}},
dateTimeController {dateTimeController},
batteryController {batteryController},
settingsController {settingsController},
motionController {motionController} {
lfs_file f = {};
if (filesystem.FileOpen(&f, "/fonts/pinecone_28.bin", LFS_O_RDONLY) >= 0) {
filesystem.FileClose(&f);
font_pinecone_28 = lv_font_load("F:/fonts/pinecone_28.bin");
}
if (filesystem.FileOpen(&f, "/fonts/pinecone_70.bin", LFS_O_RDONLY) >= 0) {
filesystem.FileClose(&f);
font_pinecone_70 = lv_font_load("F:/fonts/pinecone_70.bin");
}
// Black background covering the whole screen
background = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_size(background, 240, 240);
lv_obj_align(background, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0);
// Battery indicator line
lineBatteryBg = lv_line_create(lv_scr_act(), nullptr);
lineBatteryFg = lv_line_create(lv_scr_act(), nullptr);
lv_style_init(&lineBatteryBgStyle);
lv_style_set_line_width(&lineBatteryBgStyle, LV_STATE_DEFAULT, 4);
lv_style_set_line_color(&lineBatteryBgStyle, LV_STATE_DEFAULT, lv_color_hex(0x181818));
lv_obj_add_style(lineBatteryBg, LV_LINE_PART_MAIN, &lineBatteryBgStyle);
lineBatteryBgPoints[0] = {116, 40};
lineBatteryBgPoints[1] = {116, 200};
lv_line_set_points(lineBatteryBg, lineBatteryBgPoints, 2);
lv_style_init(&lineBatteryFgStyle);
lv_style_set_line_width(&lineBatteryFgStyle, LV_STATE_DEFAULT, 4);
lv_style_set_line_color(&lineBatteryFgStyle, LV_STATE_DEFAULT, lv_color_hex(hourlyColors[0]));
lv_obj_add_style(lineBatteryFg, LV_LINE_PART_MAIN, &lineBatteryFgStyle);
lineBatteryFgPoints[0] = {116, 40};
lineBatteryFgPoints[1] = {116, 200};
lv_line_set_points(lineBatteryFg, lineBatteryFgPoints, 2);
// Hour indicator lines at bottom
for (int i = 0; i < 24; i++) {
hourLines[i] = lv_line_create(lv_scr_act(), nullptr);
lv_style_init(&hourLineStyles[i]);
lv_style_set_line_width(&hourLineStyles[i], LV_STATE_DEFAULT, 5);
lv_style_set_line_color(&hourLineStyles[i], LV_STATE_DEFAULT, lv_color_hex(hourlyColors[i]));
lv_obj_add_style(hourLines[i], LV_LINE_PART_MAIN, &hourLineStyles[i]);
hourLinePoints[i][0] = {static_cast<lv_coord_t>(i * 10), 237};
hourLinePoints[i][1] = {static_cast<lv_coord_t>((i + 1) * 10), 237};
lv_line_set_points(hourLines[i], hourLinePoints[i], 2);
}
// Hour (split digits due to non-monospaced font)
labelHourFirstDigit = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelHourFirstDigit, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_70);
lv_label_set_text(labelHourFirstDigit, "0");
lv_obj_align(labelHourFirstDigit, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 130, -43);
labelHourSecondDigit = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelHourSecondDigit, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_70);
lv_label_set_text(labelHourSecondDigit, "0");
lv_obj_align(labelHourSecondDigit, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 174, -43);
// Minutes (split digits due to non-monospaced font)
labelMinutesFirstDigit = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelMinutesFirstDigit, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_70);
lv_label_set_text(labelMinutesFirstDigit, "0");
lv_obj_align(labelMinutesFirstDigit, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 130, 44);
labelMinutesSecondDigit = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelMinutesSecondDigit, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_70);
lv_label_set_text(labelMinutesSecondDigit, "0");
lv_obj_align(labelMinutesSecondDigit, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 174, 44);
// Day of week
labelDayOfWeek = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(labelDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xbebebe));
lv_obj_set_style_local_text_font(labelDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_28);
lv_obj_align(labelDayOfWeek, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -140, -60);
lv_label_set_text(labelDayOfWeek, "MON");
// Month
labelMonth = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_28);
lv_obj_align(labelMonth, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -140, -20);
lv_label_set_text(labelMonth, "JAN");
// Day of month
labelDate = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xbebebe));
lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_28);
lv_obj_align(labelDate, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -140, 20);
lv_label_set_text(labelDate, "01");
// Number of steps
stepValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_pinecone_28);
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -140, 60);
lv_label_set_text(stepValue, "0");
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Refresh();
}
WatchFaceHorizon::~WatchFaceHorizon() {
lv_task_del(taskRefresh);
// Reset styles
lv_style_reset(&lineBatteryFgStyle);
lv_style_reset(&lineBatteryBgStyle);
for (int i = 0; i < 24; i++) {
lv_style_reset(&hourLineStyles[i]);
}
// Free font resources
if (font_pinecone_28 != nullptr) {
lv_font_free(font_pinecone_28);
}
if (font_pinecone_70 != nullptr) {
lv_font_free(font_pinecone_70);
}
lv_obj_clean(lv_scr_act());
}
void WatchFaceHorizon::Refresh() {
currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
uint8_t hour = dateTimeController.Hours();
uint8_t minute = dateTimeController.Minutes();
uint8_t day = dateTimeController.Day();
char minutesChar[3];
sprintf(minutesChar, "%02d", static_cast<int>(minute));
char hoursChar[3];
int displayHour = hour;
// Account for 12-hour time
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
if (hour < 12) {
if (hour == 0) {
displayHour = 12;
}
} else {
if (hour != 12) {
displayHour = hour - 12;
}
}
}
sprintf(hoursChar, "%02d", displayHour);
// Hour has updated
if (hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1]) {
displayedChar[0] = hoursChar[0];
displayedChar[1] = hoursChar[1];
// Update colors appropriately
lv_obj_set_style_local_text_color(labelHourFirstDigit, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(hourlyColors[hour]));
lv_obj_set_style_local_text_color(labelHourSecondDigit, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(hourlyColors[hour]));
lv_obj_set_style_local_text_color(labelMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(hourlyColors[hour]));
lv_style_set_line_color(&lineBatteryFgStyle, LV_STATE_DEFAULT, lv_color_hex(hourlyColors[hour]));
lv_label_set_text_fmt(labelHourFirstDigit, "%c", hoursChar[0]);
lv_label_set_text_fmt(labelHourSecondDigit, "%c", hoursChar[1]);
// Update hour bar on bottom
for (int i = 0; i < 24; i++) {
if (i <= hour) {
lv_obj_set_hidden(hourLines[i], false);
} else {
lv_obj_set_hidden(hourLines[i], true);
}
}
}
// Minutes have updated
if (minutesChar[0] != displayedChar[2] || minutesChar[1] != displayedChar[3]) {
displayedChar[2] = minutesChar[0];
displayedChar[3] = minutesChar[1];
lv_label_set_text_fmt(labelMinutesFirstDigit, "%c", minutesChar[0]);
lv_label_set_text_fmt(labelMinutesSecondDigit, "%c", minutesChar[1]);
}
// Date has updated
currentDate = std::chrono::time_point_cast<std::chrono::days>(currentDateTime.Get());
if (currentDate.IsUpdated()) {
lv_label_set_text_fmt(labelDayOfWeek, "%s", dateTimeController.DayOfWeekShortToString());
lv_label_set_text_fmt(labelMonth, "%s", dateTimeController.MonthShortToString());
lv_label_set_text_fmt(labelDate, "%d", day);
lv_obj_realign(labelDayOfWeek);
lv_obj_realign(labelMonth);
lv_obj_realign(labelDate);
}
}
// Set battery line
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
lineBatteryFgPoints[0] = {116, static_cast<lv_coord_t>(200 - (1.6 * batteryPercentRemaining.Get()))};
lv_line_set_points(lineBatteryFg, lineBatteryFgPoints, 2);
}
// Set step count
stepCount = motionController.NbSteps();
if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_obj_realign(stepValue);
}
}
bool WatchFaceHorizon::IsAvailable(Pinetime::Controllers::FS& filesystem) {
lfs_file file = {};
if (filesystem.FileOpen(&file, "/fonts/pinecone_28.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
if (filesystem.FileOpen(&file, "/fonts/pinecone_70.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
return true;
}

View File

@ -0,0 +1,109 @@
#pragma once
#include <lvgl/lvgl.h>
#include <chrono>
#include <cstdint>
#include <memory>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "components/ble/BleController.h"
#include "utility/DirtyValue.h"
#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Controllers {
class Settings;
class Battery;
class MotionController;
}
namespace Applications {
namespace Screens {
class WatchFaceHorizon : public Screen {
public:
WatchFaceHorizon(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController,
Controllers::FS& fs);
~WatchFaceHorizon() override;
void Refresh() override;
static bool IsAvailable(Pinetime::Controllers::FS& filesystem);
private:
char displayedChar[5] {};
uint16_t currentYear = 1970;
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
uint8_t currentDay = 0;
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
Utility::DirtyValue<bool> motionSensorOk {};
Utility::DirtyValue<uint32_t> stepCount {};
lv_obj_t* background;
lv_obj_t* hourLines[24];
lv_style_t hourLineStyles[24];
lv_point_t hourLinePoints[24][2];
lv_obj_t* labelHourFirstDigit;
lv_obj_t* labelHourSecondDigit;
lv_obj_t* labelMinutesFirstDigit;
lv_obj_t* labelMinutesSecondDigit;
lv_obj_t* lineBatteryFg;
lv_obj_t* lineBatteryBg;
lv_style_t lineBatteryFgStyle;
lv_style_t lineBatteryBgStyle;
lv_point_t lineBatteryFgPoints[2];
lv_point_t lineBatteryBgPoints[2];
lv_obj_t* labelDayOfWeek;
lv_obj_t* labelMonth;
lv_obj_t* labelDate;
lv_obj_t* stepValue;
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
lv_task_t* taskRefresh;
lv_font_t* font_pinecone_28 = nullptr;
lv_font_t* font_pinecone_70 = nullptr;
int hourlyColors[24] = {0x353f76, 0x415587, 0x4e6a98, 0x5a80a9, 0x6696ba, 0x7fa5b1, 0x98b5a7, 0xb0c49e,
0xc9d494, 0xe2e38b, 0xe3d780, 0xe4ca75, 0xe5be69, 0xe6b15e, 0xe7a553, 0xd29357,
0xbd815b, 0xa86f60, 0x935d64, 0x7e4b68, 0x6d4467, 0x4b3766, 0x3a3066, 0x292965};
};
}
template <>
struct WatchFaceTraits<WatchFace::Horizon> {
static constexpr WatchFace watchFace = WatchFace::Horizon;
static constexpr const char* name = "Horizon";
static Screens::Screen* Create;/*(AppControllers& controllers) {
return new Screens::WatchFaceHorizon(controllers.dateTimeController,
controllers.batteryController,
controllers.settingsController,
controllers.motionController,
controllers.filesystem);
};*/
static bool IsAvailable(Pinetime::Controllers::FS& filesystem) {
return Screens::WatchFaceHorizon::IsAvailable(filesystem);
}
};
}
}

View File

@ -11,6 +11,7 @@
#include "displayapp/screens/CheckboxList.h" #include "displayapp/screens/CheckboxList.h"
#include "displayapp/screens/WatchFaceInfineat.h" #include "displayapp/screens/WatchFaceInfineat.h"
#include "displayapp/screens/WatchFaceCasioStyleG7710.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h"
#include "displayapp/screens/WatchFaceHorizon.h"
namespace Pinetime { namespace Pinetime {

View File

@ -58,5 +58,29 @@
"size": 115, "size": 115,
"format": "bin", "format": "bin",
"target_path": "/fonts/" "target_path": "/fonts/"
} },
"pinecone_28" : {
"sources": [
{
"file": "fonts/Pinecone-Regular.ttf",
"symbols": "0123456789MONTUEWDHFRISAJBPYLGCV"
}
],
"bpp": 1,
"size": 28,
"format": "bin",
"target_path": "/fonts/"
},
"pinecone_70" : {
"sources": [
{
"file": "fonts/Pinecone-Regular.ttf",
"symbols": "0123456789"
}
],
"bpp": 1,
"size": 70,
"format": "bin",
"target_path": "/fonts/"
}
} }

Binary file not shown.