Merge branch 'develop' into HEAD

This commit is contained in:
Riku Isokoski
2021-08-01 11:47:26 +03:00
139 changed files with 5350 additions and 1804 deletions

View File

@@ -51,7 +51,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
{Symbols::map, Apps::Navigation},
{Symbols::shoe, Apps::Steps},
{Symbols::heartBeat, Apps::HeartRate},
{"", Apps::None},
{Symbols::hourGlass, Apps::Timer},
}};
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
@@ -62,8 +62,8 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
{Symbols::paintbrush, Apps::Paint},
{Symbols::paddle, Apps::Paddle},
{"2", Apps::Twos},
{"M", Apps::Motion},
{"", Apps::None},
{Symbols::chartLine, Apps::Motion},
{Symbols::drum, Apps::Metronome},
{"", Apps::None},
}};

View File

@@ -1,9 +1,10 @@
#include <cstdint>
#include "BatteryIcon.h"
#include "Symbols.h"
using namespace Pinetime::Applications::Screens;
const char* BatteryIcon::GetBatteryIcon(int batteryPercent) {
const char* BatteryIcon::GetBatteryIcon(uint8_t batteryPercent) {
if (batteryPercent > 90)
return Symbols::batteryFull;
if (batteryPercent > 75)

View File

@@ -6,7 +6,7 @@ namespace Pinetime {
class BatteryIcon {
public:
static const char* GetUnknownIcon();
static const char* GetBatteryIcon(int batteryPercent);
static const char* GetBatteryIcon(uint8_t batteryPercent);
static const char* GetPlugIcon(bool isCharging);
};
}

View File

@@ -9,11 +9,6 @@ static void lv_update_task(struct _lv_task_t* task) {
user_data->UpdateScreen();
}
static void lv_anim_task(struct _lv_task_t* task) {
auto user_data = static_cast<BatteryInfo*>(task->user_data);
user_data->UpdateAnim();
}
BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
: Screen(app), batteryController {batteryController} {
@@ -24,12 +19,12 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
lv_obj_set_size(charging_bar, 200, 15);
lv_bar_set_range(charging_bar, 0, 100);
lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10);
lv_bar_set_anim_time(charging_bar, 2000);
lv_bar_set_anim_time(charging_bar, 1000);
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF);
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
status = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(status, "Reading Battery status");
@@ -38,24 +33,13 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
percent = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
if (batteryPercent >= 0) {
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
} else {
lv_label_set_text(percent, "--%");
}
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
// hack to not use the flot functions from printf
uint8_t batteryVoltageBytes[2];
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
batteryVoltageBytes[0] =
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
//
voltage = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC6A600));
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
@@ -65,40 +49,15 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_LOW, this);
taskAnim = lv_task_create(lv_anim_task, 1000, LV_TASK_PRIO_LOW, this);
taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_LOW, this);
UpdateScreen();
}
BatteryInfo::~BatteryInfo() {
lv_task_del(taskUpdate);
lv_task_del(taskAnim);
lv_obj_clean(lv_scr_act());
}
void BatteryInfo::UpdateAnim() {
batteryPercent = batteryController.PercentRemaining();
if (batteryPercent >= 0) {
if (batteryController.IsCharging() and batteryPercent < 100) {
animation += 1;
if (animation >= 100) {
animation = 0;
}
} else {
if (animation > batteryPercent) {
animation--;
}
if (animation < batteryPercent) {
animation++;
}
}
lv_bar_set_value(charging_bar, animation, LV_ANIM_OFF);
}
}
void BatteryInfo::UpdateScreen() {
batteryController.Update();
@@ -106,39 +65,27 @@ void BatteryInfo::UpdateScreen() {
batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage();
if (batteryPercent >= 0) {
if (batteryController.IsCharging() and batteryPercent < 100) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_label_set_text_static(status, "Battery charging");
} else if (batteryPercent == 100) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_label_set_text_static(status, "Battery is fully charged");
} else if (batteryPercent < 10) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_label_set_text_static(status, "Battery is low");
} else {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_label_set_text_static(status, "Battery discharging");
}
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
if (batteryController.IsCharging() and batteryPercent < 100) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_label_set_text_static(status, "Charging");
} else if (batteryPercent == 100) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_label_set_text_static(status, "Fully charged");
} else if (batteryPercent < 10) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_label_set_text_static(status, "Battery low");
} else {
lv_label_set_text_static(status, "Reading Battery status");
lv_label_set_text(percent, "--%");
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_label_set_text_static(status, "Discharging");
}
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
// hack to not use the flot functions from printf
uint8_t batteryVoltageBytes[2];
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
batteryVoltageBytes[0] =
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
//
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
}
bool BatteryInfo::Refresh() {
return running;
}

View File

@@ -22,7 +22,6 @@ namespace Pinetime {
bool Refresh() override;
void UpdateScreen();
void UpdateAnim();
private:
Pinetime::Controllers::Battery& batteryController;
@@ -33,11 +32,9 @@ namespace Pinetime {
lv_obj_t* status;
lv_task_t* taskUpdate;
lv_task_t* taskAnim;
int8_t animation = 0;
int8_t batteryPercent = -1;
float batteryVoltage = 0.0f;
uint8_t batteryPercent = 0;
uint16_t batteryVoltage = 0;
};
}
}

View File

@@ -14,6 +14,7 @@
#include "../DisplayApp.h"
#include "WatchFaceDigital.h"
#include "WatchFaceAnalog.h"
#include "PineTimeStyle.h"
using namespace Pinetime::Applications::Screens;
@@ -33,21 +34,20 @@ Clock::Clock(DisplayApp* app,
settingsController {settingsController},
heartRateController {heartRateController},
motionController {motionController},
screens {app,
settingsController.GetClockFace(),
{
[this]() -> std::unique_ptr<Screen> {
return WatchFaceDigitalScreen();
},
[this]() -> std::unique_ptr<Screen> {
return WatchFaceAnalogScreen();
},
// Examples for more watch faces
//[this]() -> std::unique_ptr<Screen> { return WatchFaceMinimalScreen(); },
//[this]() -> std::unique_ptr<Screen> { return WatchFaceCustomScreen(); }
},
Screens::ScreenListModes::LongPress} {
screen {[this, &settingsController]() {
switch (settingsController.GetClockFace()) {
case 0:
return WatchFaceDigitalScreen();
break;
case 1:
return WatchFaceAnalogScreen();
break;
case 2:
return PineTimeStyleScreen();
break;
}
return WatchFaceDigitalScreen();
}()} {
settingsController.SetAppMenu(0);
}
@@ -56,12 +56,12 @@ Clock::~Clock() {
}
bool Clock::Refresh() {
screens.Refresh();
screen->Refresh();
return running;
}
bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
return screen->OnTouchEvent(event);
}
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
@@ -80,6 +80,16 @@ std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
}
std::unique_ptr<Screen> Clock::PineTimeStyleScreen() {
return std::make_unique<Screens::PineTimeStyle>(app,
dateTimeController,
batteryController,
bleController,
notificatioManager,
settingsController,
motionController);
}
/*
// Examples for more watch faces
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {

View File

@@ -4,8 +4,8 @@
#include <chrono>
#include <cstdint>
#include <memory>
#include <components/heartrate/HeartRateController.h>
#include "Screen.h"
#include "ScreenList.h"
#include "components/datetime/DateTimeController.h"
namespace Pinetime {
@@ -47,9 +47,10 @@ namespace Pinetime {
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
ScreenList<2> screens;
std::unique_ptr<Screen> screen;
std::unique_ptr<Screen> WatchFaceDigitalScreen();
std::unique_ptr<Screen> WatchFaceAnalogScreen();
std::unique_ptr<Screen> PineTimeStyleScreen();
// Examples for more watch faces
// std::unique_ptr<Screen> WatchFaceMinimalScreen();

View File

@@ -27,9 +27,10 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime
lv_bar_set_value(bar1, 0, LV_ANIM_OFF);
percentLabel = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text(percentLabel, "");
lv_label_set_text(percentLabel, "Waiting...");
lv_obj_set_auto_realign(percentLabel, true);
lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60);
startTime = xTaskGetTickCount();
}
FirmwareUpdate::~FirmwareUpdate() {
@@ -40,26 +41,42 @@ bool FirmwareUpdate::Refresh() {
switch (bleController.State()) {
default:
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
// This condition makes sure that the app is exited if somehow it got
// launched without a firmware update. This should never happen.
if (state != States::Error) {
if (xTaskGetTickCount() - startTime > (60 * 1024)) {
UpdateError();
state = States::Error;
}
} else if (xTaskGetTickCount() - startTime > (5 * 1024)) {
running = false;
}
break;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
if (state != States::Running)
state = States::Running;
return DisplayProgression();
DisplayProgression();
break;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
if (state != States::Validated) {
UpdateValidated();
state = States::Validated;
}
return running;
break;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
if (state != States::Error) {
UpdateError();
state = States::Error;
}
return running;
if (xTaskGetTickCount() - startTime > (5 * 1024)) {
running = false;
}
break;
}
return running;
}
bool FirmwareUpdate::DisplayProgression() const {
void FirmwareUpdate::DisplayProgression() const {
float current = bleController.FirmwareUpdateCurrentBytes() / 1024.0f;
float total = bleController.FirmwareUpdateTotalBytes() / 1024.0f;
int16_t pc = (current / total) * 100.0f;
@@ -67,7 +84,6 @@ bool FirmwareUpdate::DisplayProgression() const {
lv_label_set_text(percentLabel, percentStr);
lv_bar_set_value(bar1, pc, LV_ANIM_OFF);
return running;
}
void FirmwareUpdate::UpdateValidated() {
@@ -78,4 +94,9 @@ void FirmwareUpdate::UpdateValidated() {
void FirmwareUpdate::UpdateError() {
lv_label_set_recolor(percentLabel, true);
lv_label_set_text(percentLabel, "#ff0000 Error!#");
startTime = xTaskGetTickCount();
}
bool FirmwareUpdate::OnButtonPushed() {
return true;
}

View File

@@ -2,6 +2,7 @@
#include "Screen.h"
#include <lvgl/src/lv_core/lv_obj.h>
#include "FreeRTOS.h"
namespace Pinetime {
namespace Controllers {
@@ -25,13 +26,17 @@ namespace Pinetime {
lv_obj_t* titleLabel;
mutable char percentStr[10];
States state;
States state = States::Idle;
bool DisplayProgression() const;
void DisplayProgression() const;
bool OnButtonPushed() override;
void UpdateValidated();
void UpdateError();
TickType_t startTime;
};
}
}

View File

@@ -16,19 +16,18 @@ namespace {
FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator)
: Screen {app}, validator {validator} {
labelVersionInfo = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_label_set_text(labelVersionInfo, "Version : ");
lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT);
labelVersionValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
lv_label_set_recolor(labelVersionValue, true);
sprintf(version, "%ld.%ld.%ld", Version::Major(), Version::Minor(), Version::Patch());
lv_label_set_text(labelVersionValue, version);
labelVersion = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_fmt(labelVersion,
"Version : %d.%d.%d\n"
"ShortRef : %s",
Version::Major(),
Version::Minor(),
Version::Patch(),
Version::GitCommitHash());
lv_obj_align(labelVersion, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
labelIsValidated = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(labelIsValidated, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 50);
lv_obj_align(labelIsValidated, labelVersion, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
lv_label_set_recolor(labelIsValidated, true);
lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK);
lv_obj_set_width(labelIsValidated, 240);

View File

@@ -23,9 +23,7 @@ namespace Pinetime {
private:
Pinetime::Controllers::FirmwareValidator& validator;
lv_obj_t* labelVersionInfo;
lv_obj_t* labelVersionValue;
char version[9];
lv_obj_t* labelVersion;
lv_obj_t* labelIsValidated;
lv_obj_t* buttonValidate;
lv_obj_t* labelButtonValidate;

View File

@@ -39,14 +39,14 @@ FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
backgroundAction->user_data = this;
lv_obj_set_event_cb(backgroundAction, event_handler);
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
}
FlashLight::~FlashLight() {
lv_obj_clean(lv_scr_act());
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
brightness.Restore();
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
@@ -70,5 +70,5 @@ bool FlashLight::Refresh() {
}
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return true;
return false;
}

View File

@@ -63,12 +63,12 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
label_startStop = lv_label_create(btn_startStop, nullptr);
UpdateStartStopButton(isHrRunning);
if (isHrRunning)
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
}
HeartRate::~HeartRate() {
lv_obj_clean(lv_scr_act());
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
bool HeartRate::Refresh() {
@@ -95,12 +95,12 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
heartRateController.Start();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
} else {
heartRateController.Stop();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
}
}

View File

@@ -15,8 +15,6 @@ namespace Pinetime {
bool Refresh() override;
private:
bool running = true;
lv_obj_t* labelText = nullptr;
lv_point_t pageIndicatorBasePoints[2];
lv_point_t pageIndicatorPoints[2];
@@ -25,4 +23,4 @@ namespace Pinetime {
};
}
}
}
}

View File

@@ -0,0 +1,169 @@
#include "Metronome.h"
#include "Screen.h"
#include "Symbols.h"
#include "lvgl/lvgl.h"
#include "FreeRTOSConfig.h"
#include "task.h"
#include <string>
#include <tuple>
using namespace Pinetime::Applications::Screens;
namespace {
float calculateDelta(const TickType_t startTime, const TickType_t currentTime) {
TickType_t delta = 0;
// Take care of overflow
if (startTime > currentTime) {
delta = 0xffffffff - startTime;
delta += (currentTime + 1);
} else {
delta = currentTime - startTime;
}
return static_cast<float>(delta) / static_cast<float>(configTICK_RATE_HZ);
}
static void eventHandler(lv_obj_t* obj, lv_event_t event) {
Metronome* screen = static_cast<Metronome*>(obj->user_data);
screen->OnEvent(obj, event);
}
lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x = 0, uint8_t y = 0) {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_label_set_text(label, name);
lv_obj_align(label, reference, align, x, y);
return label;
}
}
Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask)
: Screen(app), running {true}, currentState {States::Stopped}, startTime {}, motorController {motorController}, systemTask {systemTask} {
bpmArc = lv_arc_create(lv_scr_act(), nullptr);
bpmArc->user_data = this;
lv_obj_set_event_cb(bpmArc, eventHandler);
lv_arc_set_bg_angles(bpmArc, 0, 270);
lv_arc_set_rotation(bpmArc, 135);
lv_arc_set_range(bpmArc, 40, 220);
lv_arc_set_value(bpmArc, bpm);
lv_obj_set_size(bpmArc, 210, 210);
lv_arc_set_adjustable(bpmArc, true);
lv_obj_align(bpmArc, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 7);
bpmValue = createLabel(std::to_string(lv_arc_get_value(bpmArc)).c_str(), bpmArc, LV_ALIGN_IN_TOP_MID, &jetbrains_mono_76, 0, 55);
bpmLegend = createLabel("bpm", bpmValue, LV_ALIGN_OUT_BOTTOM_MID, &jetbrains_mono_bold_20, 0, 0);
bpmTap = lv_btn_create(lv_scr_act(), nullptr);
bpmTap->user_data = this;
lv_obj_set_event_cb(bpmTap, eventHandler);
lv_obj_set_style_local_bg_opa(bpmTap, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_obj_set_height(bpmTap, 80);
lv_obj_align(bpmTap, bpmValue, LV_ALIGN_IN_TOP_MID, 0, 0);
bpbDropdown = lv_dropdown_create(lv_scr_act(), nullptr);
bpbDropdown->user_data = this;
lv_obj_set_event_cb(bpbDropdown, eventHandler);
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_MAIN, LV_STATE_DEFAULT, 20);
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_LIST, LV_STATE_DEFAULT, 20);
lv_obj_align(bpbDropdown, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 15, -4);
lv_dropdown_set_options(bpbDropdown, "1\n2\n3\n4\n5\n6\n7\n8\n9");
lv_dropdown_set_selected(bpbDropdown, bpb - 1);
bpbLegend = lv_label_create(bpbDropdown, nullptr);
lv_label_set_text(bpbLegend, "bpb");
lv_obj_align(bpbLegend, bpbDropdown, LV_ALIGN_IN_RIGHT_MID, -15, 0);
playPause = lv_btn_create(lv_scr_act(), nullptr);
playPause->user_data = this;
lv_obj_set_event_cb(playPause, eventHandler);
lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10);
lv_obj_set_height(playPause, 39);
playPauseLabel = lv_label_create(playPause, nullptr);
lv_label_set_text(playPauseLabel, Symbols::play);
app->SetTouchMode(DisplayApp::TouchModes::Polling);
}
Metronome::~Metronome() {
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
bool Metronome::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return true;
}
bool Metronome::Refresh() {
switch (currentState) {
case States::Stopped: {
break;
}
case States::Running: {
if (calculateDelta(startTime, xTaskGetTickCount()) >= (60.0 / bpm)) {
counter--;
startTime -= 60.0 / bpm;
startTime = xTaskGetTickCount();
if (counter == 0) {
counter = bpb;
motorController.SetDuration(90);
} else {
motorController.SetDuration(30);
}
}
break;
}
}
return running;
}
void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
switch (event) {
case LV_EVENT_VALUE_CHANGED: {
if (obj == bpmArc) {
bpm = lv_arc_get_value(bpmArc);
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
} else if (obj == bpbDropdown) {
bpb = lv_dropdown_get_selected(obj) + 1;
}
break;
}
case LV_EVENT_PRESSED: {
if (obj == bpmTap) {
float timeDelta = calculateDelta(tappedTime, xTaskGetTickCount());
if (tappedTime == 0 || timeDelta > 3) {
tappedTime = xTaskGetTickCount();
} else {
bpm = ceil(60.0 / timeDelta);
lv_arc_set_value(bpmArc, bpm);
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
tappedTime = xTaskGetTickCount();
}
}
break;
}
case LV_EVENT_CLICKED: {
if (obj == playPause) {
currentState = (currentState == States::Stopped ? States::Running : States::Stopped);
switch (currentState) {
case States::Stopped: {
lv_label_set_text(playPauseLabel, Symbols::play);
systemTask.PushMessage(System::Messages::EnableSleeping);
break;
}
case States::Running: {
lv_label_set_text(playPauseLabel, Symbols::pause);
systemTask.PushMessage(System::Messages::DisableSleeping);
startTime = xTaskGetTickCount();
counter = 1;
break;
}
}
}
break;
}
}
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "systemtask/SystemTask.h"
#include "components/motor/MotorController.h"
#include <array>
namespace Pinetime::Applications::Screens {
class Metronome : public Screen {
public:
Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask);
~Metronome() override;
bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
void OnEvent(lv_obj_t* obj, lv_event_t event);
enum class States { Running, Stopped };
private:
bool running;
States currentState;
TickType_t startTime;
TickType_t tappedTime = 0;
Controllers::MotorController& motorController;
System::SystemTask& systemTask;
uint16_t bpm = 120;
uint8_t bpb = 4;
uint8_t counter = 1;
lv_obj_t *bpmArc, *bpmTap, *bpmValue, *bpmLegend;
lv_obj_t *bpbDropdown, *bpbLegend;
lv_obj_t *playPause, *playPauseLabel;
};
}

View File

@@ -32,11 +32,10 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
lv_label_set_recolor(label, true);
labelStep = lv_label_create(lv_scr_act(), NULL);
lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_label_set_text(labelStep, "Steps ---");
}
Motion::~Motion() {
@@ -50,13 +49,12 @@ bool Motion::Refresh() {
lv_label_set_text_fmt(labelStep, "Steps %lu", motionController.NbSteps());
lv_label_set_text_fmt(label, "X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#", motionController.X() / 0x10, motionController.Y() / 0x10, motionController.Z() / 0x10);
lv_label_set_text_fmt(label,
"X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#",
motionController.X() / 0x10,
motionController.Y() / 0x10,
motionController.Z() / 0x10);
lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
return running;
}
bool Motion::OnButtonPushed() {
running = false;
return true;
}

View File

@@ -18,7 +18,6 @@ namespace Pinetime {
~Motion() override;
bool Refresh() override;
bool OnButtonPushed() override;
private:
Controllers::MotionController& motionController;
@@ -29,10 +28,7 @@ namespace Pinetime {
lv_obj_t* label;
lv_obj_t* labelStep;
static constexpr uint8_t nbStepsBufferSize = 9;
char nbStepsBuffer[nbStepsBufferSize + 1];
bool running = true;
};
}
}
}
}

View File

@@ -119,7 +119,6 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
constexpr int8_t MIDDLE_OFFSET = -25;
txtArtist = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC);
lv_label_set_anim_speed(txtArtist, 1);
lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);
lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID);
lv_obj_set_width(txtArtist, LV_HOR_RES - 12);
@@ -127,7 +126,6 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
txtTrack = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC);
lv_label_set_anim_speed(txtTrack, 1);
lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD);
lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID);
@@ -303,4 +301,4 @@ bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return true;
}
}
}
}

View File

@@ -24,6 +24,106 @@ using namespace Pinetime::Applications::Screens;
LV_FONT_DECLARE(lv_font_navi_80)
namespace {
constexpr std::array<std::pair<const char*, const char*>, 86> m_iconMap = {{
{"arrive-left", "\xEE\xA4\x81"},
{"arrive-right", "\xEE\xA4\x82"},
{"arrive-straight", "\xEE\xA4\x80"},
{"arrive", "\xEE\xA4\x80"},
{"close", "\xEE\xA4\x83"},
{"continue-left", "\xEE\xA4\x85"},
{"continue-right", "\xEE\xA4\x86"},
{"continue-slight-left", "\xEE\xA4\x87"},
{"continue-slight-right", "\xEE\xA4\x88"},
{"continue-straight", "\xEE\xA4\x84"},
{"continue-uturn", "\xEE\xA4\x89"},
{"continue", "\xEE\xA4\x84"},
{"depart-left", "\xEE\xA4\x8B"},
{"depart-right", "\xEE\xA4\x8C"},
{"depart-straight", "\xEE\xA4\x8A"},
{"end-of-road-left", "\xEE\xA4\x8D"},
{"end-of-road-right", "\xEE\xA4\x8E"},
{"ferry", "\xEE\xA4\x8F"},
{"flag", "\xEE\xA4\x90"},
{"fork-left", "\xEE\xA4\x92"},
{"fork-right", "\xEE\xA4\x93"},
{"fork-slight-left", "\xEE\xA4\x94"},
{"fork-slight-right", "\xEE\xA4\x95"},
{"fork-straight", "\xEE\xA4\x96"},
{"invalid", "\xEE\xA4\x84"},
{"invalid-left", "\xEE\xA4\x85"},
{"invalid-right", "\xEE\xA4\x86"},
{"invalid-slight-left", "\xEE\xA4\x87"},
{"invalid-slight-right", "\xEE\xA4\x88"},
{"invalid-straight", "\xEE\xA4\x84"},
{"invalid-uturn", "\xEE\xA4\x89"},
{"merge-left", "\xEE\xA4\x97"},
{"merge-right", "\xEE\xA4\x98"},
{"merge-slight-left", "\xEE\xA4\x99"},
{"merge-slight-right", "\xEE\xA4\x9A"},
{"merge-straight", "\xEE\xA4\x84"},
{"new-name-left", "\xEE\xA4\x85"},
{"new-name-right", "\xEE\xA4\x86"},
{"new-name-sharp-left", "\xEE\xA4\x9B"},
{"new-name-sharp-right", "\xEE\xA4\x9C"},
{"new-name-slight-left", "\xEE\xA4\x87"},
{"new-name-slight-right", "\xEE\xA4\x88"},
{"new-name-straight", "\xEE\xA4\x84"},
{"notification-left", "\xEE\xA4\x85"},
{"notification-right", "\xEE\xA4\x86"},
{"notification-sharp-left", "\xEE\xA4\x9B"},
{"notification-sharp-right", "\xEE\xA4\xA5"},
{"notification-slight-left", "\xEE\xA4\x87"},
{"notification-slight-right", "\xEE\xA4\x88"},
{"notification-straight", "\xEE\xA4\x84"},
{"off-ramp-left", "\xEE\xA4\x9D"},
{"off-ramp-right", "\xEE\xA4\x9E"},
{"off-ramp-slight-left", "\xEE\xA4\x9F"},
{"off-ramp-slight-right", "\xEE\xA4\xA0"},
{"on-ramp-left", "\xEE\xA4\x85"},
{"on-ramp-right", "\xEE\xA4\x86"},
{"on-ramp-sharp-left", "\xEE\xA4\x9B"},
{"on-ramp-sharp-right", "\xEE\xA4\xA5"},
{"on-ramp-slight-left", "\xEE\xA4\x87"},
{"on-ramp-slight-right", "\xEE\xA4\x88"},
{"on-ramp-straight", "\xEE\xA4\x84"},
{"rotary", "\xEE\xA4\xA1"},
{"rotary-left", "\xEE\xA4\xA2"},
{"rotary-right", "\xEE\xA4\xA3"},
{"rotary-sharp-left", "\xEE\xA4\xA4"},
{"rotary-sharp-right", "\xEE\xA4\xA5"},
{"rotary-slight-left", "\xEE\xA4\xA6"},
{"rotary-slight-right", "\xEE\xA4\xA7"},
{"rotary-straight", "\xEE\xA4\xA8"},
{"roundabout", "\xEE\xA4\xA1"},
{"roundabout-left", "\xEE\xA4\xA2"},
{"roundabout-right", "\xEE\xA4\xA3"},
{"roundabout-sharp-left", "\xEE\xA4\xA4"},
{"roundabout-sharp-right", "\xEE\xA4\xA5"},
{"roundabout-slight-left", "\xEE\xA4\xA6"},
{"roundabout-slight-right", "\xEE\xA4\xA7"},
{"roundabout-straight", "\xEE\xA4\xA8"},
{"turn-left", "\xEE\xA4\x85"},
{"turn-right", "\xEE\xA4\x86"},
{"turn-sharp-left", "\xEE\xA4\x9B"},
{"turn-sharp-right", "\xEE\xA4\xA5"},
{"turn-slight-left", "\xEE\xA4\x87"},
{"turn-slight-right", "\xEE\xA4\x88"},
{"turn-straight", "\xEE\xA4\x84"},
{"updown", "\xEE\xA4\xA9"},
{"uturn", "\xEE\xA4\x89"},
}};
const char* iconForName(const std::string& icon) {
for (auto iter : m_iconMap) {
if (iter.first == icon) {
return iter.second;
}
}
return "\xEE\xA4\x90";
}
}
/**
* Navigation watchapp
*
@@ -68,27 +168,25 @@ Navigation::~Navigation() {
}
bool Navigation::Refresh() {
if (m_flag != navService.getFlag()) {
m_flag = navService.getFlag();
lv_label_set_text(imgFlag, iconForName(m_flag));
// lv_img_set_src_arr(imgFlag, iconForName(m_flag));
if (flag != navService.getFlag()) {
flag = navService.getFlag();
lv_label_set_text(imgFlag, iconForName(flag));
}
if (m_narrative != navService.getNarrative()) {
m_narrative = navService.getNarrative();
lv_label_set_text(txtNarrative, m_narrative.data());
if (narrative != navService.getNarrative()) {
narrative = navService.getNarrative();
lv_label_set_text(txtNarrative, narrative.data());
}
if (m_manDist != navService.getManDist()) {
m_manDist = navService.getManDist();
lv_label_set_text(txtManDist, m_manDist.data());
if (manDist != navService.getManDist()) {
manDist = navService.getManDist();
lv_label_set_text(txtManDist, manDist.data());
}
if (m_progress != navService.getProgress()) {
m_progress = navService.getProgress();
lv_bar_set_value(barProgress, m_progress, LV_ANIM_OFF);
if (m_progress > 90) {
if (progress != navService.getProgress()) {
progress = navService.getProgress();
lv_bar_set_value(barProgress, progress, LV_ANIM_OFF);
if (progress > 90) {
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
} else {
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
@@ -98,11 +196,4 @@ bool Navigation::Refresh() {
return running;
}
const char* Navigation::iconForName(std::string icon) {
for (auto iter : m_iconMap) {
if (iter.first == icon) {
return iter.second;
}
}
return "\xEE\xA4\x90";
}

View File

@@ -45,103 +45,10 @@ namespace Pinetime {
Pinetime::Controllers::NavigationService& navService;
std::string m_flag;
std::string m_narrative;
std::string m_manDist;
int m_progress;
/** Watchapp */
const char* iconForName(std::string icon);
std::array<std::pair<std::string, const char*>, 89> m_iconMap = {{
{"arrive-left", "\xEE\xA4\x81"},
{"arrive-right", "\xEE\xA4\x82"},
{"arrive-straight", "\xEE\xA4\x80"},
{"arrive", "\xEE\xA4\x80"},
{"close", "\xEE\xA4\x83"},
{"continue-left", "\xEE\xA4\x85"},
{"continue-right", "\xEE\xA4\x86"},
{"continue-slight-left", "\xEE\xA4\x87"},
{"continue-slight-right", "\xEE\xA4\x88"},
{"continue-straight", "\xEE\xA4\x84"},
{"continue-uturn", "\xEE\xA4\x89"},
{"continue", "\xEE\xA4\x84"},
{"depart-left", "\xEE\xA4\x8B"},
{"depart-right", "\xEE\xA4\x8C"},
{"depart-straight", "\xEE\xA4\x8A"},
{"end-of-road-left", "\xEE\xA4\x8D"},
{"end-of-road-right", "\xEE\xA4\x8E"},
{"ferry", "\xEE\xA4\x8F"},
{"flag", "\xEE\xA4\x90"},
{"fork-left", "\xEE\xA4\x92"},
{"fork-right", "\xEE\xA4\x93"},
{"fork-slight-left", "\xEE\xA4\x94"},
{"fork-slight-right", "\xEE\xA4\x95"},
{"fork-straight", "\xEE\xA4\x96"},
{"invalid", "\xEE\xA4\x84"},
{"invalid-left", "\xEE\xA4\x85"},
{"invalid-right", "\xEE\xA4\x86"},
{"invalid-slight-left", "\xEE\xA4\x87"},
{"invalid-slight-right", "\xEE\xA4\x88"},
{"invalid-straight", "\xEE\xA4\x84"},
{"invalid-uturn", "\xEE\xA4\x89"},
{"merge-left", "\xEE\xA4\x97"},
{"merge-right", "\xEE\xA4\x98"},
{"merge-slight-left", "\xEE\xA4\x99"},
{"merge-slight-right", "\xEE\xA4\x9A"},
{"merge-straight", "\xEE\xA4\x84"},
{"new-name-left", "\xEE\xA4\x85"},
{"new-name-right", "\xEE\xA4\x86"},
{"new-name-sharp-left", "\xEE\xA4\x9B"},
{"new-name-sharp-right", "\xEE\xA4\x9C"},
{"new-name-slight-left", "\xEE\xA4\x87"},
{"new-name-slight-right", "\xEE\xA4\x88"},
{"new-name-straight", "\xEE\xA4\x84"},
{"notification-left", "\xEE\xA4\x85"},
{"notification-right", "\xEE\xA4\x86"},
{"notification-sharp-left", "\xEE\xA4\x9B"},
{"notification-sharp-right", "\xEE\xA4\xA5"},
{"notification-slight-left", "\xEE\xA4\x87"},
{"notification-slight-right", "\xEE\xA4\x88"},
{"notification-straight", "\xEE\xA4\x84"},
{"off-ramp-left", "\xEE\xA4\x9D"},
{"off-ramp-right", "\xEE\xA4\x9E"},
{"off-ramp-slight-left", "\xEE\xA4\x9F"},
{"off-ramp-slight-right", "\xEE\xA4\xA0"},
{"on-ramp-left", "\xEE\xA4\x85"},
{"on-ramp-right", "\xEE\xA4\x86"},
{"on-ramp-sharp-left", "\xEE\xA4\x9B"},
{"on-ramp-sharp-right", "\xEE\xA4\xA5"},
{"on-ramp-slight-left", "\xEE\xA4\x87"},
{"on-ramp-slight-right", "\xEE\xA4\x88"},
{"on-ramp-straight", "\xEE\xA4\x84"},
{"rotary", "\xEE\xA4\xA1"},
{"rotary-left", "\xEE\xA4\xA2"},
{"rotary-right", "\xEE\xA4\xA3"},
{"rotary-sharp-left", "\xEE\xA4\xA4"},
{"rotary-sharp-right", "\xEE\xA4\xA5"},
{"rotary-slight-left", "\xEE\xA4\xA6"},
{"rotary-slight-right", "\xEE\xA4\xA7"},
{"rotary-straight", "\xEE\xA4\xA8"},
{"roundabout", "\xEE\xA4\xA1"},
{"roundabout-left", "\xEE\xA4\xA2"},
{"roundabout-right", "\xEE\xA4\xA3"},
{"roundabout-sharp-left", "\xEE\xA4\xA4"},
{"roundabout-sharp-right", "\xEE\xA4\xA5"},
{"roundabout-slight-left", "\xEE\xA4\xA6"},
{"roundabout-slight-right", "\xEE\xA4\xA7"},
{"roundabout-straight", "\xEE\xA4\xA8"},
{"turn-left", "\xEE\xA4\x85"},
{"turn-right", "\xEE\xA4\x86"},
{"turn-sharp-left", "\xEE\xA4\x9B"},
{"turn-sharp-right", "\xEE\xA4\xA5"},
{"turn-slight-left", "\xEE\xA4\x87"},
{"turn-slight-right", "\xEE\xA4\x88"},
{"turn-straight", "\xEE\xA4\x84"},
{"updown", "\xEE\xA4\xA9"},
{"uturn", "\xEE\xA4\x89"},
}};
std::string flag;
std::string narrative;
std::string manDist;
int progress;
};
}
}

View File

@@ -185,10 +185,10 @@ Notifications::NotificationItem::NotificationItem(const char* title,
lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_pos(container1, 0, 50);
lv_obj_set_width(container1, 240);
lv_obj_set_height(container1, 190);
lv_obj_set_size(container1, LV_HOR_RES, 190);
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
lv_cont_set_fit(container1, LV_FIT_NONE);
lv_obj_t* alert_count = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb);
@@ -198,7 +198,15 @@ Notifications::NotificationItem::NotificationItem(const char* title,
lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x888888));
if (title == nullptr)
title = "Notification";
char* pchar;
pchar = strchr(title, '\n');
while (pchar != nullptr) {
*pchar = ' ';
pchar = strchr(pchar + 1, '\n');
}
lv_label_set_text(alert_type, title);
lv_label_set_long_mode(alert_type, LV_LABEL_LONG_SROLL_CIRC);
lv_obj_set_width(alert_type, 180);
lv_obj_align(alert_type, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16);
/////////
@@ -211,6 +219,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
lv_label_set_text(alert_subject, msg);
} break;
case Controllers::NotificationManager::Categories::IncomingCall: {
lv_obj_set_height(container1, 108);
lv_obj_t* alert_subject = lv_label_create(container1, nullptr);
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
@@ -223,38 +232,29 @@ Notifications::NotificationItem::NotificationItem(const char* title,
lv_obj_set_width(alert_caller, LV_HOR_RES - 20);
lv_label_set_text(alert_caller, msg);
lv_obj_t* callBtnContainer = lv_cont_create(container1, NULL);
lv_obj_set_width(callBtnContainer, 240);
lv_obj_set_height(callBtnContainer, 90);
lv_cont_set_layout(callBtnContainer, LV_LAYOUT_ROW_MID);
lv_obj_set_style_local_bg_color(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x222222));
lv_obj_set_style_local_pad_all(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_margin_top(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 40);
lv_obj_set_style_local_margin_left(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, -8);
lv_obj_set_style_local_pad_inner(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
lv_obj_set_style_local_border_width(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
bt_accept = lv_btn_create(callBtnContainer, nullptr);
bt_accept = lv_btn_create(lv_scr_act(), nullptr);
bt_accept->user_data = this;
lv_obj_set_event_cb(bt_accept, AcceptIncomingCallEventHandler);
lv_obj_set_size(bt_accept, (LV_HOR_RES / 3) - 5, 80);
lv_obj_set_size(bt_accept, 76, 76);
lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
label_accept = lv_label_create(bt_accept, nullptr);
lv_label_set_text(label_accept, Symbols::phone);
lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
bt_reject = lv_btn_create(callBtnContainer, nullptr);
bt_reject = lv_btn_create(lv_scr_act(), nullptr);
bt_reject->user_data = this;
lv_obj_set_event_cb(bt_reject, RejectIncomingCallEventHandler);
lv_obj_set_size(bt_reject, (LV_HOR_RES / 3) - 5, 80);
lv_obj_set_size(bt_reject, 76, 76);
lv_obj_align(bt_reject, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
label_reject = lv_label_create(bt_reject, nullptr);
lv_label_set_text(label_reject, Symbols::phoneSlash);
lv_obj_set_style_local_bg_color(bt_reject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
bt_mute = lv_btn_create(callBtnContainer, nullptr);
bt_mute = lv_btn_create(lv_scr_act(), nullptr);
bt_mute->user_data = this;
lv_obj_set_event_cb(bt_mute, MuteIncomingCallEventHandler);
lv_obj_set_size(bt_mute, (LV_HOR_RES / 3) - 5, 80);
lv_obj_set_size(bt_mute, 76, 76);
lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
label_mute = lv_label_create(bt_mute, nullptr);
lv_label_set_text(label_mute, Symbols::volumMute);
lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);

View File

@@ -4,98 +4,31 @@
using namespace Pinetime::Applications::Screens;
namespace {
const uint8_t paddle_map[] = {
0xfc, 0xfe, 0xfc, 0xff, /*Color of index 0*/
0xff, 0xff, 0xff, 0xff, /*Color of index 1*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t ball_map[] = {
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed,
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed,
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
};
}
Paddle::Paddle(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
app->SetTouchMode(DisplayApp::TouchModes::Polling);
background = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_size(background, LV_HOR_RES + 1, LV_VER_RES);
lv_obj_set_pos(background, -1, 0);
lv_obj_set_style_local_radius(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_bg_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_border_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_border_width(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 1);
points = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(points, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text(points, "0000");
lv_obj_set_style_local_text_color(points, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x444444));
lv_obj_align(points, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0);
lv_obj_align(points, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 10);
paddle.header.always_zero = 0;
paddle.header.w = 4;
paddle.header.h = 60;
paddle.data_size = 68;
paddle.header.cf = LV_IMG_CF_INDEXED_1BIT;
paddle.data = paddle_map;
paddle_image = lv_img_create(lv_scr_act(), nullptr);
lv_img_set_src(paddle_image, &paddle);
paddle = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(paddle, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_radius(paddle, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(paddle, 4, 60);
ball.header.always_zero = 0;
ball.header.w = 24;
ball.header.h = 24;
ball.data_size = 24 * 24 * LV_COLOR_SIZE / 8;
ball.header.cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
ball.data = ball_map;
ball_image = lv_img_create(lv_scr_act(), nullptr);
lv_img_set_src(ball_image, &ball);
ball = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_radius(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_size(ball, ballSize, ballSize);
}
Paddle::~Paddle() {
@@ -105,41 +38,37 @@ Paddle::~Paddle() {
}
bool Paddle::Refresh() {
if ((counter++ % 5) == 0) {
counter = 0;
ballX += dx;
ballY += dy;
ballX += dx;
ballY += dy;
lv_obj_set_pos(ball, ballX, ballY);
lv_obj_set_pos(ball_image, ballX, ballY);
// checks if it has touched the sides (floor and ceiling)
if (ballY <= 1 || ballY >= LV_VER_RES - ballSize - 2) {
dy *= -1;
}
// checks if it has touched the sides (floor and ceiling)
if (ballY <= 0 || ballY >= 215) {
dy *= -1;
}
// checks if it has touched the side (left side)
if (ballX >= LV_VER_RES - ballSize - 1) {
dx *= -1;
}
// checks if it has touched the side (left side)
if (ballX >= 215) {
dx *= -1;
}
// checks if it is in the position of the paddle
if (ballY <= (paddleBottomY + 16) && ballY >= (paddleTopY - 8)) {
if (ballX >= 0 && ballX < 4) {
lv_obj_set_pos(ball_image, 5, ballY);
// checks if it is in the position of the paddle
if (dx < 0 && ballX <= 4) {
if (ballX >= -ballSize / 4) {
if (ballY <= (paddlePos + 30 - ballSize / 4) && ballY >= (paddlePos - 30 - ballSize + ballSize / 4)) {
dx *= -1;
score++;
}
}
// checks if it has gone behind the paddle
else if (ballX <= -40) {
ballX = 107;
ballY = 107;
else if (ballX <= -ballSize * 2) {
ballX = (LV_HOR_RES - ballSize) / 2;
ballY = (LV_VER_RES - ballSize) / 2;
score = 0;
}
lv_label_set_text_fmt(points, "%04d", score);
}
lv_label_set_text_fmt(points, "%04d", score);
return running;
}
@@ -148,11 +77,8 @@ bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
bool Paddle::OnTouchEvent(uint16_t x, uint16_t y) {
lv_obj_set_pos(
paddle_image,
0,
y - 30); // sets the center paddle pos. (30px offset) with the the y_coordinate of the finger and defaults the x_coordinate to 0
paddleTopY = y - 30; // refreshes the upper extreme of the paddle
paddleBottomY = y + 30; // refreshes the lower extreme of the paddle
// sets the center paddle pos. (30px offset) with the the y_coordinate of the finger
lv_obj_set_pos(paddle, 0, y - 30);
paddlePos = y;
return true;
}

View File

@@ -24,24 +24,22 @@ namespace Pinetime {
private:
Pinetime::Components::LittleVgl& lvgl;
int paddleBottomY = 90; // bottom extreme of the paddle
int paddleTopY = 150; // top extreme of the paddle
const uint8_t ballSize = 16;
int ballX = 107; // Initial x_coordinate for the ball (12px offset from the center to counteract the ball's 24px size)
int ballY = 107; // Initial y_coordinate for the ball
uint16_t paddlePos = 30; // Paddle center
int dx = 2; // Velocity of the ball in the x_coordinate
int dy = 3; // Velocity of the ball in the y_coordinate
int16_t ballX = (LV_HOR_RES - ballSize) / 2;
int16_t ballY = (LV_VER_RES - ballSize) / 2;
int counter = 0; // init Frame refresh limit counter
int score = 0;
int8_t dx = 2; // Velocity of the ball in the x_coordinate
int8_t dy = 3; // Velocity of the ball in the y_coordinate
lv_img_dsc_t paddle;
lv_img_dsc_t ball;
uint16_t score = 0;
lv_obj_t* points;
lv_obj_t* paddle_image; // pointer to paddle image
lv_obj_t* ball_image; // pointer to ball image
lv_obj_t* paddle;
lv_obj_t* ball;
lv_obj_t* background;
};
}
}

View File

@@ -0,0 +1,340 @@
/*
* This file is part of the Infinitime distribution (https://github.com/JF002/Infinitime).
* Copyright (c) 2021 Kieran Cawthray.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* PineTimeStyle watchface for Infinitime created by Kieran Cawthray
* Based on WatchFaceDigital
* Style/layout copied from TimeStyle for Pebble by Dan Tilden (github.com/tilden)
*/
#include "PineTimeStyle.h"
#include <date/date.h>
#include <lvgl/lvgl.h>
#include <cstdio>
#include "BatteryIcon.h"
#include "BleIcon.h"
#include "NotificationIcon.h"
#include "Symbols.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "components/motion/MotionController.h"
#include "components/settings/Settings.h"
#include "../DisplayApp.h"
using namespace Pinetime::Applications::Screens;
PineTimeStyle::PineTimeStyle(DisplayApp* app,
Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController)
: Screen(app),
currentDateTime {{}},
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
notificatioManager {notificatioManager},
settingsController {settingsController},
motionController {motionController} {
/* This sets the watchface number to return to after leaving the menu */
settingsController.SetClockFace(2);
displayedChar[0] = 0;
displayedChar[1] = 0;
displayedChar[2] = 0;
displayedChar[3] = 0;
displayedChar[4] = 0;
/* Create a 200px wide background rectangle */
timebar = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_radius(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(timebar, 200, 240);
lv_obj_align(timebar, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 0);
/* Display the time */
timeDD1 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
lv_label_set_text(timeDD1, "12");
lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5);
timeDD2 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
lv_label_set_text(timeDD2, "34");
lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5);
timeAMPM = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3);
lv_label_set_text(timeAMPM, "");
lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20);
/* Create a 40px wide bar down the right side of the screen */
sidebar = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
lv_obj_set_style_local_radius(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(sidebar, 40, 240);
lv_obj_align(sidebar, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
/* Display icons */
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_label_set_text(batteryIcon, Symbols::batteryFull);
lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_align(batteryPlug, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25);
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 40);
/* Calendar icon */
calendarOuter = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarOuter, 34, 34);
lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0);
calendarInner = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
lv_obj_set_style_local_radius(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarInner, 27, 27);
lv_obj_align(calendarInner, calendarOuter, LV_ALIGN_CENTER, 0, 0);
calendarBar1 = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_radius(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarBar1, 3, 12);
lv_obj_align(calendarBar1, calendarOuter, LV_ALIGN_IN_TOP_MID, -6, -3);
calendarBar2 = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_radius(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarBar2, 3, 12);
lv_obj_align(calendarBar2, calendarOuter, LV_ALIGN_IN_TOP_MID, 6, -3);
calendarCrossBar1 = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_radius(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarCrossBar1, 8, 3);
lv_obj_align(calendarCrossBar1, calendarBar1, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
calendarCrossBar2 = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_radius(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarCrossBar2, 8, 3);
lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
/* Display date */
dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_label_set_text(dateDayOfWeek, "THU");
lv_obj_align(dateDayOfWeek, sidebar, LV_ALIGN_CENTER, 0, -34);
dateDay = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_label_set_text(dateDay, "25");
lv_obj_align(dateDay, sidebar, LV_ALIGN_CENTER, 0, 3);
dateMonth = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(dateMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_label_set_text(dateMonth, "MAR");
lv_obj_align(dateMonth, sidebar, LV_ALIGN_CENTER, 0, 32);
// Step count gauge
needle_colors[0] = LV_COLOR_WHITE;
stepGauge = lv_gauge_create(lv_scr_act(), nullptr);
lv_gauge_set_needle_count(stepGauge, 1, needle_colors);
lv_obj_set_size(stepGauge, 40, 40);
lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_gauge_set_scale(stepGauge, 360, 11, 0);
lv_gauge_set_angle_offset(stepGauge, 180);
lv_gauge_set_critical_value(stepGauge, 100);
lv_gauge_set_range(stepGauge, 0, 100);
lv_gauge_set_value(stepGauge, 0, 0);
lv_obj_set_style_local_pad_right(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_pad_left(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_pad_bottom(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_obj_set_style_local_scale_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4);
lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4);
lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_click(backgroundLabel, true);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text(backgroundLabel, "");
}
PineTimeStyle::~PineTimeStyle() {
lv_obj_clean(lv_scr_act());
}
bool PineTimeStyle::Refresh() {
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
if (batteryController.IsCharging()) {
auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
lv_obj_realign(batteryPlug);
lv_label_set_text(batteryIcon, "");
} else {
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
lv_label_set_text(batteryPlug, "");
}
}
bleState = bleController.IsConnected();
if (bleState.IsUpdated()) {
if (bleState.Get() == true) {
lv_label_set_text(bleIcon, BleIcon::GetIcon(true));
lv_obj_realign(bleIcon);
} else {
lv_label_set_text(bleIcon, BleIcon::GetIcon(false));
}
}
notificationState = notificatioManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
if (notificationState.Get() == true) {
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true));
lv_obj_realign(notificationIcon);
} else {
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
}
}
currentDateTime = dateTimeController.CurrentDateTime();
if (currentDateTime.IsUpdated()) {
auto newDateTime = currentDateTime.Get();
auto dp = date::floor<date::days>(newDateTime);
auto time = date::make_time(newDateTime - dp);
auto yearMonthDay = date::year_month_day(dp);
auto year = (int) yearMonthDay.year();
auto month = static_cast<Pinetime::Controllers::DateTime::Months>((unsigned) yearMonthDay.month());
auto day = (unsigned) yearMonthDay.day();
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
int hour = time.hours().count();
auto minute = time.minutes().count();
char minutesChar[3];
sprintf(minutesChar, "%02d", static_cast<int>(minute));
char hoursChar[3];
char ampmChar[5];
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
sprintf(hoursChar, "%02d", hour);
} else {
if (hour == 0 && hour != 12) {
hour = 12;
sprintf(ampmChar, "A\nM");
} else if (hour == 12 && hour != 0) {
hour = 12;
sprintf(ampmChar, "P\nM");
} else if (hour < 12 && hour != 0) {
sprintf(ampmChar, "A\nM");
} else if (hour > 12 && hour != 0) {
hour = hour - 12;
sprintf(ampmChar, "P\nM");
}
sprintf(hoursChar, "%02d", hour);
}
if (hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] ||
minutesChar[1] != displayedChar[3]) {
displayedChar[0] = hoursChar[0];
displayedChar[1] = hoursChar[1];
displayedChar[2] = minutesChar[0];
displayedChar[3] = minutesChar[1];
char hourStr[3];
char minStr[3];
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
lv_label_set_text(timeAMPM, ampmChar);
}
/* Display the time as 2 pairs of digits */
sprintf(hourStr, "%c%c", hoursChar[0], hoursChar[1]);
lv_label_set_text(timeDD1, hourStr);
sprintf(minStr, "%c%c", minutesChar[0], minutesChar[1]);
lv_label_set_text(timeDD2, minStr);
}
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
char dayOfWeekStr[4];
char dayStr[3];
char monthStr[4];
sprintf(dayOfWeekStr, "%s", dateTimeController.DayOfWeekShortToString());
sprintf(dayStr, "%d", day);
sprintf(monthStr, "%s", dateTimeController.MonthShortToString());
lv_label_set_text(dateDayOfWeek, dayOfWeekStr);
lv_label_set_text(dateDay, dayStr);
lv_obj_realign(dateDay);
lv_label_set_text(dateMonth, monthStr);
currentYear = year;
currentMonth = month;
currentDayOfWeek = dayOfWeek;
currentDay = day;
}
}
stepCount = motionController.NbSteps();
motionSensorOk = motionController.IsSensorOk();
if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
lv_gauge_set_value(stepGauge, 0, (stepCount.Get() / (settingsController.GetStepsGoal() / 100)));
lv_obj_realign(stepGauge);
if (stepCount.Get() > settingsController.GetStepsGoal()) {
lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
}
}
return running;
}

View File

@@ -0,0 +1,86 @@
#pragma once
#include <lvgl/src/lv_core/lv_obj.h>
#include <chrono>
#include <cstdint>
#include <memory>
#include "Screen.h"
#include "ScreenList.h"
#include "components/datetime/DateTimeController.h"
namespace Pinetime {
namespace Controllers {
class Settings;
class Battery;
class Ble;
class NotificationManager;
class HeartRateController;
}
namespace Applications {
namespace Screens {
class PineTimeStyle : public Screen {
public:
PineTimeStyle(DisplayApp* app,
Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController);
~PineTimeStyle() override;
bool Refresh() override;
void OnObjectEvent(lv_obj_t* pObj, lv_event_t i);
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;
DirtyValue<uint8_t> batteryPercentRemaining {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};
DirtyValue<uint32_t> stepCount {};
DirtyValue<bool> notificationState {};
lv_obj_t* timebar;
lv_obj_t* sidebar;
lv_obj_t* timeDD1;
lv_obj_t* timeDD2;
lv_obj_t* timeAMPM;
lv_obj_t* dateDayOfWeek;
lv_obj_t* dateDay;
lv_obj_t* dateMonth;
lv_obj_t* backgroundLabel;
lv_obj_t* batteryIcon;
lv_obj_t* bleIcon;
lv_obj_t* batteryPlug;
lv_obj_t* calendarOuter;
lv_obj_t* calendarInner;
lv_obj_t* calendarBar1;
lv_obj_t* calendarBar2;
lv_obj_t* calendarCrossBar1;
lv_obj_t* calendarCrossBar2;
lv_obj_t* heartbeatIcon;
lv_obj_t* heartbeatValue;
lv_obj_t* heartbeatBpm;
lv_obj_t* notificationIcon;
lv_obj_t* stepGauge;
lv_color_t needle_colors[1];
Controllers::DateTime& dateTimeController;
Controllers::Battery& batteryController;
Controllers::Ble& bleController;
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
};
}
}
}

View File

@@ -13,8 +13,12 @@ namespace Pinetime {
DirtyValue() = default; // Use NSDMI
explicit DirtyValue(T const& v) : value {v} {
} // Use MIL and const-lvalue-ref
bool IsUpdated() const {
return isUpdated;
bool IsUpdated() {
if (this->isUpdated) {
this->isUpdated = false;
return true;
}
return false;
}
T const& Get() {
this->isUpdated = false;

View File

@@ -15,12 +15,17 @@ namespace Pinetime {
public:
ScreenList(DisplayApp* app,
uint8_t initScreen,
std::array<std::function<std::unique_ptr<Screen>()>, N>&& screens,
const std::array<std::function<std::unique_ptr<Screen>()>, N>&& screens,
ScreenListModes mode)
: Screen(app), initScreen {initScreen}, screens {std::move(screens)}, mode {mode}, current {this->screens[initScreen]()} {
screenIndex = initScreen;
: Screen(app), initScreen {initScreen}, screens {std::move(screens)}, mode {mode}, screenIndex{initScreen}, current {this->screens[initScreen]()} {
}
ScreenList(const ScreenList&) = delete;
ScreenList& operator=(const ScreenList&) = delete;
ScreenList(ScreenList&&) = delete;
ScreenList& operator=(ScreenList&&) = delete;
~ScreenList() override {
lv_obj_clean(lv_scr_act());
}
@@ -97,7 +102,7 @@ namespace Pinetime {
private:
uint8_t initScreen = 0;
std::array<std::function<std::unique_ptr<Screen>()>, N> screens;
const std::array<std::function<std::unique_ptr<Screen>()>, N> screens;
ScreenListModes mode = ScreenListModes::UpDown;
uint8_t screenIndex = 0;

View File

@@ -5,20 +5,17 @@
using namespace Pinetime::Applications::Screens;
Steps::Steps(
Pinetime::Applications::DisplayApp *app,
Controllers::MotionController& motionController,
Controllers::Settings &settingsController)
: Screen(app),
motionController{motionController},
settingsController{settingsController} {
Steps::Steps(Pinetime::Applications::DisplayApp* app,
Controllers::MotionController& motionController,
Controllers::Settings& settingsController)
: Screen(app), motionController {motionController}, settingsController {settingsController} {
stepsArc = lv_arc_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
lv_obj_set_style_local_border_width(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2);
lv_obj_set_style_local_radius(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0x0000FF));
lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
lv_obj_set_style_local_border_width(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2);
lv_obj_set_style_local_radius(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0x0000FF));
lv_arc_set_end_angle(stepsArc, 200);
lv_obj_set_size(stepsArc, 220, 220);
lv_arc_set_range(stepsArc, 0, 500);
@@ -30,27 +27,26 @@ Steps::Steps(
lSteps = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
lv_obj_set_style_local_text_font(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
lv_obj_set_style_local_text_font(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
lv_obj_t * lstepsL = lv_label_create(lv_scr_act(), nullptr);
lv_obj_t* lstepsL = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(lstepsL, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
lv_label_set_text_static(lstepsL, "Steps");
lv_label_set_text_static(lstepsL, "Steps");
lv_obj_align(lstepsL, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
lv_obj_t * lstepsGoal = lv_label_create(lv_scr_act(), nullptr);
lv_obj_t* lstepsGoal = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(lstepsGoal, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_CYAN);
lv_label_set_text_fmt(lstepsGoal,"Goal\n%i", settingsController.GetStepsGoal());
lv_label_set_text_fmt(lstepsGoal, "Goal\n%lu", settingsController.GetStepsGoal());
lv_label_set_align(lstepsGoal, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lstepsGoal, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 60);
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
}
Steps::~Steps() {
@@ -58,15 +54,13 @@ Steps::~Steps() {
}
bool Steps::Refresh() {
stepsCount = motionController.NbSteps();
lv_label_set_text_fmt(lSteps,"%li", stepsCount);
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
return running;
}

View File

@@ -45,38 +45,51 @@ static void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) {
stopWatch->stopLapBtnEventHandler(event);
}
StopWatch::StopWatch(DisplayApp* app)
StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask)
: Screen(app),
systemTask {systemTask},
running {true},
currentState {States::Init},
currentEvent {Events::Stop},
startTime {},
oldTimeElapsed {},
currentTimeSeparated {},
lapBuffer {},
lapNr {},
lapPressed {false} {
lapNr {} {
time = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_label_set_text(time, "00:00");
lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -45);
lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45);
msecTime = lv_label_create(lv_scr_act(), nullptr);
// lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_label_set_text(msecTime, "00");
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 108, 3);
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3);
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
btnPlayPause->user_data = this;
lv_obj_set_event_cb(btnPlayPause, play_pause_event_handler);
lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -10);
lv_obj_set_height(btnPlayPause, 40);
lv_obj_set_height(btnPlayPause, 50);
lv_obj_set_width(btnPlayPause, 115);
lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
txtPlayPause = lv_label_create(btnPlayPause, nullptr);
lv_label_set_text(txtPlayPause, Symbols::play);
btnStopLap = lv_btn_create(lv_scr_act(), nullptr);
btnStopLap->user_data = this;
lv_obj_set_event_cb(btnStopLap, stop_lap_event_handler);
lv_obj_set_height(btnStopLap, 50);
lv_obj_set_width(btnStopLap, 115);
lv_obj_align(btnStopLap, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_obj_set_style_local_bg_color(btnStopLap, LV_BTN_PART_MAIN, LV_STATE_DISABLED, lv_color_hex(0x080808));
txtStopLap = lv_label_create(btnStopLap, nullptr);
lv_obj_set_style_local_text_color(txtStopLap, LV_BTN_PART_MAIN, LV_STATE_DISABLED, lv_color_hex(0x888888));
lv_label_set_text(txtStopLap, Symbols::stop);
lv_obj_set_state(btnStopLap, LV_STATE_DISABLED);
lv_obj_set_state(txtStopLap, LV_STATE_DISABLED);
lapOneText = lv_label_create(lv_scr_act(), nullptr);
// lv_obj_set_style_local_text_font(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_obj_set_style_local_text_color(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
@@ -88,140 +101,103 @@ StopWatch::StopWatch(DisplayApp* app)
lv_obj_set_style_local_text_color(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55);
lv_label_set_text(lapTwoText, "");
// We don't want this button in the init state
btnStopLap = nullptr;
}
StopWatch::~StopWatch() {
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
void StopWatch::reset() {
currentState = States::Init;
oldTimeElapsed = 0;
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_label_set_text(time, "00:00");
lv_label_set_text(msecTime, "00");
lv_label_set_text(lapOneText, "");
lv_label_set_text(lapTwoText, "");
lapBuffer.clearBuffer();
lapNr = 0;
lv_obj_set_state(btnStopLap, LV_STATE_DISABLED);
lv_obj_set_state(txtStopLap, LV_STATE_DISABLED);
}
void StopWatch::start() {
lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT);
lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_label_set_text(txtPlayPause, Symbols::pause);
lv_label_set_text(txtStopLap, Symbols::lapsFlag);
startTime = xTaskGetTickCount();
currentState = States::Running;
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
}
void StopWatch::pause() {
startTime = 0;
// Store the current time elapsed in cache
oldTimeElapsed += timeElapsed;
currentState = States::Halted;
lv_label_set_text(txtPlayPause, Symbols::play);
lv_label_set_text(txtStopLap, Symbols::stop);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
bool StopWatch::Refresh() {
// @startuml CHIP8_state
// State "Init" as init
// State "Running" as run
// State "Halted" as halt
if (currentState == States::Running) {
timeElapsed = calculateDelta(startTime, xTaskGetTickCount());
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
// [*] --> init
// init -> run : press play
// run -> run : press lap
// run --> halt : press pause
// halt --> run : press play
// halt --> init : press stop
// @enduml
// Copy paste the above plantuml text to visualize the state diagram
switch (currentState) {
// Init state when an user first opens the app
// and when a stop/reset button is pressed
case States::Init: {
if (btnStopLap != nullptr) {
lv_obj_del(btnStopLap);
btnStopLap = nullptr;
}
// The initial default value
lv_label_set_text(time, "00:00");
lv_label_set_text(msecTime, "00");
lv_label_set_text(lapOneText, "");
lv_label_set_text(lapTwoText, "");
lapBuffer.clearBuffer();
lapNr = 0;
if (currentEvent == Events::Play) {
btnStopLap = lv_btn_create(lv_scr_act(), nullptr);
btnStopLap->user_data = this;
lv_obj_set_event_cb(btnStopLap, stop_lap_event_handler);
lv_obj_align(btnStopLap, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0);
lv_obj_set_height(btnStopLap, 40);
txtStopLap = lv_label_create(btnStopLap, nullptr);
lv_label_set_text(txtStopLap, Symbols::lapsFlag);
startTime = xTaskGetTickCount();
currentState = States::Running;
}
break;
}
case States::Running: {
lv_label_set_text(txtPlayPause, Symbols::pause);
lv_label_set_text(txtStopLap, Symbols::lapsFlag);
const auto timeElapsed = calculateDelta(startTime, xTaskGetTickCount());
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
if (lapPressed == true) {
if (lapBuffer[1]) {
lv_label_set_text_fmt(
lapOneText, "#%2d %2d:%02d.%02d", (lapNr - 1), lapBuffer[1]->mins, lapBuffer[1]->secs, lapBuffer[1]->hundredths);
}
if (lapBuffer[0]) {
lv_label_set_text_fmt(
lapTwoText, "#%2d %2d:%02d.%02d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->hundredths);
}
// Reset the bool to avoid setting the text in each cycle until there is a change
lapPressed = false;
}
if (currentEvent == Events::Pause) {
// Reset the start time
startTime = 0;
// Store the current time elapsed in cache
oldTimeElapsed += timeElapsed;
currentState = States::Halted;
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
} else {
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
}
break;
}
case States::Halted: {
lv_label_set_text(txtPlayPause, Symbols::play);
lv_label_set_text(txtStopLap, Symbols::stop);
if (currentEvent == Events::Play) {
startTime = xTaskGetTickCount();
currentState = States::Running;
}
if (currentEvent == Events::Stop) {
currentState = States::Init;
oldTimeElapsed = 0;
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
}
break;
}
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
}
return running;
}
void StopWatch::playPauseBtnEventHandler(lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
if (currentState == States::Init) {
currentEvent = Events::Play;
} else {
// Simple Toggle for play/pause
currentEvent = (currentEvent == Events::Play ? Events::Pause : Events::Play);
}
if (event != LV_EVENT_PRESSED) {
return;
}
if (currentState == States::Init) {
start();
} else if (currentState == States::Running) {
pause();
} else if (currentState == States::Halted) {
start();
}
}
void StopWatch::stopLapBtnEventHandler(lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
// If running, then this button is used to save laps
if (currentState == States::Running) {
lapBuffer.addLaps(currentTimeSeparated);
lapNr++;
lapPressed = true;
} else if (currentState == States::Halted) {
currentEvent = Events::Stop;
} else {
// Not possible to reach here. Do nothing.
if (event != LV_EVENT_PRESSED) {
return;
}
// If running, then this button is used to save laps
if (currentState == States::Running) {
lapBuffer.addLaps(currentTimeSeparated);
lapNr++;
if (lapBuffer[1]) {
lv_label_set_text_fmt(
lapOneText, "#%2d %2d:%02d.%02d", (lapNr - 1), lapBuffer[1]->mins, lapBuffer[1]->secs, lapBuffer[1]->hundredths);
}
if (lapBuffer[0]) {
lv_label_set_text_fmt(lapTwoText, "#%2d %2d:%02d.%02d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->hundredths);
}
} else if (currentState == States::Halted) {
reset();
}
}
bool StopWatch::OnButtonPushed() {
if (currentState == States::Running) {
pause();
} else {
running = false;
}
return true;
}

View File

@@ -8,13 +8,12 @@
#include "portmacro_cmsis.h"
#include <array>
#include "systemtask/SystemTask.h"
namespace Pinetime::Applications::Screens {
enum class States { Init, Running, Halted };
enum class Events { Play, Pause, Stop };
struct TimeSeparated_t {
int mins;
int secs;
@@ -63,23 +62,28 @@ namespace Pinetime::Applications::Screens {
class StopWatch : public Screen {
public:
StopWatch(DisplayApp* app);
StopWatch(DisplayApp* app, System::SystemTask& systemTask);
~StopWatch() override;
bool Refresh() override;
void playPauseBtnEventHandler(lv_event_t event);
void stopLapBtnEventHandler(lv_event_t event);
bool OnButtonPushed() override;
void reset();
void start();
void pause();
private:
Pinetime::System::SystemTask& systemTask;
TickType_t timeElapsed;
bool running;
States currentState;
Events currentEvent;
TickType_t startTime;
TickType_t oldTimeElapsed;
TimeSeparated_t currentTimeSeparated; // Holds Mins, Secs, millisecs
LapTextBuffer_t<2> lapBuffer;
int lapNr;
bool lapPressed;
int lapNr = 0;
lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
lv_obj_t *lapOneText, *lapTwoText;
};

View File

@@ -38,7 +38,12 @@ namespace Pinetime {
static constexpr const char* pause = "\xEF\x81\x8C";
static constexpr const char* stop = "\xEF\x81\x8D";
static constexpr const char* stopWatch = "\xEF\x8B\xB2";
static constexpr const char* hourGlass = "\xEF\x89\x92";
static constexpr const char* lapsFlag = "\xEF\x80\xA4";
static constexpr const char* drum = "\xEF\x95\xA9";
static constexpr const char* chartLine = "\xEF\x88\x81";
static constexpr const char* eye = "\xEF\x81\xAE";
static constexpr const char* home = "\xEF\x80\x95";
// lv_font_sys_48.c
static constexpr const char* settings = "\xEE\xA4\x82"; // e902

View File

@@ -3,26 +3,44 @@
#include "../DisplayApp.h"
#include "Label.h"
#include "Version.h"
#include "BootloaderVersion.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/brightness/BrightnessController.h"
#include "components/datetime/DateTimeController.h"
#include "components/motion/MotionController.h"
#include "drivers/Watchdog.h"
using namespace Pinetime::Applications::Screens;
namespace {
const char* ToString(const Pinetime::Controllers::MotionController::DeviceTypes deviceType) {
switch (deviceType) {
case Pinetime::Controllers::MotionController::DeviceTypes::BMA421:
return "BMA421";
case Pinetime::Controllers::MotionController::DeviceTypes::BMA425:
return "BMA425";
case Pinetime::Controllers::MotionController::DeviceTypes::Unknown:
return "???";
}
return "???";
}
}
SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::DateTime& dateTimeController,
Pinetime::Controllers::Battery& batteryController,
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::WatchdogView& watchdog)
Pinetime::Drivers::WatchdogView& watchdog,
Pinetime::Controllers::MotionController& motionController)
: Screen(app),
dateTimeController {dateTimeController},
batteryController {batteryController},
brightnessController {brightnessController},
bleController {bleController},
watchdog {watchdog},
motionController{motionController},
screens {app,
0,
{[this]() -> std::unique_ptr<Screen> {
@@ -54,11 +72,6 @@ bool SystemInfo::Refresh() {
return running;
}
bool SystemInfo::OnButtonPushed() {
running = false;
return true;
}
bool SystemInfo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
}
@@ -68,24 +81,26 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() {
lv_label_set_recolor(label, true);
lv_label_set_text_fmt(label,
"#FFFF00 InfiniTime#\n\n"
"#444444 Version# %ld.%ld.%ld\n\n"
"#444444 Version# %ld.%ld.%ld\n"
"#444444 Short Ref# %s\n"
"#444444 Build date#\n"
"%s\n"
"%s\n",
"%s\n\n"
"#444444 Bootloader# %s",
Version::Major(),
Version::Minor(),
Version::Patch(),
Version::GitCommitHash(),
__DATE__,
__TIME__);
__TIME__,
BootloaderVersion::VersionString());
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label));
return std::make_unique<Screens::Label>(0, 5, app, label);
}
std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
auto batteryPercent = static_cast<uint8_t>(batteryController.PercentRemaining());
float batteryVoltage = batteryController.Voltage();
auto batteryPercent = batteryController.PercentRemaining();
auto resetReason = [this]() {
switch (watchdog.ResetReason()) {
case Drivers::Watchdog::ResetReasons::Watchdog:
@@ -124,25 +139,16 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
uptimeSeconds = uptimeSeconds % secondsInAMinute;
// TODO handle more than 100 days of uptime
if (batteryPercent == -1)
batteryPercent = 0;
// hack to not use the flot functions from printf
uint8_t batteryVoltageBytes[2];
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
batteryVoltageBytes[0] =
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
//
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
lv_label_set_text_fmt(label,
"#444444 Date# %02d/%02d/%04d\n"
"#444444 Time# %02d:%02d:%02d\n"
"#444444 Uptime#\n %02lud %02lu:%02lu:%02lu\n"
"#444444 Battery# %d%%/%1i.%02iv\n"
"#444444 Battery# %d%%/%03imV\n"
"#444444 Backlight# %s\n"
"#444444 Last reset# %s\n",
"#444444 Last reset# %s\n"
"#444444 Accel.# %s\n",
dateTimeController.Day(),
static_cast<uint8_t>(dateTimeController.Month()),
dateTimeController.Year(),
@@ -154,12 +160,12 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
uptimeMinutes,
uptimeSeconds,
batteryPercent,
batteryVoltageBytes[1],
batteryVoltageBytes[0],
batteryController.Voltage(),
brightnessController.ToString(),
resetReason);
resetReason,
ToString(motionController.DeviceType()));
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(1, 4, app, label));
return std::make_unique<Screens::Label>(1, 5, app, label);
}
std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
@@ -173,59 +179,83 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
"#444444 BLE MAC#\n"
" %02x:%02x:%02x:%02x:%02x:%02x"
"\n"
"#444444 Memory#\n"
"#444444 LVGL Memory#\n"
" #444444 used# %d (%d%%)\n"
" #444444 max used# %lu\n"
" #444444 frag# %d%%\n"
" #444444 free# %d"
"\n"
"#444444 Steps# %li",
"#444444 Steps# %i",
bleAddr[5],
bleAddr[4],
bleAddr[3],
bleAddr[2],
bleAddr[1],
bleAddr[0],
(int) mon.total_size - mon.free_size,
static_cast<int>(mon.total_size - mon.free_size),
mon.used_pct,
mon.max_used,
mon.frag_pct,
(int) mon.free_biggest_size,
static_cast<int>(mon.free_biggest_size),
0);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(2, 5, app, label));
return std::make_unique<Screens::Label>(2, 5, app, label);
}
bool sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
bool SystemInfo::sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
return lhs.xTaskNumber < rhs.xTaskNumber;
}
std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
TaskStatus_t tasksStatus[7];
lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL);
lv_table_set_col_cnt(infoTask, 3);
lv_table_set_col_cnt(infoTask, 4);
lv_table_set_row_cnt(infoTask, 8);
lv_obj_set_pos(infoTask, 10, 10);
lv_obj_set_pos(infoTask, 0, 10);
lv_table_set_cell_value(infoTask, 0, 0, "#");
lv_table_set_col_width(infoTask, 0, 50);
lv_table_set_cell_value(infoTask, 0, 1, "Task");
lv_table_set_col_width(infoTask, 1, 80);
lv_table_set_cell_value(infoTask, 0, 2, "Free");
lv_table_set_col_width(infoTask, 2, 90);
lv_table_set_col_width(infoTask, 0, 30);
lv_table_set_cell_value(infoTask, 0, 1, "S"); // State
lv_table_set_col_width(infoTask, 1, 30);
lv_table_set_cell_value(infoTask, 0, 2, "Task");
lv_table_set_col_width(infoTask, 2, 80);
lv_table_set_cell_value(infoTask, 0, 3, "Free");
lv_table_set_col_width(infoTask, 3, 90);
auto nb = uxTaskGetSystemState(tasksStatus, 7, nullptr);
std::sort(tasksStatus, tasksStatus + nb, sortById);
for (uint8_t i = 0; i < nb; i++) {
lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
lv_table_set_cell_value(infoTask, i + 1, 1, tasksStatus[i].pcTaskName);
char state[2] = {0};
switch (tasksStatus[i].eCurrentState) {
case eReady:
case eRunning:
state[0] = 'R';
break;
case eBlocked:
state[0] = 'B';
break;
case eSuspended:
state[0] = 'S';
break;
case eDeleted:
state[0] = 'D';
break;
default:
state[0] = 'I'; // Invalid
break;
}
lv_table_set_cell_value(infoTask, i + 1, 1, state);
lv_table_set_cell_value(infoTask, i + 1, 2, tasksStatus[i].pcTaskName);
if (tasksStatus[i].usStackHighWaterMark < 20) {
std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low";
lv_table_set_cell_value(infoTask, i + 1, 2, str1.c_str());
lv_table_set_cell_value(infoTask, i + 1, 3, str1.c_str());
} else {
lv_table_set_cell_value(infoTask, i + 1, 2, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
lv_table_set_cell_value(infoTask, i + 1, 3, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
}
}
return std::unique_ptr<Screen>(new Screens::Label(3, 5, app, infoTask));
return std::make_unique<Screens::Label>(3, 5, app, infoTask);
}
std::unique_ptr<Screen> SystemInfo::CreateScreen5() {
@@ -241,5 +271,5 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen5() {
"#FFFF00 JF002/InfiniTime#");
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(4, 5, app, label));
return std::make_unique<Screens::Label>(4, 5, app, label);
}

View File

@@ -27,22 +27,24 @@ namespace Pinetime {
Pinetime::Controllers::Battery& batteryController,
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::WatchdogView& watchdog);
Pinetime::Drivers::WatchdogView& watchdog,
Pinetime::Controllers::MotionController& motionController);
~SystemInfo() override;
bool Refresh() override;
bool OnButtonPushed() override;
bool OnTouchEvent(TouchEvents event) override;
private:
bool running = true;
Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Controllers::Battery& batteryController;
Pinetime::Controllers::BrightnessController& brightnessController;
Pinetime::Controllers::Ble& bleController;
Pinetime::Drivers::WatchdogView& watchdog;
Pinetime::Controllers::MotionController& motionController;
ScreenList<5> screens;
static bool sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs);
std::unique_ptr<Screen> CreateScreen1();
std::unique_ptr<Screen> CreateScreen2();
std::unique_ptr<Screen> CreateScreen3();
@@ -51,4 +53,4 @@ namespace Pinetime {
};
}
}
}
}

View File

@@ -6,15 +6,17 @@ using namespace Pinetime::Applications::Screens;
namespace {
static void lv_update_task(struct _lv_task_t* task) {
auto user_data = static_cast<Tile*>(task->user_data);
auto* user_data = static_cast<Tile*>(task->user_data);
user_data->UpdateScreen();
}
static void event_handler(lv_obj_t* obj, lv_event_t event) {
if (event != LV_EVENT_VALUE_CHANGED) return;
Tile* screen = static_cast<Tile*>(obj->user_data);
uint32_t* eventDataPtr = (uint32_t*) lv_event_get_data();
auto* eventDataPtr = (uint32_t*) lv_event_get_data();
uint32_t eventData = *eventDataPtr;
screen->OnObjectEvent(obj, event, eventData);
screen->OnValueChangedEvent(obj, eventData);
}
}
@@ -107,7 +109,7 @@ Tile::Tile(uint8_t screenID,
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this);
taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this);
}
Tile::~Tile() {
@@ -124,9 +126,9 @@ bool Tile::Refresh() {
return running;
}
void Tile::OnObjectEvent(lv_obj_t* obj, lv_event_t event, uint32_t buttonId) {
if (event == LV_EVENT_VALUE_CHANGED) {
app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Up);
running = false;
}
void Tile::OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId) {
if(obj != btnm1) return;
app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Up);
running = false;
}

View File

@@ -32,7 +32,7 @@ namespace Pinetime {
bool Refresh() override;
void UpdateScreen();
void OnObjectEvent(lv_obj_t* obj, lv_event_t event, uint32_t buttonId);
void OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId);
private:
Pinetime::Controllers::Battery& batteryController;

View File

@@ -0,0 +1,173 @@
#include "Timer.h"
#include "Screen.h"
#include "Symbols.h"
#include "lvgl/lvgl.h"
using namespace Pinetime::Applications::Screens;
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
Timer* screen = static_cast<Timer*>(obj->user_data);
screen->OnButtonEvent(obj, event);
}
void Timer::createButtons() {
btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr);
btnMinutesUp->user_data = this;
lv_obj_set_event_cb(btnMinutesUp, btnEventHandler);
lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -80);
lv_obj_set_height(btnMinutesUp, 40);
lv_obj_set_width(btnMinutesUp, 60);
txtMUp = lv_label_create(btnMinutesUp, nullptr);
lv_label_set_text(txtMUp, "+");
btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr);
btnMinutesDown->user_data = this;
lv_obj_set_event_cb(btnMinutesDown, btnEventHandler);
lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, +40);
lv_obj_set_height(btnMinutesDown, 40);
lv_obj_set_width(btnMinutesDown, 60);
txtMDown = lv_label_create(btnMinutesDown, nullptr);
lv_label_set_text(txtMDown, "-");
btnSecondsUp = lv_btn_create(lv_scr_act(), nullptr);
btnSecondsUp->user_data = this;
lv_obj_set_event_cb(btnSecondsUp, btnEventHandler);
lv_obj_align(btnSecondsUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 10, -80);
lv_obj_set_height(btnSecondsUp, 40);
lv_obj_set_width(btnSecondsUp, 60);
txtSUp = lv_label_create(btnSecondsUp, nullptr);
lv_label_set_text(txtSUp, "+");
btnSecondsDown = lv_btn_create(lv_scr_act(), nullptr);
btnSecondsDown->user_data = this;
lv_obj_set_event_cb(btnSecondsDown, btnEventHandler);
lv_obj_align(btnSecondsDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 10, +40);
lv_obj_set_height(btnSecondsDown, 40);
lv_obj_set_width(btnSecondsDown, 60);
txtSDown = lv_label_create(btnSecondsDown, nullptr);
lv_label_set_text(txtSDown, "-");
}
Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController)
: Screen(app),
running{true},
timerController{timerController} {
time = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60);
lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20);
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
btnPlayPause->user_data = this;
lv_obj_set_event_cb(btnPlayPause, btnEventHandler);
lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -10);
lv_obj_set_height(btnPlayPause, 40);
txtPlayPause = lv_label_create(btnPlayPause, nullptr);
if (timerController.IsRunning()) {
lv_label_set_text(txtPlayPause, Symbols::pause);
} else {
lv_label_set_text(txtPlayPause, Symbols::play);
createButtons();
}
}
Timer::~Timer() {
lv_obj_clean(lv_scr_act());
}
bool Timer::Refresh() {
if (timerController.IsRunning()) {
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60);
}
return running;
}
void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
if (obj == btnPlayPause) {
if (timerController.IsRunning()) {
lv_label_set_text(txtPlayPause, Symbols::play);
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
minutesToSet = seconds / 60;
secondsToSet = seconds % 60;
timerController.StopTimer();
createButtons();
} else if (secondsToSet + minutesToSet > 0) {
lv_label_set_text(txtPlayPause, Symbols::pause);
timerController.StartTimer((secondsToSet + minutesToSet * 60) * 1000);
lv_obj_del(btnSecondsDown);
btnSecondsDown = nullptr;
lv_obj_del(btnSecondsUp);
btnSecondsUp = nullptr;
lv_obj_del(btnMinutesDown);
btnMinutesDown = nullptr;
lv_obj_del(btnMinutesUp);
btnMinutesUp = nullptr;
}
} else {
if (!timerController.IsRunning()) {
if (obj == btnMinutesUp) {
if (minutesToSet >= 59) {
minutesToSet = 0;
} else {
minutesToSet++;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
} else if (obj == btnMinutesDown) {
if (minutesToSet == 0) {
minutesToSet = 59;
} else {
minutesToSet--;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
} else if (obj == btnSecondsUp) {
if (secondsToSet >= 59) {
secondsToSet = 0;
} else {
secondsToSet++;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
} else if (obj == btnSecondsDown) {
if (secondsToSet == 0) {
secondsToSet = 59;
} else {
secondsToSet--;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
}
}
}
}
}
void Timer::setDone() {
lv_label_set_text(time, "00:00");
lv_label_set_text(txtPlayPause, Symbols::play);
secondsToSet = 0;
minutesToSet = 0;
createButtons();
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include "Screen.h"
#include "components/datetime/DateTimeController.h"
#include "systemtask/SystemTask.h"
#include "../LittleVgl.h"
#include "components/timer/TimerController.h"
namespace Pinetime::Applications::Screens {
class Timer : public Screen {
public:
enum class Modes {
Normal, Done
};
Timer(DisplayApp* app, Controllers::TimerController& timerController);
~Timer() override;
bool Refresh() override;
void setDone();
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
private:
bool running;
uint8_t secondsToSet = 0;
uint8_t minutesToSet = 0;
Controllers::TimerController& timerController;
void createButtons();
lv_obj_t* time, * msecTime, * btnPlayPause, * txtPlayPause, * btnMinutesUp, * btnMinutesDown, * btnSecondsUp, * btnSecondsDown, * txtMUp,
* txtMDown, * txtSUp, * txtSDown;
};
}

View File

@@ -5,39 +5,56 @@
#include "Symbols.h"
#include "NotificationIcon.h"
#include <cmath>
LV_IMG_DECLARE(bg_clock);
using namespace Pinetime::Applications::Screens;
#define HOUR_LENGTH 70
#define MINUTE_LENGTH 90
#define SECOND_LENGTH 110
#define PI 3.14159265358979323846
namespace {
// ##
static int16_t coordinate_x_relocate(int16_t x) {
return ((x) + LV_HOR_RES / 2);
constexpr auto HOUR_LENGTH = 70;
constexpr auto MINUTE_LENGTH = 90;
constexpr auto SECOND_LENGTH = 110;
// sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor
const auto LV_TRIG_SCALE = _lv_trigo_sin(90);
int16_t cosine(int16_t angle) {
return _lv_trigo_sin(angle + 90);
}
// ##
static int16_t coordinate_y_relocate(int16_t y) {
return (((y) -LV_HOR_RES / 2) < 0) ? (0 - ((y) -LV_HOR_RES / 2)) : ((y) -LV_HOR_RES / 2);
int16_t sine(int16_t angle) {
return _lv_trigo_sin(angle);
}
int16_t coordinate_x_relocate(int16_t x) {
return (x + LV_HOR_RES / 2);
}
int16_t coordinate_y_relocate(int16_t y) {
return std::abs(y - LV_HOR_RES / 2);
}
lv_point_t coordinate_relocate(int16_t radius, int16_t angle) {
return lv_point_t{
.x = coordinate_x_relocate(radius * static_cast<int32_t>(sine(angle)) / LV_TRIG_SCALE),
.y = coordinate_y_relocate(radius * static_cast<int32_t>(cosine(angle)) / LV_TRIG_SCALE)
};
}
} // namespace
WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController)
: Screen(app),
currentDateTime {{}},
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
notificatioManager {notificatioManager},
notificationManager {notificationManager},
settingsController {settingsController} {
settingsController.SetClockFace(1);
@@ -123,15 +140,12 @@ void WatchFaceAnalog::UpdateClock() {
second = dateTimeController.Seconds();
if (sMinute != minute) {
minute_point[0].x = coordinate_x_relocate(30 * sin(minute * 6 * PI / 180));
minute_point[0].y = coordinate_y_relocate(30 * cos(minute * 6 * PI / 180));
minute_point[1].x = coordinate_x_relocate(MINUTE_LENGTH * sin(minute * 6 * PI / 180));
minute_point[1].y = coordinate_y_relocate(MINUTE_LENGTH * cos(minute * 6 * PI / 180));
auto const angle = minute * 6;
minute_point[0] = coordinate_relocate(30, angle);
minute_point[1] = coordinate_relocate(MINUTE_LENGTH, angle);
minute_point_trace[0].x = coordinate_x_relocate(5 * sin(minute * 6 * PI / 180));
minute_point_trace[0].y = coordinate_y_relocate(5 * cos(minute * 6 * PI / 180));
minute_point_trace[1].x = coordinate_x_relocate(31 * sin(minute * 6 * PI / 180));
minute_point_trace[1].y = coordinate_y_relocate(31 * cos(minute * 6 * PI / 180));
minute_point_trace[0] = coordinate_relocate(5, angle);
minute_point_trace[1] = coordinate_relocate(31, angle);
lv_line_set_points(minute_body, minute_point, 2);
lv_line_set_points(minute_body_trace, minute_point_trace, 2);
@@ -140,15 +154,13 @@ void WatchFaceAnalog::UpdateClock() {
if (sHour != hour || sMinute != minute) {
sHour = hour;
sMinute = minute;
hour_point[0].x = coordinate_x_relocate(30 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point[0].y = coordinate_y_relocate(30 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point[1].x = coordinate_x_relocate(HOUR_LENGTH * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point[1].y = coordinate_y_relocate(HOUR_LENGTH * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
auto const angle = (hour * 30 + minute / 2);
hour_point_trace[0].x = coordinate_x_relocate(5 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point_trace[0].y = coordinate_y_relocate(5 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point_trace[1].x = coordinate_x_relocate(31 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point_trace[1].y = coordinate_y_relocate(31 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point[0] = coordinate_relocate(30, angle);
hour_point[1] = coordinate_relocate(HOUR_LENGTH, angle);
hour_point_trace[0] = coordinate_relocate(5, angle);
hour_point_trace[1] = coordinate_relocate(31, angle);
lv_line_set_points(hour_body, hour_point, 2);
lv_line_set_points(hour_body_trace, hour_point_trace, 2);
@@ -156,23 +168,22 @@ void WatchFaceAnalog::UpdateClock() {
if (sSecond != second) {
sSecond = second;
second_point[0].x = coordinate_x_relocate(20 * sin((180 + second * 6) * PI / 180));
second_point[0].y = coordinate_y_relocate(20 * cos((180 + second * 6) * PI / 180));
second_point[1].x = coordinate_x_relocate(SECOND_LENGTH * sin(second * 6 * PI / 180));
second_point[1].y = coordinate_y_relocate(SECOND_LENGTH * cos(second * 6 * PI / 180));
auto const angle = second * 6;
second_point[0] = coordinate_relocate(-20, angle);
second_point[1] = coordinate_relocate(SECOND_LENGTH, angle);
lv_line_set_points(second_body, second_point, 2);
}
}
bool WatchFaceAnalog::Refresh() {
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
}
notificationState = notificatioManager.AreNewNotificationsAvailable();
notificationState = notificationManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
if (notificationState.Get() == true)
@@ -202,4 +213,4 @@ bool WatchFaceAnalog::Refresh() {
}
return true;
}
}

View File

@@ -27,7 +27,7 @@ namespace Pinetime {
Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController);
~WatchFaceAnalog() override;
@@ -48,7 +48,7 @@ namespace Pinetime {
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
uint8_t currentDay = 0;
DirtyValue<float> batteryPercentRemaining {0};
DirtyValue<uint8_t> batteryPercentRemaining {0};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
DirtyValue<bool> notificationState {false};
@@ -79,11 +79,11 @@ namespace Pinetime {
Controllers::DateTime& dateTimeController;
Controllers::Battery& batteryController;
Controllers::Ble& bleController;
Controllers::NotificationManager& notificatioManager;
Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController;
void UpdateClock();
};
}
}
}
}

View File

@@ -45,7 +45,7 @@ namespace Pinetime {
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
uint8_t currentDay = 0;
DirtyValue<int> batteryPercentRemaining {};
DirtyValue<uint8_t> batteryPercentRemaining {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};

View File

@@ -7,12 +7,12 @@ using namespace Pinetime::Applications::Screens;
namespace {
static void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
QuickSettings* screen = static_cast<QuickSettings*>(obj->user_data);
auto* screen = static_cast<QuickSettings*>(obj->user_data);
screen->OnButtonEvent(obj, event);
}
static void lv_update_task(struct _lv_task_t* task) {
auto user_data = static_cast<QuickSettings*>(task->user_data);
auto* user_data = static_cast<QuickSettings*>(task->user_data);
user_data->UpdateScreen();
}
}
@@ -27,7 +27,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
batteryController {batteryController},
dateTimeController {dateTimeController},
brightness {brightness},
motorController{motorController},
motorController {motorController},
settingsController {settingsController} {
// Time
@@ -110,7 +110,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this);
taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this);
}
QuickSettings::~QuickSettings() {
@@ -154,17 +154,6 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
}
}
bool QuickSettings::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
switch (event) {
case Pinetime::Applications::TouchEvents::SwipeLeft:
running = false;
return false;
default:
return true;
}
}
bool QuickSettings::Refresh() {
return running;
}

View File

@@ -29,7 +29,6 @@ namespace Pinetime {
bool Refresh() override;
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
void UpdateScreen();

View File

@@ -45,7 +45,7 @@ SettingSteps::SettingSteps(
stepValue = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(stepValue,"%i", settingsController.GetStepsGoal());
lv_label_set_text_fmt(stepValue, "%lu", settingsController.GetStepsGoal());
lv_label_set_align(stepValue, LV_LABEL_ALIGN_CENTER);
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
@@ -81,7 +81,7 @@ void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) {
value += 1000;
if ( value <= 500000 ) {
settingsController.SetStepsGoal(value);
lv_label_set_text_fmt(stepValue,"%i", settingsController.GetStepsGoal());
lv_label_set_text_fmt(stepValue, "%lu", settingsController.GetStepsGoal());
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
}
}
@@ -90,7 +90,7 @@ void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) {
value -= 1000;
if ( value >= 1000 ) {
settingsController.SetStepsGoal(value);
lv_label_set_text_fmt(stepValue,"%i", settingsController.GetStepsGoal());
lv_label_set_text_fmt(stepValue, "%lu", settingsController.GetStepsGoal());
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
}
}

View File

@@ -16,7 +16,7 @@ namespace {
SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
: Screen(app), settingsController {settingsController} {
ignoringEvents = false;
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
@@ -36,24 +36,16 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
lv_label_set_text_static(icon, Symbols::clock);
lv_label_set_text_static(icon, Symbols::eye);
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
optionsTotal = 0;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " None");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::None) {
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " Single Tap");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::SingleTap) {
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) {
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
@@ -61,7 +53,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
lv_checkbox_set_text_static(cbOption[optionsTotal], " Double Tap");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) {
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
@@ -69,7 +61,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
lv_checkbox_set_text_static(cbOption[optionsTotal], " Raise Wrist");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) {
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) {
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
@@ -85,27 +77,31 @@ bool SettingWakeUp::Refresh() {
}
void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_VALUE_CHANGED) {
for (int i = 0; i < optionsTotal; i++) {
if (object == cbOption[i]) {
lv_checkbox_set_checked(cbOption[i], true);
using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode;
if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) {
ignoringEvents = true;
if (i == 0) {
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::None);
};
if (i == 1) {
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::SingleTap);
};
if (i == 2) {
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap);
};
if (i == 3) {
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist);
};
} else {
lv_checkbox_set_checked(cbOption[i], false);
// Find the index of the checkbox that triggered the event
int index = 0;
for (; index < optionsTotal; ++index) {
if (cbOption[index] == object) {
break;
}
}
// Toggle needed wakeup mode
auto mode = static_cast<WakeUpMode>(index);
auto currentState = settingsController.isWakeUpModeOn(mode);
settingsController.setWakeUpMode(mode, !currentState);
// Update checkbox according to current wakeup modes.
// This is needed because we can have extra logic when setting or unsetting wakeup modes,
// for example, when setting SingleTap, DoubleTap is unset and vice versa.
auto modes = settingsController.getWakeUpModes();
for (int i = 0; i < optionsTotal; ++i) {
lv_checkbox_set_checked(cbOption[i], modes[i]);
}
ignoringEvents = false;
}
}
}

View File

@@ -22,6 +22,11 @@ namespace Pinetime {
Controllers::Settings& settingsController;
uint8_t optionsTotal;
lv_obj_t* cbOption[4];
// When UpdateSelected is called, it uses lv_checkbox_set_checked,
// which can cause extra events to be fired,
// which might trigger UpdateSelected again, causing a loop.
// This variable is used as a mutex to prevent that.
bool ignoringEvents;
};
}
}

View File

@@ -36,7 +36,7 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pine
lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
lv_label_set_text_static(icon, Symbols::clock);
lv_label_set_text_static(icon, Symbols::home);
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
@@ -58,6 +58,15 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pine
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " PineTimeStyle");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.GetClockFace() == 2) {
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
}
@@ -81,4 +90,4 @@ void SettingWatchFace::UpdateSelected(lv_obj_t* object, lv_event_t event) {
}
}
}
}
}

View File

@@ -41,12 +41,12 @@ std::unique_ptr<Screen> Settings::CreateScreen1() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::sun, "Display", Apps::SettingDisplay},
{Symbols::clock, "Wake Up", Apps::SettingWakeUp},
{Symbols::eye, "Wake Up", Apps::SettingWakeUp},
{Symbols::clock, "Time format", Apps::SettingTimeFormat},
{Symbols::clock, "Watch face", Apps::SettingWatchFace},
{Symbols::home, "Watch face", Apps::SettingWatchFace},
}};
return std::unique_ptr<Screen>(new Screens::List(0, 2, app, settingsController, applications));
return std::make_unique<Screens::List>(0, 2, app, settingsController, applications);
}
std::unique_ptr<Screen> Settings::CreateScreen2() {
@@ -58,5 +58,5 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
{Symbols::list, "About", Apps::SysInfo},
}};
return std::unique_ptr<Screen>(new Screens::List(1, 2, app, settingsController, applications));
return std::make_unique<Screens::List>(1, 2, app, settingsController, applications);
}

View File

@@ -16,7 +16,6 @@ namespace Pinetime {
bool Refresh() override;
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
private: