Merge pull request #231 from Panky-codes/feature/add-stop-watch
Added stopwatch
This commit is contained in:
commit
7b39130f88
|
@ -44,6 +44,7 @@ As of now, here is the list of achievements of this project:
|
|||
* Notification (displays the last notification received)
|
||||
* Paddle (single player pong-like game)
|
||||
* Two (2048 clone game)
|
||||
* Stopwatch (with all the necessary functions such as play, pause, lap, stop)
|
||||
- Supported by 2 companion apps (development is in progress):
|
||||
* [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android)
|
||||
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
|
||||
|
|
|
@ -485,6 +485,7 @@ list(APPEND SOURCE_FILES
|
|||
displayapp/screens/Meter.cpp
|
||||
displayapp/screens/InfiniPaint.cpp
|
||||
displayapp/screens/Paddle.cpp
|
||||
displayapp/screens/StopWatch.cpp
|
||||
displayapp/screens/BatteryIcon.cpp
|
||||
displayapp/screens/BleIcon.cpp
|
||||
displayapp/screens/NotificationIcon.cpp
|
||||
|
@ -644,6 +645,7 @@ set(INCLUDE_FILES
|
|||
displayapp/screens/Tile.h
|
||||
displayapp/screens/Meter.h
|
||||
displayapp/screens/InfiniPaint.h
|
||||
displayapp/screens/StopWatch.h
|
||||
displayapp/screens/Paddle.h
|
||||
displayapp/screens/DropDownDemo.h
|
||||
displayapp/screens/BatteryIcon.h
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
enum class Apps {None, Launcher, Clock, SysInfo, Meter, Brightness, Music, FirmwareValidation, Paint, Paddle, Notifications, Twos, HeartRate, Navigation};
|
||||
enum class Apps {None, Launcher, Clock, SysInfo, Meter, Brightness, Music, FirmwareValidation, Paint, Paddle, Notifications, Twos, HeartRate, Navigation, StopWatch};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "displayapp/screens/FirmwareValidation.h"
|
||||
#include "displayapp/screens/InfiniPaint.h"
|
||||
#include "displayapp/screens/Paddle.h"
|
||||
#include "displayapp/screens/StopWatch.h"
|
||||
#include "displayapp/screens/Meter.h"
|
||||
#include "displayapp/screens/Music.h"
|
||||
#include "displayapp/screens/Navigation.h"
|
||||
|
@ -204,6 +205,7 @@ void DisplayApp::RunningState() {
|
|||
break;
|
||||
case Apps::SysInfo: currentScreen.reset(new Screens::SystemInfo(this, dateTimeController, batteryController, brightnessController, bleController, watchdog)); break;
|
||||
case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break;
|
||||
case Apps::StopWatch: currentScreen.reset(new Screens::StopWatch(this)); break;
|
||||
case Apps::Twos: currentScreen.reset(new Screens::Twos(this)); break;
|
||||
case Apps::Paint: currentScreen.reset(new Screens::InfiniPaint(this, lvgl)); break;
|
||||
case Apps::Paddle: currentScreen.reset(new Screens::Paddle(this, lvgl)); break;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* Bpp : 1 bit-per-pixel
|
||||
* Do not enable font compression and horizontal subpixel hinting
|
||||
* Load the file `JetBrainsMono-Bold.tff` and specify the following range : `0x20-0x7f, 0x410-0x44f`
|
||||
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd`
|
||||
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024`
|
||||
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
|
||||
|
||||
Add new symbols:
|
||||
|
|
|
@ -466,8 +466,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
|
|||
0x66, 0x66, 0x66, 0x6c, 0x63,
|
||||
|
||||
/* U+417 "З" */
|
||||
0x1f, 0x8f, 0xfd, 0xc7, 0x80, 0x70, 0x1c, 0x3e,
|
||||
0x7, 0xf0, 0xf, 0x0, 0xe0, 0x1d, 0x83, 0xb8,
|
||||
0x1f, 0xf, 0xf3, 0xc7, 0x0, 0x60, 0x1c, 0x1e,
|
||||
0x3, 0xf0, 0xe, 0x0, 0xe0, 0x1f, 0x83, 0xf8,
|
||||
0xf7, 0xfc, 0x3e, 0x0,
|
||||
|
||||
/* U+418 "И" */
|
||||
|
@ -615,7 +615,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
|
|||
0x70,
|
||||
|
||||
/* U+437 "з" */
|
||||
0x3f, 0x1f, 0xfe, 0x1c, 0x7, 0x1f, 0x7, 0xe0,
|
||||
0x3f, 0x1f, 0xfe, 0x1c, 0x7, 0x1f, 0x87, 0xe0,
|
||||
0x1c, 0x7, 0xe1, 0xdf, 0xe3, 0xf0,
|
||||
|
||||
/* U+438 "и" */
|
||||
|
@ -738,6 +738,15 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
|
|||
0xcf, 0x9f, 0xff, 0xf1, 0xff, 0xfc, 0x1f, 0xff,
|
||||
0x1, 0xff, 0xc0, 0x1f, 0xf0, 0x0, 0x70, 0x0,
|
||||
|
||||
/* U+F024 "" */
|
||||
0x70, 0x0, 0xf, 0x80, 0x0, 0xf8, 0x0, 0xf,
|
||||
0xff, 0xf, 0x7f, 0xff, 0xf7, 0xff, 0xff, 0x7f,
|
||||
0xff, 0xf7, 0xff, 0xff, 0x7f, 0xff, 0xf7, 0xff,
|
||||
0xff, 0x7f, 0xff, 0xf7, 0xff, 0xff, 0x7f, 0xff,
|
||||
0xf7, 0xff, 0xff, 0x7f, 0x7f, 0xe7, 0x0, 0x78,
|
||||
0x70, 0x0, 0x7, 0x0, 0x0, 0x70, 0x0, 0x7,
|
||||
0x0, 0x0,
|
||||
|
||||
/* U+F027 "" */
|
||||
0x0, 0xc0, 0x3, 0x80, 0xf, 0x0, 0x3e, 0xf,
|
||||
0xfc, 0x9f, 0xf9, 0xbf, 0xf1, 0xff, 0xe3, 0xff,
|
||||
|
@ -789,6 +798,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
|
|||
0xff, 0xfc, 0xff, 0xff, 0x3f, 0xff, 0xcf, 0xff,
|
||||
0xf3, 0xff, 0xfc, 0xff, 0x7e, 0x1f, 0x80,
|
||||
|
||||
/* U+F04D "" */
|
||||
0x7f, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x80,
|
||||
|
||||
/* U+F051 "" */
|
||||
0xe0, 0x3f, 0x81, 0xfe, 0xf, 0xf8, 0x7f, 0xe3,
|
||||
0xff, 0x9f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
@ -897,6 +913,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
|
|||
0x81, 0xf8, 0x6d, 0x99, 0x9a, 0x36, 0x7, 0x80,
|
||||
0xe0, 0x18, 0x2, 0x0, 0x0,
|
||||
|
||||
/* U+F2F2 "" */
|
||||
0x7, 0xe0, 0x7, 0xe0, 0x1, 0x80, 0x3, 0xc0,
|
||||
0xf, 0xf2, 0x1f, 0xff, 0x3e, 0x7e, 0x7e, 0x7e,
|
||||
0xfe, 0x7e, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
|
||||
0xfe, 0x7f, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe,
|
||||
0x3f, 0xfc, 0x1f, 0xf8, 0x7, 0xe0,
|
||||
|
||||
/* U+F3DD "" */
|
||||
0x40, 0x0, 0x40, 0x70, 0x0, 0x7e, 0x3c, 0x0,
|
||||
0x3f, 0x8f, 0x80, 0x1f, 0x81, 0xe0, 0x1f, 0xc0,
|
||||
|
@ -1080,7 +1103,7 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||
{.bitmap_index = 1514, .adv_w = 192, .box_w = 11, .box_h = 17, .ofs_x = 1, .ofs_y = -3},
|
||||
{.bitmap_index = 1538, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
|
||||
{.bitmap_index = 1554, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 1575, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 1575, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 1595, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 1611, .adv_w = 192, .box_w = 9, .box_h = 19, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 1633, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
|
||||
|
@ -1139,36 +1162,39 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||
{.bitmap_index = 2498, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 2511, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 2561, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 2609, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 2638, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 2693, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 2732, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 2775, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
||||
{.bitmap_index = 2803, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 2851, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 2890, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
||||
{.bitmap_index = 2918, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 2966, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3019, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3038, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3088, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3124, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3172, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 3215, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3253, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3291, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3329, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3367, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3405, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3},
|
||||
{.bitmap_index = 3443, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3472, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3538, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 3587, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3637, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3697, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3750, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3805, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3858, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0}
|
||||
{.bitmap_index = 2609, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 2659, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 2688, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 2743, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 2782, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 2825, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
||||
{.bitmap_index = 2853, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 2901, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 2940, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 2979, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
||||
{.bitmap_index = 3007, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3055, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3108, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3127, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3177, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3213, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3261, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 3304, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3342, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3380, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3418, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3456, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3494, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3},
|
||||
{.bitmap_index = 3532, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3561, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 3599, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3665, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 3714, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3764, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3824, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3877, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3932, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3985, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
|
@ -1176,10 +1202,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||
*--------------------*/
|
||||
|
||||
static const uint16_t unicode_list_2[] = {
|
||||
0x0, 0x16, 0x26, 0x27, 0x28, 0x39, 0x47, 0x4a,
|
||||
0x4b, 0x50, 0x68, 0x94, 0x128, 0x184, 0x1e5, 0x1fb,
|
||||
0x21d, 0x23f, 0x240, 0x241, 0x242, 0x243, 0x292, 0x293,
|
||||
0x3dc, 0x3fc, 0x45c, 0x54a, 0x55f, 0x59e, 0x59f, 0x6a8
|
||||
0x0, 0x16, 0x23, 0x26, 0x27, 0x28, 0x39, 0x47,
|
||||
0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x94, 0x128, 0x184,
|
||||
0x1e5, 0x1fb, 0x21d, 0x23f, 0x240, 0x241, 0x242, 0x243,
|
||||
0x292, 0x293, 0x2f1, 0x3dc, 0x3fc, 0x45c, 0x54a, 0x55f,
|
||||
0x59e, 0x59f, 0x6a8
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
|
@ -1195,7 +1222,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
|||
},
|
||||
{
|
||||
.range_start = 61441, .range_length = 1705, .glyph_id_start = 160,
|
||||
.unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 32, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 35, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
|||
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||
std::array<Screens::Tile::Applications, 6> applications {
|
||||
{{Symbols::map, Apps::Navigation},
|
||||
{Symbols::asterisk, Apps::Meter},
|
||||
{Symbols::stopWatch, Apps::StopWatch},
|
||||
{Symbols::paintbrush, Apps::Paint},
|
||||
{Symbols::info, Apps::Notifications},
|
||||
{Symbols::paddle, Apps::Paddle},
|
||||
|
|
210
src/displayapp/screens/StopWatch.cpp
Normal file
210
src/displayapp/screens/StopWatch.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
#include "StopWatch.h"
|
||||
|
||||
#include "Screen.h"
|
||||
#include "Symbols.h"
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "projdefs.h"
|
||||
#include "FreeRTOSConfig.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
// Anonymous namespace for local functions
|
||||
namespace {
|
||||
TimeSeparated_t convertTicksToTimeSegments(const TickType_t timeElapsed) {
|
||||
const int timeElapsedMillis = (static_cast<float>(timeElapsed) / static_cast<float>(configTICK_RATE_HZ)) * 1000;
|
||||
|
||||
const int milliSecs = (timeElapsedMillis % 1000) / 10; // Get only the first two digits and ignore the last
|
||||
const int secs = (timeElapsedMillis / 1000) % 60;
|
||||
const int mins = (timeElapsedMillis / 1000) / 60;
|
||||
return TimeSeparated_t {mins, secs, milliSecs};
|
||||
}
|
||||
|
||||
TickType_t calculateDelta(const TickType_t startTime, const TickType_t currentTime) {
|
||||
TickType_t delta = 0;
|
||||
// Take care of overflow
|
||||
if (startTime > currentTime) {
|
||||
delta = 0xffffffff - startTime;
|
||||
delta += (currentTime + 1);
|
||||
} else {
|
||||
delta = currentTime - startTime;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
|
||||
static void play_pause_event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
auto stopWatch = static_cast<StopWatch*>(obj->user_data);
|
||||
stopWatch->playPauseBtnEventHandler(event);
|
||||
}
|
||||
|
||||
static void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
auto stopWatch = static_cast<StopWatch*>(obj->user_data);
|
||||
stopWatch->stopLapBtnEventHandler(event);
|
||||
}
|
||||
|
||||
StopWatch::StopWatch(DisplayApp* app)
|
||||
: Screen(app), running {true}, currentState {States::Init}, currentEvent {Events::Stop}, startTime {}, oldTimeElapsed {},
|
||||
currentTimeSeparated {}, lapBuffer {}, lapNr {}, lapPressed {false} {
|
||||
|
||||
time = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
|
||||
lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -45);
|
||||
lv_label_set_text(time, "00:00");
|
||||
|
||||
msecTime = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
|
||||
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 108, 3);
|
||||
lv_label_set_text(msecTime, "00");
|
||||
|
||||
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnPlayPause->user_data = this;
|
||||
lv_obj_set_event_cb(btnPlayPause, play_pause_event_handler);
|
||||
lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -10);
|
||||
lv_obj_set_height(btnPlayPause, 40);
|
||||
txtPlayPause = lv_label_create(btnPlayPause, nullptr);
|
||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||
|
||||
lapOneText = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
|
||||
lv_obj_align(lapOneText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 30);
|
||||
lv_label_set_text(lapOneText, "");
|
||||
|
||||
lapTwoText = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
|
||||
lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55);
|
||||
lv_label_set_text(lapTwoText, "");
|
||||
|
||||
// We don't want this button in the init state
|
||||
btnStopLap = nullptr;
|
||||
}
|
||||
|
||||
StopWatch::~StopWatch() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool StopWatch::Refresh() {
|
||||
// @startuml CHIP8_state
|
||||
// State "Init" as init
|
||||
// State "Running" as run
|
||||
// State "Halted" as halt
|
||||
|
||||
// [*] --> init
|
||||
// init -> run : press play
|
||||
// run -> run : press lap
|
||||
// run --> halt : press pause
|
||||
// halt --> run : press play
|
||||
// halt --> init : press stop
|
||||
// @enduml
|
||||
// Copy paste the above plantuml text to visualize the state diagram
|
||||
switch (currentState) {
|
||||
// Init state when an user first opens the app
|
||||
// and when a stop/reset button is pressed
|
||||
case States::Init: {
|
||||
if (btnStopLap) {
|
||||
lv_obj_del(btnStopLap);
|
||||
}
|
||||
// The initial default value
|
||||
lv_label_set_text(time, "00:00");
|
||||
lv_label_set_text(msecTime, "00");
|
||||
|
||||
lv_label_set_text(lapOneText, "");
|
||||
lv_label_set_text(lapTwoText, "");
|
||||
lapBuffer.clearBuffer();
|
||||
lapNr = 0;
|
||||
|
||||
if (currentEvent == Events::Play) {
|
||||
btnStopLap = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnStopLap->user_data = this;
|
||||
lv_obj_set_event_cb(btnStopLap, stop_lap_event_handler);
|
||||
lv_obj_align(btnStopLap, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0);
|
||||
lv_obj_set_height(btnStopLap, 40);
|
||||
txtStopLap = lv_label_create(btnStopLap, nullptr);
|
||||
lv_label_set_text(txtStopLap, Symbols::lapsFlag);
|
||||
|
||||
startTime = xTaskGetTickCount();
|
||||
currentState = States::Running;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case States::Running: {
|
||||
lv_label_set_text(txtPlayPause, Symbols::pause);
|
||||
lv_label_set_text(txtStopLap, Symbols::lapsFlag);
|
||||
|
||||
const auto timeElapsed = calculateDelta(startTime, xTaskGetTickCount());
|
||||
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
|
||||
|
||||
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
|
||||
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.msecs);
|
||||
|
||||
if (lapPressed == true) {
|
||||
if (lapBuffer[1]) {
|
||||
lv_label_set_text_fmt(lapOneText, "#%d %d:%d:%d", (lapNr - 1), lapBuffer[1]->mins, lapBuffer[1]->secs, lapBuffer[1]->msecs);
|
||||
}
|
||||
if (lapBuffer[0]) {
|
||||
lv_label_set_text_fmt(lapTwoText, "#%d %d:%d:%d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->msecs);
|
||||
}
|
||||
// Reset the bool to avoid setting the text in each cycle until there is a change
|
||||
lapPressed = false;
|
||||
}
|
||||
|
||||
if (currentEvent == Events::Pause) {
|
||||
// Reset the start time
|
||||
startTime = 0;
|
||||
// Store the current time elapsed in cache
|
||||
oldTimeElapsed += timeElapsed;
|
||||
currentState = States::Halted;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case States::Halted: {
|
||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||
lv_label_set_text(txtStopLap, Symbols::stop);
|
||||
|
||||
if (currentEvent == Events::Play) {
|
||||
startTime = xTaskGetTickCount();
|
||||
currentState = States::Running;
|
||||
}
|
||||
if (currentEvent == Events::Stop) {
|
||||
currentState = States::Init;
|
||||
oldTimeElapsed = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
bool StopWatch::OnButtonPushed() {
|
||||
running = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void StopWatch::playPauseBtnEventHandler(lv_event_t event) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
if (currentState == States::Init) {
|
||||
currentEvent = Events::Play;
|
||||
} else {
|
||||
// Simple Toggle for play/pause
|
||||
currentEvent = (currentEvent == Events::Play ? Events::Pause : Events::Play);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StopWatch::stopLapBtnEventHandler(lv_event_t event) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
// If running, then this button is used to save laps
|
||||
if (currentState == States::Running) {
|
||||
lapBuffer.addLaps(currentTimeSeparated);
|
||||
lapNr++;
|
||||
lapPressed = true;
|
||||
|
||||
} else if (currentState == States::Halted) {
|
||||
currentEvent = Events::Stop;
|
||||
} else {
|
||||
// Not possible to reach here. Do nothing.
|
||||
}
|
||||
}
|
||||
}
|
86
src/displayapp/screens/StopWatch.h
Normal file
86
src/displayapp/screens/StopWatch.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#include "Screen.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "../LittleVgl.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "portmacro_cmsis.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace Pinetime::Applications::Screens {
|
||||
|
||||
enum class States { Init, Running, Halted };
|
||||
|
||||
enum class Events { Play, Pause, Stop };
|
||||
|
||||
struct TimeSeparated_t {
|
||||
int mins;
|
||||
int secs;
|
||||
int msecs;
|
||||
};
|
||||
|
||||
// A simple buffer to hold the latest two laps
|
||||
template <int N> struct LapTextBuffer_t {
|
||||
LapTextBuffer_t() : buffer {}, currentSize {}, capacity {N}, head {-1} {
|
||||
}
|
||||
|
||||
void addLaps(const TimeSeparated_t& timeVal) {
|
||||
head++;
|
||||
head %= capacity;
|
||||
buffer[head] = timeVal;
|
||||
|
||||
if (currentSize < capacity) {
|
||||
currentSize++;
|
||||
}
|
||||
}
|
||||
|
||||
void clearBuffer() {
|
||||
buffer = {};
|
||||
currentSize = 0;
|
||||
head = -1;
|
||||
}
|
||||
|
||||
TimeSeparated_t* operator[](std::size_t idx) {
|
||||
// Sanity check for out-of-bounds
|
||||
if (idx >= 0 && idx < capacity) {
|
||||
if (idx < currentSize) {
|
||||
// This transformation is to ensure that head is always pointing to index 0.
|
||||
const auto transformed_idx = (head - idx) % capacity;
|
||||
return (&buffer[transformed_idx]);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<TimeSeparated_t, N> buffer;
|
||||
uint8_t currentSize;
|
||||
uint8_t capacity;
|
||||
int8_t head;
|
||||
};
|
||||
|
||||
class StopWatch : public Screen {
|
||||
public:
|
||||
StopWatch(DisplayApp* app);
|
||||
~StopWatch() override;
|
||||
bool Refresh() override;
|
||||
bool OnButtonPushed() override;
|
||||
void playPauseBtnEventHandler(lv_event_t event);
|
||||
void stopLapBtnEventHandler(lv_event_t event);
|
||||
|
||||
private:
|
||||
bool running;
|
||||
States currentState;
|
||||
Events currentEvent;
|
||||
TickType_t startTime;
|
||||
TickType_t oldTimeElapsed;
|
||||
TimeSeparated_t currentTimeSeparated; // Holds Mins, Secs, millisecs
|
||||
LapTextBuffer_t<2> lapBuffer;
|
||||
int lapNr;
|
||||
bool lapPressed;
|
||||
lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
|
||||
lv_obj_t *lapOneText, *lapTwoText;
|
||||
};
|
||||
}
|
|
@ -36,6 +36,9 @@ namespace Pinetime {
|
|||
static constexpr const char* stepBackward = "\xEF\x81\x88";
|
||||
static constexpr const char* play = "\xEF\x81\x8B";
|
||||
static constexpr const char* pause = "\xEF\x81\x8C";
|
||||
static constexpr const char* stop = "\xEF\x81\x8D";
|
||||
static constexpr const char* stopWatch = "\xEF\x8B\xB2";
|
||||
static constexpr const char* lapsFlag = "\xEF\x80\xA4";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user