From d17afc878651ea39a47cf6bed20be133591fd241 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 22 Feb 2023 22:25:11 +0100 Subject: [PATCH 001/141] Updated old class name --- include/{osw_app.h => OswAppV1.h} | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) rename include/{osw_app.h => OswAppV1.h} (82%) diff --git a/include/osw_app.h b/include/OswAppV1.h similarity index 82% rename from include/osw_app.h rename to include/OswAppV1.h index 924a72bb0..73938f811 100644 --- a/include/osw_app.h +++ b/include/OswAppV1.h @@ -1,13 +1,11 @@ -#ifndef OSW_APP_H -#define OSW_APP_H - +#pragma once #include #ifdef OSW_EMULATOR #include "imgui.h" #endif -class OswApp { +class OswAppV1 { public: virtual void setup() = 0; virtual void loop() = 0; @@ -17,4 +15,4 @@ class OswApp { #endif }; -#endif \ No newline at end of file +typedef OswAppV1 OswApp; \ No newline at end of file From aba2b705dddca5f8b2123bf90c7b54fe8ee4217f Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 23 Feb 2023 20:14:47 +0100 Subject: [PATCH 002/141] Fixed broken include reference --- include/OswAppV1.h | 2 +- include/apps/_experiments/OswAppWeather.h | 2 +- include/apps/_experiments/autumn.h | 2 +- include/apps/_experiments/dnatilt.h | 2 +- include/apps/_experiments/fadein_display.h | 2 +- include/apps/_experiments/fireworks.h | 2 +- include/apps/_experiments/gif_player.h | 2 +- include/apps/_experiments/hello_world.h | 2 +- include/apps/_experiments/magnetometer_calibrate.h | 2 +- include/apps/_experiments/power_demo.h | 2 +- include/apps/_experiments/runtime_test.h | 2 +- include/apps/_experiments/show_display_size.h | 2 +- include/apps/clock/OswAppAlarm.h | 2 +- include/apps/clock/OswAppTimer.h | 2 +- include/apps/clock/stopwatch.h | 2 +- include/apps/examples/fonts/fonts_example.h | 2 +- include/apps/games/brick_breaker.h | 2 +- include/apps/games/snake_game.h | 2 +- include/apps/main/luaapp.h | 2 +- include/apps/main/map.h | 2 +- include/apps/main/switcher.h | 2 +- include/apps/tools/OswAppBLEMediaCtrl.h | 2 +- include/apps/tools/OswAppCalculator.h | 2 +- include/apps/tools/OswAppDistStats.h | 2 +- include/apps/tools/OswAppFitnessStats.h | 2 +- include/apps/tools/OswAppFlashLight.h | 2 +- include/apps/tools/OswAppKcalStats.h | 2 +- include/apps/tools/OswAppPrintDebug.h | 2 +- include/apps/tools/OswAppStepStats.h | 2 +- include/apps/tools/OswAppTimeConfig.h | 2 +- include/apps/tools/OswAppWaterLevel.h | 2 +- include/apps/tools/OswAppWebserver.h | 2 +- include/apps/tools/button_test.h | 2 +- include/apps/watchfaces/OswAppWatchface.h | 2 +- include/apps/watchfaces/OswAppWatchfaceBinary.h | 2 +- include/apps/watchfaces/OswAppWatchfaceDigital.h | 2 +- include/apps/watchfaces/OswAppWatchfaceDual.h | 2 +- include/apps/watchfaces/OswAppWatchfaceFitness.h | 2 +- include/apps/watchfaces/OswAppWatchfaceMix.h | 2 +- include/apps/watchfaces/OswAppWatchfaceMonotimer.h | 2 +- include/apps/watchfaces/OswAppWatchfaceNumerals.h | 2 +- include/osw_service.h | 2 +- src/apps/_experiments/OswAppWeather.cpp | 2 +- src/apps/_experiments/autumn.cpp | 2 +- src/apps/_experiments/dnatilt.cpp | 2 +- src/apps/_experiments/fadein_display.cpp | 2 +- src/apps/_experiments/fireworks.cpp | 2 +- src/apps/_experiments/gif_player.cpp | 2 +- src/apps/_experiments/hello_world.cpp | 2 +- src/apps/_experiments/magnetometer_calibrate.cpp | 2 +- src/apps/_experiments/power_demo.cpp | 2 +- src/apps/_experiments/show_display_size.cpp | 2 +- src/apps/clock/stopwatch.cpp | 2 +- src/apps/games/brick_breaker.cpp | 2 +- src/apps/games/snake_game.cpp | 2 +- src/apps/main/luaapp.cpp | 2 +- src/apps/main/map.cpp | 2 +- src/apps/tools/OswAppBLEMediaCtrl.cpp | 2 +- src/apps/tools/OswAppCalculator.cpp | 2 +- src/apps/tools/OswAppDistStats.cpp | 2 +- src/apps/tools/OswAppFitnessStats.cpp | 2 +- src/apps/tools/OswAppFlashLight.cpp | 2 +- src/apps/tools/OswAppKcalStats.cpp | 2 +- src/apps/tools/OswAppPrintDebug.cpp | 2 +- src/apps/tools/OswAppStepStats.cpp | 2 +- src/apps/tools/OswAppTimeConfig.cpp | 2 +- src/apps/tools/OswAppWaterLevel.cpp | 2 +- src/apps/tools/OswAppWebserver.cpp | 2 +- src/apps/tools/button_test.cpp | 2 +- src/apps/watchfaces/OswAppWatchface.cpp | 2 +- src/apps/watchfaces/OswAppWatchfaceBinary.cpp | 2 +- src/apps/watchfaces/OswAppWatchfaceDigital.cpp | 2 +- src/apps/watchfaces/OswAppWatchfaceDual.cpp | 2 +- src/apps/watchfaces/OswAppWatchfaceFitness.cpp | 2 +- src/apps/watchfaces/OswAppWatchfaceMix.cpp | 2 +- src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp | 2 +- src/apps/watchfaces/OswAppWatchfaceNumerals.cpp | 2 +- src/main.cpp | 2 +- 78 files changed, 78 insertions(+), 78 deletions(-) diff --git a/include/OswAppV1.h b/include/OswAppV1.h index 73938f811..01d076ec2 100644 --- a/include/OswAppV1.h +++ b/include/OswAppV1.h @@ -15,4 +15,4 @@ class OswAppV1 { #endif }; -typedef OswAppV1 OswApp; \ No newline at end of file +typedef OswAppV1 OswApp; // For backwards compatibility \ No newline at end of file diff --git a/include/apps/_experiments/OswAppWeather.h b/include/apps/_experiments/OswAppWeather.h index d65b3ec23..995884680 100644 --- a/include/apps/_experiments/OswAppWeather.h +++ b/include/apps/_experiments/OswAppWeather.h @@ -2,7 +2,7 @@ #ifdef OSW_FEATURE_WEATHER #include #include -#include "osw_app.h" +#include #include "OswAppWeatherIconPrinter.h" class OswAppWeather : public OswApp { diff --git a/include/apps/_experiments/autumn.h b/include/apps/_experiments/autumn.h index eae345639..5050be2a6 100644 --- a/include/apps/_experiments/autumn.h +++ b/include/apps/_experiments/autumn.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppAutumn : public OswApp { public: diff --git a/include/apps/_experiments/dnatilt.h b/include/apps/_experiments/dnatilt.h index 81d835be6..7c802621c 100644 --- a/include/apps/_experiments/dnatilt.h +++ b/include/apps/_experiments/dnatilt.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppDNATilt : public OswApp { public: diff --git a/include/apps/_experiments/fadein_display.h b/include/apps/_experiments/fadein_display.h index 57081d561..981a6401b 100644 --- a/include/apps/_experiments/fadein_display.h +++ b/include/apps/_experiments/fadein_display.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppFadeInDisplay : public OswApp { public: diff --git a/include/apps/_experiments/fireworks.h b/include/apps/_experiments/fireworks.h index ebee0b01f..3f253b0c0 100644 --- a/include/apps/_experiments/fireworks.h +++ b/include/apps/_experiments/fireworks.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppFireworks : public OswApp { public: diff --git a/include/apps/_experiments/gif_player.h b/include/apps/_experiments/gif_player.h index 6d181ec55..11c1b701c 100644 --- a/include/apps/_experiments/gif_player.h +++ b/include/apps/_experiments/gif_player.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppGifPlayer : public OswApp { public: diff --git a/include/apps/_experiments/hello_world.h b/include/apps/_experiments/hello_world.h index cff70cc53..aee95a2f7 100644 --- a/include/apps/_experiments/hello_world.h +++ b/include/apps/_experiments/hello_world.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppHelloWorld : public OswApp { public: diff --git a/include/apps/_experiments/magnetometer_calibrate.h b/include/apps/_experiments/magnetometer_calibrate.h index e76ac011c..e6b818762 100644 --- a/include/apps/_experiments/magnetometer_calibrate.h +++ b/include/apps/_experiments/magnetometer_calibrate.h @@ -1,7 +1,7 @@ #pragma once #include -#include "osw_app.h" +#include #if OSW_PLATFORM_ENVIRONMENT_MAGNETOMETER == 1 && OSW_PLATFORM_HARDWARE_QMC5883L == 1 class OswAppMagnetometerCalibrate : public OswApp { diff --git a/include/apps/_experiments/power_demo.h b/include/apps/_experiments/power_demo.h index 13ea3dedb..893a5d995 100644 --- a/include/apps/_experiments/power_demo.h +++ b/include/apps/_experiments/power_demo.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppPowerDemo : public OswApp { public: diff --git a/include/apps/_experiments/runtime_test.h b/include/apps/_experiments/runtime_test.h index 84929fb1a..a84792d93 100644 --- a/include/apps/_experiments/runtime_test.h +++ b/include/apps/_experiments/runtime_test.h @@ -4,7 +4,7 @@ #include -#include "osw_app.h" +#include class MiniIotClient; class OswAppRuntimeTest : public OswApp { diff --git a/include/apps/_experiments/show_display_size.h b/include/apps/_experiments/show_display_size.h index 1d6cae629..c6e6732ef 100644 --- a/include/apps/_experiments/show_display_size.h +++ b/include/apps/_experiments/show_display_size.h @@ -3,7 +3,7 @@ #include -#include "osw_app.h" +#include class OswAppShowDisplaySize : public OswApp { public: diff --git a/include/apps/clock/OswAppAlarm.h b/include/apps/clock/OswAppAlarm.h index 9d327b47d..d0673727b 100644 --- a/include/apps/clock/OswAppAlarm.h +++ b/include/apps/clock/OswAppAlarm.h @@ -3,7 +3,7 @@ #include "../lib/date/date.h" -#include +#include #include #include #include "apps/main/switcher.h" diff --git a/include/apps/clock/OswAppTimer.h b/include/apps/clock/OswAppTimer.h index 5183e99a6..532600da4 100644 --- a/include/apps/clock/OswAppTimer.h +++ b/include/apps/clock/OswAppTimer.h @@ -3,7 +3,7 @@ #include "../lib/date/date.h" -#include "osw_app.h" +#include #include #include #include "apps/main/switcher.h" diff --git a/include/apps/clock/stopwatch.h b/include/apps/clock/stopwatch.h index dca2956df..32bc47d0e 100644 --- a/include/apps/clock/stopwatch.h +++ b/include/apps/clock/stopwatch.h @@ -2,7 +2,7 @@ #include #include -#include "osw_app.h" +#include #define maxLaps 36 #define lapsPerPage 5 diff --git a/include/apps/examples/fonts/fonts_example.h b/include/apps/examples/fonts/fonts_example.h index f80cc303c..727eeef0a 100644 --- a/include/apps/examples/fonts/fonts_example.h +++ b/include/apps/examples/fonts/fonts_example.h @@ -1,7 +1,7 @@ #ifndef OSW_APP_FONTS_EXAMPLE_H #define OSW_APP_FONTS_EXAMPLE_H -#include +#include class OswAppFontsExample: public OswApp { public: OswAppFontsExample(void) {}; diff --git a/include/apps/games/brick_breaker.h b/include/apps/games/brick_breaker.h index 86c63db20..b0f3047d1 100644 --- a/include/apps/games/brick_breaker.h +++ b/include/apps/games/brick_breaker.h @@ -4,7 +4,7 @@ #include #include -#include "osw_app.h" +#include class OswAppBrickBreaker : public OswApp { public: diff --git a/include/apps/games/snake_game.h b/include/apps/games/snake_game.h index 57face9d2..b421b971a 100644 --- a/include/apps/games/snake_game.h +++ b/include/apps/games/snake_game.h @@ -4,7 +4,7 @@ #include #include -#include "osw_app.h" +#include class OswAppSnakeGame : public OswApp { public: diff --git a/include/apps/main/luaapp.h b/include/apps/main/luaapp.h index c7fbee15d..4d3dce17d 100644 --- a/include/apps/main/luaapp.h +++ b/include/apps/main/luaapp.h @@ -4,7 +4,7 @@ #include #include -#include "osw_app.h" +#include #define LUA_SETUP_FUNC "setup" #define LUA_LOOP_FUNC "loop" diff --git a/include/apps/main/map.h b/include/apps/main/map.h index 884391498..6e2cc947d 100644 --- a/include/apps/main/map.h +++ b/include/apps/main/map.h @@ -4,7 +4,7 @@ #include #include -#include "osw_app.h" +#include class OswAppMap : public OswApp { public: diff --git a/include/apps/main/switcher.h b/include/apps/main/switcher.h index c28c90731..818668ae2 100644 --- a/include/apps/main/switcher.h +++ b/include/apps/main/switcher.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include diff --git a/include/apps/tools/OswAppBLEMediaCtrl.h b/include/apps/tools/OswAppBLEMediaCtrl.h index 74ed095b2..aed7dc926 100644 --- a/include/apps/tools/OswAppBLEMediaCtrl.h +++ b/include/apps/tools/OswAppBLEMediaCtrl.h @@ -2,7 +2,7 @@ #pragma once #include -#include "osw_app.h" +#include class OswAppBLEMediaCtrl : public OswApp { public: diff --git a/include/apps/tools/OswAppCalculator.h b/include/apps/tools/OswAppCalculator.h index 59ee47996..7755d28dc 100644 --- a/include/apps/tools/OswAppCalculator.h +++ b/include/apps/tools/OswAppCalculator.h @@ -2,7 +2,7 @@ #include #include -#include "osw_app.h" +#include class OswAppCalculator : public OswApp { public: diff --git a/include/apps/tools/OswAppDistStats.h b/include/apps/tools/OswAppDistStats.h index a53f1b69b..7f3ff4af5 100644 --- a/include/apps/tools/OswAppDistStats.h +++ b/include/apps/tools/OswAppDistStats.h @@ -4,7 +4,7 @@ #include #include -#include "osw_app.h" +#include class OswAppDistStats : public OswApp { public: diff --git a/include/apps/tools/OswAppFitnessStats.h b/include/apps/tools/OswAppFitnessStats.h index 5d09a7ffc..f22cb3bde 100644 --- a/include/apps/tools/OswAppFitnessStats.h +++ b/include/apps/tools/OswAppFitnessStats.h @@ -2,7 +2,7 @@ #include #include -#include "osw_app.h" +#include class OswAppFitnessStats : public OswApp { public: diff --git a/include/apps/tools/OswAppFlashLight.h b/include/apps/tools/OswAppFlashLight.h index 21c3340f8..e7d69ee67 100644 --- a/include/apps/tools/OswAppFlashLight.h +++ b/include/apps/tools/OswAppFlashLight.h @@ -2,7 +2,7 @@ #include #include -#include "osw_app.h" +#include class OswAppFlashLight : public OswApp { diff --git a/include/apps/tools/OswAppKcalStats.h b/include/apps/tools/OswAppKcalStats.h index 581476945..c034260c0 100644 --- a/include/apps/tools/OswAppKcalStats.h +++ b/include/apps/tools/OswAppKcalStats.h @@ -4,7 +4,7 @@ #include #include -#include "osw_app.h" +#include class OswAppKcalStats : public OswApp { public: diff --git a/include/apps/tools/OswAppPrintDebug.h b/include/apps/tools/OswAppPrintDebug.h index 813289d3a..26c992322 100644 --- a/include/apps/tools/OswAppPrintDebug.h +++ b/include/apps/tools/OswAppPrintDebug.h @@ -2,7 +2,7 @@ #pragma once #include -#include "osw_app.h" +#include class OswAppPrintDebug : public OswApp { public: diff --git a/include/apps/tools/OswAppStepStats.h b/include/apps/tools/OswAppStepStats.h index 0d2f057e0..0ca523862 100644 --- a/include/apps/tools/OswAppStepStats.h +++ b/include/apps/tools/OswAppStepStats.h @@ -4,7 +4,7 @@ #include #include -#include "osw_app.h" +#include class OswAppStepStats : public OswApp { public: diff --git a/include/apps/tools/OswAppTimeConfig.h b/include/apps/tools/OswAppTimeConfig.h index 091772621..5c6aa8aac 100644 --- a/include/apps/tools/OswAppTimeConfig.h +++ b/include/apps/tools/OswAppTimeConfig.h @@ -3,7 +3,7 @@ #include #include #include "apps/main/switcher.h" -#include "osw_app.h" +#include class OswAppTimeConfig : public OswApp { public: diff --git a/include/apps/tools/OswAppWaterLevel.h b/include/apps/tools/OswAppWaterLevel.h index 04956b867..994eec2eb 100644 --- a/include/apps/tools/OswAppWaterLevel.h +++ b/include/apps/tools/OswAppWaterLevel.h @@ -2,7 +2,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWaterLevel : public OswApp { public: diff --git a/include/apps/tools/OswAppWebserver.h b/include/apps/tools/OswAppWebserver.h index 6a8d86a46..b39053ceb 100644 --- a/include/apps/tools/OswAppWebserver.h +++ b/include/apps/tools/OswAppWebserver.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWebserver : public OswApp { public: diff --git a/include/apps/tools/button_test.h b/include/apps/tools/button_test.h index 6b166c1b6..ce105fda2 100644 --- a/include/apps/tools/button_test.h +++ b/include/apps/tools/button_test.h @@ -1,7 +1,7 @@ #pragma once #include -#include "osw_app.h" +#include class OswButtonTest : public OswApp { public: diff --git a/include/apps/watchfaces/OswAppWatchface.h b/include/apps/watchfaces/OswAppWatchface.h index 5fa4fa9a8..f58199bcf 100644 --- a/include/apps/watchfaces/OswAppWatchface.h +++ b/include/apps/watchfaces/OswAppWatchface.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include #ifdef ANIMATION #include #endif diff --git a/include/apps/watchfaces/OswAppWatchfaceBinary.h b/include/apps/watchfaces/OswAppWatchfaceBinary.h index 94901d2a8..0ad35bbb6 100644 --- a/include/apps/watchfaces/OswAppWatchfaceBinary.h +++ b/include/apps/watchfaces/OswAppWatchfaceBinary.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWatchfaceBinary : public OswApp { public: diff --git a/include/apps/watchfaces/OswAppWatchfaceDigital.h b/include/apps/watchfaces/OswAppWatchfaceDigital.h index efc0992fb..215327c41 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDigital.h +++ b/include/apps/watchfaces/OswAppWatchfaceDigital.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWatchfaceDigital : public OswApp { public: diff --git a/include/apps/watchfaces/OswAppWatchfaceDual.h b/include/apps/watchfaces/OswAppWatchfaceDual.h index a72edfc14..b505aca43 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDual.h +++ b/include/apps/watchfaces/OswAppWatchfaceDual.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWatchfaceDual : public OswApp { public: diff --git a/include/apps/watchfaces/OswAppWatchfaceFitness.h b/include/apps/watchfaces/OswAppWatchfaceFitness.h index 6593c165b..bdaed61f5 100644 --- a/include/apps/watchfaces/OswAppWatchfaceFitness.h +++ b/include/apps/watchfaces/OswAppWatchfaceFitness.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWatchfaceFitness : public OswApp { public: diff --git a/include/apps/watchfaces/OswAppWatchfaceMix.h b/include/apps/watchfaces/OswAppWatchfaceMix.h index bd89cc623..5d31caf7f 100644 --- a/include/apps/watchfaces/OswAppWatchfaceMix.h +++ b/include/apps/watchfaces/OswAppWatchfaceMix.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWatchfaceMix : public OswApp { public: diff --git a/include/apps/watchfaces/OswAppWatchfaceMonotimer.h b/include/apps/watchfaces/OswAppWatchfaceMonotimer.h index 2378357f8..893ec7f73 100644 --- a/include/apps/watchfaces/OswAppWatchfaceMonotimer.h +++ b/include/apps/watchfaces/OswAppWatchfaceMonotimer.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWatchfaceMonotimer : public OswApp { public: diff --git a/include/apps/watchfaces/OswAppWatchfaceNumerals.h b/include/apps/watchfaces/OswAppWatchfaceNumerals.h index 9380318e3..1d1dccbef 100644 --- a/include/apps/watchfaces/OswAppWatchfaceNumerals.h +++ b/include/apps/watchfaces/OswAppWatchfaceNumerals.h @@ -3,7 +3,7 @@ #include #include -#include "osw_app.h" +#include class OswAppWatchfaceNumerals : public OswApp { public: diff --git a/include/osw_service.h b/include/osw_service.h index ce7beff0f..af90c8847 100644 --- a/include/osw_service.h +++ b/include/osw_service.h @@ -1,6 +1,6 @@ #ifndef OSW_SERVICE_H #define OSW_SERVICE_H -#include +#include class OswServiceTask : public OswApp { public: diff --git a/src/apps/_experiments/OswAppWeather.cpp b/src/apps/_experiments/OswAppWeather.cpp index f2babe00a..b813a3f3e 100644 --- a/src/apps/_experiments/OswAppWeather.cpp +++ b/src/apps/_experiments/OswAppWeather.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include "fonts/DS_DIGI12pt7b.h" #include "ArduinoJson.h" diff --git a/src/apps/_experiments/autumn.cpp b/src/apps/_experiments/autumn.cpp index a7ecabea0..4d5d6f305 100644 --- a/src/apps/_experiments/autumn.cpp +++ b/src/apps/_experiments/autumn.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) diff --git a/src/apps/_experiments/dnatilt.cpp b/src/apps/_experiments/dnatilt.cpp index d36ff4f67..0934dc6d1 100644 --- a/src/apps/_experiments/dnatilt.cpp +++ b/src/apps/_experiments/dnatilt.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/apps/_experiments/fadein_display.cpp b/src/apps/_experiments/fadein_display.cpp index 532692a3b..f84658812 100644 --- a/src/apps/_experiments/fadein_display.cpp +++ b/src/apps/_experiments/fadein_display.cpp @@ -2,7 +2,7 @@ #include "./apps/_experiments/fadein_display.h" #include -#include +#include #include void OswAppFadeInDisplay::loop() { diff --git a/src/apps/_experiments/fireworks.cpp b/src/apps/_experiments/fireworks.cpp index bff357ca5..30d9406b5 100644 --- a/src/apps/_experiments/fireworks.cpp +++ b/src/apps/_experiments/fireworks.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include // OswAppHelloWorld::OswAppHelloWorld(void) : OswApp() {} diff --git a/src/apps/_experiments/gif_player.cpp b/src/apps/_experiments/gif_player.cpp index 233b9a9dd..87c3df6a2 100644 --- a/src/apps/_experiments/gif_player.cpp +++ b/src/apps/_experiments/gif_player.cpp @@ -3,7 +3,7 @@ #ifndef OSW_EMULATOR #include #include -#include +#include #include #include "assets/mwdu.h" diff --git a/src/apps/_experiments/hello_world.cpp b/src/apps/_experiments/hello_world.cpp index ce23ef231..b0fc8a680 100644 --- a/src/apps/_experiments/hello_world.cpp +++ b/src/apps/_experiments/hello_world.cpp @@ -2,7 +2,7 @@ #include "./apps/_experiments/hello_world.h" #include -#include +#include #include // define global scope variables bool red = false; diff --git a/src/apps/_experiments/magnetometer_calibrate.cpp b/src/apps/_experiments/magnetometer_calibrate.cpp index a1dc79623..8c1b623b6 100644 --- a/src/apps/_experiments/magnetometer_calibrate.cpp +++ b/src/apps/_experiments/magnetometer_calibrate.cpp @@ -2,7 +2,7 @@ #include "./apps/_experiments/magnetometer_calibrate.h" #include -#include +#include #include #include diff --git a/src/apps/_experiments/power_demo.cpp b/src/apps/_experiments/power_demo.cpp index 226c955a5..2bd3f009d 100644 --- a/src/apps/_experiments/power_demo.cpp +++ b/src/apps/_experiments/power_demo.cpp @@ -2,7 +2,7 @@ #include "./apps/_experiments/power_demo.h" #include -#include +#include #include void drawColors() { diff --git a/src/apps/_experiments/show_display_size.cpp b/src/apps/_experiments/show_display_size.cpp index 5754264be..3e81c7932 100644 --- a/src/apps/_experiments/show_display_size.cpp +++ b/src/apps/_experiments/show_display_size.cpp @@ -2,7 +2,7 @@ #include "./apps/_experiments/show_display_size.h" #include -#include +#include #include // OswAppHelloWorld::OswAppHelloWorld(void) : OswApp() {} diff --git a/src/apps/clock/stopwatch.cpp b/src/apps/clock/stopwatch.cpp index cf843f3af..f0e50a6cf 100644 --- a/src/apps/clock/stopwatch.cpp +++ b/src/apps/clock/stopwatch.cpp @@ -2,7 +2,7 @@ #include "config_defaults.h" // Include the config here again to access the language definitions of it #include "gfx_util.h" -#include "osw_app.h" +#include #include "osw_hal.h" #include "osw_ui.h" diff --git a/src/apps/games/brick_breaker.cpp b/src/apps/games/brick_breaker.cpp index 44906c4a7..01853dd80 100644 --- a/src/apps/games/brick_breaker.cpp +++ b/src/apps/games/brick_breaker.cpp @@ -2,7 +2,7 @@ #include "./apps/games/brick_breaker.h" #include -#include +#include #include #include #include diff --git a/src/apps/games/snake_game.cpp b/src/apps/games/snake_game.cpp index 3476b53ea..12f3bb648 100644 --- a/src/apps/games/snake_game.cpp +++ b/src/apps/games/snake_game.cpp @@ -3,7 +3,7 @@ // #define GIF_BG #include -#include +#include #include #include #include diff --git a/src/apps/main/luaapp.cpp b/src/apps/main/luaapp.cpp index b89b4b12d..31a0c3f51 100644 --- a/src/apps/main/luaapp.cpp +++ b/src/apps/main/luaapp.cpp @@ -1,7 +1,7 @@ #ifdef OSW_FEATURE_LUA #include "./apps/main/luaapp.h" -#include +#include #include #include diff --git a/src/apps/main/map.cpp b/src/apps/main/map.cpp index 6b155f67c..aaca7138a 100644 --- a/src/apps/main/map.cpp +++ b/src/apps/main/map.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #ifdef PROGMEM_TILES diff --git a/src/apps/tools/OswAppBLEMediaCtrl.cpp b/src/apps/tools/OswAppBLEMediaCtrl.cpp index e2b4fb59c..c0ef95174 100644 --- a/src/apps/tools/OswAppBLEMediaCtrl.cpp +++ b/src/apps/tools/OswAppBLEMediaCtrl.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include BleKeyboard* bleKeyboard; diff --git a/src/apps/tools/OswAppCalculator.cpp b/src/apps/tools/OswAppCalculator.cpp index 8f85b79fc..d02d85a87 100644 --- a/src/apps/tools/OswAppCalculator.cpp +++ b/src/apps/tools/OswAppCalculator.cpp @@ -8,7 +8,7 @@ #include "config_defaults.h" #include "gfx_util.h" -#include "osw_app.h" +#include #include "osw_hal.h" #include "osw_ui.h" diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp index b9b622e9e..88d4cea7e 100644 --- a/src/apps/tools/OswAppDistStats.cpp +++ b/src/apps/tools/OswAppDistStats.cpp @@ -5,7 +5,7 @@ #include "./apps/tools/OswAppStepStats.h" #include -#include +#include #include #include diff --git a/src/apps/tools/OswAppFitnessStats.cpp b/src/apps/tools/OswAppFitnessStats.cpp index be82d565c..fbd59549e 100644 --- a/src/apps/tools/OswAppFitnessStats.cpp +++ b/src/apps/tools/OswAppFitnessStats.cpp @@ -3,7 +3,7 @@ #include "./apps/watchfaces/OswAppWatchfaceFitness.h" #include -#include +#include #include #include diff --git a/src/apps/tools/OswAppFlashLight.cpp b/src/apps/tools/OswAppFlashLight.cpp index e0cde5ef0..a4f1868c7 100644 --- a/src/apps/tools/OswAppFlashLight.cpp +++ b/src/apps/tools/OswAppFlashLight.cpp @@ -2,7 +2,7 @@ #include "config_defaults.h" // Include the config here again to access the language definitions of it #include "gfx_util.h" -#include "osw_app.h" +#include #include "osw_hal.h" #include "osw_ui.h" diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index b1b13ef42..1114c3b49 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -5,7 +5,7 @@ #include "./apps/tools/OswAppStepStats.h" #include -#include +#include #include #include diff --git a/src/apps/tools/OswAppPrintDebug.cpp b/src/apps/tools/OswAppPrintDebug.cpp index 2d438e98a..5f864f746 100644 --- a/src/apps/tools/OswAppPrintDebug.cpp +++ b/src/apps/tools/OswAppPrintDebug.cpp @@ -3,7 +3,7 @@ #include "./apps/tools/OswAppPrintDebug.h" #include -#include +#include #include #include #include "services/OswServiceTasks.h" diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 6cae87b07..a3e818f7f 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -4,7 +4,7 @@ #include "./apps/watchfaces/OswAppWatchfaceFitness.h" #include -#include +#include #include #include diff --git a/src/apps/tools/OswAppTimeConfig.cpp b/src/apps/tools/OswAppTimeConfig.cpp index 219b9abbb..8bc90c0e5 100644 --- a/src/apps/tools/OswAppTimeConfig.cpp +++ b/src/apps/tools/OswAppTimeConfig.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/apps/tools/OswAppWaterLevel.cpp b/src/apps/tools/OswAppWaterLevel.cpp index e67603407..7164143f2 100644 --- a/src/apps/tools/OswAppWaterLevel.cpp +++ b/src/apps/tools/OswAppWaterLevel.cpp @@ -2,7 +2,7 @@ #include "./apps/tools/OswAppWaterLevel.h" #include -#include +#include #include const int middleX = 120; diff --git a/src/apps/tools/OswAppWebserver.cpp b/src/apps/tools/OswAppWebserver.cpp index ce695d0bb..1ce4fd032 100644 --- a/src/apps/tools/OswAppWebserver.cpp +++ b/src/apps/tools/OswAppWebserver.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/apps/tools/button_test.cpp b/src/apps/tools/button_test.cpp index 2aeb9abfb..babf8d10e 100644 --- a/src/apps/tools/button_test.cpp +++ b/src/apps/tools/button_test.cpp @@ -2,7 +2,7 @@ #include "./apps/tools/button_test.h" #include -#include +#include #include void OswButtonTest::setup() {} diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index 341967449..b6ab145f8 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -7,7 +7,7 @@ #endif #include -#include +#include #include #include #include diff --git a/src/apps/watchfaces/OswAppWatchfaceBinary.cpp b/src/apps/watchfaces/OswAppWatchfaceBinary.cpp index b0bdb7852..3e1090d08 100644 --- a/src/apps/watchfaces/OswAppWatchfaceBinary.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceBinary.cpp @@ -3,7 +3,7 @@ #include "apps/watchfaces/OswAppWatchface.h" #include -#include +#include #include #include #include diff --git a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp index 5a6527188..d555d32d6 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/apps/watchfaces/OswAppWatchfaceDual.cpp b/src/apps/watchfaces/OswAppWatchfaceDual.cpp index 8b12fd667..0e953882d 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDual.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDual.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp index 65bdc77a3..5a7402b3e 100644 --- a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/apps/watchfaces/OswAppWatchfaceMix.cpp b/src/apps/watchfaces/OswAppWatchfaceMix.cpp index dde2cd16f..0788417da 100644 --- a/src/apps/watchfaces/OswAppWatchfaceMix.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceMix.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp b/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp index e7073da07..c5a427144 100644 --- a/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp @@ -4,7 +4,7 @@ // #define GIF_BG #include -#include +#include #include #include #include diff --git a/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp b/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp index a143885b0..092a29ac5 100644 --- a/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp @@ -7,7 +7,7 @@ #include "apps/watchfaces/OswAppWatchface.h" #include -#include +#include #include #include #include diff --git a/src/main.cpp b/src/main.cpp index a96a60b59..67c2ee858 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include From 5ff1a2a8874feae3129e2f166999f4072ab872f2 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 23 Feb 2023 21:44:47 +0100 Subject: [PATCH 003/141] Implemented new example for OswAppV2 - and started integration of it --- include/OswAppV2.h | 37 ++++++++ include/OswIcon.h | 14 +++ include/apps/_experiments/hello_world.h | 19 ---- include/apps/examples/OswAppExample.h | 23 +++++ include/apps/tools/OswAppTutorial.h | 24 +++++ include/osw_ui.h | 11 ++- src/OswAppV2.cpp | 45 ++++++++++ src/OswIcon.cpp | 11 +++ src/apps/_experiments/hello_world.cpp | 64 -------------- src/apps/examples/OswAppExample.cpp | 67 ++++++++++++++ src/apps/tools/OswAppTutorial.cpp | 29 ++++++ src/main.cpp | 13 ++- src/osw_ui.cpp | 113 ++++++++++++++---------- 13 files changed, 333 insertions(+), 137 deletions(-) create mode 100644 include/OswAppV2.h create mode 100644 include/OswIcon.h delete mode 100644 include/apps/_experiments/hello_world.h create mode 100644 include/apps/examples/OswAppExample.h create mode 100644 include/apps/tools/OswAppTutorial.h create mode 100644 src/OswAppV2.cpp create mode 100644 src/OswIcon.cpp delete mode 100644 src/apps/_experiments/hello_world.cpp create mode 100644 src/apps/examples/OswAppExample.cpp create mode 100644 src/apps/tools/OswAppTutorial.cpp diff --git a/include/OswAppV2.h b/include/OswAppV2.h new file mode 100644 index 000000000..ed5933d95 --- /dev/null +++ b/include/OswAppV2.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include + +class OswHal; +class OswAppV2 { + public: + enum ViewFlags { + NONE = 0, + NO_OVERLAYS = 1 + }; + bool needsRedraw = false; + + virtual const char* getAppId() = 0; + virtual const char* getAppName() = 0; + virtual OswIcon& getAppIcon(); + + virtual void onStart(); + virtual void onLoop(); + virtual void onDraw(); + virtual void onStop(); + + virtual void onButton(int id, bool down, bool shortPress, bool longPress); +#ifdef OSW_EMULATOR + virtual void onLoopDebug(); // By default no debug loop (GUI) is implemented +#endif + + ViewFlags getViewFlags(); + protected: + OswHal* hal = nullptr; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 + ViewFlags viewFlags = NONE; + + private: + static OswIcon defaultAppIcon; + + void updateCachedHal(); +}; \ No newline at end of file diff --git a/include/OswIcon.h b/include/OswIcon.h new file mode 100644 index 000000000..66fff5b0e --- /dev/null +++ b/include/OswIcon.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +class OswIcon { + public: + OswIcon(unsigned char* data, uint16_t color); + + void draw(Graphics2D* gfx, int x, int y); + private: + unsigned char* data; + uint16_t color; +}; \ No newline at end of file diff --git a/include/apps/_experiments/hello_world.h b/include/apps/_experiments/hello_world.h deleted file mode 100644 index aee95a2f7..000000000 --- a/include/apps/_experiments/hello_world.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef OSW_APP_HELLO_WORLD_H -#define OSW_APP_HELLO_WORLD_H - -#include - -#include - -class OswAppHelloWorld : public OswApp { - public: - OswAppHelloWorld(void) {}; - virtual void setup() override; - virtual void loop() override; - virtual void stop() override; - ~OswAppHelloWorld() {}; - - private: -}; - -#endif diff --git a/include/apps/examples/OswAppExample.h b/include/apps/examples/OswAppExample.h new file mode 100644 index 000000000..bd202548b --- /dev/null +++ b/include/apps/examples/OswAppExample.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include + +class OswAppExample : public OswAppV2 { + public: + OswAppExample() {}; + ~OswAppExample() {}; + + const char* getAppId() override; + const char* getAppName() override; + + void onStart() override; + void onLoop() override; + void onDraw() override; + void onStop() override; + + private: + // define global scope variables + bool red = false; +}; diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h new file mode 100644 index 000000000..91e18e186 --- /dev/null +++ b/include/apps/tools/OswAppTutorial.h @@ -0,0 +1,24 @@ +#ifndef OSW_APP_HELLO_WORLD_H +#define OSW_APP_HELLO_WORLD_H + +#include + +#include + +class OswAppTutorial : public OswAppV2 { + public: + OswAppTutorial() {}; + ~OswAppTutorial() {}; + + const char* getAppId() override; + const char* getAppName() override; + + // void onStart() override; + // void onLoop() override; + // void onDraw() override; + // void onStop() override; + + private: +}; + +#endif diff --git a/include/osw_ui.h b/include/osw_ui.h index ccf7ab54d..f9d0c4b81 100644 --- a/include/osw_ui.h +++ b/include/osw_ui.h @@ -1,11 +1,12 @@ #ifndef OSW_UI_H #define OSW_UI_H -#include - #include #include +#include + +class OswAppV2; class OswAppSwitcher; class OswUI { public: @@ -62,10 +63,13 @@ class OswUI { bool mEnableTargetFPS = true; OswUI(); - void loop(OswAppSwitcher& mainAppSwitcher, uint16_t& mainAppIndex); static OswUI* getInstance(); static void resetInstance(); + // void loop(OswAppSwitcher& mainAppSwitcher, uint16_t& mainAppIndex); + void loop(); + void setRootApplication(OswAppV2& rootApplication); + uint16_t getBackgroundColor(void); uint16_t getBackgroundDimmedColor(void); uint16_t getForegroundColor(void); @@ -105,6 +109,7 @@ class OswUI { unsigned int lastBGFlush = 0; std::mutex mNotificationsLock; std::list mNotifications; + OswAppV2* rootApplication = nullptr; }; #endif diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp new file mode 100644 index 000000000..76bb61c57 --- /dev/null +++ b/src/OswAppV2.cpp @@ -0,0 +1,45 @@ +#include + +#include + +OswIcon OswAppV2::defaultAppIcon = OswIcon(nullptr, rgb565(100, 200, 50)); // TODO + +OswIcon& OswAppV2::getAppIcon() { + return this->defaultAppIcon; +} + +OswAppV2::ViewFlags OswAppV2::getViewFlags() { + return this->viewFlags; +} + +void OswAppV2::onStart() { + this->updateCachedHal(); + this->needsRedraw = true; +} + +void OswAppV2::onLoop() { + this->updateCachedHal(); + // TODO handle button changes and pass them to onButton +} + +void OswAppV2::onDraw() { + this->updateCachedHal(); +} + +void OswAppV2::onStop() { + this->updateCachedHal(); +} + +void OswAppV2::updateCachedHal() { + this->hal = OswHal::getInstance(); +} + +void OswAppV2::onButton(int id, bool down, bool shortPress, bool longPress) { + OSW_LOG_W("Not inplemented yet!"); +} + +#ifdef OSW_EMULATOR +void OswAppV2::onLoopDebug() { + // By default no debug loop (GUI) is implemented +} +#endif \ No newline at end of file diff --git a/src/OswIcon.cpp b/src/OswIcon.cpp new file mode 100644 index 000000000..5ce1c4073 --- /dev/null +++ b/src/OswIcon.cpp @@ -0,0 +1,11 @@ +#include + +#include + +OswIcon::OswIcon(unsigned char* data, uint16_t color): data(data), color(color) { + OSW_LOG_W("OswIcon::OswIcon() is not implemented yet!"); +} + +void OswIcon::draw(Graphics2D* gfx, int x, int y) { + OSW_LOG_W("OswIcon::draw() is not implemented yet!"); +} \ No newline at end of file diff --git a/src/apps/_experiments/hello_world.cpp b/src/apps/_experiments/hello_world.cpp deleted file mode 100644 index b0fc8a680..000000000 --- a/src/apps/_experiments/hello_world.cpp +++ /dev/null @@ -1,64 +0,0 @@ - -#include "./apps/_experiments/hello_world.h" - -#include -#include -#include -// define global scope variables -bool red = false; - -void OswAppHelloWorld::setup() { - // this is where you initialise code, gets called when this app is shown -} - -void OswAppHelloWorld::loop() { - // This section of the code is where you can write code that will loop. - OswHal* hal = OswHal::getInstance(); - - // Here you can execute code on a button press. For this example I am changing the value of a variable. - - if (hal->btnHasGoneDown(BUTTON_3)) { - red = true; - } - - if (hal->btnHasGoneDown(BUTTON_2)) { - red = false; - } - - // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text - - if (red) { - hal->gfx()->fill(0); - hal->gfx()->setTextSize(2); - hal->gfx()->setTextColor(rgb565(255, 0, 0), rgb565(0, 0, 0)); // colour changes: foreground, background - hal->gfx()->setTextCursor(50, 120); // set (X,Y) coordinates for the 240x204px display - hal->gfx()->print("Hello World"); - - // set a new piece of text with different properties - - hal->gfx()->setTextCursor(160, 180); - hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); - hal->gfx()->print("Off"); - - hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); - hal->gfx()->setTextCursor(160, 60); - hal->gfx()->print("Red"); - - } else { - hal->gfx()->fill(0); - hal->gfx()->setTextSize(2); - hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); - hal->gfx()->setTextCursor(50, 120); - - hal->gfx()->print("Hello World "); - hal->gfx()->setTextCursor(160, 180); - hal->gfx()->print("Off"); - - hal->gfx()->setTextCursor(160, 60); - hal->gfx()->print("Red"); - } -} - -void OswAppHelloWorld::stop() { - // this is where you de-initialize stuff, gets called when another app is shown -} diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExample.cpp new file mode 100644 index 000000000..1e372f8b9 --- /dev/null +++ b/src/apps/examples/OswAppExample.cpp @@ -0,0 +1,67 @@ +#include +#include +#include + +#include "apps/examples/OswAppExample.h" + +const char* OswAppExample::getAppId() { + return "org.osw.example"; +} + +const char* OswAppExample::getAppName() { + return "Example App"; +} + +void OswAppExample::onStart() { + OswAppV2::onStart(); // always make sure to call the base class method! + + // This is where you initialise code, gets called before this app is shown +} + +void OswAppExample::onLoop() { + OswAppV2::onLoop(); // always make sure to call the base class method! + // This section of the code is where you can write the main logic + + // In this example we will just process the button presses to change the color of the text + // TODO move this into the onButton() method + bool oldRed = red; + if (hal->btnHasGoneDown(BUTTON_3)) { + red = true; + } + + if (hal->btnHasGoneDown(BUTTON_2)) { + red = false; + } + + // Then request a redraw if the value has changed + this->needsRedraw = this->needsRedraw or oldRed != red; +} + +void OswAppExample::onDraw() { + OswAppV2::onDraw(); // always make sure to call the base class method! + + // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text + hal->gfx()->setTextSize(2); + if (red) + hal->gfx()->setTextColor(rgb565(255, 0, 0), rgb565(0, 0, 0)); + else + hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); + + hal->gfx()->setTextCursor(50, 120); + hal->gfx()->print("Hello World"); + + if(red) // only reset the text color, if the previous text was red + hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); + hal->gfx()->setTextRightAligned(); + hal->gfx()->setTextCursor(200, 180); + hal->gfx()->print("Normal"); + + hal->gfx()->setTextCursor(200, 60); + hal->gfx()->print("Red"); +} + +void OswAppExample::onStop() { + OswAppV2::onStop(); // always make sure to call the base class method! + + // This is where you de-initialize stuff, gets called when another app is shown +} diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp new file mode 100644 index 000000000..f7e0fcf78 --- /dev/null +++ b/src/apps/tools/OswAppTutorial.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include "apps/tools/OswAppTutorial.h" + +const char* OswAppTutorial::getAppId() { + return "org.osw.tutorial"; +} + +const char* OswAppTutorial::getAppName() { + return "OSW Tutorial"; +} + +// void OswAppTutorial::onStart() { +// OswAppV2::onStart(); // always make sure to call the base class method! +// } + +// void OswAppTutorial::onLoop() { +// OswAppV2::onLoop(); // always make sure to call the base class method! +// } + +// void OswAppTutorial::onDraw() { +// OswAppV2::onDraw(); // always make sure to call the base class method! +// } + +// void OswAppTutorial::onStop() { +// OswAppV2::onStop(); // always make sure to call the base class method! +// } diff --git a/src/main.cpp b/src/main.cpp index 67c2ee858..c932c4562 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,8 @@ #endif // #include "./apps/_experiments/runtime_test.h" -#include "./apps/_experiments/hello_world.h" +#include "apps/examples/OswAppExample.h" +#include "apps/tools/OswAppTutorial.h" #ifdef OSW_FEATURE_LUA #include "./apps/main/luaapp.h" #endif @@ -88,6 +89,10 @@ OswAppSwitcher fitnessAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_fit OswAppSwitcher clockAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_clockAppIndex); OswAppSwitcher settingsAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_settingsAppIndex); +// TODO temporary for testing +static OswAppExample exampleApp; +static OswAppTutorial tutorialApp; + void setup() { Serial.begin(115200); OSW_LOG_I("Welcome to the OSW-OS! This build is based on commit ", GIT_COMMIT_HASH, " from ", GIT_BRANCH_NAME, @@ -117,6 +122,10 @@ void setup() { mainAppSwitcher.registerApp(&watchFaceSwitcher); mainAppSwitcher.setup(); + // TODO temporary for testing + OswUI::getInstance()->setRootApplication(exampleApp); + // OswUI::getInstance()->setRootApplication(tutorialApp); + #if USE_ULP == 1 // register the ULP program init_ulp(); @@ -162,7 +171,7 @@ void loop() { // Now update the screen (this will maybe sleep for a while) try { - OswUI::getInstance()->loop(mainAppSwitcher, main_currentAppIndex); + OswUI::getInstance()->loop(); } catch(const std::exception& e) { OSW_LOG_E("CRITICAL ERROR AT APP: ", e.what()); sleep(_MAIN_CRASH_SLEEP); diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index 6abca1592..743fad0d8 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -1,8 +1,10 @@ -#include "osw_ui.h" +#include +#include +#include -#include "./apps/main/switcher.h" -#include "./overlays/overlays.h" -#include "osw_config.h" +#include + +#include std::unique_ptr OswUI::instance = nullptr; OswUI::OswUI() { @@ -75,7 +77,14 @@ void OswUI::setTextCursor(Button btn) { } } -void OswUI::loop(OswAppSwitcher& mainAppSwitcher, uint16_t& mainAppIndex) { +void OswUI::setRootApplication(OswAppV2& rootApplication) { + if(this->rootApplication != nullptr) + this->rootApplication->onStop(); + this->rootApplication = &rootApplication; + this->rootApplication->onStart(); +} + +void OswUI::loop() { { std::lock_guard notifyGuard(this->mNotificationsLock); auto notificationsDismissed = !this->mNotifications.empty() && (OswHal::getInstance()->btnHasGoneDown(BUTTON_1) || @@ -95,61 +104,67 @@ void OswUI::loop(OswAppSwitcher& mainAppSwitcher, uint16_t& mainAppIndex) { } } + if(this->rootApplication == nullptr) + return; // Early abort if no app is set + rootApplication->onLoop(); + // Lock UI for drawing - std::lock_guard guard(*this->drawLock); // Make sure to not modify the notifications vector during drawing - - // BG - if (OswHal::getInstance()->displayBufferEnabled()) - OswHal::getInstance()->gfx()->fill(this->getBackgroundColor()); - else if (this->lastBGFlush < millis() - 10000) { - // In case the buffering is inactive, only flush every 10 seconds the whole buffer - OswHal::getInstance()->gfx()->fill(this->getBackgroundColor()); - this->lastBGFlush = millis(); - } + if(rootApplication->needsRedraw) { + if(this->mEnableTargetFPS and (millis() - lastFlush) < (1000 / this->mTargetFPS)) + return; // Early abort if we would draw too fast + std::lock_guard guard(*this->drawLock); // Make sure to not modify the notifications vector during drawing - this->resetTextColors(); - if (this->mProgressBar == nullptr) { - // Apps - OswHal::getInstance()->gfx()->setTextSize(1.0f); - mainAppSwitcher.loop(); + // BG + if (OswHal::getInstance()->displayBufferEnabled()) + OswHal::getInstance()->gfx()->fill(this->getBackgroundColor()); + else if (this->lastBGFlush < millis() - 10000) { + // In case the buffering is inactive, only flush every 10 seconds the whole buffer + OswHal::getInstance()->gfx()->fill(this->getBackgroundColor()); + this->lastBGFlush = millis(); + } + + this->resetTextColors(); + if (this->mProgressBar == nullptr) { + // Apps + OswHal::getInstance()->gfx()->setTextLeftAligned(); + OswHal::getInstance()->gfx()->setTextSize(1.0f); + rootApplication->onDraw(); #ifdef OSW_EMULATOR #ifndef NDEBUG - mainAppSwitcher.loopDebug(); + rootApplication->onLoopDebug(); #endif #endif - } else { - // Full-Screen progress - OswHal::getInstance()->gfx()->setTextCenterAligned(); - OswHal::getInstance()->gfx()->setTextSize(2.0f); - OswHal::getInstance()->gfx()->setTextCursor(DISP_W * 0.5, DISP_W * 0.5); - OswHal::getInstance()->gfx()->print(this->mProgressText); - this->mProgressBar->draw(); - } - - this->resetTextColors(); - { - std::lock_guard notifyGuard(this->mNotificationsLock); - // Draw all notifications - auto y = DISP_H - OswUINotification::sDrawHeight; - for (const auto& notification : this->mNotifications) { - notification.draw(y); - y -= OswUINotification::sDrawHeight; + } else { + // Full-Screen progress + OswHal::getInstance()->gfx()->setTextCenterAligned(); + OswHal::getInstance()->gfx()->setTextSize(2.0f); + OswHal::getInstance()->gfx()->setTextCursor(DISP_W * 0.5, DISP_W * 0.5); + OswHal::getInstance()->gfx()->print(this->mProgressText); + this->mProgressBar->draw(); } - } - // Early abort if we would render too fast (checked here, to still allow apps to process buttons in their loop() ↑) - if (this->mEnableTargetFPS and millis() - lastFlush < 1000 / this->mTargetFPS) - return; + this->resetTextColors(); + { + std::lock_guard notifyGuard(this->mNotificationsLock); + // Draw all notifications + auto y = DISP_H - OswUINotification::sDrawHeight; + for (const auto& notification : this->mNotifications) { + notification.draw(y); + y -= OswUINotification::sDrawHeight; + } + } + + // TODO remove OswConfigAllKeys::settingDisplayOverlaysOnWatchScreen.get() and make a "force-on" setting instead - // Only draw overlays if enabled - if (OswConfigAllKeys::settingDisplayOverlays.get()) - // Only draw on first face if enabled, or on all others - if ((mainAppIndex == 0 and OswConfigAllKeys::settingDisplayOverlaysOnWatchScreen.get()) || mainAppIndex != 0) + // Only draw overlays if enabled + if (OswConfigAllKeys::settingDisplayOverlays.get() and !(rootApplication->getViewFlags() & OswAppV2::ViewFlags::NO_OVERLAYS)) drawOverlays(); - // Handle display flushing - OswHal::getInstance()->flushCanvas(); - lastFlush = millis(); + // Handle display flushing + OswHal::getInstance()->flushCanvas(); + lastFlush = millis(); + rootApplication->needsRedraw = false; + } } bool OswUI::getProgressActive() { From 45dc1aa1ac50873ef4a7c371e2e83daf9123e98d Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 23 Feb 2023 21:53:48 +0100 Subject: [PATCH 004/141] Extended example with a counter --- include/apps/examples/OswAppExample.h | 2 ++ src/apps/examples/OswAppExample.cpp | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/apps/examples/OswAppExample.h b/include/apps/examples/OswAppExample.h index bd202548b..22e788ad8 100644 --- a/include/apps/examples/OswAppExample.h +++ b/include/apps/examples/OswAppExample.h @@ -20,4 +20,6 @@ class OswAppExample : public OswAppV2 { private: // define global scope variables bool red = false; + unsigned int start = 0; + unsigned int counter = 0; }; diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExample.cpp index 1e372f8b9..5f1dd65e1 100644 --- a/src/apps/examples/OswAppExample.cpp +++ b/src/apps/examples/OswAppExample.cpp @@ -16,6 +16,7 @@ void OswAppExample::onStart() { OswAppV2::onStart(); // always make sure to call the base class method! // This is where you initialise code, gets called before this app is shown + this->start = time(nullptr); // used as offset for the counter later on } void OswAppExample::onLoop() { @@ -25,33 +26,37 @@ void OswAppExample::onLoop() { // In this example we will just process the button presses to change the color of the text // TODO move this into the onButton() method bool oldRed = red; - if (hal->btnHasGoneDown(BUTTON_3)) { + if (hal->btnHasGoneDown(BUTTON_3)) red = true; - } - - if (hal->btnHasGoneDown(BUTTON_2)) { + if (hal->btnHasGoneDown(BUTTON_2)) red = false; - } - // Then request a redraw if the value has changed - this->needsRedraw = this->needsRedraw or oldRed != red; + // Then request a redraw if the value has changed or one second passed (for the counter) + this->needsRedraw = this->needsRedraw or oldRed != red or counter != time(nullptr); } void OswAppExample::onDraw() { OswAppV2::onDraw(); // always make sure to call the base class method! + this->counter = time(nullptr); // update the counter // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text - hal->gfx()->setTextSize(2); + hal->gfx()->setTextCenterAligned(); if (red) hal->gfx()->setTextColor(rgb565(255, 0, 0), rgb565(0, 0, 0)); else hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); - hal->gfx()->setTextCursor(50, 120); + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2); hal->gfx()->print("Hello World"); + hal->gfx()->setTextSize(1); + hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2 + 10); // This places the text exactly into the space of the previous text :) + hal->gfx()->print(this->counter - this->start); + if(red) // only reset the text color, if the previous text was red hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); + hal->gfx()->setTextSize(2); hal->gfx()->setTextRightAligned(); hal->gfx()->setTextCursor(200, 180); hal->gfx()->print("Normal"); From 02cb1437544cb77ef7992c8fe24e10bfc9828f72 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 23 Feb 2023 22:03:53 +0100 Subject: [PATCH 005/141] Corrected wrong background color --- src/apps/examples/OswAppExample.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExample.cpp index 5f1dd65e1..c01cf48c1 100644 --- a/src/apps/examples/OswAppExample.cpp +++ b/src/apps/examples/OswAppExample.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "apps/examples/OswAppExample.h" @@ -42,9 +43,9 @@ void OswAppExample::onDraw() { // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text hal->gfx()->setTextCenterAligned(); if (red) - hal->gfx()->setTextColor(rgb565(255, 0, 0), rgb565(0, 0, 0)); + hal->gfx()->setTextColor(rgb565(255, 0, 0), OswUI::getInstance()->getBackgroundColor()); else - hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); + hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2); From 35bb71367526186883af821fbab05f4507c49bc6 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 01:39:26 +0100 Subject: [PATCH 006/141] Cleanup --- include/osw_ui.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/osw_ui.h b/include/osw_ui.h index f9d0c4b81..b07864b36 100644 --- a/include/osw_ui.h +++ b/include/osw_ui.h @@ -70,15 +70,15 @@ class OswUI { void loop(); void setRootApplication(OswAppV2& rootApplication); - uint16_t getBackgroundColor(void); - uint16_t getBackgroundDimmedColor(void); - uint16_t getForegroundColor(void); - uint16_t getForegroundDimmedColor(void); - uint16_t getPrimaryColor(void); - uint16_t getInfoColor(void); - uint16_t getSuccessColor(void); - uint16_t getWarningColor(void); - uint16_t getDangerColor(void); + uint16_t getBackgroundColor(); + uint16_t getBackgroundDimmedColor(); + uint16_t getForegroundColor(); + uint16_t getForegroundDimmedColor(); + uint16_t getPrimaryColor(); + uint16_t getInfoColor(); + uint16_t getSuccessColor(); + uint16_t getWarningColor(); + uint16_t getDangerColor(); void startProgress(const char* text); bool getProgressActive(); From 37671d256ef2bd4078a254206868dc7e785dd748 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 01:40:52 +0100 Subject: [PATCH 007/141] Implemented asset translator and OswIcon --- img/.gitignore | 1 + img/app.png | 3 + img/check.png | 3 + img/osw.png | 3 + img/wait.png | 3 + include/OswIcon.h | 17 +++-- include/assets/.gitignore | 1 + platformio.ini | 7 +- scripts/build/prebuild_assets.py | 108 +++++++++++++++++++++++++++++++ scripts/build/prebuild_www.py | 65 ------------------- src/OswIcon.cpp | 39 +++++++++-- 11 files changed, 176 insertions(+), 74 deletions(-) create mode 100644 img/.gitignore create mode 100644 img/app.png create mode 100644 img/check.png create mode 100644 img/osw.png create mode 100644 img/wait.png create mode 100644 scripts/build/prebuild_assets.py delete mode 100644 scripts/build/prebuild_www.py diff --git a/img/.gitignore b/img/.gitignore new file mode 100644 index 000000000..e8f6ad08c --- /dev/null +++ b/img/.gitignore @@ -0,0 +1 @@ +*.xcf \ No newline at end of file diff --git a/img/app.png b/img/app.png new file mode 100644 index 000000000..a73d3d0bc --- /dev/null +++ b/img/app.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e4ef17f88765c16b1924a3660a859b7d85264d01988e587d1877ed40aacefe8 +size 634 diff --git a/img/check.png b/img/check.png new file mode 100644 index 000000000..71026c2b2 --- /dev/null +++ b/img/check.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c50478c8879e9051d0761e477cf150a4587ad1e5bbf4851f98cb7e34aff4c65 +size 600 diff --git a/img/osw.png b/img/osw.png new file mode 100644 index 000000000..a45419ad9 --- /dev/null +++ b/img/osw.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:028cfeac6dfea46e9c662bda752dcbf2b98e7ad9dfeb6e19bea7a93c450a4eee +size 705 diff --git a/img/wait.png b/img/wait.png new file mode 100644 index 000000000..b4407f604 --- /dev/null +++ b/img/wait.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd39b858defe6a4bdb7c5a52ab9c9f0b591c2008922824a313323809d500f67d +size 600 diff --git a/include/OswIcon.h b/include/OswIcon.h index 66fff5b0e..e1d726088 100644 --- a/include/OswIcon.h +++ b/include/OswIcon.h @@ -5,10 +5,19 @@ class OswIcon { public: - OswIcon(unsigned char* data, uint16_t color); + enum class Alignment { + START, + CENTER, + END + }; + uint16_t color; + + OswIcon(const unsigned char* data, const unsigned char dimension, uint16_t color); - void draw(Graphics2D* gfx, int x, int y); + void draw(Graphics2D* gfx, int x, int y, float scale = 1, Alignment xAlign = Alignment::START, Alignment yAlign = Alignment::START); private: - unsigned char* data; - uint16_t color; + static const bool debugBackground = false; + + const unsigned char* data; + const unsigned char dimension; }; \ No newline at end of file diff --git a/include/assets/.gitignore b/include/assets/.gitignore index f8d728c11..c29126468 100644 --- a/include/assets/.gitignore +++ b/include/assets/.gitignore @@ -1 +1,2 @@ www +img \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 593f6a803..71c55d238 100755 --- a/platformio.ini +++ b/platformio.ini @@ -36,7 +36,7 @@ monitor_speed = 115200 ; Define additional build stage scripts - used to "compile" the html or define additional information extra_scripts = pre:scripts/build/prebuild_info.py - pre:scripts/build/prebuild_www.py + pre:scripts/build/prebuild_assets.py pre:scripts/build/prebuild_cppflags.py pre:scripts/build/prebuild_lua.py ; Needed to generate the .cxx file(s), enabled via "OSW_FEATURE_LUA" build flag build_unflags = -std=gnu++11 # The correct flag will be set by the cppflags python script... @@ -65,6 +65,11 @@ build_flags = -D OSW_FEATURE_LUA -D OSW_FEATURE_WIFI -D LUA_C89_NUMBERS ; Required by OSW_FEATURE_LUA +extra_scripts = + pre:scripts/build/prebuild_info.py + pre:scripts/build/prebuild_assets.py + pre:scripts/build/prebuild_cppflags.py + pre:scripts/build/prebuild_lua.py ; Needed to generate the .cxx file(s) build_type = debug ; GPS edition by hardware revisions diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py new file mode 100644 index 000000000..079d20b3e --- /dev/null +++ b/scripts/build/prebuild_assets.py @@ -0,0 +1,108 @@ +import gzip +import os +import re +from PIL import Image + +def createAssets(srcPath, assPath, convertAssetToSourceCode): + os.makedirs(assPath, exist_ok=True) + + # Get all paths of the src folder + srcFiles = {} + for subPath, _, filenames in os.walk(srcPath): + for file in filenames: + path = os.path.join(subPath, file) + srcFiles[os.path.relpath(path, srcPath)] = os.path.getmtime(path) + + # Clear the assets folder as needed + for subPath, _, filenames in os.walk(assPath): + for file in filenames: + fileStripped = file.removesuffix('.h').removesuffix('.gz') + assFile = os.path.join(subPath, fileStripped) + path = os.path.relpath(assFile, assPath) + if path not in srcFiles: + os.remove(os.path.join(subPath, file)) + print('Removed: ' + assFile) + + # Create the assets from the source codes + for subPath, mtime in srcFiles.items(): + srcFile = os.path.join(srcPath, subPath) + + makeGz = subPath.endswith('.html') or subPath.endswith('.js') or subPath.endswith('.css') + assFile = os.path.join(assPath, subPath) + if makeGz: + assFile = assFile + '.gz' # Add .gz to the end of the file as needed + assFileHeader = assFile + '.h' + + # Check if the file needs to be updated + if os.path.exists(assFileHeader) and os.path.getmtime(assFileHeader) >= mtime: + print('Skipped: ' + assFileHeader) + continue + + # Read the file + fileStr = convertAssetToSourceCode(srcFile, subPath + ('.gz' if makeGz else '')) + if fileStr is None: + print('Ignored: ' + subPath) + continue + + # Write file to asset path + os.makedirs(os.path.split(assFileHeader)[0], exist_ok=True) + with open(assFileHeader, 'w') as out: + out.write(fileStr) + out.close() + print('Updated: ' + assFileHeader) + +def makeGzStr(srcPath, subPath): + with open(srcPath, 'rb') as f: + byteFile = f.read() + if subPath.endswith('.gz'): + byteFile = gzip.compress(byteFile, 9) + + # Create new .h string + varName = re.sub('[^a-zA-Z0-9]', '_', subPath) # Replace all non-alphanumeric characters with underscores + varName = re.sub('^_*', '', varName) + fileStr = "#pragma once\nconst char " + varName + "[] PROGMEM = {\n" + for i in range(0, len(byteFile), 12): + fileStr += '\t' + subArr = byteFile[i:i+12] + for j in range(0, len(subArr)): + fileStr += hex(subArr[j]) + ', ' + fileStr += '\n' + fileStr = fileStr[:-3] # Strip the last ", \n" + fileStr += "\n};\nunsigned long " + varName + "_len PROGMEM = " + str(len(byteFile)) + ";" + return fileStr + +def makeImgStr(srcPath, subPath): + if not subPath.endswith('.png'): + return None + + img = Image.open(srcPath, 'r') + assert img.size[0] == img.size[1], 'Image must be square' + assert img.size[0] % 8 == 0, 'Image dimension must be a multiple of 8' + imgData = list(img.getdata()) + + byteFile = [] + for i in range(0, len(imgData), 8): + b = 0b00000000 + for j in range(0, 8): + if imgData[i + j] != (0, 0, 0): + b = b | (1 << j) + byteFile.append(b) + + # Create new .h string + varName = re.sub('[^a-zA-Z0-9]', '_', subPath) # Replace all non-alphanumeric characters with underscores + varName = re.sub('^_*', '', varName) + fileStr = "#pragma once\nconst unsigned char " + varName + "[] PROGMEM = {\n" + for i in range(0, len(byteFile), 12): + fileStr += '\t' + subArr = byteFile[i:i+12] + for j in range(0, len(subArr)): + fileStr += hex(subArr[j]) + ', ' + fileStr += '\n' + fileStr = fileStr[:-3] # Strip the last ", \n" + fileStr += "\n};\nunsigned char " + varName + "_dimensons PROGMEM = " + str(img.size[0]) + ";" + return fileStr + +assPath = os.path.join('include', 'assets') +createAssets(os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web'), os.path.join(assPath, 'www'), makeGzStr) + +createAssets('img', os.path.join(assPath, 'img'), makeImgStr) \ No newline at end of file diff --git a/scripts/build/prebuild_www.py b/scripts/build/prebuild_www.py deleted file mode 100644 index 9641aa1b3..000000000 --- a/scripts/build/prebuild_www.py +++ /dev/null @@ -1,65 +0,0 @@ -import gzip -import os -import re - -assPath = os.path.join('include', 'assets', 'www') -wwwPath = os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web') - -os.makedirs(assPath, exist_ok=True) - -# Get all paths of the www folder -wwwFiles = {} -for subPath, _, filenames in os.walk(wwwPath): - for file in filenames: - path = os.path.join(subPath, file) - wwwFiles[os.path.relpath(path, wwwPath)] = os.path.getmtime(path) - -# Clear the assets folder as needed -for subPath, _, filenames in os.walk(assPath): - for file in filenames: - fileStripped = file.removesuffix('.h').removesuffix('.gz') - assFile = os.path.join(subPath, fileStripped) - path = os.path.relpath(assFile, assPath) - if path not in wwwFiles: - os.remove(os.path.join(subPath, file)) - print('Removed: ' + assFile) - -# Create the assets from the source codes -for subPath, mtime in wwwFiles.items(): - wwwFile = os.path.join(wwwPath, subPath) - - makeGz = subPath.endswith('.html') or subPath.endswith('.js') or subPath.endswith('.css') - assFile = os.path.join(assPath, subPath) - assFile = assFile + '.gz' if makeGz else assFile # Add .gz to the end of the file as needed - assFileHeader = assFile + '.h' - - # Check if the file needs to be updated - if os.path.exists(assFileHeader) and os.path.getmtime(assFileHeader) >= mtime: - print('Skipped: ' + assFileHeader) - continue - - # Read the file - with open(wwwFile, 'rb') as f: - byteFile = f.read() - if makeGz: - byteFile = gzip.compress(byteFile, 9) - - # Create new .h string - varName = re.sub('[^a-zA-Z0-9]', '_', subPath + ('.gz' if makeGz else '')) # Replace all non-alphanumeric characters with underscores - varName = re.sub('^_*', '', varName) - fileStr = "const char " + varName + "[] PROGMEM = {\n" - for i in range(0, len(byteFile), 12): - fileStr += '\t' - subArr = byteFile[i:i+12] - for j in range(0, len(subArr)): - fileStr += hex(subArr[j]) + ', ' - fileStr += '\n' - fileStr = fileStr[:-3] # Strip the last ", \n" - fileStr += "\n};\nunsigned long " + varName + "_len PROGMEM = " + str(len(byteFile)) + ";" - - # Write file to asset path - os.makedirs(os.path.split(assFileHeader)[0], exist_ok=True) - with open(assFileHeader, 'w') as out: - out.write(fileStr) - out.close() - print('Updated: ' + assFileHeader) diff --git a/src/OswIcon.cpp b/src/OswIcon.cpp index 5ce1c4073..e908ae9be 100644 --- a/src/OswIcon.cpp +++ b/src/OswIcon.cpp @@ -2,10 +2,41 @@ #include -OswIcon::OswIcon(unsigned char* data, uint16_t color): data(data), color(color) { - OSW_LOG_W("OswIcon::OswIcon() is not implemented yet!"); +OswIcon::OswIcon(const unsigned char* data, const unsigned char dimension, uint16_t color): color(color), data(data), dimension(dimension) { + } -void OswIcon::draw(Graphics2D* gfx, int x, int y) { - OSW_LOG_W("OswIcon::draw() is not implemented yet!"); +void OswIcon::draw(Graphics2D* gfx, int x, int y, float scale, Alignment xAlign, Alignment yAlign) { + // modify x and y based on alignment + switch(xAlign) { + case Alignment::START: + break; + case Alignment::CENTER: + x -= dimension * scale / 2; + break; + case Alignment::END: + x -= dimension * scale; + break; + } + switch(yAlign) { + case Alignment::START: + break; + case Alignment::CENTER: + y -= dimension * scale / 2; + break; + case Alignment::END: + y -= dimension * scale; + break; + } + + // each icon consists of a 1D array of bits, where each bit represents a pixel + for(float u = x; u < x + dimension * scale; u++) { + for(float v = y; v < y + dimension * scale; v++) { + int bitindex = (int)((u - x) / scale) + (int)((v - y) / scale) * dimension; + if(this->debugBackground) + gfx->drawPixel(u, v, rgb565(80, 80, 80)); + if(data[bitindex / 8] & (1 << (bitindex % 8))) + gfx->drawPixel(u, v, color); + } + } } \ No newline at end of file From 904ff1d5574e37471dc5e05826877f0e17b1adec Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 01:41:24 +0100 Subject: [PATCH 008/141] Fixed debug overlay --- src/osw_ui.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index 743fad0d8..f86135500 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -107,6 +107,11 @@ void OswUI::loop() { if(this->rootApplication == nullptr) return; // Early abort if no app is set rootApplication->onLoop(); +#ifdef OSW_EMULATOR +#ifndef NDEBUG + rootApplication->onLoopDebug(); +#endif +#endif // Lock UI for drawing if(rootApplication->needsRedraw) { @@ -129,11 +134,6 @@ void OswUI::loop() { OswHal::getInstance()->gfx()->setTextLeftAligned(); OswHal::getInstance()->gfx()->setTextSize(1.0f); rootApplication->onDraw(); -#ifdef OSW_EMULATOR -#ifndef NDEBUG - rootApplication->onLoopDebug(); -#endif -#endif } else { // Full-Screen progress OswHal::getInstance()->gfx()->setTextCenterAligned(); From ef733bafc1cb8b078971900d836f4a755bb7315e Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 01:42:03 +0100 Subject: [PATCH 009/141] Fixed default icon color --- include/OswAppV2.h | 1 + src/OswAppV2.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index ed5933d95..e415aa4a4 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -29,6 +29,7 @@ class OswAppV2 { protected: OswHal* hal = nullptr; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 ViewFlags viewFlags = NONE; + OswIcon& getDefaultAppIcon(); private: static OswIcon defaultAppIcon; diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 76bb61c57..ee8d64780 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -1,10 +1,17 @@ #include +#include #include +#include "assets/img/app.png.h" -OswIcon OswAppV2::defaultAppIcon = OswIcon(nullptr, rgb565(100, 200, 50)); // TODO +OswIcon OswAppV2::defaultAppIcon = OswIcon(app_png, app_png_dimensons, 0x0); // Color will be set upon retreival OswIcon& OswAppV2::getAppIcon() { + return this->getDefaultAppIcon(); +} + +OswIcon& OswAppV2::getDefaultAppIcon() { + this->defaultAppIcon.color = OswUI::getInstance()->getPrimaryColor(); // Update the color of the default icon (because the static init is black or the color may changed) return this->defaultAppIcon; } From 6ac3b81de27bd42a2e752094cc633515450af809 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 01:42:21 +0100 Subject: [PATCH 010/141] Started tutorial implementation --- include/apps/tools/OswAppTutorial.h | 18 +++++--- src/apps/tools/OswAppTutorial.cpp | 72 ++++++++++++++++++++++++----- src/main.cpp | 4 +- 3 files changed, 74 insertions(+), 20 deletions(-) diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index 91e18e186..d4c27676a 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -7,18 +7,24 @@ class OswAppTutorial : public OswAppV2 { public: - OswAppTutorial() {}; - ~OswAppTutorial() {}; + OswAppTutorial(); const char* getAppId() override; const char* getAppName() override; - // void onStart() override; - // void onLoop() override; - // void onDraw() override; - // void onStop() override; + void onStart() override; + void onLoop() override; + void onDraw() override; + void onStop() override; + virtual void onButton(int id, bool down, bool shortPress, bool longPress); +#ifdef OSW_EMULATOR + void onLoopDebug() override; +#endif private: + OswIcon oswIcon; + unsigned screen; + unsigned char hsv; }; #endif diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index f7e0fcf78..42083babc 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -1,8 +1,14 @@ #include #include #include +#include #include "apps/tools/OswAppTutorial.h" +#include "assets/img/osw.png.h" + +OswAppTutorial::OswAppTutorial(): oswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)), screen(0), hsv(0) { + +} const char* OswAppTutorial::getAppId() { return "org.osw.tutorial"; @@ -12,18 +18,60 @@ const char* OswAppTutorial::getAppName() { return "OSW Tutorial"; } -// void OswAppTutorial::onStart() { -// OswAppV2::onStart(); // always make sure to call the base class method! -// } +void OswAppTutorial::onStart() { + OswAppV2::onStart(); // always make sure to call the base class method! + + this->screen = 0; +} + +void OswAppTutorial::onLoop() { + OswAppV2::onLoop(); // always make sure to call the base class method! + this->hsv = (millis() / 100) % 255; + + this->needsRedraw = this->needsRedraw or this->screen == 0; // screen 0 has an animation +} -// void OswAppTutorial::onLoop() { -// OswAppV2::onLoop(); // always make sure to call the base class method! -// } +void OswAppTutorial::onDraw() { + OswAppV2::onDraw(); // always make sure to call the base class method! -// void OswAppTutorial::onDraw() { -// OswAppV2::onDraw(); // always make sure to call the base class method! -// } + if(this->screen == 0) { + const unsigned char maxVal = 255; + unsigned char r, g, b; + hsvToRgb(this->hsv, maxVal, maxVal, r, g, b); + this->oswIcon.color = rgb565(r, g, b); + this->oswIcon.draw(hal->gfx(), DISP_W / 2, 32, 1.2, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 100); + hal->gfx()->print("Welcome!"); + hal->gfx()->setTextSize(1); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 120); + hal->gfx()->print("This is your own Open-Smartwatch!\nIn the next few seconds this\n\"tutorial\" will guide you through\nthe basic navigation concepts\nof this OS. Have fun!\n\n\nPress any button to continue.\n\n\n"); + hal->gfx()->setTextColor(rgb565(80, 80, 80), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->print(GIT_COMMIT_HASH); + } else if(this->screen == 1) { + OswIcon aaa2 = OswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)); + aaa2.draw(hal->gfx(), DISP_W / 2, DISP_H / 2 - 32, 2, OswIcon::Alignment::CENTER, OswIcon::Alignment::CENTER); + } else + this->screen = 0; +} + +void OswAppTutorial::onButton(int id, bool down, bool shortPress, bool longPress) { + if(this->screen == 0) + this->screen = 1; +} + +#ifdef OSW_EMULATOR +#include "imgui.h" + +void OswAppTutorial::onLoopDebug() { + ImGui::Begin("Debug: OswAppTutorial"); + ImGui::InputScalar("screen", ImGuiDataType_U8, &this->screen); + ImGui::End(); +} +#endif -// void OswAppTutorial::onStop() { -// OswAppV2::onStop(); // always make sure to call the base class method! -// } +void OswAppTutorial::onStop() { + OswAppV2::onStop(); // always make sure to call the base class method! +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c932c4562..4fd0c09b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -123,8 +123,8 @@ void setup() { mainAppSwitcher.setup(); // TODO temporary for testing - OswUI::getInstance()->setRootApplication(exampleApp); - // OswUI::getInstance()->setRootApplication(tutorialApp); + //OswUI::getInstance()->setRootApplication(exampleApp); + OswUI::getInstance()->setRootApplication(tutorialApp); #if USE_ULP == 1 // register the ULP program From 9c3dca3577d3a647a156956b682637efe5d06cef Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 11:50:05 +0100 Subject: [PATCH 011/141] Fixed crash due to uninitialized ImGui in headless debug loop --- src/osw_ui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index f86135500..4da85653d 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -109,7 +109,8 @@ void OswUI::loop() { rootApplication->onLoop(); #ifdef OSW_EMULATOR #ifndef NDEBUG - rootApplication->onLoopDebug(); + if(!OswEmulator::instance->isHeadless) + rootApplication->onLoopDebug(); #endif #endif From 63cfc900087081b136317d9346e6a8e116d3fa30 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 13:38:49 +0100 Subject: [PATCH 012/141] Deprecated superseeded button methods in HAL --- include/osw_hal.h | 19 ++++++++++--------- src/apps/clock/OswAppTimer.cpp | 2 +- src/apps/clock/stopwatch.cpp | 2 +- src/apps/main/switcher.cpp | 12 ++++++------ src/hal/buttons.cpp | 8 +++++++- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/include/osw_hal.h b/include/osw_hal.h index cd81af6a9..1f1cd5334 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -80,16 +80,19 @@ class OswHal { // Buttons (Engine-Style) void checkButtons(void); + bool btnIsDown(Button btn); + unsigned long btnIsDownFor(Button btn); + unsigned long btnIsDownSince(Button btn); + bool btnHasGoneUp(Button btn); bool btnHasGoneDown(Button btn); + void clearButtonState(Button btn); + + // DEPRECATED button methods, use OswAppV2::onButton instead bool btnIsDoubleClick(Button btn); - bool btnHasGoneUp(Button btn); - bool btnIsDown(Button btn); bool btnIsLongPress(Button btn); void suppressButtonUntilUp(Button btn); - unsigned long btnIsDownSince(Button btn); - void clearButtonState(Button btn); -#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) +#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) void vibrate(long millis); #endif @@ -234,6 +237,7 @@ class OswHal { OswTimeProvider* timeProvider = nullptr; unsigned long _screenOnSince; unsigned long _screenOffSince; + // array of available buttons for iteration (e.g. handling) bool _btnLastState[NUM_BUTTONS]; bool _btnIsDown[NUM_BUTTONS]; @@ -241,15 +245,12 @@ class OswHal { bool _btnSuppressUntilUpAgain[NUM_BUTTONS]; bool _btnGoneDown[NUM_BUTTONS]; unsigned long _btnIsDownMillis[NUM_BUTTONS]; - bool _btnDoubleClickTimeout[NUM_BUTTONS]; unsigned long _btnDoubleClickMillis[NUM_BUTTONS]; bool _btnDoubleClick[NUM_BUTTONS]; uint8_t _btnDetectDoubleClickCount[NUM_BUTTONS]; - bool _btnLongPress[NUM_BUTTONS]; - long _lastTap = 0; - long _lastDoubleTap = 0; + uint8_t _brightness = 0; bool _hasGPS = false; bool _debugGPS = false; diff --git a/src/apps/clock/OswAppTimer.cpp b/src/apps/clock/OswAppTimer.cpp index 4b0b46e58..f3e33c013 100644 --- a/src/apps/clock/OswAppTimer.cpp +++ b/src/apps/clock/OswAppTimer.cpp @@ -75,7 +75,7 @@ long OswAppTimer::handleResetButton() { long btnDown = 0; if (hal->btnIsDown(BUTTON_2)) { // Reset - btnDown = hal->btnIsDownSince(BUTTON_2); + btnDown = hal->btnIsDownFor(BUTTON_2); if (btnDown > btnTimeout) { state = TimerState::IDLE; notifierClient.deleteNotification(notificationId); diff --git a/src/apps/clock/stopwatch.cpp b/src/apps/clock/stopwatch.cpp index f0e50a6cf..653e1b10f 100644 --- a/src/apps/clock/stopwatch.cpp +++ b/src/apps/clock/stopwatch.cpp @@ -53,7 +53,7 @@ void OswAppStopWatch::loop() { overallTime = !overallTime; } if(hal->btnIsDown(BUTTON_2)) { // Reset - btnDown = hal->btnIsDownSince(BUTTON_2); + btnDown = hal->btnIsDownFor(BUTTON_2); if(btnDown > btnTimeout) { diff = 0; sumPaused = 0; diff --git a/src/apps/main/switcher.cpp b/src/apps/main/switcher.cpp index 3acd86290..629973f9c 100644 --- a/src/apps/main/switcher.cpp +++ b/src/apps/main/switcher.cpp @@ -20,7 +20,7 @@ void OswAppSwitcher::loop() { } // if we enable sending the watch to sleep by clicking (really really) long enough - if (_enableSleep and hal->btnIsDownSince(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { + if (_enableSleep and hal->btnIsDownFor(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { // remember we need to sleep once the button goes up _doSleep = true; } @@ -28,7 +28,7 @@ void OswAppSwitcher::loop() { // detect switch action depending on mode switch (_type) { case LONG_PRESS: - if (hal->btnIsDownSince(_btn) > this->_timeForLongPress) { + if (hal->btnIsDownFor(_btn) > this->_timeForLongPress) { _doSwitch = true; } break; @@ -119,13 +119,13 @@ void OswAppSwitcher::loop() { switch (_type) { case LONG_PRESS: // long press has the hollow square that fills (draws around short press) - if (hal->btnIsDownSince(_btn) > this->_timeForLongPress) { + if (hal->btnIsDownFor(_btn) > this->_timeForLongPress) { // draw a large frame hal->gfx()->fillCircle(btnX, btnY, 20, OswUI::getInstance()->getSuccessColor()); } else { uint8_t progress = 0; - if (hal->btnIsDownSince(_btn) > this->_timeForLongPress / 2) { - progress = (hal->btnIsDownSince(_btn) - (this->_timeForLongPress / 2)) / + if (hal->btnIsDownFor(_btn) > this->_timeForLongPress / 2) { + progress = (hal->btnIsDownFor(_btn) - (this->_timeForLongPress / 2)) / ((this->_timeForLongPress / 2) / 255.0); } hal->gfx()->drawArc(btnX, btnY, progressOffset, progressOffset + (progress / 255.0) * 180, progress / 4, 20, @@ -137,7 +137,7 @@ void OswAppSwitcher::loop() { hal->gfx()->fillCircle(btnX, btnY, 10, OswUI::getInstance()->getSuccessColor()); } - if (_enableSleep and hal->btnIsDownSince(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { + if (_enableSleep and hal->btnIsDownFor(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { // draw half moon hal->gfx()->fillCircle(btnX, btnY, 9, OswUI::getInstance()->getForegroundDimmedColor()); hal->gfx()->fillCircle(btnX, btnY, 8, OswUI::getInstance()->getBackgroundColor()); diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 13400f25c..9b105bd65 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -93,6 +93,7 @@ bool OswHal::btnHasGoneDown(Button btn) { return _btnGoneDown[btn]; } bool OswHal::btnIsDoubleClick(Button btn) { + OSW_LOG_W("Deprecated method called. Please use OswAppV2::onButton() instead."); return _btnDoubleClick[btn]; } bool OswHal::btnHasGoneUp(Button btn) { @@ -102,14 +103,19 @@ bool OswHal::btnIsDown(Button btn) { return _btnIsDown[btn]; } bool OswHal::btnIsLongPress(Button btn) { + OSW_LOG_W("Deprecated method called. Please use OswAppV2::onButton() instead."); return _btnLongPress[btn]; } void OswHal::suppressButtonUntilUp(Button btn) { + OSW_LOG_W("Deprecated method called. Please use OswAppV2::onButton() instead."); _btnSuppressUntilUpAgain[btn] = true; } -unsigned long OswHal::btnIsDownSince(Button btn) { +unsigned long OswHal::btnIsDownFor(Button btn) { return _btnIsDown[btn] ? millis() - _btnIsDownMillis[btn] : 0; } +unsigned long OswHal::btnIsDownSince(Button btn) { + return _btnIsDown[btn] ? _btnIsDownMillis[btn] : 0; +} void OswHal::clearButtonState(Button btn) { _btnGoneUp[btn] = false; _btnGoneDown[btn] = false; From 4f3de8a68edca1913971ca632b9881442bb738fe Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 13:42:07 +0100 Subject: [PATCH 013/141] Implemented OswAppV2::onButton and updated OswAppTutorial --- include/OswAppV2.h | 25 ++++++++--- include/apps/tools/OswAppTutorial.h | 2 +- src/OswAppV2.cpp | 66 +++++++++++++++++++++++++++-- src/apps/tools/OswAppTutorial.cpp | 3 +- 4 files changed, 86 insertions(+), 10 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index e415aa4a4..a3bb2d49e 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -1,16 +1,27 @@ #pragma once +#include + #include #include class OswHal; class OswAppV2 { public: - enum ViewFlags { - NONE = 0, - NO_OVERLAYS = 1 + enum ViewFlags: char { + NONE = 0, + NO_OVERLAYS = 1 + }; + enum ButtonStateNames: char { + UNDEFINED = 0, + SHORT_PRESS = 1, + LONG_PRESS = 2, + VERY_LONG_PRESS = 4, + DOUBLE_PRESS = 8 }; bool needsRedraw = false; + OswAppV2(); + virtual const char* getAppId() = 0; virtual const char* getAppName() = 0; virtual OswIcon& getAppIcon(); @@ -20,7 +31,7 @@ class OswAppV2 { virtual void onDraw(); virtual void onStop(); - virtual void onButton(int id, bool down, bool shortPress, bool longPress); + virtual void onButton(int id, bool up, ButtonStateNames state); #ifdef OSW_EMULATOR virtual void onLoopDebug(); // By default no debug loop (GUI) is implemented #endif @@ -28,11 +39,15 @@ class OswAppV2 { ViewFlags getViewFlags(); protected: OswHal* hal = nullptr; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 - ViewFlags viewFlags = NONE; + std::array knownButtonStates; // Bitmask of known button states (ignores the DOUBLE_PRESS state by default), use this to ignore unhandled button states + ViewFlags viewFlags = ViewFlags::NONE; OswIcon& getDefaultAppIcon(); private: static OswIcon defaultAppIcon; + std::array buttonDownSince; + std::array buttonLastSentState; + std::array buttonDoubleShortTimeout; void updateCachedHal(); }; \ No newline at end of file diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index d4c27676a..b82422e80 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -17,7 +17,7 @@ class OswAppTutorial : public OswAppV2 { void onDraw() override; void onStop() override; - virtual void onButton(int id, bool down, bool shortPress, bool longPress); + virtual void onButton(int id, bool up, OswAppV2::ButtonStateNames state) override; #ifdef OSW_EMULATOR void onLoopDebug() override; #endif diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index ee8d64780..3c07d9325 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -6,6 +6,12 @@ OswIcon OswAppV2::defaultAppIcon = OswIcon(app_png, app_png_dimensons, 0x0); // Color will be set upon retreival +OswAppV2::OswAppV2() { + for(int i = 0; i < NUM_BUTTONS; i++) + // Do not listen to the double press, as it may delays the short press reporting + this->knownButtonStates[i] = (ButtonStateNames) (ButtonStateNames::UNDEFINED | ButtonStateNames::SHORT_PRESS | ButtonStateNames::LONG_PRESS | ButtonStateNames::VERY_LONG_PRESS); +} + OswIcon& OswAppV2::getAppIcon() { return this->getDefaultAppIcon(); } @@ -26,7 +32,61 @@ void OswAppV2::onStart() { void OswAppV2::onLoop() { this->updateCachedHal(); - // TODO handle button changes and pass them to onButton + const unsigned long now = millis(); + const unsigned long minPressTime = 10; + // TODO move below values into the os configuration + const unsigned long doublePressTimeout = 500; + const unsigned long longPressTime = 1000; + const unsigned long veryLongPressTime = 3000; + + for(int i = 0; i < NUM_BUTTONS; i++) { + if(hal->btnIsDownSince((Button) i) > 0) { + if(buttonDownSince[i] == 0) { + // Oh, the button just went down! + buttonDownSince[i] = now; + buttonLastSentState[i] = ButtonStateNames::UNDEFINED; + if(this->knownButtonStates[i] & buttonLastSentState[i]) + this->onButton(i, false, buttonLastSentState[i]); // we can't decide the short/long press, as it just happend + } else { + // Send state updates, while the button is down + ButtonStateNames maybeNewState = ButtonStateNames::UNDEFINED; + if(now - buttonDownSince[i] >= minPressTime and now - buttonDownSince[i] < longPressTime) { + maybeNewState = ButtonStateNames::SHORT_PRESS; + } else if(now - buttonDownSince[i] >= longPressTime && now - buttonDownSince[i] < veryLongPressTime) { + maybeNewState = ButtonStateNames::LONG_PRESS; + } else if(now - buttonDownSince[i] >= veryLongPressTime) { + maybeNewState = ButtonStateNames::VERY_LONG_PRESS; + } + if(maybeNewState != buttonLastSentState[i]) { + buttonLastSentState[i] = maybeNewState; + if(this->knownButtonStates[i] & buttonLastSentState[i]) + this->onButton(i, false, buttonLastSentState[i]); + } + } + } else if(buttonDownSince[i] > 0) { + // Oh, the button just went up! + if(this->knownButtonStates[i] & ButtonStateNames::DOUBLE_PRESS and buttonLastSentState[i] == ButtonStateNames::SHORT_PRESS) { + if(buttonDoubleShortTimeout[i] > 0 and now - buttonDoubleShortTimeout[i] < doublePressTimeout) { + buttonLastSentState[i] = ButtonStateNames::DOUBLE_PRESS; + buttonDoubleShortTimeout[i] = 0; + } else { + // Do not send the short press event, as it may be a double press + buttonLastSentState[i] = ButtonStateNames::UNDEFINED; + buttonDoubleShortTimeout[i] = now; + } + } else + buttonDoubleShortTimeout[i] = 0; // Reset the double press timeout on any other button state + if(buttonLastSentState[i] != ButtonStateNames::UNDEFINED) + this->onButton(i, true, buttonLastSentState[i]); + buttonDownSince[i] = 0; + buttonLastSentState[i] = ButtonStateNames::UNDEFINED; + } + if(hal->btnIsDownSince((Button) i) == 0 and this->knownButtonStates[i] & ButtonStateNames::SHORT_PRESS) // If the button is not down, check if the double press timeout is over + if(buttonDoubleShortTimeout[i] > 0 and now - buttonDoubleShortTimeout[i] >= doublePressTimeout) { + buttonDoubleShortTimeout[i] = 0; // Reset the double press timeout (if it is set and send out the short press event as no double press happend in time) + this->onButton(i, true, ButtonStateNames::SHORT_PRESS); + } + } } void OswAppV2::onDraw() { @@ -41,8 +101,8 @@ void OswAppV2::updateCachedHal() { this->hal = OswHal::getInstance(); } -void OswAppV2::onButton(int id, bool down, bool shortPress, bool longPress) { - OSW_LOG_W("Not inplemented yet!"); +void OswAppV2::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { + OSW_LOG_D("Button event for app ", this->getAppId(),": ", id, " ", up, " ", (int) state); } #ifdef OSW_EMULATOR diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 42083babc..d014c0294 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -57,7 +57,8 @@ void OswAppTutorial::onDraw() { this->screen = 0; } -void OswAppTutorial::onButton(int id, bool down, bool shortPress, bool longPress) { +void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { + OswAppV2::onButton(id, up, state); // always make sure to call the base class method! if(this->screen == 0) this->screen = 1; } From afabd46c5f7b3125b630ede81f1ef33948e99219 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 13:42:50 +0100 Subject: [PATCH 014/141] Added example to listen to double presses --- include/apps/examples/OswAppExample.h | 3 +-- src/apps/examples/OswAppExample.cpp | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/apps/examples/OswAppExample.h b/include/apps/examples/OswAppExample.h index 22e788ad8..60cdd967c 100644 --- a/include/apps/examples/OswAppExample.h +++ b/include/apps/examples/OswAppExample.h @@ -6,8 +6,7 @@ class OswAppExample : public OswAppV2 { public: - OswAppExample() {}; - ~OswAppExample() {}; + OswAppExample(); const char* getAppId() override; const char* getAppName() override; diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExample.cpp index c01cf48c1..51354e44e 100644 --- a/src/apps/examples/OswAppExample.cpp +++ b/src/apps/examples/OswAppExample.cpp @@ -5,6 +5,11 @@ #include "apps/examples/OswAppExample.h" +OswAppExample::OswAppExample() { + // This app also supports double presses (on BUTTON_1), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) + this->knownButtonStates[BUTTON_1] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_1] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); +} + const char* OswAppExample::getAppId() { return "org.osw.example"; } From 4c7e2998acc131df7d5f45a0cb3d1f99cfa5df43 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 13:44:17 +0100 Subject: [PATCH 015/141] Extended button event logging --- src/OswAppV2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 3c07d9325..68eebefbd 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -102,7 +102,7 @@ void OswAppV2::updateCachedHal() { } void OswAppV2::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { - OSW_LOG_D("Button event for app ", this->getAppId(),": ", id, " ", up, " ", (int) state); + OSW_LOG_D("Button event for app ", this->getAppId(),": id? ", id, " up? ", up, " state? ", (int) state); } #ifdef OSW_EMULATOR From b2fdff92a2e2782f56e3550ce6871965889faaaf Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 14:04:00 +0100 Subject: [PATCH 016/141] Added tutorial step for different button modes --- include/apps/tools/OswAppTutorial.h | 8 +++- src/apps/tools/OswAppTutorial.cpp | 72 +++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index b82422e80..52eae9b86 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -23,8 +23,12 @@ class OswAppTutorial : public OswAppV2 { #endif private: OswIcon oswIcon; - unsigned screen; - unsigned char hsv; + unsigned screen = 0; + unsigned char hsv = 0; + bool gotButtonShort = false; + bool gotButtonLong = false; + bool gotButtonVeryLong = false; + bool gotButtonDouble = false; }; #endif diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index d014c0294..13edb8416 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -5,8 +5,10 @@ #include "apps/tools/OswAppTutorial.h" #include "assets/img/osw.png.h" +#include "assets/img/wait.png.h" +#include "assets/img/check.png.h" -OswAppTutorial::OswAppTutorial(): oswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)), screen(0), hsv(0) { +OswAppTutorial::OswAppTutorial(): oswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)) { } @@ -51,16 +53,78 @@ void OswAppTutorial::onDraw() { hal->gfx()->setTextColor(rgb565(80, 80, 80), OswUI::getInstance()->getBackgroundColor()); hal->gfx()->print(GIT_COMMIT_HASH); } else if(this->screen == 1) { - OswIcon aaa2 = OswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)); - aaa2.draw(hal->gfx(), DISP_W / 2, DISP_H / 2 - 32, 2, OswIcon::Alignment::CENTER, OswIcon::Alignment::CENTER); + OswIcon waiting = OswIcon(wait_png, wait_png_dimensons, rgb565(200, 0, 50)); + OswIcon checked = OswIcon(check_png, check_png_dimensons, rgb565(0, 200, 50)); + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 100); + hal->gfx()->print("Navigation"); + hal->gfx()->setTextSize(1); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 120); + hal->gfx()->print("Please press the button modes\nlisted below to continue."); + + hal->gfx()->setTextSize(1); + hal->gfx()->setTextLeftAligned(); + + short y = 160; + hal->gfx()->setTextCursor(80, y); + hal->gfx()->print("Short Press"); + if(this->gotButtonShort) + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + else + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + y += 15; + hal->gfx()->setTextCursor(80, y); + hal->gfx()->print("Long Press"); + if(this->gotButtonLong) + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + else + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + y += 15; + hal->gfx()->setTextCursor(80, y); + hal->gfx()->print("Very Long Press"); + if(this->gotButtonVeryLong) + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + else + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + y += 15; + hal->gfx()->setTextCursor(80, y); + hal->gfx()->print("Double Press"); + if(this->gotButtonDouble) + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + else + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); } else this->screen = 0; } void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { OswAppV2::onButton(id, up, state); // always make sure to call the base class method! - if(this->screen == 0) + if(!up) return; + if(this->screen == 0) { this->screen = 1; + this->needsRedraw = true; + // Also enable double press detection + for(int i = 0; i < NUM_BUTTONS; i++) + this->knownButtonStates[i] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[i] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); + } else if(this->screen == 1) { + if(state == OswAppV2::ButtonStateNames::SHORT_PRESS) + this->gotButtonShort = true; + else if(state == OswAppV2::ButtonStateNames::LONG_PRESS) + this->gotButtonLong = true; + else if(state == OswAppV2::ButtonStateNames::VERY_LONG_PRESS) + this->gotButtonVeryLong = true; + else if(state == OswAppV2::ButtonStateNames::DOUBLE_PRESS) + this->gotButtonDouble = true; + if(this->gotButtonShort and this->gotButtonLong and this->gotButtonVeryLong and this->gotButtonDouble) { + this->screen = 2; + // Disable double press detection again (speeds up short press detection again) + for(int i = 0; i < NUM_BUTTONS; i++) + this->knownButtonStates[i] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[i] ^ OswAppV2::ButtonStateNames::DOUBLE_PRESS); // Using XOR, as we know it was enabled before + } + this->needsRedraw = true; + } } #ifdef OSW_EMULATOR From ecc3e8d2c95cbb7ec6a7e740b835fd8f099cbe3c Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 14:18:41 +0100 Subject: [PATCH 017/141] Added battery-calibration notice --- include/apps/tools/OswAppTutorial.h | 1 + src/apps/tools/OswAppTutorial.cpp | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index 52eae9b86..f10274282 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -24,6 +24,7 @@ class OswAppTutorial : public OswAppV2 { private: OswIcon oswIcon; unsigned screen = 0; + unsigned currentScreen = 0; unsigned char hsv = 0; bool gotButtonShort = false; bool gotButtonLong = false; diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 13edb8416..ecba6f1e4 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -30,7 +30,8 @@ void OswAppTutorial::onLoop() { OswAppV2::onLoop(); // always make sure to call the base class method! this->hsv = (millis() / 100) % 255; - this->needsRedraw = this->needsRedraw or this->screen == 0; // screen 0 has an animation + this->needsRedraw = this->needsRedraw or this->screen == 0 or this->currentScreen != this->screen; // screen 0 has an animation + this->currentScreen = this->screen; } void OswAppTutorial::onDraw() { @@ -49,7 +50,9 @@ void OswAppTutorial::onDraw() { hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 120); - hal->gfx()->print("This is your own Open-Smartwatch!\nIn the next few seconds this\n\"tutorial\" will guide you through\nthe basic navigation concepts\nof this OS. Have fun!\n\n\nPress any button to continue.\n\n\n"); + hal->gfx()->print("This is your own Open-Smartwatch!\nIn the next few seconds this\n\"tutorial\" will guide you through\nthe basic navigation concepts\nof this OS. Have fun!"); + hal->gfx()->setTextCursor(DISP_W / 2, 180); + hal->gfx()->print("Press any button to continue.\n\n\n"); hal->gfx()->setTextColor(rgb565(80, 80, 80), OswUI::getInstance()->getBackgroundColor()); hal->gfx()->print(GIT_COMMIT_HASH); } else if(this->screen == 1) { @@ -95,6 +98,20 @@ void OswAppTutorial::onDraw() { checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); else waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + } else if(this->screen == 2) { + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 100); + hal->gfx()->print("Battery Calibration"); + hal->gfx()->setTextSize(1); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 120); + hal->gfx()->print("As this hardware has no BMS,\nthe OS has to learn the battery\ncapacity on-the-fly. Make sure to\nfully discharge the battery if\nyou see the battery icon"); + hal->gfx()->setTextColor(OswUI::getInstance()->getInfoColor(), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->print("being filled with the \"info\" color."); + OswUI::getInstance()->resetTextColors(); + hal->gfx()->setTextCursor(DISP_W / 2, 180); + hal->gfx()->print("Press any button to continue."); } else this->screen = 0; } @@ -104,7 +121,6 @@ void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) if(!up) return; if(this->screen == 0) { this->screen = 1; - this->needsRedraw = true; // Also enable double press detection for(int i = 0; i < NUM_BUTTONS; i++) this->knownButtonStates[i] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[i] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); @@ -117,13 +133,15 @@ void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) this->gotButtonVeryLong = true; else if(state == OswAppV2::ButtonStateNames::DOUBLE_PRESS) this->gotButtonDouble = true; + this->needsRedraw = true; if(this->gotButtonShort and this->gotButtonLong and this->gotButtonVeryLong and this->gotButtonDouble) { this->screen = 2; // Disable double press detection again (speeds up short press detection again) for(int i = 0; i < NUM_BUTTONS; i++) this->knownButtonStates[i] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[i] ^ OswAppV2::ButtonStateNames::DOUBLE_PRESS); // Using XOR, as we know it was enabled before } - this->needsRedraw = true; + } else if(this->screen == 2) { + this->screen = 3; } } From a74b5c22ca30e9de4509ab9dc63682e3f2dea393 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 14:42:12 +0100 Subject: [PATCH 018/141] Implemented proper handoff after the tutorial app --- include/apps/tools/OswAppTutorial.h | 3 +++ include/osw_ui.h | 5 +++-- src/apps/tools/OswAppTutorial.cpp | 15 +++++++++---- src/main.cpp | 4 ++-- src/osw_ui.cpp | 34 ++++++++++++++++++----------- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index f10274282..10c6c3a76 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -21,7 +21,10 @@ class OswAppTutorial : public OswAppV2 { #ifdef OSW_EMULATOR void onLoopDebug() override; #endif + + void changeRootAppIfNecessary(); private: + OswAppV2* previousRootApp = nullptr; OswIcon oswIcon; unsigned screen = 0; unsigned currentScreen = 0; diff --git a/include/osw_ui.h b/include/osw_ui.h index b07864b36..d133130c5 100644 --- a/include/osw_ui.h +++ b/include/osw_ui.h @@ -68,7 +68,8 @@ class OswUI { // void loop(OswAppSwitcher& mainAppSwitcher, uint16_t& mainAppIndex); void loop(); - void setRootApplication(OswAppV2& rootApplication); + void setRootApplication(OswAppV2* rootApplication); + OswAppV2* getRootApplication(); uint16_t getBackgroundColor(); uint16_t getBackgroundDimmedColor(); @@ -109,7 +110,7 @@ class OswUI { unsigned int lastBGFlush = 0; std::mutex mNotificationsLock; std::list mNotifications; - OswAppV2* rootApplication = nullptr; + OswAppV2* mRootApplication = nullptr; }; #endif diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index ecba6f1e4..5484666c0 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -106,14 +106,16 @@ void OswAppTutorial::onDraw() { hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 120); - hal->gfx()->print("As this hardware has no BMS,\nthe OS has to learn the battery\ncapacity on-the-fly. Make sure to\nfully discharge the battery if\nyou see the battery icon"); + hal->gfx()->print("As this hardware has no BMS,\nthe OS has to learn the battery\ncapacity on-the-fly. Make sure to\nfully discharge the battery if\nyou see the battery icon being"); hal->gfx()->setTextColor(OswUI::getInstance()->getInfoColor(), OswUI::getInstance()->getBackgroundColor()); - hal->gfx()->print("being filled with the \"info\" color."); + hal->gfx()->print("filled with the \"info\" color."); OswUI::getInstance()->resetTextColors(); hal->gfx()->setTextCursor(DISP_W / 2, 180); hal->gfx()->print("Press any button to continue."); - } else - this->screen = 0; + } else { + // Okay, we are done! Restore the original root app. + OswUI::getInstance()->setRootApplication(this->previousRootApp); + } } void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { @@ -157,4 +159,9 @@ void OswAppTutorial::onLoopDebug() { void OswAppTutorial::onStop() { OswAppV2::onStop(); // always make sure to call the base class method! +} + +void OswAppTutorial::changeRootAppIfNecessary() { + this->previousRootApp = OswUI::getInstance()->getRootApplication(); + OswUI::getInstance()->setRootApplication(this); } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4fd0c09b2..7bf107c92 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -123,8 +123,8 @@ void setup() { mainAppSwitcher.setup(); // TODO temporary for testing - //OswUI::getInstance()->setRootApplication(exampleApp); - OswUI::getInstance()->setRootApplication(tutorialApp); + //OswUI::getInstance()->setRootApplication(&exampleApp); + OswUI::getInstance()->setRootApplication(&tutorialApp); #if USE_ULP == 1 // register the ULP program diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index 4da85653d..8baa7777b 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -77,11 +77,16 @@ void OswUI::setTextCursor(Button btn) { } } -void OswUI::setRootApplication(OswAppV2& rootApplication) { - if(this->rootApplication != nullptr) - this->rootApplication->onStop(); - this->rootApplication = &rootApplication; - this->rootApplication->onStart(); +void OswUI::setRootApplication(OswAppV2* rootApplication) { + if(this->mRootApplication != nullptr) + this->mRootApplication->onStop(); + this->mRootApplication = rootApplication; + if(this->mRootApplication != nullptr) + this->mRootApplication->onStart(); +} + +OswAppV2* OswUI::getRootApplication() { + return this->mRootApplication; } void OswUI::loop() { @@ -104,21 +109,24 @@ void OswUI::loop() { } } - if(this->rootApplication == nullptr) + OswAppV2* rootApp = this->mRootApplication; // Create local copy of current root app, as it may change during the loop() call + if(rootApp == nullptr) { + OSW_LOG_E("No root application set!"); return; // Early abort if no app is set - rootApplication->onLoop(); + } + rootApp->onLoop(); #ifdef OSW_EMULATOR #ifndef NDEBUG if(!OswEmulator::instance->isHeadless) - rootApplication->onLoopDebug(); + rootApp->onLoopDebug(); #endif #endif // Lock UI for drawing - if(rootApplication->needsRedraw) { + if(rootApp->needsRedraw) { if(this->mEnableTargetFPS and (millis() - lastFlush) < (1000 / this->mTargetFPS)) return; // Early abort if we would draw too fast - std::lock_guard guard(*this->drawLock); // Make sure to not modify the notifications vector during drawing + std::lock_guard guard(*this->drawLock); // Make sure to not modify the notifications vector during drawing // BG if (OswHal::getInstance()->displayBufferEnabled()) @@ -134,7 +142,7 @@ void OswUI::loop() { // Apps OswHal::getInstance()->gfx()->setTextLeftAligned(); OswHal::getInstance()->gfx()->setTextSize(1.0f); - rootApplication->onDraw(); + rootApp->onDraw(); } else { // Full-Screen progress OswHal::getInstance()->gfx()->setTextCenterAligned(); @@ -158,13 +166,13 @@ void OswUI::loop() { // TODO remove OswConfigAllKeys::settingDisplayOverlaysOnWatchScreen.get() and make a "force-on" setting instead // Only draw overlays if enabled - if (OswConfigAllKeys::settingDisplayOverlays.get() and !(rootApplication->getViewFlags() & OswAppV2::ViewFlags::NO_OVERLAYS)) + if (OswConfigAllKeys::settingDisplayOverlays.get() and !(rootApp->getViewFlags() & OswAppV2::ViewFlags::NO_OVERLAYS)) drawOverlays(); // Handle display flushing OswHal::getInstance()->flushCanvas(); lastFlush = millis(); - rootApplication->needsRedraw = false; + rootApp->needsRedraw = false; } } From 9648dedfd4118268f299e39e14e97bbc1737e2ac Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 15:12:05 +0100 Subject: [PATCH 019/141] Fixed no-init arrays --- include/OswAppV2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index a3bb2d49e..e84194337 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -45,9 +45,9 @@ class OswAppV2 { private: static OswIcon defaultAppIcon; - std::array buttonDownSince; - std::array buttonLastSentState; - std::array buttonDoubleShortTimeout; + std::array buttonDownSince = {0}; + std::array buttonLastSentState = {ButtonStateNames::UNDEFINED}; + std::array buttonDoubleShortTimeout = {0}; void updateCachedHal(); }; \ No newline at end of file From 80f1ea0c921f89cc942703847ab504c5b7e4840a Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 15:12:45 +0100 Subject: [PATCH 020/141] Implemented tutorial show/hide hooks --- include/apps/tools/OswAppTutorial.h | 4 +++- src/apps/tools/OswAppTutorial.cpp | 17 ++++++++++++++--- src/main.cpp | 8 +++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index 10c6c3a76..94c2b4bd6 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -8,6 +8,7 @@ class OswAppTutorial : public OswAppV2 { public: OswAppTutorial(); + virtual ~OswAppTutorial(); const char* getAppId() override; const char* getAppName() override; @@ -22,7 +23,7 @@ class OswAppTutorial : public OswAppV2 { void onLoopDebug() override; #endif - void changeRootAppIfNecessary(); + bool changeRootAppIfNecessary(); private: OswAppV2* previousRootApp = nullptr; OswIcon oswIcon; @@ -33,6 +34,7 @@ class OswAppTutorial : public OswAppV2 { bool gotButtonLong = false; bool gotButtonVeryLong = false; bool gotButtonDouble = false; + Preferences nvs; }; #endif diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 5484666c0..97ad7171c 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "apps/tools/OswAppTutorial.h" #include "assets/img/osw.png.h" @@ -9,7 +10,12 @@ #include "assets/img/check.png.h" OswAppTutorial::OswAppTutorial(): oswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)) { + bool res = nvs.begin(this->getAppId(), false); + assert(res); +} +OswAppTutorial::~OswAppTutorial() { + nvs.end(); } const char* OswAppTutorial::getAppId() { @@ -115,6 +121,7 @@ void OswAppTutorial::onDraw() { } else { // Okay, we are done! Restore the original root app. OswUI::getInstance()->setRootApplication(this->previousRootApp); + nvs.putString("v", GIT_COMMIT_HASH); } } @@ -161,7 +168,11 @@ void OswAppTutorial::onStop() { OswAppV2::onStop(); // always make sure to call the base class method! } -void OswAppTutorial::changeRootAppIfNecessary() { - this->previousRootApp = OswUI::getInstance()->getRootApplication(); - OswUI::getInstance()->setRootApplication(this); +bool OswAppTutorial::changeRootAppIfNecessary() { + if(nvs.getString("v", "") != String(GIT_COMMIT_HASH)) { + this->previousRootApp = OswUI::getInstance()->getRootApplication(); + OswUI::getInstance()->setRootApplication(this); + return true; + } + return false; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 7bf107c92..da74e920c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -91,7 +91,7 @@ OswAppSwitcher settingsAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_se // TODO temporary for testing static OswAppExample exampleApp; -static OswAppTutorial tutorialApp; +std::unique_ptr tutorialApp; void setup() { Serial.begin(115200); @@ -123,8 +123,10 @@ void setup() { mainAppSwitcher.setup(); // TODO temporary for testing - //OswUI::getInstance()->setRootApplication(&exampleApp); - OswUI::getInstance()->setRootApplication(&tutorialApp); + OswUI::getInstance()->setRootApplication(&exampleApp); + tutorialApp.reset(new OswAppTutorial()); + if(!tutorialApp->changeRootAppIfNecessary()) + tutorialApp.reset(); // no need to keep it around, as it's not the root app #if USE_ULP == 1 // register the ULP program From 862806897899624feaa31a4c05e55f772582bbf2 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 15:28:21 +0100 Subject: [PATCH 021/141] Scale based on 16px icons --- src/OswIcon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OswIcon.cpp b/src/OswIcon.cpp index e908ae9be..199ce9617 100644 --- a/src/OswIcon.cpp +++ b/src/OswIcon.cpp @@ -8,6 +8,7 @@ OswIcon::OswIcon(const unsigned char* data, const unsigned char dimension, uint1 void OswIcon::draw(Graphics2D* gfx, int x, int y, float scale, Alignment xAlign, Alignment yAlign) { // modify x and y based on alignment + scale *= (float) 16 / this->dimension; // treat all icons as a 16x16 grid switch(xAlign) { case Alignment::START: break; From b2c737d361a64fd72dde589f236b4bdaa5a79eb2 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 15:28:50 +0100 Subject: [PATCH 022/141] Corrected icon sizes and added new (empty) page --- img/warning.png | 3 +++ src/apps/tools/OswAppTutorial.cpp | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 img/warning.png diff --git a/img/warning.png b/img/warning.png new file mode 100644 index 000000000..d82c24649 --- /dev/null +++ b/img/warning.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6126c1b932e16b622a82c64ca0df7b518e384a3a52bac9e297a2058edaff2c3 +size 604 diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 97ad7171c..9c6de7e36 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -8,6 +8,7 @@ #include "assets/img/osw.png.h" #include "assets/img/wait.png.h" #include "assets/img/check.png.h" +#include "assets/img/warning.png.h" OswAppTutorial::OswAppTutorial(): oswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)) { bool res = nvs.begin(this->getAppId(), false); @@ -48,7 +49,7 @@ void OswAppTutorial::onDraw() { unsigned char r, g, b; hsvToRgb(this->hsv, maxVal, maxVal, r, g, b); this->oswIcon.color = rgb565(r, g, b); - this->oswIcon.draw(hal->gfx(), DISP_W / 2, 32, 1.2, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); + this->oswIcon.draw(hal->gfx(), DISP_W / 2, 32, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 100); @@ -118,6 +119,9 @@ void OswAppTutorial::onDraw() { OswUI::getInstance()->resetTextColors(); hal->gfx()->setTextCursor(DISP_W / 2, 180); hal->gfx()->print("Press any button to continue."); + } else if(this->screen == 3) { + OswIcon warning = OswIcon(warning_png, warning_png_dimensons, OswUI::getInstance()->getWarningColor()); + warning.draw(hal->gfx(), DISP_W / 2, 32, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); } else { // Okay, we are done! Restore the original root app. OswUI::getInstance()->setRootApplication(this->previousRootApp); @@ -151,6 +155,8 @@ void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) } } else if(this->screen == 2) { this->screen = 3; + } else if(this->screen == 3) { + this->screen = 4; } } From d0ace2e06288c7c7361604f46b3e4504fd061a04 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 24 Feb 2023 15:39:20 +0100 Subject: [PATCH 023/141] Added hardware-problems screen --- src/apps/tools/OswAppTutorial.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 9c6de7e36..2aef70653 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -49,7 +49,7 @@ void OswAppTutorial::onDraw() { unsigned char r, g, b; hsvToRgb(this->hsv, maxVal, maxVal, r, g, b); this->oswIcon.color = rgb565(r, g, b); - this->oswIcon.draw(hal->gfx(), DISP_W / 2, 32, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); + this->oswIcon.draw(hal->gfx(), DISP_W / 2, 28, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 100); @@ -121,7 +121,31 @@ void OswAppTutorial::onDraw() { hal->gfx()->print("Press any button to continue."); } else if(this->screen == 3) { OswIcon warning = OswIcon(warning_png, warning_png_dimensons, OswUI::getInstance()->getWarningColor()); - warning.draw(hal->gfx(), DISP_W / 2, 32, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); + warning.draw(hal->gfx(), DISP_W / 2, 28, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 100); + hal->gfx()->print("Hardware Problems"); + hal->gfx()->setTextSize(1); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextCursor(DISP_W / 2, 120); + hal->gfx()->print("If you see this screen, it means\nthat we detected some hardware\nproblems. Please check the\nfollowing:"); + + short y = 160; + hal->gfx()->setTextCursor(DISP_W / 2, y); + hal->gfx()->print("No battery level with active wifi"); +#if OSW_DEVICE_ESP32_WIFI_LOWPWR == 1 + y += 10; + hal->gfx()->setTextCursor(DISP_W / 2, y); + hal->gfx()->print("Active wifi may cause CPU brown-outs"); +#endif +#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) + y += 10; + hal->gfx()->setTextCursor(DISP_W / 2, y); + hal->gfx()->print("GPS reception is... Terrible."); +#endif + hal->gfx()->setTextCursor(DISP_W / 2, 205); + hal->gfx()->print("Press any button to continue."); } else { // Okay, we are done! Restore the original root app. OswUI::getInstance()->setRootApplication(this->previousRootApp); From be22c60c6219e90aff77540a8f6e0cdcb867add7 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 25 Feb 2023 00:20:36 +0100 Subject: [PATCH 024/141] Added package build instructions --- scripts/build/prebuild_assets.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py index 079d20b3e..a55e875ab 100644 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -1,7 +1,13 @@ import gzip import os import re -from PIL import Image +try: + from PIL import Image +except ImportError: + # According to https://docs.platformio.org/en/stable/scripting/examples/extra_python_packages.html, this may help: + Import("env") + env.Execute("$PYTHONEXE -m pip install pillow") + from PIL import Image def createAssets(srcPath, assPath, convertAssetToSourceCode): os.makedirs(assPath, exist_ok=True) From fc83ac8f92497d09c5144505f2eb7d4538e70c53 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 25 Feb 2023 00:47:44 +0100 Subject: [PATCH 025/141] Implemented tutorial app timeout --- include/apps/tools/OswAppTutorial.h | 1 + src/apps/tools/OswAppTutorial.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index 94c2b4bd6..fce5d3e2d 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -35,6 +35,7 @@ class OswAppTutorial : public OswAppV2 { bool gotButtonVeryLong = false; bool gotButtonDouble = false; Preferences nvs; + unsigned long timeout = 0; }; #endif diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 2aef70653..464dd21dc 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -31,6 +31,7 @@ void OswAppTutorial::onStart() { OswAppV2::onStart(); // always make sure to call the base class method! this->screen = 0; + this->timeout = time(nullptr); } void OswAppTutorial::onLoop() { @@ -129,7 +130,7 @@ void OswAppTutorial::onDraw() { hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 120); - hal->gfx()->print("If you see this screen, it means\nthat we detected some hardware\nproblems. Please check the\nfollowing:"); + hal->gfx()->print("If you see this screen, it means\nthat we detected some hardware\nproblems. Please check by\naware of the following:"); short y = 160; hal->gfx()->setTextCursor(DISP_W / 2, y); @@ -151,11 +152,16 @@ void OswAppTutorial::onDraw() { OswUI::getInstance()->setRootApplication(this->previousRootApp); nvs.putString("v", GIT_COMMIT_HASH); } + + // Auto-hide the tutorial after one minute - in case something gets stuck + if(time(nullptr) - this->timeout > 60) + OswUI::getInstance()->setRootApplication(this->previousRootApp); } void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { OswAppV2::onButton(id, up, state); // always make sure to call the base class method! if(!up) return; + this->timeout = time(nullptr); // reset the timeout, as the user interacted with the device if(this->screen == 0) { this->screen = 1; // Also enable double press detection From a13e6fe91cfcf7cb2da43544f4d8f910536d5ff9 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 1 Mar 2023 15:08:10 +0100 Subject: [PATCH 026/141] Integrated prebuild script into cmake run --- CMakeLists.txt | 16 +++++++++++++++- scripts/build/prebuild_assets.py | 9 ++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cc61b45e..e3de47212 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.10) +cmake_minimum_required (VERSION 3.12) project (OSW-OS-Emulator) set(CMAKE_CXX_STANDARD 20) @@ -60,6 +60,17 @@ target_link_libraries(ImGUI LINK_PUBLIC ${SDL2IMAGE_LIBRARIES} ) +# OSW custom prebuild-scripts +find_package(Python3 REQUIRED COMPONENTS Interpreter) +file(GLOB_RECURSE INCLUDE_OSW_ASSETS ./include/assets/**) +add_custom_target( + osw_script_prebuild_assets ALL + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/build/prebuild_assets.py --output-asset-path ${CMAKE_CURRENT_SOURCE_DIR}/include/assets + BYPRODUCTS ${INCLUDE_OSW_ASSETS} + COMMENT "Generating OSW assets..." +) + # Emulator file(GLOB_RECURSE SOURCES_OSW ./src/*.cpp) file(GLOB_RECURSE SOURCES_OSW_EMULATOR ./emulator/src/*.cpp) @@ -67,6 +78,9 @@ add_executable(emulator.run ${SOURCES_OSW} ${SOURCES_OSW_EMULATOR} ) +add_dependencies(emulator.run + osw_script_prebuild_assets +) target_include_directories(emulator.run PUBLIC ./emulator/include ./include diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py index a55e875ab..4d5ecf11e 100644 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -1,6 +1,7 @@ import gzip import os import re +import argparse try: from PIL import Image except ImportError: @@ -108,7 +109,9 @@ def makeImgStr(srcPath, subPath): fileStr += "\n};\nunsigned char " + varName + "_dimensons PROGMEM = " + str(img.size[0]) + ";" return fileStr -assPath = os.path.join('include', 'assets') -createAssets(os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web'), os.path.join(assPath, 'www'), makeGzStr) +parser = argparse.ArgumentParser() +parser.add_argument('--output-asset-path', default=os.path.join('include', 'assets'), help='The path to the assets folder') +args = parser.parse_args() -createAssets('img', os.path.join(assPath, 'img'), makeImgStr) \ No newline at end of file +createAssets(os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web'), os.path.join(args.output_asset_path, 'www'), makeGzStr) +createAssets('img', os.path.join(args.output_asset_path, 'img'), makeImgStr) \ No newline at end of file From edf1dc5a10782c1e141a626ff5831a586b694d4c Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 1 Mar 2023 15:13:06 +0100 Subject: [PATCH 027/141] Added missing Python packages --- .github/workflows/test-EMULATOR.yml | 6 ++++-- scripts/requirements.txt | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 scripts/requirements.txt diff --git a/.github/workflows/test-EMULATOR.yml b/.github/workflows/test-EMULATOR.yml index 3112d1b66..420eb35cb 100644 --- a/.github/workflows/test-EMULATOR.yml +++ b/.github/workflows/test-EMULATOR.yml @@ -32,9 +32,11 @@ jobs: with: submodules: recursive - name: Update packages - run: sudo apt-get update && sudo apt-get upgrade -y + run: sudo apt-get update - name: Install packages - run: sudo apt-get -y install gcc g++ cmake libsdl2-dev libsdl2-image-dev + run: sudo apt-get -y install gcc g++ cmake libsdl2-dev libsdl2-image-dev python3 python3-pip + - name: Install python packages + run: pip3 install --user -r scripts/requirements.txt - name: Create build directory run: mkdir build - name: CMake ${{ matrix.build-configuration }} diff --git a/scripts/requirements.txt b/scripts/requirements.txt new file mode 100644 index 000000000..65a19bcf4 --- /dev/null +++ b/scripts/requirements.txt @@ -0,0 +1 @@ +Pillow==9.0.1 \ No newline at end of file From 4cefe131e70d20943d5689bf553bc87de02a8672 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 1 Mar 2023 15:16:51 +0100 Subject: [PATCH 028/141] Added shebang-header --- scripts/build/prebuild_assets.py | 2 ++ scripts/build/prebuild_cppflags.py | 0 scripts/build/prebuild_info.py | 2 +- scripts/build/prebuild_lua.py | 0 4 files changed, 3 insertions(+), 1 deletion(-) mode change 100644 => 100755 scripts/build/prebuild_assets.py mode change 100644 => 100755 scripts/build/prebuild_cppflags.py mode change 100644 => 100755 scripts/build/prebuild_info.py mode change 100644 => 100755 scripts/build/prebuild_lua.py diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py old mode 100644 new mode 100755 index 4d5ecf11e..8df4f6776 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -1,3 +1,5 @@ +#! /usr/bin/env python3 + import gzip import os import re diff --git a/scripts/build/prebuild_cppflags.py b/scripts/build/prebuild_cppflags.py old mode 100644 new mode 100755 diff --git a/scripts/build/prebuild_info.py b/scripts/build/prebuild_info.py old mode 100644 new mode 100755 index ebc9e4bcf..a9b0e62e7 --- a/scripts/build/prebuild_info.py +++ b/scripts/build/prebuild_info.py @@ -1,5 +1,5 @@ -import subprocess Import("env") +import subprocess # Try to execute Git, if it failes we will just display the defaults below gitAvailable = False diff --git a/scripts/build/prebuild_lua.py b/scripts/build/prebuild_lua.py old mode 100644 new mode 100755 From d178b1ba3322704cb8c21fd3e429cb3749d53d6c Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 1 Mar 2023 15:20:56 +0100 Subject: [PATCH 029/141] Added LFS clone --- .github/workflows/test-EMULATOR.yml | 1 + .github/workflows/test-FEATURE.yml | 2 ++ .github/workflows/test-OS.yml | 2 ++ .github/workflows/test-OSW.yml | 2 ++ 4 files changed, 7 insertions(+) diff --git a/.github/workflows/test-EMULATOR.yml b/.github/workflows/test-EMULATOR.yml index 420eb35cb..e16ca8712 100644 --- a/.github/workflows/test-EMULATOR.yml +++ b/.github/workflows/test-EMULATOR.yml @@ -31,6 +31,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@v1.2.1 with: submodules: recursive + lfs: 'true' - name: Update packages run: sudo apt-get update - name: Install packages diff --git a/.github/workflows/test-FEATURE.yml b/.github/workflows/test-FEATURE.yml index b1016a4bb..d6d96c740 100644 --- a/.github/workflows/test-FEATURE.yml +++ b/.github/workflows/test-FEATURE.yml @@ -28,6 +28,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@v1.2.1 with: submodules: recursive + lfs: 'true' - id: get-flag run: | echo "feature=$(python3 .github/getWorkflowMatrix.py all_flags)" >> $GITHUB_OUTPUT @@ -56,6 +57,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@v1.2.1 with: submodules: recursive + lfs: 'true' - name: Cache pip uses: actions/cache@v3 with: diff --git a/.github/workflows/test-OS.yml b/.github/workflows/test-OS.yml index 4d9f15fc7..20b2fbf26 100644 --- a/.github/workflows/test-OS.yml +++ b/.github/workflows/test-OS.yml @@ -15,6 +15,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@v1.2.1 with: submodules: recursive + lfs: 'true' - uses: dorny/paths-filter@v2.11.1 id: filter with: @@ -49,6 +50,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@v1.2.1 with: submodules: recursive + lfs: 'true' - name: Cache pip uses: actions/cache@v3 with: diff --git a/.github/workflows/test-OSW.yml b/.github/workflows/test-OSW.yml index d0561c04b..3ba7758fd 100644 --- a/.github/workflows/test-OSW.yml +++ b/.github/workflows/test-OSW.yml @@ -29,6 +29,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@v1.2.1 with: submodules: recursive + lfs: 'true' - uses: dorny/paths-filter@v2.11.1 id: filter with: @@ -62,6 +63,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@v1.2.1 with: submodules: recursive + lfs: 'true' - name: Cache pip uses: actions/cache@v3 with: From 127273df6592206f01ea61d1ea34ed8a33b89c32 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 1 Mar 2023 15:47:29 +0100 Subject: [PATCH 030/141] Ignored unknown args --- scripts/build/prebuild_assets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py index 8df4f6776..2499d8442 100755 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -113,7 +113,7 @@ def makeImgStr(srcPath, subPath): parser = argparse.ArgumentParser() parser.add_argument('--output-asset-path', default=os.path.join('include', 'assets'), help='The path to the assets folder') -args = parser.parse_args() +args, _ = parser.parse_known_args() createAssets(os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web'), os.path.join(args.output_asset_path, 'www'), makeGzStr) createAssets('img', os.path.join(args.output_asset_path, 'img'), makeImgStr) \ No newline at end of file From a42d082ef1fbc981b4bc9b7b4a42dd57c4b91370 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 2 Mar 2023 17:26:16 +0100 Subject: [PATCH 031/141] Respect key length limits --- emulator/src/Preferences.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/emulator/src/Preferences.cpp b/emulator/src/Preferences.cpp index e74264c34..f06b6bb4e 100644 --- a/emulator/src/Preferences.cpp +++ b/emulator/src/Preferences.cpp @@ -8,6 +8,8 @@ bool Preferences::begin(const char* name, bool readOnly) { // Init "NVS" nvs_flash_init(); this->name = std::string(name); + if(this->name.length() > 15) + return false; // Name too long (max 15 chars, as specified for nvs_open()) // Init Jzon tree by loading (existing) file this->path = std::filesystem::path(preferencesFolderName) / (this->name + ".json"); if(std::filesystem::exists(this->path)) { From 46efeb72922ce759ddff1acd72c94b6620122d4a Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 2 Mar 2023 17:27:54 +0100 Subject: [PATCH 032/141] Added button names Fixed crash with too long key names --- emulator/include/Emulator.hpp | 5 +++-- emulator/src/Emulator.cpp | 15 ++++++++------- emulator/src/IO.cpp | 7 ++++--- include/hal/buttons.h | 16 ++++++++++++++++ include/osw_hal.h | 8 ++------ src/apps/examples/OswAppExample.cpp | 6 +++--- src/apps/tools/OswAppTutorial.cpp | 2 +- src/apps/tools/button_test.cpp | 6 +++--- src/hal/buttons.cpp | 8 ++++++-- 9 files changed, 46 insertions(+), 27 deletions(-) create mode 100644 include/hal/buttons.h diff --git a/emulator/include/Emulator.hpp b/emulator/include/Emulator.hpp index deed4c2c8..7118ea4a8 100644 --- a/emulator/include/Emulator.hpp +++ b/emulator/include/Emulator.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "Jzon.h" @@ -46,8 +47,8 @@ class OswEmulator { void run(); void exit(); - void setButton(unsigned id, bool state); - bool getButton(unsigned id); + void setButton(Button id, bool state); + bool getButton(Button id); uint8_t getBatteryRaw(); bool isCharging(); diff --git a/emulator/src/Emulator.cpp b/emulator/src/Emulator.cpp index 3a1962f9c..00f08ede0 100644 --- a/emulator/src/Emulator.cpp +++ b/emulator/src/Emulator.cpp @@ -358,12 +358,12 @@ void OswEmulator::requestSleep(RequestSleepState state) { this->requestedSleepState = state; } -void OswEmulator::setButton(unsigned id, bool state) { +void OswEmulator::setButton(Button id, bool state) { this->buttonCheckboxes.at(id) = state; this->buttons.at(id) = state; }; -bool OswEmulator::getButton(unsigned id) { +bool OswEmulator::getButton(Button id) { return this->buttons.at(id); }; @@ -421,17 +421,18 @@ void OswEmulator::renderGUIFrameEmulator() { } this->addGUIHelp("This button will interrupt the power to the CPU and reset the OS (as from deep sleep)."); for(size_t buttonId = 0; buttonId < this->buttons.size(); ++buttonId) { - ImGui::Button(("Button " + std::to_string(buttonId + 1)).c_str()); + // Due to this checkbox-alignment they are always one frame behind the button state (but this is not a problem) + ImGui::Checkbox(("##btn" + std::to_string(buttonId + 1)).c_str(), &this->buttonCheckboxes.at(buttonId)); // "##" as prefix hides the label, but still allows for unique ids + ImGui::SameLine(); + ImGui::Button((std::string("Button ") + ButtonNames[buttonId]).c_str()); if(ImGui::IsItemActivated() or ImGui::IsItemDeactivated()) // Only use the button to control the button state, if it changed during the last frame this->buttonCheckboxes.at(buttonId) = ImGui::IsItemActive(); if(ImGui::IsItemDeactivated() and this->buttonResetAfterMultiPress) { for(size_t bId = 0; bId < this->buttonCheckboxes.size(); ++bId) if(this->buttonCheckboxes.at(bId)) - this->setButton(bId, false); + this->setButton((Button) bId, false); } - ImGui::SameLine(); - ImGui::Checkbox(("##btn" + std::to_string(buttonId + 1)).c_str(), &this->buttonCheckboxes.at(buttonId)); // "##" as prefix hides the label, but still allows for unique ids - this->setButton(buttonId, this->buttonCheckboxes.at(buttonId)); + this->setButton((Button) buttonId, this->buttonCheckboxes.at(buttonId)); } ImGui::Checkbox("Release after multi-press", &this->buttonResetAfterMultiPress); this->addGUIHelp("Whenever you press-and-hold any butten(s) by activating their checkbox(es) and then click-and-release any button normally, all other held buttons will also be released."); diff --git a/emulator/src/IO.cpp b/emulator/src/IO.cpp index 72b59a420..9dac4f491 100644 --- a/emulator/src/IO.cpp +++ b/emulator/src/IO.cpp @@ -4,6 +4,7 @@ #include "Emulator.hpp" #include OSW_TARGET_PLATFORM_HEADER +#include "hal/buttons.h" #include "osw_pins.h" // Used for BTN_* void pinMode(int pin, int mode) { @@ -24,13 +25,13 @@ uint8_t digitalRead(int pin) { const uint8_t buttonClickStates[] = BTN_STATE_ARRAY; switch (pin) { case BTN_1: - return ((OswEmulator::instance->getButton(0) ? LOW : HIGH) == buttonClickStates[0]) ? LOW : HIGH; + return ((OswEmulator::instance->getButton(Button::BUTTON_SELECT) ? LOW : HIGH) == buttonClickStates[Button::BUTTON_SELECT]) ? LOW : HIGH; break; case BTN_2: - return ((OswEmulator::instance->getButton(1) ? LOW : HIGH) == buttonClickStates[1]) ? LOW : HIGH; + return ((OswEmulator::instance->getButton(Button::BUTTON_UP) ? LOW : HIGH) == buttonClickStates[Button::BUTTON_UP]) ? LOW : HIGH; break; case BTN_3: - return ((OswEmulator::instance->getButton(2) ? LOW : HIGH) == buttonClickStates[2]) ? LOW : HIGH; + return ((OswEmulator::instance->getButton(Button::BUTTON_DOWN) ? LOW : HIGH) == buttonClickStates[Button::BUTTON_DOWN]) ? LOW : HIGH; break; case OSW_DEVICE_TPS2115A_STATPWR: return OswEmulator::instance->isCharging() ? 1 : 0; diff --git a/include/hal/buttons.h b/include/hal/buttons.h new file mode 100644 index 000000000..931fed851 --- /dev/null +++ b/include/hal/buttons.h @@ -0,0 +1,16 @@ +#pragma once + +#define NUM_BUTTONS 3 + +enum Button { + // Every button must have an id in the range of 0 to NUM_BUTTONS-1 + BUTTON_SELECT = 0, + BUTTON_DOWN = 1, + BUTTON_UP = 2, + // Historical reasons ↓ + BUTTON_1 = 0, + BUTTON_2 = 1, + BUTTON_3 = 2 +}; + +extern char* ButtonNames[]; \ No newline at end of file diff --git a/include/osw_hal.h b/include/osw_hal.h index 1f1cd5334..4c4331e97 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -17,6 +17,7 @@ #include OSW_TARGET_PLATFORM_HEADER #include "hal/osw_filesystem.h" +#include "hal/buttons.h" #include #include "osw_config_keys.h" #include "osw_pins.h" @@ -27,10 +28,6 @@ #define ERR_SD_MISSING 1 #define ERR_SD_MOUNT_FAILED 2 -#define NUM_BUTTONS 3 -// enum for user space button handling -enum Button { BUTTON_1 = 0, BUTTON_2 = 1, BUTTON_3 = 2 }; - class OswHal { public: static OswHal* getInstance(); @@ -79,7 +76,7 @@ class OswHal { void stopPower(); // Buttons (Engine-Style) - void checkButtons(void); + void checkButtons(); bool btnIsDown(Button btn); unsigned long btnIsDownFor(Button btn); unsigned long btnIsDownSince(Button btn); @@ -228,7 +225,6 @@ class OswHal { bool _requestDisableBuffer = false; bool _requestEnableBuffer = false; - Button buttons[NUM_BUTTONS] = {BUTTON_1, BUTTON_2, BUTTON_3}; private: Arduino_Canvas_Graphics2D* canvas = nullptr; diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExample.cpp index 51354e44e..538ee2331 100644 --- a/src/apps/examples/OswAppExample.cpp +++ b/src/apps/examples/OswAppExample.cpp @@ -11,7 +11,7 @@ OswAppExample::OswAppExample() { } const char* OswAppExample::getAppId() { - return "org.osw.example"; + return "osw.example"; } const char* OswAppExample::getAppName() { @@ -32,9 +32,9 @@ void OswAppExample::onLoop() { // In this example we will just process the button presses to change the color of the text // TODO move this into the onButton() method bool oldRed = red; - if (hal->btnHasGoneDown(BUTTON_3)) + if (hal->btnHasGoneDown(BUTTON_UP)) red = true; - if (hal->btnHasGoneDown(BUTTON_2)) + if (hal->btnHasGoneDown(BUTTON_DOWN)) red = false; // Then request a redraw if the value has changed or one second passed (for the counter) diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 464dd21dc..f3a362268 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -20,7 +20,7 @@ OswAppTutorial::~OswAppTutorial() { } const char* OswAppTutorial::getAppId() { - return "org.osw.tutorial"; + return "osw.tutorial"; } const char* OswAppTutorial::getAppName() { diff --git a/src/apps/tools/button_test.cpp b/src/apps/tools/button_test.cpp index babf8d10e..c06318e8b 100644 --- a/src/apps/tools/button_test.cpp +++ b/src/apps/tools/button_test.cpp @@ -10,15 +10,15 @@ void OswButtonTest::setup() {} void OswButtonTest::loop() { OswHal* hal = OswHal::getInstance(); for (uint8_t i = 0; i < NUM_BUTTONS; i++) { - if (hal->btnHasGoneDown(hal->buttons[i])) { + if (hal->btnHasGoneDown((Button) i)) { lastValue = goneDown; lastButton = i; } - if (hal->btnHasGoneUp(hal->buttons[i])) { + if (hal->btnHasGoneUp((Button) i)) { lastValue = goneUp; lastButton = i; } - if (hal->btnIsLongPress(hal->buttons[i])) { + if (hal->btnIsLongPress((Button) i)) { lastValue = longPress; lastButton = i; } diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 9b105bd65..9399b459f 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -4,12 +4,16 @@ #include "osw_hal.h" #include "osw_pins.h" +char* ButtonNames[NUM_BUTTONS] = { + (char*)"SELECT", + (char*)"UP", + (char*)"DOWN" +}; + // assign pins to buttons uint8_t buttonPins[] = {BTN_1, BTN_2, BTN_3}; // see osw_pins.h uint8_t buttonClickStates[] = BTN_STATE_ARRAY; -// Graphics2D screenBuffer(DISP_W, DISP_H, DISP_CHUNK_H); - void OswHal::setupButtons(void) { // rtc_gpio_deinit(GPIO_NUM_0); // rtc_gpio_deinit(GPIO_NUM_10); From a8a540731d43bfa36bbae888336a7b3837da58e4 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 2 Mar 2023 18:17:56 +0100 Subject: [PATCH 033/141] Removed OswHal pointer cache and replaced it with a proxy --- include/OswAppV2.h | 10 +++++++--- src/OswAppV2.cpp | 8 +------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index e84194337..e3231f5de 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -38,7 +38,13 @@ class OswAppV2 { ViewFlags getViewFlags(); protected: - OswHal* hal = nullptr; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 + class OswHalProxy { + public: + // This will proxy the "->" operator to use the current instance of OswHal + OswHal* operator->() { return OswHal::getInstance(); }; + // We intentionally do not provide an operation to implicitly convert to OswHal* to prevent accidental use of the wrong instance + }; + OswHalProxy hal; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 std::array knownButtonStates; // Bitmask of known button states (ignores the DOUBLE_PRESS state by default), use this to ignore unhandled button states ViewFlags viewFlags = ViewFlags::NONE; OswIcon& getDefaultAppIcon(); @@ -48,6 +54,4 @@ class OswAppV2 { std::array buttonDownSince = {0}; std::array buttonLastSentState = {ButtonStateNames::UNDEFINED}; std::array buttonDoubleShortTimeout = {0}; - - void updateCachedHal(); }; \ No newline at end of file diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 68eebefbd..ec1eee23c 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -26,12 +26,10 @@ OswAppV2::ViewFlags OswAppV2::getViewFlags() { } void OswAppV2::onStart() { - this->updateCachedHal(); this->needsRedraw = true; } void OswAppV2::onLoop() { - this->updateCachedHal(); const unsigned long now = millis(); const unsigned long minPressTime = 10; // TODO move below values into the os configuration @@ -90,15 +88,11 @@ void OswAppV2::onLoop() { } void OswAppV2::onDraw() { - this->updateCachedHal(); + } void OswAppV2::onStop() { - this->updateCachedHal(); -} -void OswAppV2::updateCachedHal() { - this->hal = OswHal::getInstance(); } void OswAppV2::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { From 9f5286ea01bba03b464171eef6c85381abe7f5cd Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 2 Mar 2023 18:37:48 +0100 Subject: [PATCH 034/141] Introduced app-overlay concept --- include/OswAppV2.h | 1 + include/apps/examples/OswAppExample.h | 1 + src/OswAppV2.cpp | 4 ++++ src/apps/examples/OswAppExample.cpp | 12 ++++++++++++ src/osw_ui.cpp | 1 + 5 files changed, 19 insertions(+) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index e3231f5de..2d177a0b1 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -29,6 +29,7 @@ class OswAppV2 { virtual void onStart(); virtual void onLoop(); virtual void onDraw(); + virtual void onDrawOverlay(); virtual void onStop(); virtual void onButton(int id, bool up, ButtonStateNames state); diff --git a/include/apps/examples/OswAppExample.h b/include/apps/examples/OswAppExample.h index 60cdd967c..f8636af3f 100644 --- a/include/apps/examples/OswAppExample.h +++ b/include/apps/examples/OswAppExample.h @@ -14,6 +14,7 @@ class OswAppExample : public OswAppV2 { void onStart() override; void onLoop() override; void onDraw() override; + void onDrawOverlay() override; void onStop() override; private: diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index ec1eee23c..372efe897 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -91,6 +91,10 @@ void OswAppV2::onDraw() { } +void OswAppV2::onDrawOverlay() { + +} + void OswAppV2::onStop() { } diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExample.cpp index 538ee2331..f557c97da 100644 --- a/src/apps/examples/OswAppExample.cpp +++ b/src/apps/examples/OswAppExample.cpp @@ -71,6 +71,18 @@ void OswAppExample::onDraw() { hal->gfx()->print("Red"); } +void OswAppExample::onDrawOverlay() { + /* + In this function we do nothing, but here you could draw stuff like an indicator of some kind. + But... Why are we calling the parents method at last here? Because the parent method may want + to draw something on top of what we are drawing here. So we need to make sure that we draw our + stuff first and then call the parent method. This is due to the implicit convention, that this + method will draw always on TOP of the previous content - hence called "overlay". + */ + + OswAppV2::onDrawOverlay(); // here at last!!! (and always make sure to call the base class method) +}; + void OswAppExample::onStop() { OswAppV2::onStop(); // always make sure to call the base class method! diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index 8baa7777b..a7b99d259 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -143,6 +143,7 @@ void OswUI::loop() { OswHal::getInstance()->gfx()->setTextLeftAligned(); OswHal::getInstance()->gfx()->setTextSize(1.0f); rootApp->onDraw(); + rootApp->onDrawOverlay(); } else { // Full-Screen progress OswHal::getInstance()->gfx()->setTextCenterAligned(); From fe3e32655bca9f66872c74a4088c9820f82ab5be Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 2 Mar 2023 21:07:06 +0100 Subject: [PATCH 035/141] Implemented v2 button indicators --- include/OswAppV2.h | 1 + src/OswAppV2.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index 2d177a0b1..f940a0bf1 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -55,4 +55,5 @@ class OswAppV2 { std::array buttonDownSince = {0}; std::array buttonLastSentState = {ButtonStateNames::UNDEFINED}; std::array buttonDoubleShortTimeout = {0}; + std::array buttonIndicatorProgress = {0}; }; \ No newline at end of file diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 372efe897..597c7aa76 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -37,6 +37,7 @@ void OswAppV2::onLoop() { const unsigned long longPressTime = 1000; const unsigned long veryLongPressTime = 3000; + const unsigned long indicatorMinTime = minPressTime + (longPressTime * 0.2); for(int i = 0; i < NUM_BUTTONS; i++) { if(hal->btnIsDownSince((Button) i) > 0) { if(buttonDownSince[i] == 0) { @@ -84,6 +85,24 @@ void OswAppV2::onLoop() { buttonDoubleShortTimeout[i] = 0; // Reset the double press timeout (if it is set and send out the short press event as no double press happend in time) this->onButton(i, true, ButtonStateNames::SHORT_PRESS); } + + // Now update the indicator-levels for the buttons + if(hal->btnIsDownFor((Button) i) > indicatorMinTime) { + float progress = (hal->btnIsDownFor((Button) i) - indicatorMinTime) / (float) longPressTime; + if(progress > 1.0) { + // Oh! The button is down for a very long time! + progress = 1.0 + (hal->btnIsDownFor((Button) i) - indicatorMinTime - longPressTime) / (float) (veryLongPressTime - longPressTime); + if(progress > 2.0) + progress = 2.0; + } + if(this->buttonIndicatorProgress[i] != progress) { + this->buttonIndicatorProgress[i] = progress; + this->needsRedraw = true; + } + } else if(this->buttonIndicatorProgress[i] != 0.0) { + this->buttonIndicatorProgress[i] = 0.0; + this->needsRedraw = true; + } } } @@ -92,7 +111,42 @@ void OswAppV2::onDraw() { } void OswAppV2::onDrawOverlay() { + // IDEA for monochrome displays: Just draw a (in length) increasing circle-arc, for very long fill it completely + for(int i = 0; i < NUM_BUTTONS; i++) { + uint8_t btnX = 0; + uint8_t btnY = 0; + + switch (i) { + case BUTTON_2: + btnX = 217; + btnY = 193; + break; + case BUTTON_3: + btnX = 217; + btnY = 47; + break; + case BUTTON_1: + default: + btnX = 23; + btnY = 193; + break; + } + if(this->buttonIndicatorProgress[i] == 0.0) + continue; + + const int16_t longRad = 24; + const int16_t veryLongRad = 12; + if(this->buttonIndicatorProgress[i] <= 1.0) + hal->gfx()->fillCircle(btnX, btnY, this->buttonIndicatorProgress[i] * longRad, OswUI::getInstance()->getPrimaryColor()); + else { + float overcut = 0.2; + float secondRad = (1.0 + overcut) * veryLongRad; + hal->gfx()->fillCircle(btnX, btnY, (1.0 - overcut) * longRad + (this->buttonIndicatorProgress[i] - 1.0) * secondRad, OswUI::getInstance()->getWarningColor()); + + hal->gfx()->fillCircle(btnX, btnY, longRad, OswUI::getInstance()->getPrimaryColor()); + } + } } void OswAppV2::onStop() { From 10d92b27c28f9324cde9b70a14e4a89a7607975a Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 2 Mar 2023 22:25:58 +0100 Subject: [PATCH 036/141] Unified button pixel positions (and alignment) --- include/hal/buttons.h | 6 +++--- include/osw_hal.h | 3 +++ include/osw_pins.h | 8 ++++++- include/osw_ui.h | 3 ++- src/OswAppV2.cpp | 32 ++++++++++++---------------- src/apps/examples/OswAppExample.cpp | 14 ++++++------ src/hal/buttons.cpp | 24 +++++++++++++++------ src/osw_ui.cpp | 33 ++++++++++++++++------------- 8 files changed, 69 insertions(+), 54 deletions(-) diff --git a/include/hal/buttons.h b/include/hal/buttons.h index 931fed851..268be1e1e 100644 --- a/include/hal/buttons.h +++ b/include/hal/buttons.h @@ -5,12 +5,12 @@ enum Button { // Every button must have an id in the range of 0 to NUM_BUTTONS-1 BUTTON_SELECT = 0, - BUTTON_DOWN = 1, - BUTTON_UP = 2, + BUTTON_UP = 1, + BUTTON_DOWN = 2, // Historical reasons ↓ BUTTON_1 = 0, BUTTON_2 = 1, BUTTON_3 = 2 }; -extern char* ButtonNames[]; \ No newline at end of file +extern const char* ButtonNames[]; \ No newline at end of file diff --git a/include/osw_hal.h b/include/osw_hal.h index 4c4331e97..193632f95 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -83,6 +83,9 @@ class OswHal { bool btnHasGoneUp(Button btn); bool btnHasGoneDown(Button btn); void clearButtonState(Button btn); + bool btnIsTopAligned(Button btn); + bool btnIsLeftAligned(Button btn); + void getButtonCoordinates(Button btn, int16_t& x, int16_t& y); // DEPRECATED button methods, use OswAppV2::onButton instead bool btnIsDoubleClick(Button btn); diff --git a/include/osw_pins.h b/include/osw_pins.h index 05a9aa2f3..b0ca9741a 100644 --- a/include/osw_pins.h +++ b/include/osw_pins.h @@ -54,4 +54,10 @@ #define BTN_STATE_ARRAY {HIGH, HIGH, LOW} #else #define BTN_STATE_ARRAY {LOW, HIGH, HIGH} -#endif \ No newline at end of file +#endif + +// button order is: select, down, up +#define BTN_POSX_ARRAY {24, 208, 208} +#define BTN_POSY_ARRAY {190, 190, 44} +#define BTN_POS_ISTOP_ARRAY {false, false, true} +#define BTN_POS_ISLEFT_ARRAY {true, false, false} \ No newline at end of file diff --git a/include/osw_ui.h b/include/osw_ui.h index d133130c5..fbb8ab7a2 100644 --- a/include/osw_ui.h +++ b/include/osw_ui.h @@ -89,7 +89,8 @@ class OswUI { size_t showNotification(std::string message, bool isPersistent); void hideNotification(size_t id); - void resetTextColors(void); + void resetTextColors(); + void resetTextAlignment(); void setTextCursor(Button btn); unsigned int getLastFlush() const { diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 597c7aa76..72896fa9c 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -113,27 +113,21 @@ void OswAppV2::onDraw() { void OswAppV2::onDrawOverlay() { // IDEA for monochrome displays: Just draw a (in length) increasing circle-arc, for very long fill it completely for(int i = 0; i < NUM_BUTTONS; i++) { - uint8_t btnX = 0; - uint8_t btnY = 0; - - switch (i) { - case BUTTON_2: - btnX = 217; - btnY = 193; - break; - case BUTTON_3: - btnX = 217; - btnY = 47; - break; - case BUTTON_1: - default: - btnX = 23; - btnY = 193; - break; - } - if(this->buttonIndicatorProgress[i] == 0.0) continue; + + int16_t btnX = 0; + int16_t btnY = 0; + hal->getButtonCoordinates((Button) i, btnX, btnY); + int16_t btnOffset = 4; + if(btnX < DISP_W / 2) + btnX -= btnOffset; + else + btnX += btnOffset; + if(btnY < DISP_H / 2) + btnY -= btnOffset; + else + btnY += btnOffset; const int16_t longRad = 24; const int16_t veryLongRad = 12; diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExample.cpp index f557c97da..2edbb1f37 100644 --- a/src/apps/examples/OswAppExample.cpp +++ b/src/apps/examples/OswAppExample.cpp @@ -6,8 +6,8 @@ #include "apps/examples/OswAppExample.h" OswAppExample::OswAppExample() { - // This app also supports double presses (on BUTTON_1), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) - this->knownButtonStates[BUTTON_1] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_1] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); + // This app also "supports" double presses (on BUTTON_SELECT), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) + this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); } const char* OswAppExample::getAppId() { @@ -62,13 +62,11 @@ void OswAppExample::onDraw() { if(red) // only reset the text color, if the previous text was red hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); - hal->gfx()->setTextSize(2); - hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(200, 180); - hal->gfx()->print("Normal"); - - hal->gfx()->setTextCursor(200, 60); + OswUI::getInstance()->setTextCursor(BUTTON_UP); hal->gfx()->print("Red"); + + OswUI::getInstance()->setTextCursor(BUTTON_DOWN); + hal->gfx()->print("Normal"); } void OswAppExample::onDrawOverlay() { diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 9399b459f..6fee82266 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -4,15 +4,15 @@ #include "osw_hal.h" #include "osw_pins.h" -char* ButtonNames[NUM_BUTTONS] = { - (char*)"SELECT", - (char*)"UP", - (char*)"DOWN" -}; +const char* ButtonNames[NUM_BUTTONS] = {"SELECT", "DOWN", "UP"}; // assign pins to buttons -uint8_t buttonPins[] = {BTN_1, BTN_2, BTN_3}; // see osw_pins.h -uint8_t buttonClickStates[] = BTN_STATE_ARRAY; +static uint8_t buttonPins[NUM_BUTTONS] = {BTN_1, BTN_2, BTN_3}; // see osw_pins.h +static uint8_t buttonClickStates[NUM_BUTTONS] = BTN_STATE_ARRAY; +static int16_t buttonPositionsX[NUM_BUTTONS] = BTN_POSX_ARRAY; +static int16_t buttonPositionsY[NUM_BUTTONS] = BTN_POSY_ARRAY; +static bool buttonIsTop[NUM_BUTTONS] = BTN_POS_ISTOP_ARRAY; +static bool buttonIsLeft[NUM_BUTTONS] = BTN_POS_ISLEFT_ARRAY; void OswHal::setupButtons(void) { // rtc_gpio_deinit(GPIO_NUM_0); @@ -125,3 +125,13 @@ void OswHal::clearButtonState(Button btn) { _btnGoneDown[btn] = false; _btnLongPress[btn] = false; } +bool OswHal::btnIsTopAligned(Button btn) { + return buttonIsTop[btn]; +} +bool OswHal::btnIsLeftAligned(Button btn) { + return buttonIsLeft[btn]; +} +void OswHal::getButtonCoordinates(Button btn, int16_t& x, int16_t& y) { + x = buttonPositionsX[btn]; + y = buttonPositionsY[btn]; +} \ No newline at end of file diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index a7b99d259..c794f0995 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -56,25 +56,27 @@ void OswUI::resetTextColors(void) { rgb888to565(OswConfigAllKeys::themeBackgroundColor.get())); } +void OswUI::resetTextAlignment() { + OswHal* hal = OswHal::getInstance(); + hal->gfx()->setTextLeftAligned(); + hal->gfx()->setTextBottomAligned(); +} + void OswUI::setTextCursor(Button btn) { - // TODO: this is an ugly hack and needs to go into the main repo + // TODO this should not also modify the text size, right? OswHal* hal = OswHal::getInstance(); hal->gfx()->setTextSize(2); - hal->gfx()->setTextMiddleAligned(); - switch (btn) { - case BUTTON_2: - hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(204, 196); - break; - case BUTTON_3: - hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(204, 44); - break; - case BUTTON_1: - default: + int16_t x, y; + hal->getButtonCoordinates(btn, x, y); + if(hal->btnIsLeftAligned(btn)) + hal->gfx()->setTextLeftAligned(); + else hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(46, 196); - } + if(hal->btnIsTopAligned(btn)) + hal->gfx()->setTextTopAligned(); + else + hal->gfx()->setTextBottomAligned(); + hal->gfx()->setTextCursor(x, y); } void OswUI::setRootApplication(OswAppV2* rootApplication) { @@ -138,6 +140,7 @@ void OswUI::loop() { } this->resetTextColors(); + this->resetTextAlignment(); if (this->mProgressBar == nullptr) { // Apps OswHal::getInstance()->gfx()->setTextLeftAligned(); From 45b0adcad14f9e7d0522b6704f1d26b2a0241e87 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 2 Mar 2023 23:48:24 +0100 Subject: [PATCH 037/141] Fixed too aggressive clean --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3de47212..8f7e9ed79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ target_link_libraries(ImGUI LINK_PUBLIC # OSW custom prebuild-scripts find_package(Python3 REQUIRED COMPONENTS Interpreter) -file(GLOB_RECURSE INCLUDE_OSW_ASSETS ./include/assets/**) +file(GLOB_RECURSE INCLUDE_OSW_ASSETS ./include/assets/img/** ./include/assets/www/**) add_custom_target( osw_script_prebuild_assets ALL WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} From 477c086b5b68b5a808685a5a78ef4e37e8a1b2ca Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 25 Mar 2023 12:20:43 +0100 Subject: [PATCH 038/141] Recreated OswAppV1 example and renamed v2 one --- include/apps/examples/OswAppExampleV1.h | 19 +++++++ .../{OswAppExample.h => OswAppExampleV2.h} | 6 +-- src/apps/examples/OswAppExampleV1.cpp | 54 +++++++++++++++++++ ...{OswAppExample.cpp => OswAppExampleV2.cpp} | 45 ++++++++-------- src/main.cpp | 9 ++-- 5 files changed, 106 insertions(+), 27 deletions(-) create mode 100644 include/apps/examples/OswAppExampleV1.h rename include/apps/examples/{OswAppExample.h => OswAppExampleV2.h} (76%) create mode 100644 src/apps/examples/OswAppExampleV1.cpp rename src/apps/examples/{OswAppExample.cpp => OswAppExampleV2.cpp} (76%) diff --git a/include/apps/examples/OswAppExampleV1.h b/include/apps/examples/OswAppExampleV1.h new file mode 100644 index 000000000..4b2b63cba --- /dev/null +++ b/include/apps/examples/OswAppExampleV1.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +class OswAppExampleV1 : public OswAppV1 { + public: + OswAppExampleV1(); + + void setup() override; + void loop() override; + void stop() override; + + private: + // define global scope variables + bool red = false; + unsigned int start = 0; + unsigned int counter = 0; +}; diff --git a/include/apps/examples/OswAppExample.h b/include/apps/examples/OswAppExampleV2.h similarity index 76% rename from include/apps/examples/OswAppExample.h rename to include/apps/examples/OswAppExampleV2.h index f8636af3f..71ebad93f 100644 --- a/include/apps/examples/OswAppExample.h +++ b/include/apps/examples/OswAppExampleV2.h @@ -1,12 +1,11 @@ #pragma once #include - #include -class OswAppExample : public OswAppV2 { +class OswAppExampleV2 : public OswAppV2 { public: - OswAppExample(); + OswAppExampleV2(); const char* getAppId() override; const char* getAppName() override; @@ -16,6 +15,7 @@ class OswAppExample : public OswAppV2 { void onDraw() override; void onDrawOverlay() override; void onStop() override; + void onButton(int id, bool up, ButtonStateNames state) override; private: // define global scope variables diff --git a/src/apps/examples/OswAppExampleV1.cpp b/src/apps/examples/OswAppExampleV1.cpp new file mode 100644 index 000000000..88ce230ce --- /dev/null +++ b/src/apps/examples/OswAppExampleV1.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +#include "apps/examples/OswAppExampleV1.h" + +OswAppExampleV1::OswAppExampleV1() { + +} + +void OswAppExampleV1::setup() { + // This is where you initialise code, gets called before this app is shown + this->start = time(nullptr); // used as offset for the counter later on +} + +void OswAppExampleV1::loop() { + // This section of the code is where you can write the main logic + OswHal* hal = OswHal::getInstance(); // Do not cache this reference in e.g. your constructor, as it may change! + + // In this example we will just process the button presses to change the color of the text + if (hal->btnHasGoneDown(BUTTON_UP)) + red = true; + if (hal->btnHasGoneDown(BUTTON_DOWN)) + red = false; + + this->counter = time(nullptr); // update the counter + + // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text + hal->gfx()->setTextCenterAligned(); + if (red) + hal->gfx()->setTextColor(rgb565(255, 0, 0), OswUI::getInstance()->getBackgroundColor()); + else + hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); + + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2); + hal->gfx()->print("Hello World"); + + hal->gfx()->setTextSize(1); + hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2 + 10); // This places the text exactly into the space of the previous text :) + hal->gfx()->print(this->counter - this->start); + + if(red) // only reset the text color, if the previous text was red + hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); + OswUI::getInstance()->setTextCursor(BUTTON_UP); + hal->gfx()->print("Red"); + + OswUI::getInstance()->setTextCursor(BUTTON_DOWN); + hal->gfx()->print("Normal"); +} + +void OswAppExampleV1::stop() { + // This is where you de-initialize stuff, gets called when another app is shown +} diff --git a/src/apps/examples/OswAppExample.cpp b/src/apps/examples/OswAppExampleV2.cpp similarity index 76% rename from src/apps/examples/OswAppExample.cpp rename to src/apps/examples/OswAppExampleV2.cpp index 2edbb1f37..0f69c936e 100644 --- a/src/apps/examples/OswAppExample.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -1,47 +1,38 @@ #include -#include #include #include -#include "apps/examples/OswAppExample.h" +#include "apps/examples/OswAppExampleV2.h" -OswAppExample::OswAppExample() { +OswAppExampleV2::OswAppExampleV2() { // This app also "supports" double presses (on BUTTON_SELECT), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); } -const char* OswAppExample::getAppId() { +const char* OswAppExampleV2::getAppId() { return "osw.example"; } -const char* OswAppExample::getAppName() { +const char* OswAppExampleV2::getAppName() { return "Example App"; } -void OswAppExample::onStart() { +void OswAppExampleV2::onStart() { OswAppV2::onStart(); // always make sure to call the base class method! // This is where you initialise code, gets called before this app is shown this->start = time(nullptr); // used as offset for the counter later on } -void OswAppExample::onLoop() { +void OswAppExampleV2::onLoop() { OswAppV2::onLoop(); // always make sure to call the base class method! // This section of the code is where you can write the main logic - // In this example we will just process the button presses to change the color of the text - // TODO move this into the onButton() method - bool oldRed = red; - if (hal->btnHasGoneDown(BUTTON_UP)) - red = true; - if (hal->btnHasGoneDown(BUTTON_DOWN)) - red = false; - - // Then request a redraw if the value has changed or one second passed (for the counter) - this->needsRedraw = this->needsRedraw or oldRed != red or counter != time(nullptr); + // We request a redraw if the value has changed or one second passed (for the counter) + this->needsRedraw = this->needsRedraw or counter != time(nullptr); } -void OswAppExample::onDraw() { +void OswAppExampleV2::onDraw() { OswAppV2::onDraw(); // always make sure to call the base class method! this->counter = time(nullptr); // update the counter @@ -69,7 +60,7 @@ void OswAppExample::onDraw() { hal->gfx()->print("Normal"); } -void OswAppExample::onDrawOverlay() { +void OswAppExampleV2::onDrawOverlay() { /* In this function we do nothing, but here you could draw stuff like an indicator of some kind. But... Why are we calling the parents method at last here? Because the parent method may want @@ -79,9 +70,21 @@ void OswAppExample::onDrawOverlay() { */ OswAppV2::onDrawOverlay(); // here at last!!! (and always make sure to call the base class method) -}; +} + +void OswAppExampleV2::onButton(int id, bool up, ButtonStateNames state) { + if(up and state == ButtonStateNames::SHORT_PRESS) { + if(id == Button::BUTTON_UP) { + this->red = true; + this->needsRedraw = true; + } else if(id == Button::BUTTON_DOWN) { + this->red = false; + this->needsRedraw = true; + } + } +} -void OswAppExample::onStop() { +void OswAppExampleV2::onStop() { OswAppV2::onStop(); // always make sure to call the base class method! // This is where you de-initialize stuff, gets called when another app is shown diff --git a/src/main.cpp b/src/main.cpp index da74e920c..ab42395d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,8 @@ #endif // #include "./apps/_experiments/runtime_test.h" -#include "apps/examples/OswAppExample.h" +#include "apps/examples/OswAppExampleV1.h" +#include "apps/examples/OswAppExampleV2.h" #include "apps/tools/OswAppTutorial.h" #ifdef OSW_FEATURE_LUA #include "./apps/main/luaapp.h" @@ -90,7 +91,8 @@ OswAppSwitcher clockAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_clock OswAppSwitcher settingsAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_settingsAppIndex); // TODO temporary for testing -static OswAppExample exampleApp; +static OswAppExampleV1 exampleAppV1; +static OswAppExampleV2 exampleAppV2; std::unique_ptr tutorialApp; void setup() { @@ -123,7 +125,8 @@ void setup() { mainAppSwitcher.setup(); // TODO temporary for testing - OswUI::getInstance()->setRootApplication(&exampleApp); + OswUI::getInstance()->setRootApplication(&exampleAppV2); + //OswUI::getInstance()->setRootApplication(&exampleAppV1); tutorialApp.reset(new OswAppTutorial()); if(!tutorialApp->changeRootAppIfNecessary()) tutorialApp.reset(); // no need to keep it around, as it's not the root app From 5ec41c1524a64eee2e85aec41a02fbb6b74335f6 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 25 Mar 2023 22:03:55 +0100 Subject: [PATCH 039/141] Implemented OswAppV2 compat layer for OswAppV1 --- include/OswAppV2Compat.h | 28 ++++++++++++++++++++++++++++ src/OswAppV2Compat.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/main.cpp | 3 ++- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 include/OswAppV2Compat.h create mode 100644 src/OswAppV2Compat.cpp diff --git a/include/OswAppV2Compat.h b/include/OswAppV2Compat.h new file mode 100644 index 000000000..cab96d887 --- /dev/null +++ b/include/OswAppV2Compat.h @@ -0,0 +1,28 @@ +#pragma once +#include + +#include +#include + +class OswAppV2Compat: public OswAppV2 { + public: + OswAppV2Compat(const char* id, const char* name, OswAppV1& app); + + const char* getAppId() override; + const char* getAppName() override; + + void onStart() override; + void onLoop() override; + void onDraw() override; + void onDrawOverlay() override; + void onStop() override; + +#ifdef OSW_EMULATOR + void onLoopDebug() override; +#endif + + private: + const char* id; + const char* name; + OswAppV1& app; +}; \ No newline at end of file diff --git a/src/OswAppV2Compat.cpp b/src/OswAppV2Compat.cpp new file mode 100644 index 000000000..044550ad2 --- /dev/null +++ b/src/OswAppV2Compat.cpp @@ -0,0 +1,39 @@ +#include + +OswAppV2Compat::OswAppV2Compat(const char* id, const char* name, OswAppV1& app): id(id), name(name), app(app) { + +} + +const char* OswAppV2Compat::getAppId() { + return this->id; +} + +const char* OswAppV2Compat::getAppName() { + return this->name; +} + +void OswAppV2Compat::onStart() { + this->app.setup(); +} + +void OswAppV2Compat::onLoop() { + this->needsRedraw = true; +} + +void OswAppV2Compat::onDraw() { + this->app.loop(); // v1 apps draw in their loop, so we call loop here (which may causes rendering slowdown) +} + +void OswAppV2Compat::onDrawOverlay() { + // Unsupported. +} + +void OswAppV2Compat::onStop() { + this->app.stop(); +} + +#ifdef OSW_EMULATOR +void OswAppV2Compat::onLoopDebug() { + this->app.loopDebug(); +} +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ab42395d6..f850e782e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ #endif // #include "./apps/_experiments/runtime_test.h" +#include "OswAppV2Compat.h" #include "apps/examples/OswAppExampleV1.h" #include "apps/examples/OswAppExampleV2.h" #include "apps/tools/OswAppTutorial.h" @@ -126,7 +127,7 @@ void setup() { // TODO temporary for testing OswUI::getInstance()->setRootApplication(&exampleAppV2); - //OswUI::getInstance()->setRootApplication(&exampleAppV1); + //OswUI::getInstance()->setRootApplication(new OswAppV2Compat("org.example.v1", "Example V1", exampleAppV1)); tutorialApp.reset(new OswAppTutorial()); if(!tutorialApp->changeRootAppIfNecessary()) tutorialApp.reset(); // no need to keep it around, as it's not the root app From 975a74ef1a6d5c4a27b450aa1948016dd11c2b33 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Mar 2023 21:55:48 +0200 Subject: [PATCH 040/141] Moved icons into subfolder --- img/{ => icons}/.gitignore | 0 img/{ => icons}/app.png | 0 img/{ => icons}/check.png | 0 img/{ => icons}/osw.png | 0 img/{ => icons}/wait.png | 0 img/{ => icons}/warning.png | 0 scripts/build/prebuild_assets.py | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) rename img/{ => icons}/.gitignore (100%) rename img/{ => icons}/app.png (100%) rename img/{ => icons}/check.png (100%) rename img/{ => icons}/osw.png (100%) rename img/{ => icons}/wait.png (100%) rename img/{ => icons}/warning.png (100%) diff --git a/img/.gitignore b/img/icons/.gitignore similarity index 100% rename from img/.gitignore rename to img/icons/.gitignore diff --git a/img/app.png b/img/icons/app.png similarity index 100% rename from img/app.png rename to img/icons/app.png diff --git a/img/check.png b/img/icons/check.png similarity index 100% rename from img/check.png rename to img/icons/check.png diff --git a/img/osw.png b/img/icons/osw.png similarity index 100% rename from img/osw.png rename to img/icons/osw.png diff --git a/img/wait.png b/img/icons/wait.png similarity index 100% rename from img/wait.png rename to img/icons/wait.png diff --git a/img/warning.png b/img/icons/warning.png similarity index 100% rename from img/warning.png rename to img/icons/warning.png diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py index 2499d8442..765ba0e25 100755 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -116,4 +116,4 @@ def makeImgStr(srcPath, subPath): args, _ = parser.parse_known_args() createAssets(os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web'), os.path.join(args.output_asset_path, 'www'), makeGzStr) -createAssets('img', os.path.join(args.output_asset_path, 'img'), makeImgStr) \ No newline at end of file +createAssets(os.path.join('img', 'icons'), os.path.join(args.output_asset_path, 'img'), makeImgStr) \ No newline at end of file From 07ca5dfa3687c94aa020352b28fc43b84672786e Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Mar 2023 22:22:13 +0200 Subject: [PATCH 041/141] Added static assets and fixed typo --- scripts/build/prebuild_assets.py | 31 +++++++++++++++++++++++++++++-- src/OswAppV2.cpp | 4 ++-- src/apps/tools/OswAppTutorial.cpp | 16 ++++++++-------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py index 765ba0e25..65b6dc1e7 100755 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -1,6 +1,7 @@ #! /usr/bin/env python3 import gzip +import io import os import re import argparse @@ -108,7 +109,32 @@ def makeImgStr(srcPath, subPath): fileStr += hex(subArr[j]) + ', ' fileStr += '\n' fileStr = fileStr[:-3] # Strip the last ", \n" - fileStr += "\n};\nunsigned char " + varName + "_dimensons PROGMEM = " + str(img.size[0]) + ";" + fileStr += "\n};\nunsigned char " + varName + "_dimensions PROGMEM = " + str(img.size[0]) + ";" + return fileStr + +def makePngImgStr(srcPath, subPath): + if not subPath.endswith('.png'): + return None + + img = Image.open(srcPath, 'r') + + byts = io.BytesIO() + img.save(byts, format='PNG', optimize=True, compress_level=9) + byteFile = byts.getvalue() + + # Create new .h string + varName = re.sub('[^a-zA-Z0-9]', '_', subPath) # Replace all non-alphanumeric characters with underscores + varName = re.sub('^_*', '', varName) + fileStr = "#pragma once\nconst unsigned char " + varName + "[] PROGMEM = {\n" + for i in range(0, len(byteFile), 12): + fileStr += '\t' + subArr = byteFile[i:i+12] + for j in range(0, len(subArr)): + fileStr += hex(subArr[j]) + ', ' + fileStr += '\n' + fileStr = fileStr[:-3] # Strip the last ", \n" + fileStr += "\n};\nunsigned char " + varName + "_dimension_width PROGMEM = " + str(img.size[0]) + ";" + fileStr += "\nunsigned char " + varName + "_dimension_height PROGMEM = " + str(img.size[1]) + ";" return fileStr parser = argparse.ArgumentParser() @@ -116,4 +142,5 @@ def makeImgStr(srcPath, subPath): args, _ = parser.parse_known_args() createAssets(os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web'), os.path.join(args.output_asset_path, 'www'), makeGzStr) -createAssets(os.path.join('img', 'icons'), os.path.join(args.output_asset_path, 'img'), makeImgStr) \ No newline at end of file +createAssets(os.path.join('img', 'icons'), os.path.join(args.output_asset_path, 'img', 'icons'), makeImgStr) +createAssets(os.path.join('img', 'static'), os.path.join(args.output_asset_path, 'img', 'static'), makePngImgStr) \ No newline at end of file diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 72896fa9c..cd355c76d 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -2,9 +2,9 @@ #include #include -#include "assets/img/app.png.h" +#include "assets/img/icons/app.png.h" -OswIcon OswAppV2::defaultAppIcon = OswIcon(app_png, app_png_dimensons, 0x0); // Color will be set upon retreival +OswIcon OswAppV2::defaultAppIcon = OswIcon(app_png, app_png_dimensions, 0x0); // Color will be set upon retreival OswAppV2::OswAppV2() { for(int i = 0; i < NUM_BUTTONS; i++) diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index f3a362268..14a1b84af 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -5,12 +5,12 @@ #include #include "apps/tools/OswAppTutorial.h" -#include "assets/img/osw.png.h" -#include "assets/img/wait.png.h" -#include "assets/img/check.png.h" -#include "assets/img/warning.png.h" +#include "assets/img/icons/osw.png.h" +#include "assets/img/icons/wait.png.h" +#include "assets/img/icons/check.png.h" +#include "assets/img/icons/warning.png.h" -OswAppTutorial::OswAppTutorial(): oswIcon(osw_png, osw_png_dimensons, rgb565(200, 0, 50)) { +OswAppTutorial::OswAppTutorial(): oswIcon(osw_png, osw_png_dimensions, rgb565(200, 0, 50)) { bool res = nvs.begin(this->getAppId(), false); assert(res); } @@ -64,8 +64,8 @@ void OswAppTutorial::onDraw() { hal->gfx()->setTextColor(rgb565(80, 80, 80), OswUI::getInstance()->getBackgroundColor()); hal->gfx()->print(GIT_COMMIT_HASH); } else if(this->screen == 1) { - OswIcon waiting = OswIcon(wait_png, wait_png_dimensons, rgb565(200, 0, 50)); - OswIcon checked = OswIcon(check_png, check_png_dimensons, rgb565(0, 200, 50)); + OswIcon waiting = OswIcon(wait_png, wait_png_dimensions, rgb565(200, 0, 50)); + OswIcon checked = OswIcon(check_png, check_png_dimensions, rgb565(0, 200, 50)); hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 100); @@ -121,7 +121,7 @@ void OswAppTutorial::onDraw() { hal->gfx()->setTextCursor(DISP_W / 2, 180); hal->gfx()->print("Press any button to continue."); } else if(this->screen == 3) { - OswIcon warning = OswIcon(warning_png, warning_png_dimensons, OswUI::getInstance()->getWarningColor()); + OswIcon warning = OswIcon(warning_png, warning_png_dimensions, OswUI::getInstance()->getWarningColor()); warning.draw(hal->gfx(), DISP_W / 2, 28, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); From ca8d2ff9eed3c2002c1a0fa3276e6382abed2756 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 00:14:56 +0200 Subject: [PATCH 042/141] Added static image asset read&draw Integrated into example apps --- img/static/example.png | 3 ++ include/OswIcon.h | 9 ++-- include/OswImage.h | 31 +++++++++++ include/apps/examples/OswAppExampleV1.h | 4 +- include/apps/examples/OswAppExampleV2.h | 2 + scripts/build/prebuild_assets.py | 9 ++-- src/OswIcon.cpp | 14 ++--- src/OswImage.cpp | 70 +++++++++++++++++++++++++ src/apps/examples/OswAppExampleV1.cpp | 12 ++++- src/apps/examples/OswAppExampleV2.cpp | 20 +++++-- src/apps/tools/OswAppTutorial.cpp | 20 +++---- 11 files changed, 162 insertions(+), 32 deletions(-) create mode 100644 img/static/example.png create mode 100644 include/OswImage.h create mode 100644 src/OswImage.cpp diff --git a/img/static/example.png b/img/static/example.png new file mode 100644 index 000000000..cdbb52aba --- /dev/null +++ b/img/static/example.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42063150e44c9fbb98434ab5b026d9f931f7cc9bb9e82e53467290545d134e0c +size 26440 diff --git a/include/OswIcon.h b/include/OswIcon.h index e1d726088..b7bbb20ec 100644 --- a/include/OswIcon.h +++ b/include/OswIcon.h @@ -3,18 +3,15 @@ #include #include +#include + class OswIcon { public: - enum class Alignment { - START, - CENTER, - END - }; uint16_t color; OswIcon(const unsigned char* data, const unsigned char dimension, uint16_t color); - void draw(Graphics2D* gfx, int x, int y, float scale = 1, Alignment xAlign = Alignment::START, Alignment yAlign = Alignment::START); + void draw(Graphics2D* gfx, int x, int y, float scale = 1, OswImage::Alignment xAlign = OswImage::Alignment::START, OswImage::Alignment yAlign = OswImage::Alignment::START); private: static const bool debugBackground = false; diff --git a/include/OswImage.h b/include/OswImage.h new file mode 100644 index 000000000..650e4c055 --- /dev/null +++ b/include/OswImage.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +class OswImage { + public: + enum class Alignment { + START, + CENTER, + END + }; + + OswImage(const unsigned char* data, unsigned int length, unsigned short width, unsigned short height); + + void draw(Graphics2D* gfx, int x, int y, float scale = 1, Alignment xAlign = Alignment::START, Alignment yAlign = Alignment::START); + private: + static Graphics2D* cbGfx; + static unsigned int cbOffX; + static unsigned int cbOffY; + static Alignment cbAlignX; + static Alignment cbAlignY; + static float cbScale; + const unsigned char* data; + const unsigned int length; + const unsigned short width; + const unsigned short height; + + static void drawCallback(pngle_t* pngle, unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned char rgba[4]); +}; \ No newline at end of file diff --git a/include/apps/examples/OswAppExampleV1.h b/include/apps/examples/OswAppExampleV1.h index 4b2b63cba..94da24e69 100644 --- a/include/apps/examples/OswAppExampleV1.h +++ b/include/apps/examples/OswAppExampleV1.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include class OswAppExampleV1 : public OswAppV1 { public: @@ -14,6 +14,8 @@ class OswAppExampleV1 : public OswAppV1 { private: // define global scope variables bool red = false; + bool showImage = false; unsigned int start = 0; unsigned int counter = 0; + OswImage image; }; diff --git a/include/apps/examples/OswAppExampleV2.h b/include/apps/examples/OswAppExampleV2.h index 71ebad93f..9b5b61f6d 100644 --- a/include/apps/examples/OswAppExampleV2.h +++ b/include/apps/examples/OswAppExampleV2.h @@ -20,6 +20,8 @@ class OswAppExampleV2 : public OswAppV2 { private: // define global scope variables bool red = false; + bool showImage = false; unsigned int start = 0; unsigned int counter = 0; + OswImage image; }; diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py index 65b6dc1e7..632e7dacd 100755 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -78,7 +78,7 @@ def makeGzStr(srcPath, subPath): fileStr += hex(subArr[j]) + ', ' fileStr += '\n' fileStr = fileStr[:-3] # Strip the last ", \n" - fileStr += "\n};\nunsigned long " + varName + "_len PROGMEM = " + str(len(byteFile)) + ";" + fileStr += "\n};\nconst unsigned long " + varName + "_len PROGMEM = " + str(len(byteFile)) + ";" return fileStr def makeImgStr(srcPath, subPath): @@ -109,7 +109,7 @@ def makeImgStr(srcPath, subPath): fileStr += hex(subArr[j]) + ', ' fileStr += '\n' fileStr = fileStr[:-3] # Strip the last ", \n" - fileStr += "\n};\nunsigned char " + varName + "_dimensions PROGMEM = " + str(img.size[0]) + ";" + fileStr += "\n};\nconst unsigned char " + varName + "_dimensions PROGMEM = " + str(img.size[0]) + ";" return fileStr def makePngImgStr(srcPath, subPath): @@ -133,8 +133,9 @@ def makePngImgStr(srcPath, subPath): fileStr += hex(subArr[j]) + ', ' fileStr += '\n' fileStr = fileStr[:-3] # Strip the last ", \n" - fileStr += "\n};\nunsigned char " + varName + "_dimension_width PROGMEM = " + str(img.size[0]) + ";" - fileStr += "\nunsigned char " + varName + "_dimension_height PROGMEM = " + str(img.size[1]) + ";" + fileStr += "\n};\nconst unsigned int " + varName + "_length PROGMEM = " + str(len(byteFile)) + ";" + fileStr += "\nconst unsigned short " + varName + "_width PROGMEM = " + str(img.size[0]) + ";" + fileStr += "\nconst unsigned short " + varName + "_height PROGMEM = " + str(img.size[1]) + ";" return fileStr parser = argparse.ArgumentParser() diff --git a/src/OswIcon.cpp b/src/OswIcon.cpp index 199ce9617..0f6a4b705 100644 --- a/src/OswIcon.cpp +++ b/src/OswIcon.cpp @@ -6,26 +6,26 @@ OswIcon::OswIcon(const unsigned char* data, const unsigned char dimension, uint1 } -void OswIcon::draw(Graphics2D* gfx, int x, int y, float scale, Alignment xAlign, Alignment yAlign) { +void OswIcon::draw(Graphics2D* gfx, int x, int y, float scale, OswImage::Alignment xAlign, OswImage::Alignment yAlign) { // modify x and y based on alignment scale *= (float) 16 / this->dimension; // treat all icons as a 16x16 grid switch(xAlign) { - case Alignment::START: + case OswImage::Alignment::START: break; - case Alignment::CENTER: + case OswImage::Alignment::CENTER: x -= dimension * scale / 2; break; - case Alignment::END: + case OswImage::Alignment::END: x -= dimension * scale; break; } switch(yAlign) { - case Alignment::START: + case OswImage::Alignment::START: break; - case Alignment::CENTER: + case OswImage::Alignment::CENTER: y -= dimension * scale / 2; break; - case Alignment::END: + case OswImage::Alignment::END: y -= dimension * scale; break; } diff --git a/src/OswImage.cpp b/src/OswImage.cpp new file mode 100644 index 000000000..1e7d0e65a --- /dev/null +++ b/src/OswImage.cpp @@ -0,0 +1,70 @@ +#include + +#include + +Graphics2D* OswImage::cbGfx = nullptr; +unsigned int OswImage::cbOffX = 0; +unsigned int OswImage::cbOffY = 0; +float OswImage::cbScale = 0; +OswImage::Alignment OswImage::cbAlignX = OswImage::Alignment::START; +OswImage::Alignment OswImage::cbAlignY = OswImage::Alignment::START; + +OswImage::OswImage(const unsigned char* data, unsigned int length, unsigned short width, unsigned short height): data(data), length(length), width(width), height(height) { + +} + +/** + * @brief Draws the image to the given Graphics2D instance - somewhat slow (because the PNG is decoded on the fly) + * + * @param gfx + * @param x + * @param y + * @param scale Dirty hack to scale the image - this is not a proper implementation of scaling and will not work for > 1.0! + * @param xAlign + * @param yAlign + */ +void OswImage::draw(Graphics2D* gfx, int x, int y, float scale, Alignment xAlign, Alignment yAlign) { + pngle_t* pngle = pngle_new(); + OswImage::cbGfx = gfx; + OswImage::cbOffX = x; + OswImage::cbOffY = y; + OswImage::cbAlignX = xAlign; + OswImage::cbAlignY = yAlign; + OswImage::cbScale = scale; + switch(OswImage::cbAlignX) { + case OswImage::Alignment::START: + break; + case OswImage::Alignment::CENTER: + OswImage::cbOffX -= this->width * scale / 2; + break; + case OswImage::Alignment::END: + OswImage::cbOffX -= this->width * scale; + break; + } + switch(OswImage::cbAlignY) { + case OswImage::Alignment::START: + break; + case OswImage::Alignment::CENTER: + OswImage::cbOffY -= this->height * scale / 2; + break; + case OswImage::Alignment::END: + OswImage::cbOffY -= this->height * scale; + break; + } + pngle_set_draw_callback(pngle, OswImage::drawCallback); + if (pngle_feed(pngle, this->data, this->length) < 0) + OSW_LOG_E(pngle_error(pngle)); // Whoopsie! + pngle_destroy(pngle); +} + +void OswImage::drawCallback(pngle_t* pngle, unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned char rgba[4]) { + const unsigned char r = rgba[0]; // 0 - 255 + const unsigned char g = rgba[1]; // 0 - 255 + const unsigned char b = rgba[2]; // 0 - 255 + const unsigned char a = rgba[3]; // 0: fully transparent, 255: fully opaque + const float scale = OswImage::cbScale; + + // We pretty much ignore alpha - and just draw the pixel if it's not transparent + if (a > 0) + OswImage::cbGfx->drawPixel(OswImage::cbOffX + x * scale, OswImage::cbOffY + y * scale, rgb565(r, g, b)); +} \ No newline at end of file diff --git a/src/apps/examples/OswAppExampleV1.cpp b/src/apps/examples/OswAppExampleV1.cpp index 88ce230ce..06487fba2 100644 --- a/src/apps/examples/OswAppExampleV1.cpp +++ b/src/apps/examples/OswAppExampleV1.cpp @@ -3,8 +3,9 @@ #include #include "apps/examples/OswAppExampleV1.h" +#include "assets/img/static/example.png.h" -OswAppExampleV1::OswAppExampleV1() { +OswAppExampleV1::OswAppExampleV1(): image(example_png, example_png_length, example_png_width, example_png_height) { } @@ -22,9 +23,15 @@ void OswAppExampleV1::loop() { red = true; if (hal->btnHasGoneDown(BUTTON_DOWN)) red = false; + if (hal->btnHasGoneDown(BUTTON_SELECT)) + this->showImage = !this->showImage; this->counter = time(nullptr); // update the counter + // Maybe draw a background image... + if(this->showImage) + this->image.draw(hal->gfx(), DISP_W / 2, DISP_H / 2, 0.8, OswImage::Alignment::CENTER, OswImage::Alignment::CENTER); + // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text hal->gfx()->setTextCenterAligned(); if (red) @@ -47,6 +54,9 @@ void OswAppExampleV1::loop() { OswUI::getInstance()->setTextCursor(BUTTON_DOWN); hal->gfx()->print("Normal"); + + OswUI::getInstance()->setTextCursor(BUTTON_SELECT); + hal->gfx()->print("Image"); } void OswAppExampleV1::stop() { diff --git a/src/apps/examples/OswAppExampleV2.cpp b/src/apps/examples/OswAppExampleV2.cpp index 0f69c936e..b2b11ce54 100644 --- a/src/apps/examples/OswAppExampleV2.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -3,10 +3,13 @@ #include #include "apps/examples/OswAppExampleV2.h" +#include "assets/img/static/example.png.h" -OswAppExampleV2::OswAppExampleV2() { +OswAppExampleV2::OswAppExampleV2(): image(example_png, example_png_length, example_png_width, example_png_height) { // This app also "supports" double presses (on BUTTON_SELECT), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) - this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); + this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit + // ...but this will delay the processing of the "image" button - so we will disable it again ;) + this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] ^ OswAppV2::ButtonStateNames::DOUBLE_PRESS); // XOR to toggle the bit } const char* OswAppExampleV2::getAppId() { @@ -36,7 +39,11 @@ void OswAppExampleV2::onDraw() { OswAppV2::onDraw(); // always make sure to call the base class method! this->counter = time(nullptr); // update the counter - // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text + // Maybe draw a background image... + if(this->showImage) + this->image.draw(hal->gfx(), DISP_W / 2, DISP_H / 2, 0.8, OswImage::Alignment::CENTER, OswImage::Alignment::CENTER); + + // As the variable 'red' is changed, this if-conditional adjusts the colour of the 'hello world' text hal->gfx()->setTextCenterAligned(); if (red) hal->gfx()->setTextColor(rgb565(255, 0, 0), OswUI::getInstance()->getBackgroundColor()); @@ -58,6 +65,9 @@ void OswAppExampleV2::onDraw() { OswUI::getInstance()->setTextCursor(BUTTON_DOWN); hal->gfx()->print("Normal"); + + OswUI::getInstance()->setTextCursor(BUTTON_SELECT); + hal->gfx()->print("Image"); } void OswAppExampleV2::onDrawOverlay() { @@ -73,6 +83,7 @@ void OswAppExampleV2::onDrawOverlay() { } void OswAppExampleV2::onButton(int id, bool up, ButtonStateNames state) { + OswAppV2::onButton(id, up, state); // always make sure to call the base class method! if(up and state == ButtonStateNames::SHORT_PRESS) { if(id == Button::BUTTON_UP) { this->red = true; @@ -80,6 +91,9 @@ void OswAppExampleV2::onButton(int id, bool up, ButtonStateNames state) { } else if(id == Button::BUTTON_DOWN) { this->red = false; this->needsRedraw = true; + } else if(id == Button::BUTTON_SELECT) { + this->showImage = !this->showImage; + this->needsRedraw = true; } } } diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 14a1b84af..0b645ff12 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -50,7 +50,7 @@ void OswAppTutorial::onDraw() { unsigned char r, g, b; hsvToRgb(this->hsv, maxVal, maxVal, r, g, b); this->oswIcon.color = rgb565(r, g, b); - this->oswIcon.draw(hal->gfx(), DISP_W / 2, 28, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); + this->oswIcon.draw(hal->gfx(), DISP_W / 2, 28, 3, OswImage::Alignment::CENTER, OswImage::Alignment::START); hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 100); @@ -82,30 +82,30 @@ void OswAppTutorial::onDraw() { hal->gfx()->setTextCursor(80, y); hal->gfx()->print("Short Press"); if(this->gotButtonShort) - checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); else - waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); y += 15; hal->gfx()->setTextCursor(80, y); hal->gfx()->print("Long Press"); if(this->gotButtonLong) - checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); else - waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); y += 15; hal->gfx()->setTextCursor(80, y); hal->gfx()->print("Very Long Press"); if(this->gotButtonVeryLong) - checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); else - waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); y += 15; hal->gfx()->setTextCursor(80, y); hal->gfx()->print("Double Press"); if(this->gotButtonDouble) - checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); else - waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswIcon::Alignment::END, OswIcon::Alignment::CENTER); + waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); } else if(this->screen == 2) { hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); @@ -122,7 +122,7 @@ void OswAppTutorial::onDraw() { hal->gfx()->print("Press any button to continue."); } else if(this->screen == 3) { OswIcon warning = OswIcon(warning_png, warning_png_dimensions, OswUI::getInstance()->getWarningColor()); - warning.draw(hal->gfx(), DISP_W / 2, 28, 3, OswIcon::Alignment::CENTER, OswIcon::Alignment::START); + warning.draw(hal->gfx(), DISP_W / 2, 28, 3, OswImage::Alignment::CENTER, OswImage::Alignment::START); hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 100); From 7552c05155ffdf0979bfbb80b28e911dd7d00f3d Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 00:27:49 +0200 Subject: [PATCH 043/141] Fixed label background-colors --- src/apps/examples/OswAppExampleV1.cpp | 2 +- src/apps/examples/OswAppExampleV2.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/examples/OswAppExampleV1.cpp b/src/apps/examples/OswAppExampleV1.cpp index 06487fba2..1499abb89 100644 --- a/src/apps/examples/OswAppExampleV1.cpp +++ b/src/apps/examples/OswAppExampleV1.cpp @@ -48,7 +48,7 @@ void OswAppExampleV1::loop() { hal->gfx()->print(this->counter - this->start); if(red) // only reset the text color, if the previous text was red - hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); + hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); OswUI::getInstance()->setTextCursor(BUTTON_UP); hal->gfx()->print("Red"); diff --git a/src/apps/examples/OswAppExampleV2.cpp b/src/apps/examples/OswAppExampleV2.cpp index b2b11ce54..4e364a8fa 100644 --- a/src/apps/examples/OswAppExampleV2.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -59,7 +59,7 @@ void OswAppExampleV2::onDraw() { hal->gfx()->print(this->counter - this->start); if(red) // only reset the text color, if the previous text was red - hal->gfx()->setTextColor(rgb565(255, 255, 255), rgb565(0, 0, 0)); + hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); OswUI::getInstance()->setTextCursor(BUTTON_UP); hal->gfx()->print("Red"); From f2a581e74fcb20d156021beffa393811c7463ad9 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 00:52:39 +0200 Subject: [PATCH 044/141] Added deprecation warning --- src/hal/progmem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/progmem.cpp b/src/hal/progmem.cpp index 3f20fbf43..55bf42959 100644 --- a/src/hal/progmem.cpp +++ b/src/hal/progmem.cpp @@ -23,7 +23,7 @@ void drawPngProgmem(pngle_t* pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t } void OswHal::loadPNGfromProgmem(Graphics2D* target, const unsigned char* data, unsigned int length) { - // + OSW_LOG_W("Deprecated method called. Please use OswImage instead."); pngBufferProgmem = target; pngOffsetXProgmem = 0; From 18e99b3f54a9f7337c2bc6b46157eee16999a6e2 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 01:58:08 +0200 Subject: [PATCH 045/141] Added KEEP_DISPLAY_ON flag --- include/OswAppV2.h | 3 ++- include/osw_hal.h | 7 +++++-- src/hal/buttons.cpp | 2 ++ src/hal/power.cpp | 19 +++++++++++++++++++ src/main.cpp | 3 ++- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index f940a0bf1..df7fd7fab 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -9,7 +9,8 @@ class OswAppV2 { public: enum ViewFlags: char { NONE = 0, - NO_OVERLAYS = 1 + NO_OVERLAYS = 1, + KEEP_DISPLAY_ON = 2 }; enum ButtonStateNames: char { UNDEFINED = 0, diff --git a/include/osw_hal.h b/include/osw_hal.h index 193632f95..1f8cbaed7 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -167,6 +167,8 @@ class OswHal { void deepSleep(); void lightSleep(); void handleWakeupFromLightSleep(); + void noteUserInteraction(); + void handleDisplayTimout(); // Power: WakeUpConfigs size_t addWakeUpConfig(const WakeUpConfig& config); @@ -234,8 +236,9 @@ class OswHal { static OswHal* instance; OswTimeProvider* timeProvider = nullptr; - unsigned long _screenOnSince; - unsigned long _screenOffSince; + unsigned long _screenOnSince = 0; + unsigned long _screenOffSince = 0; + unsigned long _lastUserInteraction = 0; // array of available buttons for iteration (e.g. handling) bool _btnLastState[NUM_BUTTONS]; diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 6fee82266..7114c4160 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -50,6 +50,8 @@ void OswHal::checkButtons(void) { // Buttons (Engine) for (uint8_t i = 0; i < NUM_BUTTONS; i++) { _btnIsDown[i] = digitalRead(buttonPins[i]) == buttonClickStates[i]; + if(_btnIsDown[i]) + this->noteUserInteraction(); // Button pressing counts as user interaction } for (uint8_t i = 0; i < NUM_BUTTONS; i++) { diff --git a/src/hal/power.cpp b/src/hal/power.cpp index 56fcb903a..2c48553b0 100644 --- a/src/hal/power.cpp +++ b/src/hal/power.cpp @@ -4,7 +4,9 @@ #include "driver/rtc_io.h" #endif #include "osw_hal.h" +#include "osw_ui.h" #include "osw_pins.h" +#include "OswAppV2.h" #include #include @@ -39,6 +41,7 @@ void OswHal::setupPower(bool fromLightSleep) { config.value().used(); } } + this->noteUserInteraction(); } void OswHal::stopPower() { @@ -280,4 +283,20 @@ std::optional OswHal::readAndResetWakeUpConfig(bool fromLi } this->resetWakeUpConfig(fromLightSleep); return config; +} + +void OswHal::noteUserInteraction() { + this->_lastUserInteraction = millis(); +} + +void OswHal::handleDisplayTimout() { + // Did enough time pass since the last user interaction? + if(OswConfigAllKeys::settingDisplayTimeout.get() == 0 or this->_lastUserInteraction + OswConfigAllKeys::settingDisplayTimeout.get() * 1000 > millis()) + return; + // Does the UI allow us to go to sleep? + OswAppV2* app = OswUI::getInstance()->getRootApplication(); + if(app == nullptr or app->getViewFlags() & OswAppV2::ViewFlags::KEEP_DISPLAY_ON) + return; + this->lightSleep(); + this->noteUserInteraction(); // Oh, we came back from sleep, so we are "interacting" with the watch } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f850e782e..ca6a30238 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,7 +127,7 @@ void setup() { // TODO temporary for testing OswUI::getInstance()->setRootApplication(&exampleAppV2); - //OswUI::getInstance()->setRootApplication(new OswAppV2Compat("org.example.v1", "Example V1", exampleAppV1)); + // OswUI::getInstance()->setRootApplication(new OswAppV2Compat("org.example.v1", "Example V1", exampleAppV1)); tutorialApp.reset(new OswAppTutorial()); if(!tutorialApp->changeRootAppIfNecessary()) tutorialApp.reset(); // no need to keep it around, as it's not the root app @@ -151,6 +151,7 @@ void loop() { #endif try { + OswHal::getInstance()->handleDisplayTimout(); OswHal::getInstance()->handleWakeupFromLightSleep(); OswHal::getInstance()->checkButtons(); OswHal::getInstance()->devices()->update(); From 0a651c414bf5edbece45505d0e42224fefe28b0a Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 01:58:39 +0200 Subject: [PATCH 046/141] Removed display timeout on tutorial/example apps --- src/apps/examples/OswAppExampleV2.cpp | 1 + src/apps/tools/OswAppTutorial.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/apps/examples/OswAppExampleV2.cpp b/src/apps/examples/OswAppExampleV2.cpp index 4e364a8fa..2d6f46db4 100644 --- a/src/apps/examples/OswAppExampleV2.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -25,6 +25,7 @@ void OswAppExampleV2::onStart() { // This is where you initialise code, gets called before this app is shown this->start = time(nullptr); // used as offset for the counter later on + this->viewFlags = (OswAppV2::ViewFlags) (this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); // by default we want to keep the display on } void OswAppExampleV2::onLoop() { diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 0b645ff12..d5da8057c 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -32,6 +32,7 @@ void OswAppTutorial::onStart() { this->screen = 0; this->timeout = time(nullptr); + this->viewFlags = (OswAppV2::ViewFlags) (this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); } void OswAppTutorial::onLoop() { From b2a376901647c6660bed11ab23f40e607c30119b Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 20:47:28 +0200 Subject: [PATCH 047/141] Corrected swapped up/down buttons --- include/osw_pins.h | 18 +++++++++--------- src/hal/buttons.cpp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/osw_pins.h b/include/osw_pins.h index b0ca9741a..329b68c2d 100644 --- a/include/osw_pins.h +++ b/include/osw_pins.h @@ -35,18 +35,18 @@ #if defined(GPS_EDITION) #define BTN_1 0 -#define BTN_2 33 -#define BTN_3 13 +#define BTN_2 13 +#define BTN_3 33 #define VIBRATE 35 #elif defined(GPS_EDITION_ROTATED) #define BTN_1 13 -#define BTN_2 0 -#define BTN_3 33 +#define BTN_2 33 +#define BTN_3 0 #define VIBRATE 35 #else #define BTN_1 0 -#define BTN_2 10 -#define BTN_3 13 +#define BTN_2 13 +#define BTN_3 10 #endif // assign active LOW or HIGH states according to hardware @@ -56,8 +56,8 @@ #define BTN_STATE_ARRAY {LOW, HIGH, HIGH} #endif -// button order is: select, down, up +// button order is: select, up, down #define BTN_POSX_ARRAY {24, 208, 208} -#define BTN_POSY_ARRAY {190, 190, 44} -#define BTN_POS_ISTOP_ARRAY {false, false, true} +#define BTN_POSY_ARRAY {190, 44, 190} +#define BTN_POS_ISTOP_ARRAY {false, true, false} #define BTN_POS_ISLEFT_ARRAY {true, false, false} \ No newline at end of file diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 7114c4160..21f759717 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -4,7 +4,7 @@ #include "osw_hal.h" #include "osw_pins.h" -const char* ButtonNames[NUM_BUTTONS] = {"SELECT", "DOWN", "UP"}; +const char* ButtonNames[NUM_BUTTONS] = {"SELECT", "UP", "DOWN"}; // assign pins to buttons static uint8_t buttonPins[NUM_BUTTONS] = {BTN_1, BTN_2, BTN_3}; // see osw_pins.h From 411f52e54b0e13b1d84f7597a0dde32a1778eba5 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 21:02:42 +0200 Subject: [PATCH 048/141] Implemented ignore-fps-limit for v1 apps --- include/OswAppV2.h | 10 +++++++--- src/OswAppV2.cpp | 8 ++++++++ src/OswAppV2Compat.cpp | 1 + src/osw_ui.cpp | 6 +++--- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index df7fd7fab..54d00b6fa 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -10,7 +10,8 @@ class OswAppV2 { enum ViewFlags: char { NONE = 0, NO_OVERLAYS = 1, - KEEP_DISPLAY_ON = 2 + KEEP_DISPLAY_ON = 2, + NO_FPS_LIMIT = 4 }; enum ButtonStateNames: char { UNDEFINED = 0, @@ -19,9 +20,9 @@ class OswAppV2 { VERY_LONG_PRESS = 4, DOUBLE_PRESS = 8 }; - bool needsRedraw = false; OswAppV2(); + virtual ~OswAppV2() = default; virtual const char* getAppId() = 0; virtual const char* getAppName() = 0; @@ -38,7 +39,9 @@ class OswAppV2 { virtual void onLoopDebug(); // By default no debug loop (GUI) is implemented #endif - ViewFlags getViewFlags(); + virtual ViewFlags getViewFlags(); + virtual bool getNeedsRedraw(); + virtual void resetNeedsRedraw(); protected: class OswHalProxy { public: @@ -49,6 +52,7 @@ class OswAppV2 { OswHalProxy hal; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 std::array knownButtonStates; // Bitmask of known button states (ignores the DOUBLE_PRESS state by default), use this to ignore unhandled button states ViewFlags viewFlags = ViewFlags::NONE; + bool needsRedraw = false; OswIcon& getDefaultAppIcon(); private: diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index cd355c76d..e12538bb0 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -25,6 +25,14 @@ OswAppV2::ViewFlags OswAppV2::getViewFlags() { return this->viewFlags; } +bool OswAppV2::getNeedsRedraw() { + return this->needsRedraw; +} + +void OswAppV2::resetNeedsRedraw() { + this->needsRedraw = false; +} + void OswAppV2::onStart() { this->needsRedraw = true; } diff --git a/src/OswAppV2Compat.cpp b/src/OswAppV2Compat.cpp index 044550ad2..cafa6755e 100644 --- a/src/OswAppV2Compat.cpp +++ b/src/OswAppV2Compat.cpp @@ -13,6 +13,7 @@ const char* OswAppV2Compat::getAppName() { } void OswAppV2Compat::onStart() { + this->viewFlags = (OswAppV2::ViewFlags)(this->viewFlags | OswAppV2::ViewFlags::NO_FPS_LIMIT); // this causes draw() to be called upon every loop() call -> preventing the loss of input events (like the button just went down) this->app.setup(); } diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index c794f0995..5fc7adbb4 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -125,8 +125,8 @@ void OswUI::loop() { #endif // Lock UI for drawing - if(rootApp->needsRedraw) { - if(this->mEnableTargetFPS and (millis() - lastFlush) < (1000 / this->mTargetFPS)) + if(rootApp->getNeedsRedraw() or (rootApp->getViewFlags() & OswAppV2::ViewFlags::NO_FPS_LIMIT)) { + if(not (rootApp->getViewFlags() & OswAppV2::ViewFlags::NO_FPS_LIMIT) and this->mEnableTargetFPS and (millis() - lastFlush) < (1000 / this->mTargetFPS)) return; // Early abort if we would draw too fast std::lock_guard guard(*this->drawLock); // Make sure to not modify the notifications vector during drawing @@ -176,7 +176,7 @@ void OswUI::loop() { // Handle display flushing OswHal::getInstance()->flushCanvas(); lastFlush = millis(); - rootApp->needsRedraw = false; + rootApp->resetNeedsRedraw(); } } From f27d2a3c7252ca0445922e8568b2e403af1151f8 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 23:34:02 +0200 Subject: [PATCH 049/141] Cross-sync button detection state across apps --- include/OswAppV2.h | 9 +++++---- src/OswAppV2.cpp | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index 54d00b6fa..056eb102b 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -57,8 +57,9 @@ class OswAppV2 { private: static OswIcon defaultAppIcon; - std::array buttonDownSince = {0}; - std::array buttonLastSentState = {ButtonStateNames::UNDEFINED}; - std::array buttonDoubleShortTimeout = {0}; - std::array buttonIndicatorProgress = {0}; + // the button states-variables (↓) are shared between all apps, so they do not detect presses, which were already handled by another app (which may wrapped them) + static std::array buttonDownSince; + static std::array buttonLastSentState; + static std::array buttonDoubleShortTimeout; + static std::array buttonIndicatorProgress; }; \ No newline at end of file diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index e12538bb0..62ca7bd1f 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -5,6 +5,10 @@ #include "assets/img/icons/app.png.h" OswIcon OswAppV2::defaultAppIcon = OswIcon(app_png, app_png_dimensions, 0x0); // Color will be set upon retreival +std::array OswAppV2::buttonDownSince = {0}; +std::array OswAppV2::buttonLastSentState = {ButtonStateNames::UNDEFINED}; +std::array OswAppV2::buttonDoubleShortTimeout = {0}; +std::array OswAppV2::buttonIndicatorProgress = {0}; OswAppV2::OswAppV2() { for(int i = 0; i < NUM_BUTTONS; i++) From 81ce87e5364162c426963b962474417822e1e26c Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 23:34:50 +0200 Subject: [PATCH 050/141] Exposed base size for icons --- include/OswIcon.h | 1 + src/OswIcon.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/OswIcon.h b/include/OswIcon.h index b7bbb20ec..f9b3f0cda 100644 --- a/include/OswIcon.h +++ b/include/OswIcon.h @@ -7,6 +7,7 @@ class OswIcon { public: + static const unsigned int baseDimensions = 16; uint16_t color; OswIcon(const unsigned char* data, const unsigned char dimension, uint16_t color); diff --git a/src/OswIcon.cpp b/src/OswIcon.cpp index 0f6a4b705..3d9216f64 100644 --- a/src/OswIcon.cpp +++ b/src/OswIcon.cpp @@ -8,7 +8,7 @@ OswIcon::OswIcon(const unsigned char* data, const unsigned char dimension, uint1 void OswIcon::draw(Graphics2D* gfx, int x, int y, float scale, OswImage::Alignment xAlign, OswImage::Alignment yAlign) { // modify x and y based on alignment - scale *= (float) 16 / this->dimension; // treat all icons as a 16x16 grid + scale *= (float) this->baseDimensions / this->dimension; // treat all icons as a 16x16 grid switch(xAlign) { case OswImage::Alignment::START: break; From e6118c678297a83649e9ba8c1fdc3f2b167f3e0d Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 23:35:27 +0200 Subject: [PATCH 051/141] Simplified & synced colors for example apps --- src/apps/examples/OswAppExampleV1.cpp | 6 +++--- src/apps/examples/OswAppExampleV2.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/apps/examples/OswAppExampleV1.cpp b/src/apps/examples/OswAppExampleV1.cpp index 1499abb89..01d70903c 100644 --- a/src/apps/examples/OswAppExampleV1.cpp +++ b/src/apps/examples/OswAppExampleV1.cpp @@ -35,9 +35,9 @@ void OswAppExampleV1::loop() { // As the variable 'red' is changed, this if loop adjusts the colour of the 'hello world' text hal->gfx()->setTextCenterAligned(); if (red) - hal->gfx()->setTextColor(rgb565(255, 0, 0), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->setTextColor(rgb565(255, 0, 0)); // this is how you can set a custom color else - hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->setTextColor(OswUI::getInstance()->getForegroundColor()); // this is how you can use the "theme" color hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2); @@ -48,7 +48,7 @@ void OswAppExampleV1::loop() { hal->gfx()->print(this->counter - this->start); if(red) // only reset the text color, if the previous text was red - hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->setTextColor(OswUI::getInstance()->getForegroundColor()); OswUI::getInstance()->setTextCursor(BUTTON_UP); hal->gfx()->print("Red"); diff --git a/src/apps/examples/OswAppExampleV2.cpp b/src/apps/examples/OswAppExampleV2.cpp index 2d6f46db4..561df1f27 100644 --- a/src/apps/examples/OswAppExampleV2.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -13,11 +13,11 @@ OswAppExampleV2::OswAppExampleV2(): image(example_png, example_png_length, examp } const char* OswAppExampleV2::getAppId() { - return "osw.example"; + return "osw.example.v2"; } const char* OswAppExampleV2::getAppName() { - return "Example App"; + return "Example App v2"; } void OswAppExampleV2::onStart() { @@ -47,9 +47,9 @@ void OswAppExampleV2::onDraw() { // As the variable 'red' is changed, this if-conditional adjusts the colour of the 'hello world' text hal->gfx()->setTextCenterAligned(); if (red) - hal->gfx()->setTextColor(rgb565(255, 0, 0), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->setTextColor(rgb565(255, 0, 0)); // this is how you can set a custom color else - hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->setTextColor(OswUI::getInstance()->getForegroundColor()); // this is how you can use the "theme" color hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2); @@ -60,7 +60,7 @@ void OswAppExampleV2::onDraw() { hal->gfx()->print(this->counter - this->start); if(red) // only reset the text color, if the previous text was red - hal->gfx()->setTextColor(rgb565(255, 255, 255), OswUI::getInstance()->getBackgroundColor()); + hal->gfx()->setTextColor(OswUI::getInstance()->getForegroundColor()); OswUI::getInstance()->setTextCursor(BUTTON_UP); hal->gfx()->print("Red"); From 488a6e6a5ef49c1c35efc15e389bee770e3f9cc1 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 23:47:41 +0200 Subject: [PATCH 052/141] Implemented osw app drawer --- include/OswAppDrawer.h | 84 +++++++++++++++ src/OswAppDrawer.cpp | 225 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 309 insertions(+) create mode 100644 include/OswAppDrawer.h create mode 100644 src/OswAppDrawer.cpp diff --git a/include/OswAppDrawer.h b/include/OswAppDrawer.h new file mode 100644 index 000000000..66b07a162 --- /dev/null +++ b/include/OswAppDrawer.h @@ -0,0 +1,84 @@ +#pragma once +#include +#include + +#include +#include + +class OswAppDrawer: public OswAppV2 { + public: + OswAppDrawer(const char* defaultCategory, size_t defaultAppIndex); + + const char* getAppId() override; + const char* getAppName() override; + + void onStart() override; + void onLoop() override; + void onDraw() override; + void onDrawOverlay() override; + void onStop() override; + + void onButton(int id, bool up, ButtonStateNames state) override; +#ifdef OSW_EMULATOR + void onLoopDebug() override; +#endif + + ViewFlags getViewFlags() override; + bool getNeedsRedraw() override; + void resetNeedsRedraw() override; + + void registerApp(const char* category, OswAppV2* app); + template + void registerAppLazy(const char* category) { + if(!this->apps.count(category)) + this->apps.insert({category, {}}); + this->apps.at(category).push_back({nullptr}); + this->apps.at(category).back().set(); + }; + private: + class LazyInit { + public: + LazyInit(OswAppV2* given) { + this->ptr = given; + }; + + template + void set() { + this->init = []() -> OswAppV2* { + return new T(); + }; + } + + OswAppV2* operator->() { + if(this->ptr == nullptr) + this->ptr = this->init(); + return this->ptr; + } + + void cleanup() { + if(this->init != nullptr) { + delete this->ptr; + this->ptr = nullptr; + } + } + + virtual ~LazyInit() { + this->cleanup(); + } + private: + OswAppV2* (*init)() = nullptr; + OswAppV2* ptr = nullptr; + }; + static bool minimizeButtonLabels; // if you know one drawer, you know them all ;) + std::map> apps; + LazyInit* current = nullptr; + const char* defaultCategory; + const size_t defaultAppIndex; + bool showDrawer = false; + size_t highlightCategoryIndex = 0; + size_t highlightAppIndex = 0; + size_t categoryIndexOffset = 0; + LazyInit* highlightApp = nullptr; + + LazyInit& getCurrent(); +}; \ No newline at end of file diff --git a/src/OswAppDrawer.cpp b/src/OswAppDrawer.cpp new file mode 100644 index 000000000..fe9337c48 --- /dev/null +++ b/src/OswAppDrawer.cpp @@ -0,0 +1,225 @@ +#include + +#include + +bool OswAppDrawer::minimizeButtonLabels = false; + +OswAppDrawer::OswAppDrawer(const char* defaultCategory, size_t defaultAppIndex): defaultCategory(defaultCategory), defaultAppIndex(defaultAppIndex) { + // nothing to do here +} + +const char* OswAppDrawer::getAppId() { + return "osw.drawer"; +} + +const char* OswAppDrawer::getAppName() { + return "OSW Drawer"; +} + +void OswAppDrawer::registerApp(const char* category, OswAppV2* app) { + if(!this->apps.count(category)) // if the category does not exist yet, create it + this->apps.insert({category, {}}); + this->apps.at(category).push_back({app}); +} + +OswAppDrawer::LazyInit& OswAppDrawer::getCurrent() { + if(this->current == nullptr) { + // If the current app is not set, we search and set the default app + if(!this->apps.count(this->defaultCategory)) + throw std::runtime_error("Invalid default category"); + auto& categoryList = this->apps.at(this->defaultCategory); + if(categoryList.size() <= this->defaultAppIndex) + throw std::runtime_error("Invalid default app index"); + auto it = categoryList.begin(); + std::advance(it, this->defaultAppIndex); + this->current = &*it; + } + return *this->current; +} + +void OswAppDrawer::onStart() { + OswAppV2::onStart(); + if(this->showDrawer) + this->viewFlags = (OswAppV2::ViewFlags)(this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); // in the drawer, we want to keep the display on + else + this->getCurrent()->onStart(); +} + +void OswAppDrawer::onLoop() { + OswAppV2::onLoop(); + if(!this->showDrawer) + this->getCurrent()->onLoop(); // if we are not in the drawer, we want to call the current app's onLoop +} + +void OswAppDrawer::onDraw() { + OswAppV2::onDraw(); + if(this->showDrawer) { + this->hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2); + + // some constants for the drawer layout + const int categoryHeightStart = 48; + const int categoryHeightPadding = 8; // used for the category texts and their horizontal divider lines + const int categoryWidthStart = 40; + const int categoryWidth = DISP_W - 2 * categoryWidthStart; + const int horizontalAppCount = 3; + const int categoryCount = 3; + const int horizontalAppSize = (categoryWidth - horizontalAppCount * categoryHeightPadding) / horizontalAppCount; + + // handle (over-)scrolling + if(this->highlightCategoryIndex > (categoryCount - 1)) { + // if we scrolled over the display end -> advance the offset + --this->highlightCategoryIndex; + ++this->categoryIndexOffset; + } + if(this->categoryIndexOffset + this->highlightCategoryIndex >= this->apps.size()) { + // if we scrolled over the end -> reset to the beginning + this->highlightCategoryIndex = 0; + this->categoryIndexOffset = 0; + } + + // now draw all the categories + char const* selectedAppName = nullptr; + size_t categoryIndex = 0; + auto categoryIterator = this->apps.begin(); + std::advance(categoryIterator, this->categoryIndexOffset); + for(; categoryIterator != this->apps.end(); categoryIterator++) { + auto& categoryName = categoryIterator->first; + auto& categoryApps = categoryIterator->second; + const int currentCategoryHeightStart = categoryHeightStart + (horizontalAppSize + categoryHeightPadding) * categoryIndex; + // draw the category name + this->hal->gfx()->setTextCursor(categoryWidthStart, currentCategoryHeightStart); + this->hal->gfx()->setTextColor(OswUI::getInstance()->getForegroundColor()); + this->hal->gfx()->print(categoryName); + // calc the app page + if(categoryIndex == this->highlightCategoryIndex and this->highlightAppIndex > categoryApps.size() - 1) + this->highlightAppIndex = 0; + const size_t categoryAppPage = (categoryIndex == this->highlightCategoryIndex) ? this->highlightAppIndex / horizontalAppCount : 0; + // if needed, print the page number (and maximum) + if(categoryApps.size() > horizontalAppCount) { + this->hal->gfx()->print(" "); + this->hal->gfx()->print(String(categoryAppPage + 1)); + this->hal->gfx()->print("/"); + this->hal->gfx()->print(String((int) std::ceil((float) categoryApps.size() / horizontalAppCount))); + } + // draw the horizontal divider line - starting at the end of the category name (and potential page number) + this->hal->gfx()->drawHLine(this->hal->gfx()->getTextCursorX(), currentCategoryHeightStart - 3, categoryWidth - (this->hal->gfx()->getTextCursorX() - categoryWidthStart), OswUI::getInstance()->getForegroundDimmedColor()); + // draw the apps + size_t categoryAppIndex = 0; + auto appIterator = categoryApps.begin(); + std::advance(appIterator, categoryAppPage * horizontalAppCount); + for(; appIterator != categoryApps.end(); appIterator++) { + auto& app = *appIterator; + const int currentCategoryWidth = categoryWidthStart + (horizontalAppSize + categoryHeightPadding) * categoryAppIndex; + // draw a frame about the selected app (and store refs to the app and its name) + if(categoryAppIndex == (this->highlightAppIndex % horizontalAppCount) and categoryIndex == this->highlightCategoryIndex) { + this->hal->gfx()->drawFrame(currentCategoryWidth, currentCategoryHeightStart, horizontalAppSize, horizontalAppSize, OswUI::getInstance()->getInfoColor()); + selectedAppName = app->getAppName(); + highlightApp = &app; + } + // draw the app icon + const float iconScale = horizontalAppSize / app->getAppIcon().baseDimensions; + app->getAppIcon().draw(this->hal->gfx(), currentCategoryWidth + horizontalAppSize / 2, currentCategoryHeightStart + horizontalAppSize / 2, iconScale, OswImage::Alignment::CENTER, OswImage::Alignment::CENTER); + ++categoryAppIndex; + if(categoryAppIndex > (horizontalAppCount - 1)) + break; + } + ++categoryIndex; + if(categoryIndex > (categoryCount - 1)) + break; + } + + // draw the selected app name + if(selectedAppName) { + this->hal->gfx()->setTextCursor(DISP_W / 2, DISP_H - 16); + this->hal->gfx()->setTextCenterAligned(); + this->hal->gfx()->print(selectedAppName); + } + + // draw the button labels + if(!this->minimizeButtonLabels) { + OswUI::getInstance()->setTextCursor(Button::BUTTON_UP); + this->hal->gfx()->print("Category"); + + OswUI::getInstance()->setTextCursor(Button::BUTTON_DOWN); + this->hal->gfx()->print("App"); + + OswUI::getInstance()->setTextCursor(Button::BUTTON_SELECT); + } else { + OswUI::getInstance()->setTextCursor(Button::BUTTON_SELECT); + this->hal->gfx()->setTextSize(1); + } + this->hal->gfx()->print("OK"); + } else + this->getCurrent()->onDraw(); +} + +void OswAppDrawer::onDrawOverlay() { + if(!this->showDrawer) + this->getCurrent()->onDrawOverlay(); // forward to the current app + OswAppV2::onDrawOverlay(); +} + +void OswAppDrawer::onStop() { + OswAppV2::onStop(); + if(!this->showDrawer) + this->getCurrent()->onStop(); // forward to the current app +} + +void OswAppDrawer::onButton(int id, bool up, ButtonStateNames state) { + OswAppV2::onButton(id, up, state); + if(this->showDrawer) { + if(up and state == OswAppV2::ButtonStateNames::SHORT_PRESS) { + if(id == Button::BUTTON_UP) { + this->highlightCategoryIndex = (this->highlightCategoryIndex + 1) % this->apps.size(); + this->needsRedraw = true; + } else if(id == Button::BUTTON_DOWN) { + ++this->highlightAppIndex; + this->needsRedraw = true; + } else if(id == Button::BUTTON_SELECT) { + this->onStop(); + this->showDrawer = false; + this->current = highlightApp; + this->getCurrent()->onStart(); + this->needsRedraw = true; + } + } + this->minimizeButtonLabels = true; // any button press will minimize the button labels + } else { + if(up == true and id == Button::BUTTON_SELECT and state == OswAppV2::ButtonStateNames::LONG_PRESS) { + this->showDrawer = true; + this->getCurrent()->onStop(); + this->current = nullptr; + this->onStart(); // "start" the drawer app + } else + this->getCurrent()->onButton(id, up, state); + } +} + +#ifdef OSW_EMULATOR +void OswAppDrawer::onLoopDebug() { + OswAppV2::onLoopDebug(); + if(!this->showDrawer) + this->getCurrent()->onLoopDebug(); // forward to the current app +} +#endif + +OswAppV2::ViewFlags OswAppDrawer::getViewFlags() { + if(this->showDrawer) + return OswAppV2::getViewFlags(); + else + return this->getCurrent()->getViewFlags(); // forward to the current app +} + +bool OswAppDrawer::getNeedsRedraw() { + if(this->showDrawer) + return OswAppV2::getNeedsRedraw(); + else + return OswAppV2::getNeedsRedraw() or this->getCurrent()->getNeedsRedraw(); // still respect the redraw of the drawers overlays +} + +void OswAppDrawer::resetNeedsRedraw() { + if(this->showDrawer) + OswAppV2::resetNeedsRedraw(); + else + this->getCurrent()->resetNeedsRedraw(); // forward to the current app +} \ No newline at end of file From ae8fafcf63582d901f8c215de42b30941b16226d Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 23:54:29 +0200 Subject: [PATCH 053/141] Optional drawer defaults --- include/OswAppDrawer.h | 2 +- src/OswAppDrawer.cpp | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/OswAppDrawer.h b/include/OswAppDrawer.h index 66b07a162..5b987469c 100644 --- a/include/OswAppDrawer.h +++ b/include/OswAppDrawer.h @@ -7,7 +7,7 @@ class OswAppDrawer: public OswAppV2 { public: - OswAppDrawer(const char* defaultCategory, size_t defaultAppIndex); + OswAppDrawer(const char* defaultCategory = nullptr, size_t defaultAppIndex = 0); const char* getAppId() override; const char* getAppName() override; diff --git a/src/OswAppDrawer.cpp b/src/OswAppDrawer.cpp index fe9337c48..e6e3f54d7 100644 --- a/src/OswAppDrawer.cpp +++ b/src/OswAppDrawer.cpp @@ -25,12 +25,18 @@ void OswAppDrawer::registerApp(const char* category, OswAppV2* app) { OswAppDrawer::LazyInit& OswAppDrawer::getCurrent() { if(this->current == nullptr) { // If the current app is not set, we search and set the default app - if(!this->apps.count(this->defaultCategory)) - throw std::runtime_error("Invalid default category"); - auto& categoryList = this->apps.at(this->defaultCategory); - if(categoryList.size() <= this->defaultAppIndex) + std::list* categoryList; + if(this->defaultCategory) { + if(!this->apps.count(this->defaultCategory)) + throw std::runtime_error("Invalid default category"); + categoryList = &this->apps.at(this->defaultCategory); + } else { + // well, guess we have to take the first category then + categoryList = &this->apps.begin()->second; + } + if(categoryList->size() <= this->defaultAppIndex) throw std::runtime_error("Invalid default app index"); - auto it = categoryList.begin(); + auto it = categoryList->begin(); std::advance(it, this->defaultAppIndex); this->current = &*it; } From 0c8d44478b656dd9ca33872e99930414e0433f24 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Wed, 29 Mar 2023 23:54:52 +0200 Subject: [PATCH 054/141] Updated main for drawer --- src/main.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ca6a30238..0d0c448d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ // #include "./apps/_experiments/runtime_test.h" #include "OswAppV2Compat.h" +#include "OswAppDrawer.h" #include "apps/examples/OswAppExampleV1.h" #include "apps/examples/OswAppExampleV2.h" #include "apps/tools/OswAppTutorial.h" @@ -94,6 +95,7 @@ OswAppSwitcher settingsAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_se // TODO temporary for testing static OswAppExampleV1 exampleAppV1; static OswAppExampleV2 exampleAppV2; +static OswAppDrawer mainDrawer; std::unique_ptr tutorialApp; void setup() { @@ -126,8 +128,9 @@ void setup() { mainAppSwitcher.setup(); // TODO temporary for testing - OswUI::getInstance()->setRootApplication(&exampleAppV2); - // OswUI::getInstance()->setRootApplication(new OswAppV2Compat("org.example.v1", "Example V1", exampleAppV1)); + mainDrawer.registerAppLazy("OswAppV2"); + mainDrawer.registerApp("OswAppV1", new OswAppV2Compat("org.example.v1", "Example App v1", exampleAppV1)); + OswUI::getInstance()->setRootApplication(&mainDrawer); tutorialApp.reset(new OswAppTutorial()); if(!tutorialApp->changeRootAppIfNecessary()) tutorialApp.reset(); // no need to keep it around, as it's not the root app From 8980a20df74329ecd0f1bc8bb9ab7d69b129be0c Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 30 Mar 2023 00:09:01 +0200 Subject: [PATCH 055/141] Implemented app instance cleanup Fixed stuck redraw-request, causing high (useless) framerates --- include/OswAppDrawer.h | 9 +++++++++ src/OswAppDrawer.cpp | 20 +++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/OswAppDrawer.h b/include/OswAppDrawer.h index 5b987469c..08362da8e 100644 --- a/include/OswAppDrawer.h +++ b/include/OswAppDrawer.h @@ -55,6 +55,14 @@ class OswAppDrawer: public OswAppV2 { return this->ptr; } + bool operator==(const LazyInit& other) const { + return this->init == other.init or this->ptr == other.ptr; + } + + bool operator!=(const LazyInit& other) const { + return not (*this == other); + } + void cleanup() { if(this->init != nullptr) { delete this->ptr; @@ -81,4 +89,5 @@ class OswAppDrawer: public OswAppV2 { LazyInit* highlightApp = nullptr; LazyInit& getCurrent(); + void cleanup(); }; \ No newline at end of file diff --git a/src/OswAppDrawer.cpp b/src/OswAppDrawer.cpp index e6e3f54d7..b65e14194 100644 --- a/src/OswAppDrawer.cpp +++ b/src/OswAppDrawer.cpp @@ -187,6 +187,7 @@ void OswAppDrawer::onButton(int id, bool up, ButtonStateNames state) { this->current = highlightApp; this->getCurrent()->onStart(); this->needsRedraw = true; + this->cleanup(); } } this->minimizeButtonLabels = true; // any button press will minimize the button labels @@ -224,8 +225,21 @@ bool OswAppDrawer::getNeedsRedraw() { } void OswAppDrawer::resetNeedsRedraw() { - if(this->showDrawer) - OswAppV2::resetNeedsRedraw(); - else + OswAppV2::resetNeedsRedraw(); + if(!this->showDrawer) this->getCurrent()->resetNeedsRedraw(); // forward to the current app +} + +/** + * @brief This destorys all cached app instances, leaving only the current app running. + * + */ +void OswAppDrawer::cleanup() { + for(auto categoryIterator = this->apps.begin(); categoryIterator != this->apps.end(); categoryIterator++) { + for(auto appIterator = categoryIterator->second.begin(); appIterator != categoryIterator->second.end(); appIterator++) { + if(*appIterator != *this->current) { + appIterator->cleanup(); + } + } + } } \ No newline at end of file From 7230fbf534e72e75f2b96fc2bc73a4388638ca3c Mon Sep 17 00:00:00 2001 From: simonmicro Date: Thu, 30 Mar 2023 00:52:29 +0200 Subject: [PATCH 056/141] Put presses together --- src/apps/tools/OswAppTutorial.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index d5da8057c..70d69d4c6 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -88,22 +88,22 @@ void OswAppTutorial::onDraw() { waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); y += 15; hal->gfx()->setTextCursor(80, y); - hal->gfx()->print("Long Press"); - if(this->gotButtonLong) + hal->gfx()->print("Double Press"); + if(this->gotButtonDouble) checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); else waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); y += 15; hal->gfx()->setTextCursor(80, y); - hal->gfx()->print("Very Long Press"); - if(this->gotButtonVeryLong) + hal->gfx()->print("Long Press"); + if(this->gotButtonLong) checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); else waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); y += 15; hal->gfx()->setTextCursor(80, y); - hal->gfx()->print("Double Press"); - if(this->gotButtonDouble) + hal->gfx()->print("Very Long Press"); + if(this->gotButtonVeryLong) checked.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); else waiting.draw(hal->gfx(), 80 - 5, y - 3, 1, OswImage::Alignment::END, OswImage::Alignment::CENTER); From 9ed574d5b346df7946165344f77ffb244c7ad978 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 15:00:01 +0200 Subject: [PATCH 057/141] Implemented sleep-persistant indices --- include/OswAppDrawer.h | 5 ++- src/OswAppDrawer.cpp | 71 +++++++++++++++++++++++++++++++++--------- src/main.cpp | 4 ++- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/include/OswAppDrawer.h b/include/OswAppDrawer.h index 08362da8e..01558466b 100644 --- a/include/OswAppDrawer.h +++ b/include/OswAppDrawer.h @@ -7,7 +7,9 @@ class OswAppDrawer: public OswAppV2 { public: - OswAppDrawer(const char* defaultCategory = nullptr, size_t defaultAppIndex = 0); + static const size_t UNDEFINED_SLEEP_APP_INDEX = (size_t) -1; // just use a very large number + + OswAppDrawer(const char* defaultCategory = nullptr, size_t defaultAppIndex = 0, size_t* sleepPersistantAppIndex = nullptr); const char* getAppId() override; const char* getAppName() override; @@ -87,6 +89,7 @@ class OswAppDrawer: public OswAppV2 { size_t highlightAppIndex = 0; size_t categoryIndexOffset = 0; LazyInit* highlightApp = nullptr; + size_t* sleepPersistantAppIndex; LazyInit& getCurrent(); void cleanup(); diff --git a/src/OswAppDrawer.cpp b/src/OswAppDrawer.cpp index b65e14194..9e50768a7 100644 --- a/src/OswAppDrawer.cpp +++ b/src/OswAppDrawer.cpp @@ -4,7 +4,7 @@ bool OswAppDrawer::minimizeButtonLabels = false; -OswAppDrawer::OswAppDrawer(const char* defaultCategory, size_t defaultAppIndex): defaultCategory(defaultCategory), defaultAppIndex(defaultAppIndex) { +OswAppDrawer::OswAppDrawer(const char* defaultCategory, size_t defaultAppIndex, size_t* sleepPersistantAppIndex): defaultCategory(defaultCategory), defaultAppIndex(defaultAppIndex), sleepPersistantAppIndex(sleepPersistantAppIndex) { // nothing to do here } @@ -24,22 +24,45 @@ void OswAppDrawer::registerApp(const char* category, OswAppV2* app) { OswAppDrawer::LazyInit& OswAppDrawer::getCurrent() { if(this->current == nullptr) { - // If the current app is not set, we search and set the default app - std::list* categoryList; - if(this->defaultCategory) { - if(!this->apps.count(this->defaultCategory)) - throw std::runtime_error("Invalid default category"); - categoryList = &this->apps.at(this->defaultCategory); - } else { - // well, guess we have to take the first category then - categoryList = &this->apps.begin()->second; + // If the current app is not set, try to find it... + if(this->sleepPersistantAppIndex != nullptr and *this->sleepPersistantAppIndex != UNDEFINED_SLEEP_APP_INDEX) { + // Using the sleep-persistant app index, we are maybe able to recover the last app + size_t categoryIndex = 0; + for(auto& category: this->apps) { + for(auto& app: category.second) { + if(categoryIndex == *this->sleepPersistantAppIndex) { + this->current = &app; + OSW_LOG_D("Selected app based on sleep persistant app index: ", *this->sleepPersistantAppIndex); + break; + } + ++categoryIndex; + } + if(this->current != nullptr) + break; + } + } + + // Either the previous step failed, or we did not have a sleep-persistant app index + if(this->current == nullptr) { + // Maybe a default category / index was set? + if(this->defaultCategory) { + if(!this->apps.count(this->defaultCategory)) + throw std::runtime_error("Invalid default category"); + auto& categoryList = this->apps.at(this->defaultCategory); + if(categoryList.size() <= this->defaultAppIndex) + throw std::runtime_error("Invalid default app index"); + auto it = categoryList.begin(); + std::advance(it, this->defaultAppIndex); + this->current = &*it; + OSW_LOG_D("Selected app based on default category and index: \"", this->defaultCategory, "\", ", this->defaultAppIndex); + } else { + // Well, guess we have to take the "first" then + this->current = &this->apps.begin()->second.front(); + OSW_LOG_D("Selected app based who came first..."); + } } - if(categoryList->size() <= this->defaultAppIndex) - throw std::runtime_error("Invalid default app index"); - auto it = categoryList->begin(); - std::advance(it, this->defaultAppIndex); - this->current = &*it; } + assert(this->current != nullptr && "Drawer failed to determine current app (this should never happen) - or is the drawer empty?"); return *this->current; } @@ -188,6 +211,24 @@ void OswAppDrawer::onButton(int id, bool up, ButtonStateNames state) { this->getCurrent()->onStart(); this->needsRedraw = true; this->cleanup(); + // store the selected app "index" persistently, if variable was set + if(this->sleepPersistantAppIndex != nullptr) { + size_t index = 0; + for(auto& category : this->apps) { + bool found = false; + for(auto& app : category.second) { + if(&app == this->current) { + *this->sleepPersistantAppIndex = index; + found = true; + OSW_LOG_D("Stored sleep-persistant app index: ", index); + break; + } + ++index; + } + if(found) + break; + } + } } } this->minimizeButtonLabels = true; // any button press will minimize the button labels diff --git a/src/main.cpp b/src/main.cpp index 0d0c448d1..ae5597464 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,7 +95,9 @@ OswAppSwitcher settingsAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_se // TODO temporary for testing static OswAppExampleV1 exampleAppV1; static OswAppExampleV2 exampleAppV2; -static OswAppDrawer mainDrawer; + +RTC_DATA_ATTR size_t tempIndexSleepy = OswAppDrawer::UNDEFINED_SLEEP_APP_INDEX; +static OswAppDrawer mainDrawer{nullptr, 0, &tempIndexSleepy}; std::unique_ptr tutorialApp; void setup() { From f3de49f7f432276a246ed4516504de99eba612f5 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 16:43:21 +0200 Subject: [PATCH 058/141] Fixed copy-ref crash Moved app hand-off/drawer-open into functions Moved knownButtonStates into start() --- include/OswAppDrawer.h | 14 +- include/OswAppV2.h | 10 +- src/OswAppDrawer.cpp | 226 ++++++++++++++------------ src/OswAppV2.cpp | 16 +- src/apps/examples/OswAppExampleV2.cpp | 12 +- 5 files changed, 148 insertions(+), 130 deletions(-) diff --git a/include/OswAppDrawer.h b/include/OswAppDrawer.h index 01558466b..b417924f2 100644 --- a/include/OswAppDrawer.h +++ b/include/OswAppDrawer.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include @@ -25,7 +26,7 @@ class OswAppDrawer: public OswAppV2 { void onLoopDebug() override; #endif - ViewFlags getViewFlags() override; + const ViewFlags& getViewFlags() override; bool getNeedsRedraw() override; void resetNeedsRedraw() override; @@ -33,8 +34,8 @@ class OswAppDrawer: public OswAppV2 { template void registerAppLazy(const char* category) { if(!this->apps.count(category)) - this->apps.insert({category, {}}); - this->apps.at(category).push_back({nullptr}); + this->apps.emplace(std::make_pair(category, std::move(std::list()))); + this->apps.at(category).emplace_back(nullptr); this->apps.at(category).back().set(); }; private: @@ -43,6 +44,7 @@ class OswAppDrawer: public OswAppV2 { LazyInit(OswAppV2* given) { this->ptr = given; }; + LazyInit(LazyInit& other) = delete; // prevent copying, which may causes issues with the cleanup template void set() { @@ -51,7 +53,7 @@ class OswAppDrawer: public OswAppV2 { }; } - OswAppV2* operator->() { + OswAppV2* get() { if(this->ptr == nullptr) this->ptr = this->init(); return this->ptr; @@ -84,13 +86,13 @@ class OswAppDrawer: public OswAppV2 { LazyInit* current = nullptr; const char* defaultCategory; const size_t defaultAppIndex; - bool showDrawer = false; size_t highlightCategoryIndex = 0; size_t highlightAppIndex = 0; size_t categoryIndexOffset = 0; LazyInit* highlightApp = nullptr; size_t* sleepPersistantAppIndex; - LazyInit& getCurrent(); void cleanup(); + void drawer(); + void open(LazyInit& app); }; \ No newline at end of file diff --git a/include/OswAppV2.h b/include/OswAppV2.h index 056eb102b..7be359bd0 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -39,7 +39,7 @@ class OswAppV2 { virtual void onLoopDebug(); // By default no debug loop (GUI) is implemented #endif - virtual ViewFlags getViewFlags(); + virtual const ViewFlags& getViewFlags(); virtual bool getNeedsRedraw(); virtual void resetNeedsRedraw(); protected: @@ -54,12 +54,14 @@ class OswAppV2 { ViewFlags viewFlags = ViewFlags::NONE; bool needsRedraw = false; OswIcon& getDefaultAppIcon(); + void clearKnownButtonStates(); private: static OswIcon defaultAppIcon; // the button states-variables (↓) are shared between all apps, so they do not detect presses, which were already handled by another app (which may wrapped them) static std::array buttonDownSince; - static std::array buttonLastSentState; - static std::array buttonDoubleShortTimeout; - static std::array buttonIndicatorProgress; + // these button states-variables (↓) are app-specific, so they can't be shared + std::array buttonLastSentState = {ButtonStateNames::UNDEFINED}; + std::array buttonDoubleShortTimeout = {0}; + std::array buttonIndicatorProgress = {0}; }; \ No newline at end of file diff --git a/src/OswAppDrawer.cpp b/src/OswAppDrawer.cpp index 9e50768a7..7026e659c 100644 --- a/src/OswAppDrawer.cpp +++ b/src/OswAppDrawer.cpp @@ -18,71 +18,66 @@ const char* OswAppDrawer::getAppName() { void OswAppDrawer::registerApp(const char* category, OswAppV2* app) { if(!this->apps.count(category)) // if the category does not exist yet, create it - this->apps.insert({category, {}}); - this->apps.at(category).push_back({app}); + this->apps.emplace(std::make_pair(category, std::move(std::list()))); + this->apps.at(category).emplace_back(app); } -OswAppDrawer::LazyInit& OswAppDrawer::getCurrent() { - if(this->current == nullptr) { - // If the current app is not set, try to find it... - if(this->sleepPersistantAppIndex != nullptr and *this->sleepPersistantAppIndex != UNDEFINED_SLEEP_APP_INDEX) { - // Using the sleep-persistant app index, we are maybe able to recover the last app - size_t categoryIndex = 0; - for(auto& category: this->apps) { - for(auto& app: category.second) { - if(categoryIndex == *this->sleepPersistantAppIndex) { - this->current = &app; - OSW_LOG_D("Selected app based on sleep persistant app index: ", *this->sleepPersistantAppIndex); - break; - } - ++categoryIndex; - } - if(this->current != nullptr) +void OswAppDrawer::onStart() { + OswAppV2::onStart(); + this->viewFlags = (OswAppV2::ViewFlags)(this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); // in the drawer, we want to keep the display on + // the known button states are handled with drawer/app open/close + + // Try to find it the default app... + LazyInit* defaultApp = nullptr; + if(this->sleepPersistantAppIndex != nullptr and *this->sleepPersistantAppIndex != UNDEFINED_SLEEP_APP_INDEX) { + // Using the sleep-persistant app index, we are maybe able to recover the last app + size_t categoryIndex = 0; + for(auto& category: this->apps) { + for(auto& app: category.second) { + if(categoryIndex == *this->sleepPersistantAppIndex) { + defaultApp = &app; + OSW_LOG_D("Selected app based on sleep persistant app index: ", *this->sleepPersistantAppIndex); break; + } + ++categoryIndex; } + if(defaultApp != nullptr) + break; } - - // Either the previous step failed, or we did not have a sleep-persistant app index - if(this->current == nullptr) { - // Maybe a default category / index was set? - if(this->defaultCategory) { - if(!this->apps.count(this->defaultCategory)) - throw std::runtime_error("Invalid default category"); - auto& categoryList = this->apps.at(this->defaultCategory); - if(categoryList.size() <= this->defaultAppIndex) - throw std::runtime_error("Invalid default app index"); - auto it = categoryList.begin(); - std::advance(it, this->defaultAppIndex); - this->current = &*it; - OSW_LOG_D("Selected app based on default category and index: \"", this->defaultCategory, "\", ", this->defaultAppIndex); - } else { - // Well, guess we have to take the "first" then - this->current = &this->apps.begin()->second.front(); - OSW_LOG_D("Selected app based who came first..."); - } + } + + // Either the previous step failed, or we did not have a sleep-persistant app index + if(defaultApp == nullptr) { + // Maybe a default category / index was set? + if(this->defaultCategory) { + if(!this->apps.count(this->defaultCategory)) + throw std::runtime_error("Invalid default category"); + auto& categoryList = this->apps.at(this->defaultCategory); + if(categoryList.size() <= this->defaultAppIndex) + throw std::runtime_error("Invalid default app index"); + auto it = categoryList.begin(); + std::advance(it, this->defaultAppIndex); + defaultApp = &*it; + OSW_LOG_D("Selected app based on default category and index: \"", this->defaultCategory, "\", ", this->defaultAppIndex); + } else { + // Well, guess we have to take the "first" then + defaultApp = &this->apps.begin()->second.front(); + OSW_LOG_D("Selected app based who came first..."); } } - assert(this->current != nullptr && "Drawer failed to determine current app (this should never happen) - or is the drawer empty?"); - return *this->current; -} - -void OswAppDrawer::onStart() { - OswAppV2::onStart(); - if(this->showDrawer) - this->viewFlags = (OswAppV2::ViewFlags)(this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); // in the drawer, we want to keep the display on - else - this->getCurrent()->onStart(); + assert(defaultApp != nullptr && "Drawer failed to determine default app (this should never happen) - or is the drawer empty?"); + this->open(*defaultApp); } void OswAppDrawer::onLoop() { - OswAppV2::onLoop(); - if(!this->showDrawer) - this->getCurrent()->onLoop(); // if we are not in the drawer, we want to call the current app's onLoop + OswAppV2::onLoop(); // needed to detect long-press of menu-select / navigation with drawer open + if(this->current) + this->current->get()->onLoop(); // if we are not in the drawer, we want to call the current app's onLoop } void OswAppDrawer::onDraw() { - OswAppV2::onDraw(); - if(this->showDrawer) { + if(!this->current) { + OswAppV2::onDraw(); this->hal->gfx()->setTextCursor(DISP_W / 2, DISP_H / 2); // some constants for the drawer layout @@ -107,7 +102,7 @@ void OswAppDrawer::onDraw() { } // now draw all the categories - char const* selectedAppName = nullptr; + char const* highlightedAppName = nullptr; size_t categoryIndex = 0; auto categoryIterator = this->apps.begin(); std::advance(categoryIterator, this->categoryIndexOffset); @@ -142,12 +137,12 @@ void OswAppDrawer::onDraw() { // draw a frame about the selected app (and store refs to the app and its name) if(categoryAppIndex == (this->highlightAppIndex % horizontalAppCount) and categoryIndex == this->highlightCategoryIndex) { this->hal->gfx()->drawFrame(currentCategoryWidth, currentCategoryHeightStart, horizontalAppSize, horizontalAppSize, OswUI::getInstance()->getInfoColor()); - selectedAppName = app->getAppName(); + highlightedAppName = app.get()->getAppName(); highlightApp = &app; } // draw the app icon - const float iconScale = horizontalAppSize / app->getAppIcon().baseDimensions; - app->getAppIcon().draw(this->hal->gfx(), currentCategoryWidth + horizontalAppSize / 2, currentCategoryHeightStart + horizontalAppSize / 2, iconScale, OswImage::Alignment::CENTER, OswImage::Alignment::CENTER); + const float iconScale = horizontalAppSize / app.get()->getAppIcon().baseDimensions; + app.get()->getAppIcon().draw(this->hal->gfx(), currentCategoryWidth + horizontalAppSize / 2, currentCategoryHeightStart + horizontalAppSize / 2, iconScale, OswImage::Alignment::CENTER, OswImage::Alignment::CENTER); ++categoryAppIndex; if(categoryAppIndex > (horizontalAppCount - 1)) break; @@ -158,10 +153,10 @@ void OswAppDrawer::onDraw() { } // draw the selected app name - if(selectedAppName) { + if(highlightedAppName) { this->hal->gfx()->setTextCursor(DISP_W / 2, DISP_H - 16); this->hal->gfx()->setTextCenterAligned(); - this->hal->gfx()->print(selectedAppName); + this->hal->gfx()->print(highlightedAppName); } // draw the button labels @@ -179,24 +174,24 @@ void OswAppDrawer::onDraw() { } this->hal->gfx()->print("OK"); } else - this->getCurrent()->onDraw(); + this->current->get()->onDraw(); } void OswAppDrawer::onDrawOverlay() { - if(!this->showDrawer) - this->getCurrent()->onDrawOverlay(); // forward to the current app - OswAppV2::onDrawOverlay(); + if(this->current) + this->current->get()->onDrawOverlay(); // forward to the current app + OswAppV2::onDrawOverlay(); // always needed to draw e.g. the animation for the menu button } void OswAppDrawer::onStop() { + if(this->current) + this->current->get()->onStop(); // forward to the current app OswAppV2::onStop(); - if(!this->showDrawer) - this->getCurrent()->onStop(); // forward to the current app } void OswAppDrawer::onButton(int id, bool up, ButtonStateNames state) { OswAppV2::onButton(id, up, state); - if(this->showDrawer) { + if(!this->current) { if(up and state == OswAppV2::ButtonStateNames::SHORT_PRESS) { if(id == Button::BUTTON_UP) { this->highlightCategoryIndex = (this->highlightCategoryIndex + 1) % this->apps.size(); @@ -205,70 +200,45 @@ void OswAppDrawer::onButton(int id, bool up, ButtonStateNames state) { ++this->highlightAppIndex; this->needsRedraw = true; } else if(id == Button::BUTTON_SELECT) { - this->onStop(); - this->showDrawer = false; - this->current = highlightApp; - this->getCurrent()->onStart(); - this->needsRedraw = true; - this->cleanup(); - // store the selected app "index" persistently, if variable was set - if(this->sleepPersistantAppIndex != nullptr) { - size_t index = 0; - for(auto& category : this->apps) { - bool found = false; - for(auto& app : category.second) { - if(&app == this->current) { - *this->sleepPersistantAppIndex = index; - found = true; - OSW_LOG_D("Stored sleep-persistant app index: ", index); - break; - } - ++index; - } - if(found) - break; - } - } + this->open(*highlightApp); } } this->minimizeButtonLabels = true; // any button press will minimize the button labels } else { if(up == true and id == Button::BUTTON_SELECT and state == OswAppV2::ButtonStateNames::LONG_PRESS) { - this->showDrawer = true; - this->getCurrent()->onStop(); - this->current = nullptr; - this->onStart(); // "start" the drawer app - } else - this->getCurrent()->onButton(id, up, state); + this->drawer(); + } + // Do not forward the button press to the current app if the drawer is open } } #ifdef OSW_EMULATOR void OswAppDrawer::onLoopDebug() { - OswAppV2::onLoopDebug(); - if(!this->showDrawer) - this->getCurrent()->onLoopDebug(); // forward to the current app + if(this->current) + this->current->get()->onLoopDebug(); // forward to the current app + else + OswAppV2::onLoopDebug(); } #endif -OswAppV2::ViewFlags OswAppDrawer::getViewFlags() { - if(this->showDrawer) - return OswAppV2::getViewFlags(); +const OswAppV2::ViewFlags& OswAppDrawer::getViewFlags() { + if(this->current) + return this->current->get()->getViewFlags(); // forward to the current app else - return this->getCurrent()->getViewFlags(); // forward to the current app + return OswAppV2::getViewFlags(); } bool OswAppDrawer::getNeedsRedraw() { - if(this->showDrawer) - return OswAppV2::getNeedsRedraw(); + if(this->current) + return OswAppV2::getNeedsRedraw() or this->current->get()->getNeedsRedraw(); // still respect the redraw of the drawers overlays else - return OswAppV2::getNeedsRedraw() or this->getCurrent()->getNeedsRedraw(); // still respect the redraw of the drawers overlays + return OswAppV2::getNeedsRedraw(); } void OswAppDrawer::resetNeedsRedraw() { OswAppV2::resetNeedsRedraw(); - if(!this->showDrawer) - this->getCurrent()->resetNeedsRedraw(); // forward to the current app + if(this->current) + this->current->get()->resetNeedsRedraw(); // forward to the current app } /** @@ -278,9 +248,49 @@ void OswAppDrawer::resetNeedsRedraw() { void OswAppDrawer::cleanup() { for(auto categoryIterator = this->apps.begin(); categoryIterator != this->apps.end(); categoryIterator++) { for(auto appIterator = categoryIterator->second.begin(); appIterator != categoryIterator->second.end(); appIterator++) { - if(*appIterator != *this->current) { + if(this->current and *appIterator != this->current->get()) { appIterator->cleanup(); } } } +} + +void OswAppDrawer::drawer() { + if(!this->current) + return; + this->current->get()->onStop(); + this->current = nullptr; + this->knownButtonStates[Button::BUTTON_UP] = ButtonStateNames::SHORT_PRESS; + this->knownButtonStates[Button::BUTTON_DOWN] = ButtonStateNames::SHORT_PRESS; + this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::SHORT_PRESS; + this->needsRedraw = true; +} + +void OswAppDrawer::open(LazyInit& app) { + this->drawer(); // stop current app (by "opening" the drawer), ignores if drawer is already open + this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::LONG_PRESS; + + // start app + this->current = &app; + this->current->get()->onStart(); + this->cleanup(); // cleanup all other apps + + // store the selected app "index" persistently, if variable was set + if(this->sleepPersistantAppIndex != nullptr) { + size_t index = 0; + for(auto& category : this->apps) { + bool found = false; + for(auto& app : category.second) { + if(app == this->current->get()) { + *this->sleepPersistantAppIndex = index; + found = true; + OSW_LOG_D("Stored sleep-persistant app index: ", index); + break; + } + ++index; + } + if(found) + break; + } + } } \ No newline at end of file diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 62ca7bd1f..83e8a4e7e 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -6,14 +6,9 @@ OswIcon OswAppV2::defaultAppIcon = OswIcon(app_png, app_png_dimensions, 0x0); // Color will be set upon retreival std::array OswAppV2::buttonDownSince = {0}; -std::array OswAppV2::buttonLastSentState = {ButtonStateNames::UNDEFINED}; -std::array OswAppV2::buttonDoubleShortTimeout = {0}; -std::array OswAppV2::buttonIndicatorProgress = {0}; OswAppV2::OswAppV2() { - for(int i = 0; i < NUM_BUTTONS; i++) - // Do not listen to the double press, as it may delays the short press reporting - this->knownButtonStates[i] = (ButtonStateNames) (ButtonStateNames::UNDEFINED | ButtonStateNames::SHORT_PRESS | ButtonStateNames::LONG_PRESS | ButtonStateNames::VERY_LONG_PRESS); + } OswIcon& OswAppV2::getAppIcon() { @@ -25,7 +20,7 @@ OswIcon& OswAppV2::getDefaultAppIcon() { return this->defaultAppIcon; } -OswAppV2::ViewFlags OswAppV2::getViewFlags() { +const OswAppV2::ViewFlags& OswAppV2::getViewFlags() { return this->viewFlags; } @@ -39,6 +34,13 @@ void OswAppV2::resetNeedsRedraw() { void OswAppV2::onStart() { this->needsRedraw = true; + this->clearKnownButtonStates(); +} + +void OswAppV2::clearKnownButtonStates() { + for(int i = 0; i < NUM_BUTTONS; i++) + // Do not listen to the double press, as it may delays the short press reporting + this->knownButtonStates[i] = (ButtonStateNames) (ButtonStateNames::UNDEFINED | ButtonStateNames::SHORT_PRESS | ButtonStateNames::LONG_PRESS | ButtonStateNames::VERY_LONG_PRESS); } void OswAppV2::onLoop() { diff --git a/src/apps/examples/OswAppExampleV2.cpp b/src/apps/examples/OswAppExampleV2.cpp index 561df1f27..f7ca52b8b 100644 --- a/src/apps/examples/OswAppExampleV2.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -6,10 +6,7 @@ #include "assets/img/static/example.png.h" OswAppExampleV2::OswAppExampleV2(): image(example_png, example_png_length, example_png_width, example_png_height) { - // This app also "supports" double presses (on BUTTON_SELECT), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) - this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit - // ...but this will delay the processing of the "image" button - so we will disable it again ;) - this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] ^ OswAppV2::ButtonStateNames::DOUBLE_PRESS); // XOR to toggle the bit + } const char* OswAppExampleV2::getAppId() { @@ -22,8 +19,13 @@ const char* OswAppExampleV2::getAppName() { void OswAppExampleV2::onStart() { OswAppV2::onStart(); // always make sure to call the base class method! - // This is where you initialise code, gets called before this app is shown + + // This app also "supports" double presses (on BUTTON_SELECT), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) + this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit + // ...but this will delay the processing of the "image" button - so we will disable it again ;) + this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] ^ OswAppV2::ButtonStateNames::DOUBLE_PRESS); // XOR to toggle the bit + this->start = time(nullptr); // used as offset for the counter later on this->viewFlags = (OswAppV2::ViewFlags) (this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); // by default we want to keep the display on } From 40fd501006c0bed82ff09595c4a46e4ee6d22333 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 16:49:35 +0200 Subject: [PATCH 059/141] Fixed broken buttons in app v2 Added full/partial knownButtonState cleanup --- include/OswAppV2.h | 6 ++---- src/OswAppDrawer.cpp | 2 ++ src/OswAppV2.cpp | 7 +++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index 7be359bd0..5ba51b7af 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -54,13 +54,11 @@ class OswAppV2 { ViewFlags viewFlags = ViewFlags::NONE; bool needsRedraw = false; OswIcon& getDefaultAppIcon(); - void clearKnownButtonStates(); + void clearKnownButtonStates(bool useDefaults); private: static OswIcon defaultAppIcon; - // the button states-variables (↓) are shared between all apps, so they do not detect presses, which were already handled by another app (which may wrapped them) - static std::array buttonDownSince; - // these button states-variables (↓) are app-specific, so they can't be shared + std::array buttonDownSince = {0}; std::array buttonLastSentState = {ButtonStateNames::UNDEFINED}; std::array buttonDoubleShortTimeout = {0}; std::array buttonIndicatorProgress = {0}; diff --git a/src/OswAppDrawer.cpp b/src/OswAppDrawer.cpp index 7026e659c..040026556 100644 --- a/src/OswAppDrawer.cpp +++ b/src/OswAppDrawer.cpp @@ -260,6 +260,7 @@ void OswAppDrawer::drawer() { return; this->current->get()->onStop(); this->current = nullptr; + this->clearKnownButtonStates(false); this->knownButtonStates[Button::BUTTON_UP] = ButtonStateNames::SHORT_PRESS; this->knownButtonStates[Button::BUTTON_DOWN] = ButtonStateNames::SHORT_PRESS; this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::SHORT_PRESS; @@ -268,6 +269,7 @@ void OswAppDrawer::drawer() { void OswAppDrawer::open(LazyInit& app) { this->drawer(); // stop current app (by "opening" the drawer), ignores if drawer is already open + this->clearKnownButtonStates(false); this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::LONG_PRESS; // start app diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 83e8a4e7e..0996382ae 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -5,7 +5,6 @@ #include "assets/img/icons/app.png.h" OswIcon OswAppV2::defaultAppIcon = OswIcon(app_png, app_png_dimensions, 0x0); // Color will be set upon retreival -std::array OswAppV2::buttonDownSince = {0}; OswAppV2::OswAppV2() { @@ -34,13 +33,13 @@ void OswAppV2::resetNeedsRedraw() { void OswAppV2::onStart() { this->needsRedraw = true; - this->clearKnownButtonStates(); + this->clearKnownButtonStates(true); } -void OswAppV2::clearKnownButtonStates() { +void OswAppV2::clearKnownButtonStates(bool useDefaults) { for(int i = 0; i < NUM_BUTTONS; i++) // Do not listen to the double press, as it may delays the short press reporting - this->knownButtonStates[i] = (ButtonStateNames) (ButtonStateNames::UNDEFINED | ButtonStateNames::SHORT_PRESS | ButtonStateNames::LONG_PRESS | ButtonStateNames::VERY_LONG_PRESS); + this->knownButtonStates[i] = (ButtonStateNames) (useDefaults ? (ButtonStateNames::UNDEFINED | ButtonStateNames::SHORT_PRESS | ButtonStateNames::LONG_PRESS | ButtonStateNames::VERY_LONG_PRESS) : 0); } void OswAppV2::onLoop() { From 8e6ca61f6fbfb5946418ef3cb5542670f1964b99 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 17:36:55 +0200 Subject: [PATCH 060/141] Simplified default-app selection for drawer --- include/OswAppDrawer.h | 9 ++++---- src/OswAppDrawer.cpp | 49 ++++++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/include/OswAppDrawer.h b/include/OswAppDrawer.h index b417924f2..402449360 100644 --- a/include/OswAppDrawer.h +++ b/include/OswAppDrawer.h @@ -10,7 +10,7 @@ class OswAppDrawer: public OswAppV2 { public: static const size_t UNDEFINED_SLEEP_APP_INDEX = (size_t) -1; // just use a very large number - OswAppDrawer(const char* defaultCategory = nullptr, size_t defaultAppIndex = 0, size_t* sleepPersistantAppIndex = nullptr); + OswAppDrawer(size_t* sleepPersistantAppIndex = nullptr); const char* getAppId() override; const char* getAppName() override; @@ -30,6 +30,7 @@ class OswAppDrawer: public OswAppV2 { bool getNeedsRedraw() override; void resetNeedsRedraw() override; + void setDefault(const char* defaultAppId); void registerApp(const char* category, OswAppV2* app); template void registerAppLazy(const char* category) { @@ -60,7 +61,8 @@ class OswAppDrawer: public OswAppV2 { } bool operator==(const LazyInit& other) const { - return this->init == other.init or this->ptr == other.ptr; + // either the app-instance is the same, or the initialization function is the same + return (this->ptr != nullptr and other.ptr != nullptr and this->ptr == other.ptr) or (this->init != nullptr and other.init != nullptr and this->init == other.init); } bool operator!=(const LazyInit& other) const { @@ -84,8 +86,7 @@ class OswAppDrawer: public OswAppV2 { static bool minimizeButtonLabels; // if you know one drawer, you know them all ;) std::map> apps; LazyInit* current = nullptr; - const char* defaultCategory; - const size_t defaultAppIndex; + const char* defaultAppId = nullptr; size_t highlightCategoryIndex = 0; size_t highlightAppIndex = 0; size_t categoryIndexOffset = 0; diff --git a/src/OswAppDrawer.cpp b/src/OswAppDrawer.cpp index 040026556..ca8dcbfff 100644 --- a/src/OswAppDrawer.cpp +++ b/src/OswAppDrawer.cpp @@ -4,10 +4,14 @@ bool OswAppDrawer::minimizeButtonLabels = false; -OswAppDrawer::OswAppDrawer(const char* defaultCategory, size_t defaultAppIndex, size_t* sleepPersistantAppIndex): defaultCategory(defaultCategory), defaultAppIndex(defaultAppIndex), sleepPersistantAppIndex(sleepPersistantAppIndex) { +OswAppDrawer::OswAppDrawer(size_t* sleepPersistantAppIndex): sleepPersistantAppIndex(sleepPersistantAppIndex) { // nothing to do here } +void OswAppDrawer::setDefault(const char* defaultAppId) { + this->defaultAppId = defaultAppId; +} + const char* OswAppDrawer::getAppId() { return "osw.drawer"; } @@ -36,7 +40,7 @@ void OswAppDrawer::onStart() { for(auto& app: category.second) { if(categoryIndex == *this->sleepPersistantAppIndex) { defaultApp = &app; - OSW_LOG_D("Selected app based on sleep persistant app index: ", *this->sleepPersistantAppIndex); + OSW_LOG_D("Selected default app based on sleep persistent index: ", *this->sleepPersistantAppIndex); break; } ++categoryIndex; @@ -49,22 +53,30 @@ void OswAppDrawer::onStart() { // Either the previous step failed, or we did not have a sleep-persistant app index if(defaultApp == nullptr) { // Maybe a default category / index was set? - if(this->defaultCategory) { - if(!this->apps.count(this->defaultCategory)) - throw std::runtime_error("Invalid default category"); - auto& categoryList = this->apps.at(this->defaultCategory); - if(categoryList.size() <= this->defaultAppIndex) - throw std::runtime_error("Invalid default app index"); - auto it = categoryList.begin(); - std::advance(it, this->defaultAppIndex); - defaultApp = &*it; - OSW_LOG_D("Selected app based on default category and index: \"", this->defaultCategory, "\", ", this->defaultAppIndex); + if(this->defaultAppId) { + std::string defaultAppId = this->defaultAppId; // using a string here, as we need to compare it to the app id + for(auto& category: this->apps) { + for(auto& app: category.second) { + if(app.get()->getAppId() == defaultAppId) { + defaultApp = &app; + OSW_LOG_D("Selected default app based on app id: \"", this->defaultAppId, "\""); + break; + } + } + if(defaultApp != nullptr) + break; + } } else { - // Well, guess we have to take the "first" then - defaultApp = &this->apps.begin()->second.front(); - OSW_LOG_D("Selected app based who came first..."); } } + + // Okay, let's hope we can select the first app in the "first" category (sorted based on hash) + if(defaultApp == nullptr and this->apps.size() > 0) { + // Well, guess we have to take the "first" then + defaultApp = &this->apps.begin()->second.front(); + OSW_LOG_D("Selected default app based who came \"first\"..."); + } + assert(defaultApp != nullptr && "Drawer failed to determine default app (this should never happen) - or is the drawer empty?"); this->open(*defaultApp); } @@ -280,10 +292,10 @@ void OswAppDrawer::open(LazyInit& app) { // store the selected app "index" persistently, if variable was set if(this->sleepPersistantAppIndex != nullptr) { size_t index = 0; + bool found = false; for(auto& category : this->apps) { - bool found = false; - for(auto& app : category.second) { - if(app == this->current->get()) { + for(auto& catApp : category.second) { + if(catApp == *this->current) { *this->sleepPersistantAppIndex = index; found = true; OSW_LOG_D("Stored sleep-persistant app index: ", index); @@ -294,5 +306,6 @@ void OswAppDrawer::open(LazyInit& app) { if(found) break; } + assert(found && "Could not find the current app in the app drawer?!"); // this should never happen } } \ No newline at end of file From 7bbd6959d9dfc379ea89211eeffd9a2d722c345f Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 18:35:53 +0200 Subject: [PATCH 061/141] Readded all apps via compat-layer Removed old switcher Moved main varaibles into globals Allowed example apps via optional flag --- CMakeLists.txt | 1 + emulator/src/tests/OswAppAlarm.cpp | 3 +- emulator/src/tests/OswAppTimer.cpp | 3 +- include/{ => apps}/OswAppDrawer.h | 0 include/{ => apps}/OswAppV2Compat.h | 0 include/apps/clock/OswAppAlarm.h | 4 +- include/apps/clock/OswAppTimer.h | 4 +- include/apps/main/switcher.h | 49 ------ include/apps/tools/OswAppTimeConfig.h | 5 +- include/globals.h | 40 ++--- include/osw_ui.h | 2 - src/{ => apps}/OswAppDrawer.cpp | 2 +- src/{ => apps}/OswAppV2Compat.cpp | 2 +- src/apps/clock/OswAppAlarm.cpp | 9 +- src/apps/clock/OswAppTimer.cpp | 6 +- src/apps/examples/OswAppExampleV2.cpp | 2 +- src/apps/main/switcher.cpp | 194 ------------------------ src/apps/tools/OswAppTimeConfig.cpp | 4 - src/apps/watchfaces/OswAppWatchface.cpp | 2 +- src/globals.cpp | 11 +- src/main.cpp | 151 +++++++++--------- src/osw_ui.cpp | 1 - 22 files changed, 122 insertions(+), 373 deletions(-) rename include/{ => apps}/OswAppDrawer.h (100%) rename include/{ => apps}/OswAppV2Compat.h (100%) delete mode 100644 include/apps/main/switcher.h rename src/{ => apps}/OswAppDrawer.cpp (99%) rename src/{ => apps}/OswAppV2Compat.cpp (96%) delete mode 100644 src/apps/main/switcher.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f7e9ed79..63f76746b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,7 @@ target_compile_definitions(emulator.run PUBLIC > # Comment these as you wish... OSW_FEATURE_STATS_STEPS + OSW_APPS_EXAMPLES=1 GAME_SNAKE=1 GAME_BRICK_BREAKER=1 TOOL_FLASHLIGHT=1 diff --git a/emulator/src/tests/OswAppAlarm.cpp b/emulator/src/tests/OswAppAlarm.cpp index 8648015bd..24b3dcf3c 100644 --- a/emulator/src/tests/OswAppAlarm.cpp +++ b/emulator/src/tests/OswAppAlarm.cpp @@ -44,8 +44,7 @@ class TestAlarm { // Helpers static OswAppAlarm createAlarm() { - std::shared_ptr mockSwitcher = std::make_shared(BUTTON_1, SHORT_PRESS, false, false, nullptr); - OswAppAlarm alarm{mockSwitcher.get()}; + OswAppAlarm alarm; return alarm; } diff --git a/emulator/src/tests/OswAppTimer.cpp b/emulator/src/tests/OswAppTimer.cpp index ab0aadfdd..522dad23b 100644 --- a/emulator/src/tests/OswAppTimer.cpp +++ b/emulator/src/tests/OswAppTimer.cpp @@ -44,8 +44,7 @@ class TestTimer { // Helpers static OswAppTimer createTimer() { - std::shared_ptr mockSwitcher = std::make_shared(BUTTON_1, SHORT_PRESS, false, false, nullptr); - OswAppTimer timer{mockSwitcher.get()}; + OswAppTimer timer; return timer; } diff --git a/include/OswAppDrawer.h b/include/apps/OswAppDrawer.h similarity index 100% rename from include/OswAppDrawer.h rename to include/apps/OswAppDrawer.h diff --git a/include/OswAppV2Compat.h b/include/apps/OswAppV2Compat.h similarity index 100% rename from include/OswAppV2Compat.h rename to include/apps/OswAppV2Compat.h diff --git a/include/apps/clock/OswAppAlarm.h b/include/apps/clock/OswAppAlarm.h index d0673727b..51e2b7932 100644 --- a/include/apps/clock/OswAppAlarm.h +++ b/include/apps/clock/OswAppAlarm.h @@ -6,7 +6,6 @@ #include #include #include -#include "apps/main/switcher.h" #include "./services/NotifierClient.h" #include @@ -22,7 +21,7 @@ class OswAppAlarm : public OswApp { DAY_PICKER }; - OswAppAlarm(OswAppSwitcher* clockAppSwitcher); + OswAppAlarm(); void setup() override; void loop() override; void stop() override; @@ -36,7 +35,6 @@ class OswAppAlarm : public OswApp { void resetAlarmState(); void listAlarms(); - OswAppSwitcher* clockAppSwitcher{}; NotifierClient notifierClient{"org.open-smartwatch.osw.alarm"}; AlarmState state{}; unsigned char step{}; diff --git a/include/apps/clock/OswAppTimer.h b/include/apps/clock/OswAppTimer.h index 532600da4..684315b7d 100644 --- a/include/apps/clock/OswAppTimer.h +++ b/include/apps/clock/OswAppTimer.h @@ -6,7 +6,6 @@ #include #include #include -#include "apps/main/switcher.h" #include "./services/NotifierClient.h" #include @@ -20,7 +19,7 @@ class OswAppTimer : public OswApp { PAUSED }; - OswAppTimer(OswAppSwitcher* clockAppSwitcher); + OswAppTimer(); void setup() override; void loop() override; void stop() override; @@ -41,7 +40,6 @@ class OswAppTimer : public OswApp { void drawNumber(const int number, const int index); void drawTime(const int totalSeconds); - OswAppSwitcher* clockAppSwitcher{}; NotifierClient notifierClient{"org.open-smartwatch.osw.timer"}; TimerState state{}; unsigned char step{}; diff --git a/include/apps/main/switcher.h b/include/apps/main/switcher.h deleted file mode 100644 index 818668ae2..000000000 --- a/include/apps/main/switcher.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include -#include -#include - -#include - -enum OswAppSwitcherType { SHORT_PRESS, LONG_PRESS }; - -class OswAppSwitcher : public OswApp { - public: - OswAppSwitcher(Button btn, OswAppSwitcherType type, bool enableAutoSleep, bool enableSleep, uint16_t* rtcAppIndex) { - _btn = btn; - _type = type; - _enableAutoSleep = enableAutoSleep; - _enableSleep = enableSleep; - _rtcAppIndex = rtcAppIndex; - } - OswAppSwitcher() {}; - virtual void setup() override; - virtual void loop() override; -#ifdef OSW_EMULATOR - virtual void loopDebug() override; -#endif - virtual void stop() override; - void paginationDisable(); - void paginationEnable(); - void registerApp(OswApp* app); - ~OswAppSwitcher() {}; - - private: - void cycleApp(); - void sleep(); - Button _btn = BUTTON_1; - OswAppSwitcherType _type = LONG_PRESS; - std::vector _apps; - uint16_t* _rtcAppIndex; - uint16_t _appCount = 0; - bool _pagination = true; - bool _paginationIndicator = false; - bool _enableAutoSleep = false; - bool _checked = false; - bool _enableSleep; - bool _doSleep = false; - bool _doSwitch = false; - long appOnScreenSince = 0; - unsigned long _timeForLongPress = APPSWITCHER_LONG_PRESS; - unsigned long _timeForSleepPress = APPSWITCHER_SLEEP_TIMEOUT; -}; diff --git a/include/apps/tools/OswAppTimeConfig.h b/include/apps/tools/OswAppTimeConfig.h index 5c6aa8aac..c69bc4d70 100644 --- a/include/apps/tools/OswAppTimeConfig.h +++ b/include/apps/tools/OswAppTimeConfig.h @@ -2,14 +2,12 @@ #include #include -#include "apps/main/switcher.h" #include class OswAppTimeConfig : public OswApp { public: - OswAppTimeConfig(OswAppSwitcher* settingsAppSwitcher) { + OswAppTimeConfig() { ui = OswUI::getInstance(); - this->settingsAppSwitcher = settingsAppSwitcher; }; virtual void setup() override; virtual void loop() override; @@ -25,5 +23,4 @@ class OswAppTimeConfig : public OswApp { int8_t manualSettingStep = 0; int16_t manualSettingTimestamp[11]; OswUI* ui = nullptr; - OswAppSwitcher* settingsAppSwitcher = nullptr; }; \ No newline at end of file diff --git a/include/globals.h b/include/globals.h index 477a3f9c6..21a5845f4 100644 --- a/include/globals.h +++ b/include/globals.h @@ -1,23 +1,27 @@ #pragma once #include // For RTC_DATA_ATTR +#include -/** - * As a rule of thumb: Try to avoid global variables, as they are not reset (e.g. inside the emulator), - * because they are not bound to a lifetime of an object. This also applies to applications and their states. - * Furthermore, their names may collide and cause unreleated bugs! - * - * Yes, they are helpful during early development, but should not be used inside the final code! - */ +#include "apps/OswAppDrawer.h" +#include "apps/tools/OswAppTutorial.h" -/** - * These are the current states of the main.cpp watchfaces and app switchers. - * They are commonly initialized in the setup() function and then used in the loop() function. - * - * These are global variables, as the setup() and loop() functions are not part of any class. - */ -RTC_DATA_ATTR extern uint16_t main_watchFaceIndex; // Will only be initialized after deep sleep inside the setup() method! -extern uint16_t main_currentAppIndex; // -> wakeup from deep sleep returns to watch face (and allows auto sleep) -extern uint16_t main_fitnessAppIndex; -extern uint16_t main_clockAppIndex; -extern uint16_t main_settingsAppIndex; \ No newline at end of file +namespace OswGlobals { + /** + * As a rule of thumb: Try to avoid global variables, as they are not reset (e.g. inside the emulator), + * because they are not bound to a lifetime of an object. This also applies to applications and their states. + * Furthermore, their names may collide and cause unreleated bugs! + * + * Yes, they are helpful during early development, but should not be used inside the final code! + */ + + /** + * These are the current states of the main.cpp watchfaces/drawers. + * They are commonly initialized in the setup() function and then used in the loop() function. + * + * These are global variables, as the setup() and loop() functions are not part of any class. + */ + RTC_DATA_ATTR extern size_t main_AppIndex; + extern OswAppDrawer main_mainDrawer; + extern std::unique_ptr main_tutorialApp; +} \ No newline at end of file diff --git a/include/osw_ui.h b/include/osw_ui.h index fbb8ab7a2..051c4f77e 100644 --- a/include/osw_ui.h +++ b/include/osw_ui.h @@ -7,7 +7,6 @@ #include class OswAppV2; -class OswAppSwitcher; class OswUI { public: class OswUIProgress { @@ -66,7 +65,6 @@ class OswUI { static OswUI* getInstance(); static void resetInstance(); - // void loop(OswAppSwitcher& mainAppSwitcher, uint16_t& mainAppIndex); void loop(); void setRootApplication(OswAppV2* rootApplication); OswAppV2* getRootApplication(); diff --git a/src/OswAppDrawer.cpp b/src/apps/OswAppDrawer.cpp similarity index 99% rename from src/OswAppDrawer.cpp rename to src/apps/OswAppDrawer.cpp index ca8dcbfff..37a0ee6af 100644 --- a/src/OswAppDrawer.cpp +++ b/src/apps/OswAppDrawer.cpp @@ -1,6 +1,6 @@ #include -#include +#include bool OswAppDrawer::minimizeButtonLabels = false; diff --git a/src/OswAppV2Compat.cpp b/src/apps/OswAppV2Compat.cpp similarity index 96% rename from src/OswAppV2Compat.cpp rename to src/apps/OswAppV2Compat.cpp index cafa6755e..b92505eb8 100644 --- a/src/OswAppV2Compat.cpp +++ b/src/apps/OswAppV2Compat.cpp @@ -1,4 +1,4 @@ -#include +#include OswAppV2Compat::OswAppV2Compat(const char* id, const char* name, OswAppV1& app): id(id), name(name), app(app) { diff --git a/src/apps/clock/OswAppAlarm.cpp b/src/apps/clock/OswAppAlarm.cpp index 8747404d3..0a8b00a5c 100644 --- a/src/apps/clock/OswAppAlarm.cpp +++ b/src/apps/clock/OswAppAlarm.cpp @@ -6,8 +6,7 @@ void OswAppAlarm::setup() { void OswAppAlarm::stop() { } -OswAppAlarm::OswAppAlarm(OswAppSwitcher* clockAppSwitcher) { - this->clockAppSwitcher = clockAppSwitcher; +OswAppAlarm::OswAppAlarm() { state = AlarmState::IDLE; notifications = notifierClient.readNotifications(); } @@ -42,7 +41,6 @@ void OswAppAlarm::handleTimeIncrementButton() { notifications = notifierClient.readNotifications(); step = {}; timestamp = {}; - clockAppSwitcher->paginationEnable(); break; case 5: if (10 * timestamp[0] + timestamp[1] < 24) { @@ -83,7 +81,6 @@ void OswAppAlarm::resetAlarmState() { step = {}; timestamp = {}; daysOfWeek = {}; - clockAppSwitcher->paginationEnable(); } void OswAppAlarm::handleFrequencyIncrementButton() { @@ -284,12 +281,10 @@ void OswAppAlarm::loop() { if (hal->btnHasGoneDown(BUTTON_2) && !notifications.empty()) { state = AlarmState::LIST; notifications = notifierClient.readNotifications(); - clockAppSwitcher->paginationDisable(); } if (hal->btnHasGoneDown(BUTTON_3) && notifications.size() < ALARM_COUNT) { state = AlarmState::TIME_PICKER; - clockAppSwitcher->paginationDisable(); } listAlarms(); @@ -304,14 +299,12 @@ void OswAppAlarm::loop() { state = AlarmState::IDLE; notifications = notifierClient.readNotifications(); step = {}; - clockAppSwitcher->paginationEnable(); } if (hal->btnHasGoneDown(BUTTON_3)) { state = AlarmState::IDLE; notifications = notifierClient.readNotifications(); step = {}; - clockAppSwitcher->paginationEnable(); } listAlarms(); diff --git a/src/apps/clock/OswAppTimer.cpp b/src/apps/clock/OswAppTimer.cpp index f3e33c013..139f2c047 100644 --- a/src/apps/clock/OswAppTimer.cpp +++ b/src/apps/clock/OswAppTimer.cpp @@ -4,8 +4,7 @@ void OswAppTimer::setup() {} void OswAppTimer::stop() {} -OswAppTimer::OswAppTimer(OswAppSwitcher* clockAppSwitcher) { - this->clockAppSwitcher = clockAppSwitcher; +OswAppTimer::OswAppTimer() { state = TimerState::IDLE; } @@ -20,7 +19,6 @@ void OswAppTimer::resetTimer() { step = {}; timestamp = {}; timerLeftSec = {}; - clockAppSwitcher->paginationEnable(); } void OswAppTimer::handleIncrementButton() { @@ -45,7 +43,6 @@ void OswAppTimer::handleIncrementButton() { auto currentTime = utcTime + std::chrono::seconds{static_cast(OswHal::getInstance()->getTimezoneOffsetPrimary())}; timeToFire = std::chrono::time_point_cast(currentTime) + timerLeftSec; notificationId = notifierClient.createNotification(timeToFire).second.getId(); - clockAppSwitcher->paginationEnable(); } break; } @@ -258,7 +255,6 @@ void OswAppTimer::loop() { case TimerState::IDLE: { if (hal->btnHasGoneDown(BUTTON_3)) { state = TimerState::SET_TIMER_SCREEN; - clockAppSwitcher->paginationDisable(); } } break; diff --git a/src/apps/examples/OswAppExampleV2.cpp b/src/apps/examples/OswAppExampleV2.cpp index f7ca52b8b..6e10951cb 100644 --- a/src/apps/examples/OswAppExampleV2.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -10,7 +10,7 @@ OswAppExampleV2::OswAppExampleV2(): image(example_png, example_png_length, examp } const char* OswAppExampleV2::getAppId() { - return "osw.example.v2"; + return "osw.example.v2"; // use less than 15 characters to avoid issues with some api calls (e.g. Preferences) } const char* OswAppExampleV2::getAppName() { diff --git a/src/apps/main/switcher.cpp b/src/apps/main/switcher.cpp deleted file mode 100644 index 629973f9c..000000000 --- a/src/apps/main/switcher.cpp +++ /dev/null @@ -1,194 +0,0 @@ - -#include "./apps/main/switcher.h" - -void OswAppSwitcher::setup() { - appOnScreenSince = millis(); - if (*_rtcAppIndex >= _appCount) { - *_rtcAppIndex = 0; - } - _apps[*_rtcAppIndex]->setup(); - this->_timeForLongPress = OswConfigAllKeys::appSwitcherLongPress.get(); - this->_timeForSleepPress = OswConfigAllKeys::appSwitcherSleepPress.get(); -} - -void OswAppSwitcher::loop() { - OswHal* hal = OswHal::getInstance(); - - if (appOnScreenSince == 0) { - // if appOnScreenSince was 0, it was set to 0 before light sleep. this is a nasty hack. - appOnScreenSince = millis(); - } - - // if we enable sending the watch to sleep by clicking (really really) long enough - if (_enableSleep and hal->btnIsDownFor(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { - // remember we need to sleep once the button goes up - _doSleep = true; - } - - // detect switch action depending on mode - switch (_type) { - case LONG_PRESS: - if (hal->btnIsDownFor(_btn) > this->_timeForLongPress) { - _doSwitch = true; - } - break; - case SHORT_PRESS: - default: - if (hal->btnHasGoneDown(_btn)) { - _doSwitch = true; - } - } - - bool sleeping = false; - - // do action only once the button goes up - if (hal->btnHasGoneUp(_btn)) { - if (_doSleep) { - _doSleep = false; - _doSwitch = false; // if lightsleep is enabled then doSwitch is still true and will be used the next time. - sleeping = true; // because in lightsleep the next _app will use the button and switch the app which isn't what we want - sleep(); - } else if (_doSwitch) { - _doSwitch = false; - cycleApp(); - // we need to clear the button state, otherwise nested switchers - // using the same button will switch too - hal->clearButtonState(_btn); - } - } - - if (_enableAutoSleep && *_rtcAppIndex == 0) { - if (hal->btnIsDown(BUTTON_1) || hal->btnIsDown(BUTTON_2) || hal->btnIsDown(BUTTON_3)) { - appOnScreenSince = millis(); - } - short timeout = OswConfigAllKeys::settingDisplayTimeout.get(); - if (timeout > 0 && (millis() - appOnScreenSince) > (unsigned short) timeout * 1000) { - OSW_LOG_I("Going to sleep after ", timeout, " seconds"); - this->sleep(); - } - } - - hal->gfx()->resetText(); - OswUI::getInstance()->resetTextColors(); // yes this resets the colors in hal->gfx() - if (!sleeping) - _apps[*_rtcAppIndex]->loop(); - - // draw Pagination Indicator - if(_paginationIndicator) { - uint16_t rDot = 4; // Size (radius) of the dot - uint16_t spacing = 10; // Distance (deg) between dots - uint16_t r = (DISP_W / 2) - 8; // Distance from the center of the watch (radius) - uint16_t alpha0 = 146 + (spacing / 2 * (_appCount-1)); // Angle of the first Element (146deg = Button 1) - for(uint8_t i = 0; i < _appCount; i++) { - uint16_t alpha = alpha0 - (i * spacing); - uint16_t x = (DISP_W / 2) + (cos(alpha * PI / 180) * r); - uint16_t y = (DISP_H / 2) + (sin(alpha * PI / 180) * r); - if(i == *_rtcAppIndex) { - hal->getCanvas()->fillCircle(x, y, rDot, OswUI::getInstance()->getInfoColor()); - } else { - hal->getCanvas()->fillCircle(x, y, rDot, OswUI::getInstance()->getForegroundColor()); - } - } - } - - // draw app switcher - if (hal->btnIsDown(_btn)) { - uint8_t btnX = 0; - uint8_t btnY = 0; - int16_t progressOffset = 0; - // draw button switcher close to button - switch (_btn) { - case BUTTON_2: - btnX = 214; - btnY = 190; - progressOffset = 135; - break; - case BUTTON_3: - btnX = 214; - btnY = 50; - progressOffset = 135; - break; - case BUTTON_1: - default: - btnX = 26; - btnY = 190; - progressOffset = -45; - break; - } - - switch (_type) { - case LONG_PRESS: - // long press has the hollow square that fills (draws around short press) - if (hal->btnIsDownFor(_btn) > this->_timeForLongPress) { - // draw a large frame - hal->gfx()->fillCircle(btnX, btnY, 20, OswUI::getInstance()->getSuccessColor()); - } else { - uint8_t progress = 0; - if (hal->btnIsDownFor(_btn) > this->_timeForLongPress / 2) { - progress = (hal->btnIsDownFor(_btn) - (this->_timeForLongPress / 2)) / - ((this->_timeForLongPress / 2) / 255.0); - } - hal->gfx()->drawArc(btnX, btnY, progressOffset, progressOffset + (progress / 255.0) * 180, progress / 4, 20, - 3, OswUI::getInstance()->getForegroundColor()); - } - break; - case SHORT_PRESS: - default: - hal->gfx()->fillCircle(btnX, btnY, 10, OswUI::getInstance()->getSuccessColor()); - } - - if (_enableSleep and hal->btnIsDownFor(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { - // draw half moon - hal->gfx()->fillCircle(btnX, btnY, 9, OswUI::getInstance()->getForegroundDimmedColor()); - hal->gfx()->fillCircle(btnX, btnY, 8, OswUI::getInstance()->getBackgroundColor()); - hal->gfx()->fillCircle(btnX + 3, btnY, 6, OswUI::getInstance()->getForegroundDimmedColor()); - } - } -} - -#ifdef OSW_EMULATOR -void OswAppSwitcher::loopDebug() { - _apps[*_rtcAppIndex]->loopDebug(); -} -#endif - -void OswAppSwitcher::cycleApp() { - appOnScreenSince = millis(); - if(_pagination) { - _apps[*_rtcAppIndex]->stop(); - *_rtcAppIndex = *_rtcAppIndex + 1; - if (*_rtcAppIndex == _appCount) { - *_rtcAppIndex = 0; - } - _apps[*_rtcAppIndex]->setup(); - } - OswHal::getInstance()->suppressButtonUntilUp(_btn); -} - -void OswAppSwitcher::paginationDisable() { - _pagination = false; - _paginationIndicator = false; -} - -void OswAppSwitcher::paginationEnable() { - _pagination = true; - _paginationIndicator = true; -} - -void OswAppSwitcher::sleep() { - OswHal* hal = OswHal::getInstance(); - hal->gfx()->fill(rgb565(0, 0, 0)); - hal->flushCanvas(); - - appOnScreenSince = 0; // nasty hack to prevent re-sleep after wakeup from light sleep - hal->lightSleep(); -} - -void OswAppSwitcher::stop() { - _apps[*_rtcAppIndex]->stop(); -} - -void OswAppSwitcher::registerApp(OswApp* app) { - _appCount++; - _apps.push_back(app); -} diff --git a/src/apps/tools/OswAppTimeConfig.cpp b/src/apps/tools/OswAppTimeConfig.cpp index 8bc90c0e5..a5b7141fa 100644 --- a/src/apps/tools/OswAppTimeConfig.cpp +++ b/src/apps/tools/OswAppTimeConfig.cpp @@ -35,7 +35,6 @@ void OswAppTimeConfig::enterManualMode() { manualSettingTimestamp[9] = second / 10; manualSettingTimestamp[10] = second % 10; manualSettingScreen = true; - settingsAppSwitcher->paginationDisable(); } void OswAppTimeConfig::handleIncrementButton() { @@ -56,12 +55,10 @@ void OswAppTimeConfig::handleIncrementButton() { hal->setUTCTime(epoch - hal->getTimezoneOffsetPrimary()); manualSettingScreen = false; - settingsAppSwitcher->paginationEnable(); } } else if (manualSettingStep == 11) { // CANCEL if (hal->btnHasGoneDown(BUTTON_3)) { manualSettingScreen = false; - settingsAppSwitcher->paginationEnable(); } } else { // +1 if (hal->btnHasGoneDown(BUTTON_3)) { @@ -102,7 +99,6 @@ void OswAppTimeConfig::handleDecrementButton() { if (manualSettingStep == 11) { // CANCEL if (hal->btnHasGoneDown(BUTTON_2)) { manualSettingScreen = false; - settingsAppSwitcher->paginationEnable(); } } else { // -1 if (hal->btnHasGoneDown(BUTTON_2)) { diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index b6ab145f8..dd84cc5c4 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -137,7 +137,7 @@ void OswAppWatchface::handleButtonDefaults() { OswHal::getInstance()->decreaseBrightness(25); if (OswHal::getInstance()->btnIsLongPress(BUTTON_2)) { // Set default main-watchface without Web-interface. OswConfig::getInstance()->enableWrite(); - OswConfigAllKeys::settingDisplayDefaultWatchface.set(String(main_watchFaceIndex)); + // OswConfigAllKeys::settingDisplayDefaultWatchface.set(*this); // TODO make this work OswConfig::getInstance()->disableWrite(); } } diff --git a/src/globals.cpp b/src/globals.cpp index 56c609383..8ee7540cc 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -1,7 +1,8 @@ #include "globals.h" -RTC_DATA_ATTR uint16_t main_watchFaceIndex = 0; // This is overwritten on every setup() call anyways... -uint16_t main_currentAppIndex = 0; -uint16_t main_fitnessAppIndex = 0; -uint16_t main_clockAppIndex = 0; -uint16_t main_settingsAppIndex = 0; \ No newline at end of file +#include "apps/OswAppDrawer.h" +namespace OswGlobals { + RTC_DATA_ATTR size_t main_AppIndex = OswAppDrawer::UNDEFINED_SLEEP_APP_INDEX; + OswAppDrawer main_mainDrawer{&main_AppIndex}; + std::unique_ptr main_tutorialApp; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ae5597464..6dbf0b51d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,7 +9,6 @@ #include #include #include -#include //randomSeed #include //time #ifdef OSW_FEATURE_WIFI @@ -22,8 +21,8 @@ #endif // #include "./apps/_experiments/runtime_test.h" -#include "OswAppV2Compat.h" -#include "OswAppDrawer.h" +#include "apps/OswAppV2Compat.h" +#include "apps/OswAppDrawer.h" #include "apps/examples/OswAppExampleV1.h" #include "apps/examples/OswAppExampleV2.h" #include "apps/tools/OswAppTutorial.h" @@ -40,7 +39,6 @@ #include "./apps/clock/OswAppTimer.h" #include "./apps/tools/OswAppCalculator.h" #include "./apps/tools/OswAppFlashLight.h" -#include "./apps/main/switcher.h" #include "./apps/tools/button_test.h" #ifndef NDEBUG #include "./apps/tools/OswAppPrintDebug.h" @@ -73,12 +71,14 @@ #ifdef OSW_FEATURE_WIFI #include #endif - -//_experiment weather #ifdef OSW_FEATURE_WEATHER #include "./apps/_experiments/OswAppWeather.h" #endif + +// get global variables (make sure to NOT include any headers after the "using" statements!) #include "globals.h" +using OswGlobals::main_mainDrawer; +using OswGlobals::main_tutorialApp; #ifndef NDEBUG #define _MAIN_CRASH_SLEEP 10 @@ -86,20 +86,6 @@ #define _MAIN_CRASH_SLEEP 2 #endif -OswAppSwitcher mainAppSwitcher(BUTTON_1, LONG_PRESS, true, true, &main_currentAppIndex); -OswAppSwitcher watchFaceSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_watchFaceIndex); -OswAppSwitcher fitnessAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_fitnessAppIndex); -OswAppSwitcher clockAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_clockAppIndex); -OswAppSwitcher settingsAppSwitcher(BUTTON_1, SHORT_PRESS, false, false, &main_settingsAppIndex); - -// TODO temporary for testing -static OswAppExampleV1 exampleAppV1; -static OswAppExampleV2 exampleAppV2; - -RTC_DATA_ATTR size_t tempIndexSleepy = OswAppDrawer::UNDEFINED_SLEEP_APP_INDEX; -static OswAppDrawer mainDrawer{nullptr, 0, &tempIndexSleepy}; -std::unique_ptr tutorialApp; - void setup() { Serial.begin(115200); OSW_LOG_I("Welcome to the OSW-OS! This build is based on commit ", GIT_COMMIT_HASH, " from ", GIT_BRANCH_NAME, @@ -107,7 +93,6 @@ void setup() { // Load config as early as possible, to ensure everyone can access it. OswConfig::getInstance()->setup(); - main_watchFaceIndex = OswConfigAllKeys::settingDisplayDefaultWatchface.get().toInt(); // First setup hardware/sensors/display -> might be used by background services try { @@ -118,24 +103,30 @@ void setup() { ESP.restart(); } - watchFaceSwitcher.registerApp(new OswAppWatchface()); - watchFaceSwitcher.registerApp(new OswAppWatchfaceDigital()); - watchFaceSwitcher.registerApp(new OswAppWatchfaceMix()); - watchFaceSwitcher.registerApp(new OswAppWatchfaceDual()); - watchFaceSwitcher.registerApp(new OswAppWatchfaceFitness()); - watchFaceSwitcher.registerApp(new OswAppWatchfaceBinary()); - watchFaceSwitcher.registerApp(new OswAppWatchfaceMonotimer()); - watchFaceSwitcher.registerApp(new OswAppWatchfaceNumerals()); - mainAppSwitcher.registerApp(&watchFaceSwitcher); - mainAppSwitcher.setup(); + // TODO port all v1 watchfaces to v2, to allow for lazy loading + static OswAppWatchface watchfaceAnalog; + static OswAppWatchfaceDigital watchfaceDigital; + static OswAppWatchfaceMix watchfaceMix; + static OswAppWatchfaceDual watchfaceDual; + static OswAppWatchfaceFitness watchfaceFitness; + static OswAppWatchfaceBinary watchfaceBinary; + static OswAppWatchfaceMonotimer watchfaceMono; + static OswAppWatchfaceNumerals watchfaceNumerals; + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.nlg", "Analog", watchfaceAnalog)); + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.dgtl", "Digital", watchfaceDigital)); + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.mx", "Mix", watchfaceMix)); + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.dl", "Dual", watchfaceDual)); + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.ftnss", "Fitness", watchfaceFitness)); + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.bnry", "Binary", watchfaceBinary)); + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.mn", "Mono", watchfaceMono)); + main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.nmrls", "Numerals", watchfaceNumerals)); + main_mainDrawer.setDefault("osw.wf.nlg"); // OswConfigAllKeys::settingDisplayDefaultWatchface.get().toInt(); // TODO - // TODO temporary for testing - mainDrawer.registerAppLazy("OswAppV2"); - mainDrawer.registerApp("OswAppV1", new OswAppV2Compat("org.example.v1", "Example App v1", exampleAppV1)); - OswUI::getInstance()->setRootApplication(&mainDrawer); - tutorialApp.reset(new OswAppTutorial()); - if(!tutorialApp->changeRootAppIfNecessary()) - tutorialApp.reset(); // no need to keep it around, as it's not the root app + // Install drawer and (maybe) jump into tutorial + OswUI::getInstance()->setRootApplication(&main_mainDrawer); + main_tutorialApp.reset(new OswAppTutorial()); + if(!main_tutorialApp->changeRootAppIfNecessary()) + main_tutorialApp.reset(); // no need to keep it around, as it's not the root app #if USE_ULP == 1 // register the ULP program @@ -196,68 +187,90 @@ void loop() { if (delayedAppInit) { delayedAppInit = false; + + // TODO port all v1 apps to v2, to allow for lazy loading (or let them in compat mode) #if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) - mainAppSwitcher.registerApp(new OswAppMap()); + static OswAppMap gpsOswAppMap; + main_mainDrawer.registerApp("GPS", new OswAppV2Compat("osw.gps.map", "Map", gpsOswAppMap)); #endif #if OSW_PLATFORM_ENVIRONMENT_MAGNETOMETER == 1 && OSW_PLATFORM_HARDWARE_QMC5883L == 1 - mainAppSwitcher.registerApp(new OswAppMagnetometerCalibrate()); + static OswAppMagnetometerCalibrate gpsOswAppMC; + main_mainDrawer.registerApp("GPS", new OswAppV2Compat("osw.gps.mc", "Magnetometer Calibrate", gpsOswAppMC)); +#endif + +#if OSW_APPS_EXAMPLES == 1 + // For a short "How to write your own apps" see the examples below + main_mainDrawer.registerAppLazy("Examples"); // only v2 apps support lazy loading (for now) + static OswAppExampleV1 exampleV1; // this is a static object, so it will be kept in memory until the device is reset - but it kind of defeats the purpose of lazy loading (static object = initialized on bootup, not on first use) + main_mainDrawer.registerApp("Examples", new OswAppV2Compat("osw.example.v1", "Example App v1", exampleV1)); #endif - // For a short howto write your own apps see: app below - // mainAppSwitcher.registerApp(new OswAppHelloWorld()); // Fitness App #ifdef OSW_FEATURE_STATS_STEPS - fitnessAppSwitcher.registerApp(new OswAppStepStats()); - fitnessAppSwitcher.registerApp(new OswAppKcalStats()); - fitnessAppSwitcher.registerApp(new OswAppDistStats()); + static OswAppStepStats fitnessStepStats; + static OswAppKcalStats fitnessKcalStats; + static OswAppDistStats fitnessDistStats; + main_mainDrawer.registerApp("Fitness", new OswAppV2Compat("osw.fit.ss", "Step Statistics", fitnessStepStats)); + main_mainDrawer.registerApp("Fitness", new OswAppV2Compat("osw.fit.ks", "Kcal Statistics", fitnessKcalStats)); + main_mainDrawer.registerApp("Fitness", new OswAppV2Compat("osw.fit.ds", "Distance Statistics", fitnessDistStats)); #endif - fitnessAppSwitcher.registerApp(new OswAppFitnessStats()); - fitnessAppSwitcher.paginationEnable(); - mainAppSwitcher.registerApp(&fitnessAppSwitcher); + static OswAppFitnessStats fitnessStats; + main_mainDrawer.registerApp("Fitness", new OswAppV2Compat("osw.fit.fs", "Fitness Statistics", fitnessStats)); + + // Tools #if TOOL_CLOCK == 1 - clockAppSwitcher.registerApp(new OswAppStopWatch()); - clockAppSwitcher.registerApp(new OswAppTimer(&clockAppSwitcher)); - clockAppSwitcher.registerApp(new OswAppAlarm(&clockAppSwitcher)); - clockAppSwitcher.paginationEnable(); - mainAppSwitcher.registerApp(&clockAppSwitcher); + static OswAppStopWatch toolStopWatch; + static OswAppTimer toolTimer; + static OswAppAlarm toolAlarm; + main_mainDrawer.registerApp("Tools", new OswAppV2Compat("osw.tool.sw", "Stopwatch", toolStopWatch)); + main_mainDrawer.registerApp("Tools", new OswAppV2Compat("osw.tool.tm", "Timer", toolTimer)); + main_mainDrawer.registerApp("Tools", new OswAppV2Compat("osw.tool.al", "Alarm", toolAlarm)); #endif #if TOOL_FLASHLIGHT == 1 - mainAppSwitcher.registerApp(new OswAppFlashLight()); + static OswAppFlashLight toolFlashLight; + main_mainDrawer.registerApp("Tools", new OswAppV2Compat("osw.tool.fl", "Flashlight", toolFlashLight)); #endif #if TOOL_WATERLEVEL == 1 - mainAppSwitcher.registerApp(new OswAppWaterLevel()); + static OswAppWaterLevel toolWaterLevel; + main_mainDrawer.registerApp("Tools", new OswAppV2Compat("osw.tool.wl", "Water Level", toolWaterLevel)); #endif #if TOOL_CALCULATOR == 1 - mainAppSwitcher.registerApp(new OswAppCalculator()); + static OswAppCalculator toolCalculator; + main_mainDrawer.registerApp("Tools", new OswAppV2Compat("osw.tool.ca", "Calculator", toolCalculator)); #endif - //weather + + // Weather #ifdef OSW_FEATURE_WEATHER - mainAppSwitcher.registerApp(new OswAppWeather()); + static OswAppWeather weather; + main_mainDrawer.registerApp("Weather", new OswAppV2Compat("osw.weather", "Weather", weather)); #endif - // config + // Settings #ifdef OSW_FEATURE_WIFI - settingsAppSwitcher.registerApp(new OswAppWebserver()); + static OswAppWebserver configWifi; + main_mainDrawer.registerApp("Settings", new OswAppV2Compat("osw.sets.wifi", "WiFi", configWifi)); #endif - settingsAppSwitcher.registerApp(new OswAppTimeConfig(&settingsAppSwitcher)); + static OswAppTimeConfig configTime; + main_mainDrawer.registerApp("Settings", new OswAppV2Compat("osw.sets.time", "Time", configTime)); #ifndef NDEBUG - settingsAppSwitcher.registerApp(new OswAppPrintDebug()); + static OswAppPrintDebug configDebug; + main_mainDrawer.registerApp("Settings", new OswAppV2Compat("osw.sets.debug", "Debug", configDebug)); #endif - settingsAppSwitcher.paginationEnable(); - mainAppSwitcher.registerApp(&settingsAppSwitcher); - // games + // Games #if GAME_SNAKE == 1 - mainAppSwitcher.registerApp(new OswAppSnakeGame()); + static OswAppSnakeGame gameSnake; + main_mainDrawer.registerApp("Games", new OswAppV2Compat("osw.game.snake", "Snake", gameSnake)); #endif - #if GAME_BRICK_BREAKER == 1 - mainAppSwitcher.registerApp(new OswAppBrickBreaker()); + static OswAppBrickBreaker gameBrickBreaker; + main_mainDrawer.registerApp("Games", new OswAppV2Compat("osw.game.brick", "Brick Breaker", gameBrickBreaker)); #endif #ifdef OSW_FEATURE_LUA - mainAppSwitcher.registerApp(new OswLuaApp("stopwatch.lua")); + static OswLuaApp luaApp("stopwatch.lua"); + main_mainDrawer.registerApp("LUA", new OswAppV2Compat("osw.lua", "Demo", luaApp)); #endif } diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index 5fc7adbb4..789822451 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -1,4 +1,3 @@ -#include #include #include From b711a8712d3f04b9c280133786ec798776faf2cc Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 18:40:02 +0200 Subject: [PATCH 062/141] Added missing assert --- src/apps/OswAppDrawer.cpp | 1 + src/osw_ui.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/apps/OswAppDrawer.cpp b/src/apps/OswAppDrawer.cpp index 37a0ee6af..3b3480c17 100644 --- a/src/apps/OswAppDrawer.cpp +++ b/src/apps/OswAppDrawer.cpp @@ -1,3 +1,4 @@ +#include #include #include diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index 789822451..3ab4b9cf1 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -1,6 +1,7 @@ +#include + #include #include - #include #include From a61180236506ed6f475f82090b756107a19de87f Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 19:02:36 +0200 Subject: [PATCH 063/141] Do not report any buttons by default - require explicit registration --- include/OswAppV2.h | 2 +- src/OswAppV2.cpp | 7 +++---- src/apps/OswAppDrawer.cpp | 4 ++-- src/apps/OswAppV2Compat.cpp | 3 +++ src/apps/examples/OswAppExampleV2.cpp | 13 +++++++++---- src/apps/tools/OswAppTutorial.cpp | 6 ++++-- 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index 5ba51b7af..3763b8092 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -54,7 +54,7 @@ class OswAppV2 { ViewFlags viewFlags = ViewFlags::NONE; bool needsRedraw = false; OswIcon& getDefaultAppIcon(); - void clearKnownButtonStates(bool useDefaults); + void clearKnownButtonStates(); private: static OswIcon defaultAppIcon; diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 0996382ae..bf6258a06 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -33,13 +33,12 @@ void OswAppV2::resetNeedsRedraw() { void OswAppV2::onStart() { this->needsRedraw = true; - this->clearKnownButtonStates(true); + this->clearKnownButtonStates(); } -void OswAppV2::clearKnownButtonStates(bool useDefaults) { +void OswAppV2::clearKnownButtonStates() { for(int i = 0; i < NUM_BUTTONS; i++) - // Do not listen to the double press, as it may delays the short press reporting - this->knownButtonStates[i] = (ButtonStateNames) (useDefaults ? (ButtonStateNames::UNDEFINED | ButtonStateNames::SHORT_PRESS | ButtonStateNames::LONG_PRESS | ButtonStateNames::VERY_LONG_PRESS) : 0); + this->knownButtonStates[i] = (ButtonStateNames) 0; // By default no buttons are supported } void OswAppV2::onLoop() { diff --git a/src/apps/OswAppDrawer.cpp b/src/apps/OswAppDrawer.cpp index 3b3480c17..6aa901228 100644 --- a/src/apps/OswAppDrawer.cpp +++ b/src/apps/OswAppDrawer.cpp @@ -273,7 +273,7 @@ void OswAppDrawer::drawer() { return; this->current->get()->onStop(); this->current = nullptr; - this->clearKnownButtonStates(false); + this->clearKnownButtonStates(); this->knownButtonStates[Button::BUTTON_UP] = ButtonStateNames::SHORT_PRESS; this->knownButtonStates[Button::BUTTON_DOWN] = ButtonStateNames::SHORT_PRESS; this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::SHORT_PRESS; @@ -282,7 +282,7 @@ void OswAppDrawer::drawer() { void OswAppDrawer::open(LazyInit& app) { this->drawer(); // stop current app (by "opening" the drawer), ignores if drawer is already open - this->clearKnownButtonStates(false); + this->clearKnownButtonStates(); this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::LONG_PRESS; // start app diff --git a/src/apps/OswAppV2Compat.cpp b/src/apps/OswAppV2Compat.cpp index b92505eb8..73f65ccfb 100644 --- a/src/apps/OswAppV2Compat.cpp +++ b/src/apps/OswAppV2Compat.cpp @@ -14,6 +14,9 @@ const char* OswAppV2Compat::getAppName() { void OswAppV2Compat::onStart() { this->viewFlags = (OswAppV2::ViewFlags)(this->viewFlags | OswAppV2::ViewFlags::NO_FPS_LIMIT); // this causes draw() to be called upon every loop() call -> preventing the loss of input events (like the button just went down) + // Listen to ALL the typical button events (while not processed, it allows animations to be shown for them) + for(int i = 0; i < NUM_BUTTONS; i++) + this->knownButtonStates[i] = (ButtonStateNames) (ButtonStateNames::UNDEFINED | ButtonStateNames::SHORT_PRESS | ButtonStateNames::LONG_PRESS | ButtonStateNames::VERY_LONG_PRESS); this->app.setup(); } diff --git a/src/apps/examples/OswAppExampleV2.cpp b/src/apps/examples/OswAppExampleV2.cpp index 6e10951cb..5fe05f060 100644 --- a/src/apps/examples/OswAppExampleV2.cpp +++ b/src/apps/examples/OswAppExampleV2.cpp @@ -21,10 +21,15 @@ void OswAppExampleV2::onStart() { OswAppV2::onStart(); // always make sure to call the base class method! // This is where you initialise code, gets called before this app is shown - // This app also "supports" double presses (on BUTTON_SELECT), note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) - this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit - // ...but this will delay the processing of the "image" button - so we will disable it again ;) - this->knownButtonStates[BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[BUTTON_SELECT] ^ OswAppV2::ButtonStateNames::DOUBLE_PRESS); // XOR to toggle the bit + // Report that we support short presses on all buttons + this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::SHORT_PRESS; + this->knownButtonStates[Button::BUTTON_UP] = ButtonStateNames::SHORT_PRESS; + this->knownButtonStates[Button::BUTTON_DOWN] = ButtonStateNames::SHORT_PRESS; + + // Here is a snippet to also "support" double presses (on BUTTON_SELECT) - note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) + this->knownButtonStates[Button::BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[Button::BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit + // ...so we will disable it again ;) + this->knownButtonStates[Button::BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[Button::BUTTON_SELECT] ^ OswAppV2::ButtonStateNames::DOUBLE_PRESS); // XOR to toggle the bit this->start = time(nullptr); // used as offset for the counter later on this->viewFlags = (OswAppV2::ViewFlags) (this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); // by default we want to keep the display on diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 70d69d4c6..2ebda7882 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -29,10 +29,12 @@ const char* OswAppTutorial::getAppName() { void OswAppTutorial::onStart() { OswAppV2::onStart(); // always make sure to call the base class method! + this->viewFlags = (OswAppV2::ViewFlags) (this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); + for(int i = 0; i < NUM_BUTTONS; i++) + this->knownButtonStates[i] = ButtonStateNames::SHORT_PRESS; this->screen = 0; this->timeout = time(nullptr); - this->viewFlags = (OswAppV2::ViewFlags) (this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON); } void OswAppTutorial::onLoop() { @@ -167,7 +169,7 @@ void OswAppTutorial::onButton(int id, bool up, OswAppV2::ButtonStateNames state) this->screen = 1; // Also enable double press detection for(int i = 0; i < NUM_BUTTONS; i++) - this->knownButtonStates[i] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[i] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); + this->knownButtonStates[i] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[i] | OswAppV2::ButtonStateNames::DOUBLE_PRESS | OswAppV2::ButtonStateNames::LONG_PRESS | OswAppV2::ButtonStateNames::VERY_LONG_PRESS | OswAppV2::ButtonStateNames::DOUBLE_PRESS); } else if(this->screen == 1) { if(state == OswAppV2::ButtonStateNames::SHORT_PRESS) this->gotButtonShort = true; From 791b4ea45c1d53113dd6382200d6aa3e38eb949f Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 19:40:01 +0200 Subject: [PATCH 064/141] Allow indirect casting --- include/OswAppV2.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/OswAppV2.h b/include/OswAppV2.h index 3763b8092..1c1e504e3 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -3,6 +3,7 @@ #include #include +#include class OswHal; class OswAppV2 { @@ -47,9 +48,16 @@ class OswAppV2 { public: // This will proxy the "->" operator to use the current instance of OswHal OswHal* operator->() { return OswHal::getInstance(); }; + operator OswHal*() { return OswHal::getInstance(); }; // We intentionally do not provide an operation to implicitly convert to OswHal* to prevent accidental use of the wrong instance }; OswHalProxy hal; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 + class OswUiProxy { + public: + OswUI* operator->() { return OswUI::getInstance(); }; + operator OswUI*() { return OswUI::getInstance(); }; + }; + OswUiProxy ui; std::array knownButtonStates; // Bitmask of known button states (ignores the DOUBLE_PRESS state by default), use this to ignore unhandled button states ViewFlags viewFlags = ViewFlags::NONE; bool needsRedraw = false; From 40667371e2d37956a7c3acd0a77bec335d167222 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 19:41:10 +0200 Subject: [PATCH 065/141] Ported analog watchface to v2 --- include/apps/watchfaces/OswAppWatchface.h | 24 ++++---- include/config_defaults.h | 7 ++- src/apps/OswAppDrawer.cpp | 1 - src/apps/watchfaces/OswAppWatchface.cpp | 70 +++++++++++++++++------ src/main.cpp | 5 +- src/osw_config_keys.cpp | 4 +- 6 files changed, 75 insertions(+), 36 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchface.h b/include/apps/watchfaces/OswAppWatchface.h index f58199bcf..1e57ef39f 100644 --- a/include/apps/watchfaces/OswAppWatchface.h +++ b/include/apps/watchfaces/OswAppWatchface.h @@ -3,28 +3,32 @@ #include #include -#include +#include #ifdef ANIMATION #include #endif class OswAppGifPlayer; -class OswAppWatchface : public OswApp { +class OswAppWatchface : public OswAppV2 { public: - OswAppWatchface(void) { - ui = OswUI::getInstance(); - }; - virtual void setup() override; - virtual void loop() override; - virtual void stop() override; - ~OswAppWatchface() {}; + constexpr static const char* APP_ID = "osw.wf.analog"; + const char* getAppId() override; + const char* getAppName() override; + + void onStart() override; + void onLoop() override; + void onDraw() override; + void onStop() override; + void onButton(int id, bool up, ButtonStateNames state) override; #ifdef OSW_FEATURE_STATS_STEPS static void drawStepHistory(OswUI* ui, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint32_t max); #endif static void handleButtonDefaults(); + static void onButtonDefaults(OswAppV2& app, int id, bool up, ButtonStateNames state); private: - OswUI* ui; + time_t lastTime = 0; + void drawWatch(); #ifdef ANIMATION AnimMatrix* matrix; diff --git a/include/config_defaults.h b/include/config_defaults.h index aeefa029c..22140c4a6 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -181,9 +181,10 @@ #define CONFIG_TIMEZONE_SECONDARY "" #endif -// Set the initial value for the watchface to the index below - make sure to only use a valid index! -#ifndef CONFIG_DEFAULT_WATCHFACE_INDEX -#define CONFIG_DEFAULT_WATCHFACE_INDEX 0 +// Set the initial value for the watchface to the index below +// This can be a small snippet to get the id of the app, or the app id itself +#ifndef CONFIG_DEFAULT_WATCHFACE_ID +#define CONFIG_DEFAULT_WATCHFACE_ID OswAppWatchface::APP_ID #endif #ifndef STEPS_PER_DAY diff --git a/src/apps/OswAppDrawer.cpp b/src/apps/OswAppDrawer.cpp index 6aa901228..703eda5fc 100644 --- a/src/apps/OswAppDrawer.cpp +++ b/src/apps/OswAppDrawer.cpp @@ -67,7 +67,6 @@ void OswAppDrawer::onStart() { if(defaultApp != nullptr) break; } - } else { } } diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index dd84cc5c4..2c02cc902 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -1,22 +1,26 @@ - -#include "./apps/watchfaces/OswAppWatchface.h" -// #define GIF_BG - -#ifdef ANIMATION -#include -#endif - #include -#include #include #include #include #include "globals.h" +#ifdef ANIMATION +#include +#endif #ifdef GIF_BG #include "./apps/_experiments/gif_player.h" #endif +#include "./apps/watchfaces/OswAppWatchface.h" + +const char* OswAppWatchface::getAppId() { + return OswAppWatchface::APP_ID; +} + +const char* OswAppWatchface::getAppName() { + return "Analog"; +} + #ifdef OSW_FEATURE_STATS_STEPS void OswAppWatchface::drawStepHistory(OswUI* ui, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint32_t max) { OswHal* hal = OswHal::getInstance(); @@ -115,7 +119,12 @@ void OswAppWatchface::drawWatch() { #endif } -void OswAppWatchface::setup() { +#ifdef GIF_BG +OswAppGifPlayer* bgGif = new OswAppGifPlayer(); +#endif + +void OswAppWatchface::onStart() { + OswAppV2::onStart(); #ifdef GIF_BG this->bgGif = new OswAppGifPlayer(); this->bgGif->setup(); @@ -131,19 +140,21 @@ void OswAppWatchface::setup() { * */ void OswAppWatchface::handleButtonDefaults() { + OSW_LOG_W("TODO remove this function!"); // TODO ;) if (OswHal::getInstance()->btnHasGoneDown(BUTTON_3)) OswHal::getInstance()->increaseBrightness(25); if (OswHal::getInstance()->btnHasGoneDown(BUTTON_2)) OswHal::getInstance()->decreaseBrightness(25); - if (OswHal::getInstance()->btnIsLongPress(BUTTON_2)) { // Set default main-watchface without Web-interface. - OswConfig::getInstance()->enableWrite(); - // OswConfigAllKeys::settingDisplayDefaultWatchface.set(*this); // TODO make this work - OswConfig::getInstance()->disableWrite(); - } } -void OswAppWatchface::loop() { - this->handleButtonDefaults(); +void OswAppWatchface::onLoop() { + OswAppV2::onLoop(); + + this->needsRedraw = this->needsRedraw or time(nullptr) != this->lastTime; // redraw every second +} + +void OswAppWatchface::onDraw() { + OswAppV2::onDraw(); #ifdef GIF_BG if(this->bgGif != nullptr) @@ -154,9 +165,32 @@ void OswAppWatchface::loop() { matrix->loop(OswHal::getInstance()->gfx()); #endif drawWatch(); + + this->lastTime = time(nullptr); +} + +void OswAppWatchface::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { + OswAppWatchface::onButtonDefaults(*this, id, up, state); +} + +void OswAppWatchface::onButtonDefaults(OswAppV2& app, int id, bool up, OswAppV2::ButtonStateNames state) { + if(!up) return; + if(state == OswAppV2::ButtonStateNames::SHORT_PRESS) { + if(id == Button::BUTTON_UP) { + OswHal::getInstance()->increaseBrightness(25); + } else if(id == Button::BUTTON_DOWN) { + OswHal::getInstance()->decreaseBrightness(25); + } + } else if(state == OswAppV2::ButtonStateNames::LONG_PRESS and id == Button::BUTTON_DOWN) { + OSW_LOG_I("Setting default watchface to: ", app.getAppId()); + OswConfig::getInstance()->enableWrite(); + OswConfigAllKeys::settingDisplayDefaultWatchface.set(app.getAppId()); + OswConfig::getInstance()->disableWrite(); + } } -void OswAppWatchface::stop() { +void OswAppWatchface::onStop() { + OswAppV2::onStop(); #ifdef GIF_BG if(this->bgGif != nullptr) { this->bgGif->stop(); diff --git a/src/main.cpp b/src/main.cpp index 6dbf0b51d..1d060d829 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,7 +104,6 @@ void setup() { } // TODO port all v1 watchfaces to v2, to allow for lazy loading - static OswAppWatchface watchfaceAnalog; static OswAppWatchfaceDigital watchfaceDigital; static OswAppWatchfaceMix watchfaceMix; static OswAppWatchfaceDual watchfaceDual; @@ -112,7 +111,7 @@ void setup() { static OswAppWatchfaceBinary watchfaceBinary; static OswAppWatchfaceMonotimer watchfaceMono; static OswAppWatchfaceNumerals watchfaceNumerals; - main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.nlg", "Analog", watchfaceAnalog)); + main_mainDrawer.registerAppLazy("Watchfaces"); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.dgtl", "Digital", watchfaceDigital)); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.mx", "Mix", watchfaceMix)); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.dl", "Dual", watchfaceDual)); @@ -120,7 +119,7 @@ void setup() { main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.bnry", "Binary", watchfaceBinary)); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.mn", "Mono", watchfaceMono)); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.nmrls", "Numerals", watchfaceNumerals)); - main_mainDrawer.setDefault("osw.wf.nlg"); // OswConfigAllKeys::settingDisplayDefaultWatchface.get().toInt(); // TODO + main_mainDrawer.setDefault(OswConfigAllKeys::settingDisplayDefaultWatchface.get().c_str()); // if this id is invalid, the drawer will fall back to alternatives automatically // Install drawer and (maybe) jump into tutorial OswUI::getInstance()->setRootApplication(&main_mainDrawer); diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index c242736a6..1859b2e23 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -8,6 +8,8 @@ #include "gfx_util.h" #include "osw_util.h" +#include "apps/watchfaces/OswAppWatchface.h" + /** * !!!WARNING!!! * @@ -47,7 +49,7 @@ OswConfigKeyShort settingDisplayTimeout("s2", "Display", "Display Timeout", OswConfigKeyBool settingDisplayOverlays("s3", "Display", "Display Overlays", "Show overlays at all", DISPLAY_OVERLAYS); OswConfigKeyBool settingDisplayOverlaysOnWatchScreen("s4", "Display", "Display Watchface Overlays", nullptr, DISPLAY_OVERLAYS_ON_WF); OswConfigKeyDropDown settingDisplayDefaultWatchface("n", "Display", - "Default Watchface ID (analog, digital, mix, Dual-time, Fitness-tracking, binary, monotimer, numerals)", {"0", "1","2","3","4","5","6","7"}, CONFIG_DEFAULT_WATCHFACE_INDEX); + "Default Watchface App ID", {OswAppWatchface::APP_ID}, CONFIG_DEFAULT_WATCHFACE_ID); OswConfigKeyBool settingDisplayDualHourTick("h2", "Display", "Display Dual-Time Hour Tick", "Show dual time hour tick", false); #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 OswConfigKeyBool settingDisplayStepsGoal("g1", "Display", "Display Steps Goal", "Show goal steps", true); From 133e376ceadfa261dd3ed380da025127d4281708 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 19:57:42 +0200 Subject: [PATCH 066/141] Ported digital watchface to v2 --- .../apps/watchfaces/OswAppWatchfaceDigital.h | 23 +++++----- src/apps/watchfaces/OswAppWatchface.cpp | 2 + .../watchfaces/OswAppWatchfaceDigital.cpp | 42 +++++++++++++------ src/main.cpp | 3 +- src/osw_config_keys.cpp | 3 +- 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchfaceDigital.h b/include/apps/watchfaces/OswAppWatchfaceDigital.h index 215327c41..91f6ce758 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDigital.h +++ b/include/apps/watchfaces/OswAppWatchfaceDigital.h @@ -3,17 +3,20 @@ #include #include -#include +#include -class OswAppWatchfaceDigital : public OswApp { +class OswAppWatchfaceDigital: public OswAppV2 { public: - OswAppWatchfaceDigital(void) { - ui = OswUI::getInstance(); - }; - virtual void setup() override; - virtual void loop() override; - virtual void stop() override; - ~OswAppWatchfaceDigital() {}; + constexpr static const char* APP_ID = "osw.wf.digital"; + + const char* getAppId() override; + const char* getAppName() override; + + void onStart() override; + void onLoop() override; + void onDraw() override; + void onButton(int id, bool up, ButtonStateNames state) override; + inline static uint8_t getDateFormat(); // Return 0 : mm/dd/yyyy 1 : dd.mm.yyyy 2 : yy.mm/dd static void refreshDateFormatCache(); static void drawSteps(); @@ -23,6 +26,6 @@ class OswAppWatchfaceDigital : public OswApp { static void displayWeekDay3(const char* weekday); private: - OswUI* ui; static uint8_t dateFormatCache; + time_t lastTime = 0; }; \ No newline at end of file diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index 2c02cc902..25af94018 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -125,6 +125,7 @@ OswAppGifPlayer* bgGif = new OswAppGifPlayer(); void OswAppWatchface::onStart() { OswAppV2::onStart(); + // TODO register known buttons (also the static ones) #ifdef GIF_BG this->bgGif = new OswAppGifPlayer(); this->bgGif->setup(); @@ -170,6 +171,7 @@ void OswAppWatchface::onDraw() { } void OswAppWatchface::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { + OswAppV2::onButton(id, up, state); OswAppWatchface::onButtonDefaults(*this, id, up, state); } diff --git a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp index d555d32d6..453f0964e 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp @@ -1,13 +1,12 @@ -#include "./apps/watchfaces/OswAppWatchfaceDigital.h" -#include "./apps/watchfaces/OswAppWatchface.h" - #include #include -#include #include #include #include +#include "./apps/watchfaces/OswAppWatchface.h" +#include "./apps/watchfaces/OswAppWatchfaceDigital.h" + uint8_t OswAppWatchfaceDigital::dateFormatCache = 42; uint8_t OswAppWatchfaceDigital::getDateFormat() { @@ -33,6 +32,7 @@ void OswAppWatchfaceDigital::displayWeekDay3(const char* weekday) { weekday3[3] = '\0'; hal->gfx()->print(weekday3); } + void OswAppWatchfaceDigital::dateOutput(uint32_t yearInt, uint32_t monthInt, uint32_t dayInt) { OswHal* hal = OswHal::getInstance(); switch (OswAppWatchfaceDigital::getDateFormat()) { @@ -60,7 +60,7 @@ void OswAppWatchfaceDigital::dateOutput(uint32_t yearInt, uint32_t monthInt, uin } } -void drawDate(time_t timeZone, uint8_t fontSize, uint8_t CoordY) { +static void drawDate(time_t timeZone, uint8_t fontSize, uint8_t CoordY) { uint32_t dayInt = 0; uint32_t monthInt = 0; uint32_t yearInt = 0; @@ -100,7 +100,7 @@ void OswAppWatchfaceDigital::timeOutput(uint32_t hour, uint32_t minute, uint32_t } } -void drawTime(time_t timeZone,uint8_t CoordY) { +static void drawTime(time_t timeZone,uint8_t CoordY) { uint32_t second = 0; uint32_t minute = 0; uint32_t hour = 0; @@ -126,6 +126,14 @@ void drawTime(time_t timeZone,uint8_t CoordY) { } } +const char* OswAppWatchfaceDigital::getAppId() { + return OswAppWatchfaceDigital::APP_ID; +} + +const char* OswAppWatchfaceDigital::getAppName() { + return "Digital"; +} + void OswAppWatchfaceDigital::drawSteps() { #ifdef OSW_FEATURE_STATS_STEPS uint8_t w = 8; @@ -148,19 +156,29 @@ void OswAppWatchfaceDigital::digitalWatch(short timeZone,uint8_t fontSize, uint8 drawTime(timeZone,timeCoordY); } -void OswAppWatchfaceDigital::setup() { +void OswAppWatchfaceDigital::onStart() { + OswAppV2::onStart(); + // TODO register known buttons (also the static ones) } -void OswAppWatchfaceDigital::loop() { - OswAppWatchface::handleButtonDefaults(); +void OswAppWatchfaceDigital::onLoop() { + OswAppV2::onLoop(); + this->needsRedraw = this->needsRedraw or time(nullptr) != this->lastTime; // redraw every second +} + +void OswAppWatchfaceDigital::onDraw() { + OswAppV2::onDraw(); digitalWatch(OswHal::getInstance()->getTimezoneOffsetPrimary(), 2, 80, 120); #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 drawSteps(); #endif -} -void OswAppWatchfaceDigital::stop() { - // OswHal::getInstance()->disableDisplayBuffer(); + this->lastTime = time(nullptr); } + +void OswAppWatchfaceDigital::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { + OswAppV2::onButton(id, up, state); + OswAppWatchface::onButtonDefaults(*this, id, up, state); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1d060d829..f81e88881 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,7 +104,6 @@ void setup() { } // TODO port all v1 watchfaces to v2, to allow for lazy loading - static OswAppWatchfaceDigital watchfaceDigital; static OswAppWatchfaceMix watchfaceMix; static OswAppWatchfaceDual watchfaceDual; static OswAppWatchfaceFitness watchfaceFitness; @@ -112,7 +111,7 @@ void setup() { static OswAppWatchfaceMonotimer watchfaceMono; static OswAppWatchfaceNumerals watchfaceNumerals; main_mainDrawer.registerAppLazy("Watchfaces"); - main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.dgtl", "Digital", watchfaceDigital)); + main_mainDrawer.registerAppLazy("Watchfaces"); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.mx", "Mix", watchfaceMix)); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.dl", "Dual", watchfaceDual)); main_mainDrawer.registerApp("Watchfaces", new OswAppV2Compat("osw.wf.ftnss", "Fitness", watchfaceFitness)); diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 1859b2e23..ceb9d894d 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -9,6 +9,7 @@ #include "osw_util.h" #include "apps/watchfaces/OswAppWatchface.h" +#include "apps/watchfaces/OswAppWatchfaceDigital.h" /** * !!!WARNING!!! @@ -49,7 +50,7 @@ OswConfigKeyShort settingDisplayTimeout("s2", "Display", "Display Timeout", OswConfigKeyBool settingDisplayOverlays("s3", "Display", "Display Overlays", "Show overlays at all", DISPLAY_OVERLAYS); OswConfigKeyBool settingDisplayOverlaysOnWatchScreen("s4", "Display", "Display Watchface Overlays", nullptr, DISPLAY_OVERLAYS_ON_WF); OswConfigKeyDropDown settingDisplayDefaultWatchface("n", "Display", - "Default Watchface App ID", {OswAppWatchface::APP_ID}, CONFIG_DEFAULT_WATCHFACE_ID); + "Default Watchface App ID", {OswAppWatchface::APP_ID, OswAppWatchfaceDigital::APP_ID}, CONFIG_DEFAULT_WATCHFACE_ID); OswConfigKeyBool settingDisplayDualHourTick("h2", "Display", "Display Dual-Time Hour Tick", "Show dual time hour tick", false); #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 OswConfigKeyBool settingDisplayStepsGoal("g1", "Display", "Display Steps Goal", "Show goal steps", true); From 0ba204a1be65daabf4b1aadd3a272573acb81971 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 20:03:15 +0200 Subject: [PATCH 067/141] Corrected wrong legacy-numbering of buttons --- include/hal/buttons.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/hal/buttons.h b/include/hal/buttons.h index 268be1e1e..984c823f3 100644 --- a/include/hal/buttons.h +++ b/include/hal/buttons.h @@ -9,8 +9,8 @@ enum Button { BUTTON_DOWN = 2, // Historical reasons ↓ BUTTON_1 = 0, - BUTTON_2 = 1, - BUTTON_3 = 2 + BUTTON_2 = 2, + BUTTON_3 = 1 }; extern const char* ButtonNames[]; \ No newline at end of file From c7fa20b52579451a1c90298f9f6b8f002e0cbea9 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 20:07:40 +0200 Subject: [PATCH 068/141] Fixed missing state-filter for button events on up-states --- src/OswAppV2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index bf6258a06..204c75e79 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -87,7 +87,7 @@ void OswAppV2::onLoop() { } } else buttonDoubleShortTimeout[i] = 0; // Reset the double press timeout on any other button state - if(buttonLastSentState[i] != ButtonStateNames::UNDEFINED) + if(buttonLastSentState[i] != ButtonStateNames::UNDEFINED and this->knownButtonStates[i] & buttonLastSentState[i]) this->onButton(i, true, buttonLastSentState[i]); buttonDownSince[i] = 0; buttonLastSentState[i] = ButtonStateNames::UNDEFINED; From e0c805c996db2895d96afc094089e8be4b985264 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 20:13:50 +0200 Subject: [PATCH 069/141] Added missing masking for default buttons --- include/apps/watchfaces/OswAppWatchface.h | 3 ++- src/apps/watchfaces/OswAppWatchface.cpp | 18 ++++++++++++++---- src/apps/watchfaces/OswAppWatchfaceDigital.cpp | 5 +++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchface.h b/include/apps/watchfaces/OswAppWatchface.h index 1e57ef39f..b7a0b29a8 100644 --- a/include/apps/watchfaces/OswAppWatchface.h +++ b/include/apps/watchfaces/OswAppWatchface.h @@ -25,7 +25,8 @@ class OswAppWatchface : public OswAppV2 { static void drawStepHistory(OswUI* ui, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint32_t max); #endif static void handleButtonDefaults(); - static void onButtonDefaults(OswAppV2& app, int id, bool up, ButtonStateNames state); + static void addButtonDefaults(std::array& knownButtonStates); + static bool onButtonDefaults(OswAppV2& app, int id, bool up, ButtonStateNames state); private: time_t lastTime = 0; diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index 25af94018..91904b5e0 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -125,7 +125,7 @@ OswAppGifPlayer* bgGif = new OswAppGifPlayer(); void OswAppWatchface::onStart() { OswAppV2::onStart(); - // TODO register known buttons (also the static ones) + OswAppWatchface::addButtonDefaults(this->knownButtonStates); #ifdef GIF_BG this->bgGif = new OswAppGifPlayer(); this->bgGif->setup(); @@ -172,23 +172,33 @@ void OswAppWatchface::onDraw() { void OswAppWatchface::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { OswAppV2::onButton(id, up, state); - OswAppWatchface::onButtonDefaults(*this, id, up, state); + if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) + return; // if the button was handled by the defaults, we are done here } -void OswAppWatchface::onButtonDefaults(OswAppV2& app, int id, bool up, OswAppV2::ButtonStateNames state) { - if(!up) return; +void OswAppWatchface::addButtonDefaults(std::array& knownButtonStates) { + knownButtonStates[Button::BUTTON_UP] = (OswAppV2::ButtonStateNames) (OswAppV2::ButtonStateNames::SHORT_PRESS | OswAppV2::ButtonStateNames::LONG_PRESS); + knownButtonStates[Button::BUTTON_DOWN] = OswAppV2::ButtonStateNames::SHORT_PRESS; +} + +bool OswAppWatchface::onButtonDefaults(OswAppV2& app, int id, bool up, OswAppV2::ButtonStateNames state) { + if(!up) return false; if(state == OswAppV2::ButtonStateNames::SHORT_PRESS) { if(id == Button::BUTTON_UP) { OswHal::getInstance()->increaseBrightness(25); + return true; } else if(id == Button::BUTTON_DOWN) { OswHal::getInstance()->decreaseBrightness(25); + return true; } } else if(state == OswAppV2::ButtonStateNames::LONG_PRESS and id == Button::BUTTON_DOWN) { OSW_LOG_I("Setting default watchface to: ", app.getAppId()); OswConfig::getInstance()->enableWrite(); OswConfigAllKeys::settingDisplayDefaultWatchface.set(app.getAppId()); OswConfig::getInstance()->disableWrite(); + return true; } + return false; } void OswAppWatchface::onStop() { diff --git a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp index 453f0964e..1e294f1a7 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp @@ -158,7 +158,7 @@ void OswAppWatchfaceDigital::digitalWatch(short timeZone,uint8_t fontSize, uint8 void OswAppWatchfaceDigital::onStart() { OswAppV2::onStart(); - // TODO register known buttons (also the static ones) + OswAppWatchface::addButtonDefaults(this->knownButtonStates); } void OswAppWatchfaceDigital::onLoop() { @@ -180,5 +180,6 @@ void OswAppWatchfaceDigital::onDraw() { void OswAppWatchfaceDigital::onButton(int id, bool up, OswAppV2::ButtonStateNames state) { OswAppV2::onButton(id, up, state); - OswAppWatchface::onButtonDefaults(*this, id, up, state); + if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) + return; // if the button was handled by the defaults, we are done here } \ No newline at end of file From cb44d09db8a99061f636232bf2e83c2e306f423d Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sat, 1 Apr 2023 20:17:20 +0200 Subject: [PATCH 070/141] Fix broken include --- src/apps/watchfaces/OswAppWatchfaceDigital.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp index 1e294f1a7..a5ea8a9cb 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include From d53b1c6fd295813a04b89c573cc6afdc46950feb Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sun, 2 Apr 2023 15:06:45 +0200 Subject: [PATCH 071/141] Do not show button animation if not supported --- src/OswAppV2.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 204c75e79..de6d07b2c 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -125,6 +125,10 @@ void OswAppV2::onDraw() { void OswAppV2::onDrawOverlay() { // IDEA for monochrome displays: Just draw a (in length) increasing circle-arc, for very long fill it completely for(int i = 0; i < NUM_BUTTONS; i++) { + // Is the button supported? + if(this->knownButtonStates[i] == 0) + continue; + // If the button is not down, skip it if(this->buttonIndicatorProgress[i] == 0.0) continue; @@ -142,15 +146,16 @@ void OswAppV2::onDrawOverlay() { btnY += btnOffset; const int16_t longRad = 24; - const int16_t veryLongRad = 12; - if(this->buttonIndicatorProgress[i] <= 1.0) - hal->gfx()->fillCircle(btnX, btnY, this->buttonIndicatorProgress[i] * longRad, OswUI::getInstance()->getPrimaryColor()); - else { - float overcut = 0.2; - float secondRad = (1.0 + overcut) * veryLongRad; + const int16_t veryLongRad = 14; + if(this->knownButtonStates[i] & ButtonStateNames::VERY_LONG_PRESS and this->buttonIndicatorProgress[i] > 1.0) { + // Very long-press circle + const float overcut = 0.2; + const float secondRad = (1.0 + overcut) * veryLongRad; hal->gfx()->fillCircle(btnX, btnY, (1.0 - overcut) * longRad + (this->buttonIndicatorProgress[i] - 1.0) * secondRad, OswUI::getInstance()->getWarningColor()); - - hal->gfx()->fillCircle(btnX, btnY, longRad, OswUI::getInstance()->getPrimaryColor()); + } + if(this->knownButtonStates[i] & ButtonStateNames::LONG_PRESS) { + // Long-press circle (shown if long press is supported and - if long press is not supported - also shown) + hal->gfx()->fillCircle(btnX, btnY, min(this->buttonIndicatorProgress[i] * longRad, longRad), OswUI::getInstance()->getPrimaryColor()); } } } From 224d9326874724dc08d1b26a6a1dcbb93f465f72 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sun, 2 Apr 2023 15:07:06 +0200 Subject: [PATCH 072/141] Corrected swapped button assignments --- src/apps/watchfaces/OswAppWatchface.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index 91904b5e0..d686eebe5 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -177,8 +177,8 @@ void OswAppWatchface::onButton(int id, bool up, OswAppV2::ButtonStateNames state } void OswAppWatchface::addButtonDefaults(std::array& knownButtonStates) { - knownButtonStates[Button::BUTTON_UP] = (OswAppV2::ButtonStateNames) (OswAppV2::ButtonStateNames::SHORT_PRESS | OswAppV2::ButtonStateNames::LONG_PRESS); - knownButtonStates[Button::BUTTON_DOWN] = OswAppV2::ButtonStateNames::SHORT_PRESS; + knownButtonStates[Button::BUTTON_UP] = OswAppV2::ButtonStateNames::SHORT_PRESS; + knownButtonStates[Button::BUTTON_DOWN] = (OswAppV2::ButtonStateNames) (OswAppV2::ButtonStateNames::SHORT_PRESS | OswAppV2::ButtonStateNames::LONG_PRESS); } bool OswAppWatchface::onButtonDefaults(OswAppV2& app, int id, bool up, OswAppV2::ButtonStateNames state) { @@ -191,7 +191,7 @@ bool OswAppWatchface::onButtonDefaults(OswAppV2& app, int id, bool up, OswAppV2: OswHal::getInstance()->decreaseBrightness(25); return true; } - } else if(state == OswAppV2::ButtonStateNames::LONG_PRESS and id == Button::BUTTON_DOWN) { + } else if(state == OswAppV2::ButtonStateNames::LONG_PRESS and id == Button::BUTTON_DOWN and OswConfigAllKeys::settingDisplayDefaultWatchface.get() != app.getAppId()) { OSW_LOG_I("Setting default watchface to: ", app.getAppId()); OswConfig::getInstance()->enableWrite(); OswConfigAllKeys::settingDisplayDefaultWatchface.set(app.getAppId()); From 0010ace3960ff77019a8bb71f2562c9ed44a0d05 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sun, 2 Apr 2023 15:13:25 +0200 Subject: [PATCH 073/141] Added check to reduce invisible redraws --- src/OswAppV2.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index de6d07b2c..33b999c07 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -109,7 +109,11 @@ void OswAppV2::onLoop() { } if(this->buttonIndicatorProgress[i] != progress) { this->buttonIndicatorProgress[i] = progress; - this->needsRedraw = true; + if(this->knownButtonStates[i] & ButtonStateNames::LONG_PRESS or + this->knownButtonStates[i] & ButtonStateNames::VERY_LONG_PRESS) { + // Only redraw if any of the animation need to be drawn + this->needsRedraw = true; + } } } else if(this->buttonIndicatorProgress[i] != 0.0) { this->buttonIndicatorProgress[i] = 0.0; @@ -154,7 +158,7 @@ void OswAppV2::onDrawOverlay() { hal->gfx()->fillCircle(btnX, btnY, (1.0 - overcut) * longRad + (this->buttonIndicatorProgress[i] - 1.0) * secondRad, OswUI::getInstance()->getWarningColor()); } if(this->knownButtonStates[i] & ButtonStateNames::LONG_PRESS) { - // Long-press circle (shown if long press is supported and - if long press is not supported - also shown) + // Long-press circle hal->gfx()->fillCircle(btnX, btnY, min(this->buttonIndicatorProgress[i] * longRad, longRad), OswUI::getInstance()->getPrimaryColor()); } } From d1bfae18238a9b7b6d8fccde739bfd1a6f31cb60 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sun, 2 Apr 2023 15:23:34 +0200 Subject: [PATCH 074/141] Added note for the app-drawer --- src/apps/tools/OswAppTutorial.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 2ebda7882..b94805000 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -71,12 +71,12 @@ void OswAppTutorial::onDraw() { OswIcon checked = OswIcon(check_png, check_png_dimensions, rgb565(0, 200, 50)); hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); - hal->gfx()->setTextCursor(DISP_W / 2, 100); + hal->gfx()->setTextCursor(DISP_W / 2, 80); hal->gfx()->print("Navigation"); hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); - hal->gfx()->setTextCursor(DISP_W / 2, 120); - hal->gfx()->print("Please press the button modes\nlisted below to continue."); + hal->gfx()->setTextCursor(DISP_W / 2, 100); + hal->gfx()->print("Please press the button modes\nlisted below to continue.\nYou can open the app-drawer by\n long-pressing the select-button."); hal->gfx()->setTextSize(1); hal->gfx()->setTextLeftAligned(); @@ -112,11 +112,11 @@ void OswAppTutorial::onDraw() { } else if(this->screen == 2) { hal->gfx()->setTextSize(2); hal->gfx()->setTextCenterAligned(); - hal->gfx()->setTextCursor(DISP_W / 2, 100); - hal->gfx()->print("Battery Calibration"); + hal->gfx()->setTextCursor(DISP_W / 2, 60); + hal->gfx()->print("Battery\nCalibration"); hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); - hal->gfx()->setTextCursor(DISP_W / 2, 120); + hal->gfx()->setTextCursor(DISP_W / 2, 100); hal->gfx()->print("As this hardware has no BMS,\nthe OS has to learn the battery\ncapacity on-the-fly. Make sure to\nfully discharge the battery if\nyou see the battery icon being"); hal->gfx()->setTextColor(OswUI::getInstance()->getInfoColor(), OswUI::getInstance()->getBackgroundColor()); hal->gfx()->print("filled with the \"info\" color."); From 856972f3646f7fe45f5c8541f03159c5236f7cfb Mon Sep 17 00:00:00 2001 From: simonmicro Date: Sun, 2 Apr 2023 15:41:26 +0200 Subject: [PATCH 075/141] Show button names on navigation screen --- include/apps/tools/OswAppTutorial.h | 18 ++++----- src/apps/tools/OswAppTutorial.cpp | 59 +++++++++++++++++++---------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/include/apps/tools/OswAppTutorial.h b/include/apps/tools/OswAppTutorial.h index fce5d3e2d..2723fa9e3 100644 --- a/include/apps/tools/OswAppTutorial.h +++ b/include/apps/tools/OswAppTutorial.h @@ -1,7 +1,6 @@ -#ifndef OSW_APP_HELLO_WORLD_H -#define OSW_APP_HELLO_WORLD_H +#pragma once -#include +#include #include @@ -30,12 +29,11 @@ class OswAppTutorial : public OswAppV2 { unsigned screen = 0; unsigned currentScreen = 0; unsigned char hsv = 0; - bool gotButtonShort = false; - bool gotButtonLong = false; - bool gotButtonVeryLong = false; - bool gotButtonDouble = false; + std::optional