Compare commits
10 commits
ab9eaef3fc
...
a7faa14345
| Author | SHA1 | Date | |
|---|---|---|---|
| a7faa14345 | |||
| aa3401bd52 | |||
| 14092ef883 | |||
| 17abbdd079 | |||
| 6c59dd0d1c | |||
| 5d15a0df3c | |||
| 0745ebd82c | |||
|
|
68384fc34e | ||
| bf786dac8e | |||
| a8a99bc462 |
23 changed files with 560 additions and 28 deletions
14
README.md
14
README.md
|
|
@ -1,3 +1,17 @@
|
||||||
|
# The Trax.im fork of PineTime OS InfiniTime
|
||||||
|
|
||||||
|
Includes some tweaks such as:
|
||||||
|
|
||||||
|
|Analogue |Digital |Terminal
|
||||||
|
|---|---|---
|
||||||
|
|||
|
||||||
|
|
||||||
|
|Add [Calculator](https://github.com/InfiniTimeOrg/InfiniTime/pull/375) |Tweak Settings |Pulse: never say '0'
|
||||||
|
|---|---|---
|
||||||
|
|||
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
8
doc/Calculator.md
Normal file
8
doc/Calculator.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Calculator Manual
|
||||||
|
This is a simple Calculator with support for the four basic arithmetic operations, parenthesis and exponents.
|
||||||
|
Here is what you need to know to make full use of it:
|
||||||
|
- Swipe left to access parenthesis and exponents
|
||||||
|
- A long tap on the screen will reset the text field to `0`.
|
||||||
|
- If the entered term is invalid, the watch will vibrate.
|
||||||
|
- results are rounded to 4 digits after the decimal point
|
||||||
|
- **TIP:** you can use `^(1/2)` to calculate square roots
|
||||||
BIN
doc/img/InfiniSim_2024-08-27-ana.png
Normal file
BIN
doc/img/InfiniSim_2024-08-27-ana.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
BIN
doc/img/InfiniSim_2024-08-27-dig.png
Normal file
BIN
doc/img/InfiniSim_2024-08-27-dig.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
BIN
doc/img/InfiniSim_2024-08-27-nopulse-ana.png
Normal file
BIN
doc/img/InfiniSim_2024-08-27-nopulse-ana.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
BIN
doc/img/InfiniSim_2024-08-27-term.png
Normal file
BIN
doc/img/InfiniSim_2024-08-27-term.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
BIN
doc/img/InfiniSim_2024-08-28-calculator.png
Normal file
BIN
doc/img/InfiniSim_2024-08-28-calculator.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
doc/img/InfiniSim_2024-08-28-settings1.png
Normal file
BIN
doc/img/InfiniSim_2024-08-28-settings1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
|
|
@ -26,6 +26,7 @@ export GCC_ARM_PATH="gcc-arm-none-eabi-$GCC_ARM_VER"
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local target="$1"
|
local target="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
mkdir -p "$TOOLS_DIR"
|
mkdir -p "$TOOLS_DIR"
|
||||||
|
|
||||||
|
|
@ -35,7 +36,7 @@ main() {
|
||||||
|
|
||||||
mkdir -p "$BUILD_DIR"
|
mkdir -p "$BUILD_DIR"
|
||||||
|
|
||||||
CmakeGenerate
|
CmakeGenerate "$@"
|
||||||
CmakeBuild $target
|
CmakeBuild $target
|
||||||
BUILD_RESULT=$?
|
BUILD_RESULT=$?
|
||||||
if [ "$DISABLE_POSTBUILD" != "true" -a "$BUILD_RESULT" == 0 ]; then
|
if [ "$DISABLE_POSTBUILD" != "true" -a "$BUILD_RESULT" == 0 ]; then
|
||||||
|
|
@ -68,13 +69,16 @@ CmakeGenerate() {
|
||||||
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_PATH" \
|
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_PATH" \
|
||||||
-DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \
|
-DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \
|
||||||
-DBUILD_DFU=1 \
|
-DBUILD_DFU=1 \
|
||||||
-DBUILD_RESOURCES=1
|
-DBUILD_RESOURCES=1 \
|
||||||
|
"$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# CmakeBuild [target [CMAKE_ARGS...]]
|
||||||
|
# CMAKE_ARGS can include a '--' arg, with the same meaning as it has in 'cmake'.
|
||||||
CmakeBuild() {
|
CmakeBuild() {
|
||||||
local target="$1"
|
local target="$1"
|
||||||
[ -n "$target" ] && target="--target $target"
|
[ -n "$target" ] && target="--target $target" && shift
|
||||||
cmake --build "$BUILD_DIR" --config $BUILD_TYPE $target -- -j$(nproc)
|
cmake --build "$BUILD_DIR" --config $BUILD_TYPE $target "$@" -- -j$(nproc)
|
||||||
BUILD_RESULT=$?
|
BUILD_RESULT=$?
|
||||||
return $BUILD_RESULT
|
return $BUILD_RESULT
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
justfile
Normal file
48
justfile
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
set positional-arguments
|
||||||
|
|
||||||
|
default:
|
||||||
|
@just --list --justfile {{justfile()}}
|
||||||
|
|
||||||
|
# Specifying apps and watchfaces: see doc/code/Apps.md
|
||||||
|
# defaults: see src/displayapp/apps/CMakeLists.txt
|
||||||
|
USERAPPS_DEFAULT := "StopWatch Alarm Timer Steps HeartRate Music Paint Paddle Twos Metronome Navigation" # Weather Motion
|
||||||
|
|
||||||
|
export USERAPPS := "Steps Motion HeartRate StopWatch Alarm Timer Metronome Music Paint Paddle Calculator"
|
||||||
|
export WATCHFACES := "Analog Digital Terminal"
|
||||||
|
|
||||||
|
build-all: (build-app)
|
||||||
|
|
||||||
|
build-app \
|
||||||
|
ot="PineTime" ots="pine64" \
|
||||||
|
u=`python3 -c "print(','.join(['Apps::'+x for x in '${USERAPPS}'.split()]))"` \
|
||||||
|
w=`python3 -c "print(','.join(['WatchFace::'+x for x in '${WATCHFACES}'.split()]))"` \
|
||||||
|
: (build 'pinetime-mcuboot-app' '-DOWNER_TEXT='+ot '-DOWNER_TEXT_SHORT='+ots '-DENABLE_USERAPPS='+u '-DENABLE_WATCHFACES='+w)
|
||||||
|
|
||||||
|
test1: (build "pinetime-mcuboot-app" "-D`just get-userapps-arg '${USERAPPS}'`" "-D`just get-watchfaces-arg '${WATCHFACES}'`")
|
||||||
|
|
||||||
|
build *TARGET_AND_CMAKE_ARGS:
|
||||||
|
docker run --rm -it -v ${PWD}:/sources --user $(id -u):$(id -g) ${MY_REGISTRY}/infinitime-build /opt/build.sh "$@"
|
||||||
|
|
||||||
|
builder:
|
||||||
|
docker build -t ${MY_REGISTRY}/infinitime-build ./docker
|
||||||
|
#docker push
|
||||||
|
|
||||||
|
list-userapps-default:
|
||||||
|
sed -n -e 's/^ *\(#*\)set(DEFAULT_USER_APP_TYPES .*\(Apps::[^"]*\).*/\1\2/;T;p' < ./src/displayapp/apps/CMakeLists.txt
|
||||||
|
|
||||||
|
list-watchfaces-default:
|
||||||
|
sed -n -e 's/^ *\(#*\)set(DEFAULT_WATCHFACE_TYPES .*\(WatchFace::[^"]*\).*/\1\2/;T;p' < ./src/displayapp/apps/CMakeLists.txt
|
||||||
|
|
||||||
|
list-userapps-all:
|
||||||
|
sed -n -e '/enum class \<Apps\>.*{/,/}/p' < ./src/displayapp/apps/Apps.h.in
|
||||||
|
|
||||||
|
list-watchfaces-all:
|
||||||
|
sed -n -e '/enum class \<WatchFace\>.*{/,/}/p' < ./src/displayapp/apps/Apps.h.in
|
||||||
|
|
||||||
|
get-userapps-arg apps:
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
print('ENABLE_USERAPPS=' + ','.join(['Apps::'+x for x in "{{apps}}".split()]), end='')
|
||||||
|
|
||||||
|
get-watchfaces-arg faces:
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
print('ENABLE_WATCHFACES=' + ','.join(['WatchFace::'+x for x in "{{faces}}".split()]), end='')
|
||||||
|
|
@ -390,6 +390,7 @@ list(APPEND SOURCE_FILES
|
||||||
displayapp/screens/CheckboxList.cpp
|
displayapp/screens/CheckboxList.cpp
|
||||||
displayapp/screens/BatteryInfo.cpp
|
displayapp/screens/BatteryInfo.cpp
|
||||||
displayapp/screens/Steps.cpp
|
displayapp/screens/Steps.cpp
|
||||||
|
displayapp/screens/Calculator.cpp
|
||||||
displayapp/screens/Timer.cpp
|
displayapp/screens/Timer.cpp
|
||||||
displayapp/screens/Dice.cpp
|
displayapp/screens/Dice.cpp
|
||||||
displayapp/screens/PassKey.cpp
|
displayapp/screens/PassKey.cpp
|
||||||
|
|
@ -610,6 +611,7 @@ set(INCLUDE_FILES
|
||||||
displayapp/screens/HeartRate.h
|
displayapp/screens/HeartRate.h
|
||||||
displayapp/screens/Metronome.h
|
displayapp/screens/Metronome.h
|
||||||
displayapp/screens/Motion.h
|
displayapp/screens/Motion.h
|
||||||
|
displayapp/screens/Calculator.h
|
||||||
displayapp/screens/Timer.h
|
displayapp/screens/Timer.h
|
||||||
displayapp/screens/Dice.h
|
displayapp/screens/Dice.h
|
||||||
displayapp/screens/Alarm.h
|
displayapp/screens/Alarm.h
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include "displayapp/screens/SystemInfo.h"
|
#include "displayapp/screens/SystemInfo.h"
|
||||||
#include "displayapp/screens/Tile.h"
|
#include "displayapp/screens/Tile.h"
|
||||||
#include "displayapp/screens/Twos.h"
|
#include "displayapp/screens/Twos.h"
|
||||||
|
#include "displayapp/screens/Calculator.h"
|
||||||
#include "displayapp/screens/FlashLight.h"
|
#include "displayapp/screens/FlashLight.h"
|
||||||
#include "displayapp/screens/BatteryInfo.h"
|
#include "displayapp/screens/BatteryInfo.h"
|
||||||
#include "displayapp/screens/Steps.h"
|
#include "displayapp/screens/Steps.h"
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ namespace Pinetime {
|
||||||
StopWatch,
|
StopWatch,
|
||||||
Metronome,
|
Metronome,
|
||||||
Motion,
|
Motion,
|
||||||
|
Calculator,
|
||||||
Steps,
|
Steps,
|
||||||
Dice,
|
Dice,
|
||||||
Weather,
|
Weather,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ else ()
|
||||||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome")
|
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome")
|
||||||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
|
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
|
||||||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
|
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
|
||||||
|
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Calculator")
|
||||||
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion")
|
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion")
|
||||||
set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware")
|
set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,16 @@
|
||||||
"jetbrains_mono_bold_20": {
|
"jetbrains_mono_bold_20": {
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"file": "JetBrainsMono-Bold.ttf",
|
"file": "open_sans_light.ttf",
|
||||||
"range": "0x20-0x7e, 0x410-0x44f, 0xB0"
|
"range": "0x20-0x7e, 0x410-0x44f, 0xB0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "FontAwesome5-Solid+Brands+Regular.woff",
|
"file": "FontAwesome5-Solid+Brands+Regular.woff",
|
||||||
"range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743"
|
"range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf743, 0xf1ec"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"bpp": 1,
|
"bpp": 1,
|
||||||
"size": 20,
|
"size": 20
|
||||||
"patches": ["jetbrains_mono_bold_20.c_zero.patch", "jetbrains_mono_bold_20.c_M.patch"]
|
|
||||||
},
|
},
|
||||||
"jetbrains_mono_42": {
|
"jetbrains_mono_42": {
|
||||||
"sources": [
|
"sources": [
|
||||||
|
|
|
||||||
394
src/displayapp/screens/Calculator.cpp
Normal file
394
src/displayapp/screens/Calculator.cpp
Normal file
|
|
@ -0,0 +1,394 @@
|
||||||
|
#include "Calculator.h"
|
||||||
|
#include <string>
|
||||||
|
#include <stack>
|
||||||
|
#include <cfloat>
|
||||||
|
#include <cmath>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
// Anonymous Namespace for all the structs
|
||||||
|
namespace {
|
||||||
|
struct CalcTreeNode {
|
||||||
|
virtual double calculate() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NumNode : CalcTreeNode {
|
||||||
|
double value;
|
||||||
|
|
||||||
|
double calculate() override {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BinOp : CalcTreeNode {
|
||||||
|
std::shared_ptr<CalcTreeNode> left;
|
||||||
|
std::shared_ptr<CalcTreeNode> right;
|
||||||
|
|
||||||
|
char op;
|
||||||
|
|
||||||
|
double calculate() override {
|
||||||
|
// make sure we have actual numbers
|
||||||
|
if (!right || !left) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rightVal = right->calculate();
|
||||||
|
double leftVal = left->calculate();
|
||||||
|
switch (op) {
|
||||||
|
case '^':
|
||||||
|
// detect overflow
|
||||||
|
if (log2(leftVal) + rightVal > 31) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return pow(leftVal, rightVal);
|
||||||
|
case 'x':
|
||||||
|
// detect over/underflowflow
|
||||||
|
if ((DBL_MAX / abs(rightVal)) < abs(leftVal)) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return leftVal * rightVal;
|
||||||
|
case '/':
|
||||||
|
// detect under/overflow
|
||||||
|
if ((DBL_MAX * abs(rightVal)) < abs(leftVal)) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
// detect divison by zero
|
||||||
|
if (rightVal == 0.0) {
|
||||||
|
errno = EDOM;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return leftVal / rightVal;
|
||||||
|
case '+':
|
||||||
|
// detect overflow
|
||||||
|
if ((DBL_MAX - rightVal) < leftVal) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return leftVal + rightVal;
|
||||||
|
case '-':
|
||||||
|
// detect underflow
|
||||||
|
if ((DBL_MIN + rightVal) > leftVal) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return leftVal - rightVal;
|
||||||
|
}
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t getPrecedence(char op) {
|
||||||
|
switch (op) {
|
||||||
|
case '^':
|
||||||
|
return 4;
|
||||||
|
case 'x':
|
||||||
|
case '/':
|
||||||
|
return 3;
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool leftAssociative(char op) {
|
||||||
|
switch (op) {
|
||||||
|
case '^':
|
||||||
|
return false;
|
||||||
|
case 'x':
|
||||||
|
case '/':
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||||
|
auto calc = static_cast<Calculator*>(obj->user_data);
|
||||||
|
calc->OnButtonEvent(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Calculator::~Calculator() {
|
||||||
|
lv_obj_clean(lv_scr_act());
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* const buttonMap1[] = {
|
||||||
|
"7", "8", "9", "/", "\n",
|
||||||
|
"4", "5", "6", "x", "\n",
|
||||||
|
"1", "2", "3", "-", "\n",
|
||||||
|
".", "0", "=", "+", "",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* const buttonMap2[] = {
|
||||||
|
"7", "8", "9", "(", "\n",
|
||||||
|
"4", "5", "6", ")", "\n",
|
||||||
|
"1", "2", "3", "^", "\n",
|
||||||
|
".", "0", "=", "+", "",
|
||||||
|
};
|
||||||
|
|
||||||
|
Calculator::Calculator(Controllers::MotorController& motorController) : motorController {motorController} {
|
||||||
|
result = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_label_set_long_mode(result, LV_LABEL_LONG_BREAK);
|
||||||
|
lv_label_set_text(result, "0");
|
||||||
|
lv_obj_set_size(result, 180, 60);
|
||||||
|
lv_obj_set_pos(result, 0, 0);
|
||||||
|
|
||||||
|
returnButton = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
|
lv_obj_set_size(returnButton, 52, 52);
|
||||||
|
lv_obj_set_pos(returnButton, 186, 0);
|
||||||
|
lv_obj_t* returnLabel;
|
||||||
|
returnLabel = lv_label_create(returnButton, nullptr);
|
||||||
|
lv_label_set_text(returnLabel, "<=");
|
||||||
|
lv_obj_align(returnLabel, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
returnButton->user_data = this;
|
||||||
|
lv_obj_set_event_cb(returnButton, eventHandler);
|
||||||
|
|
||||||
|
buttonMatrix = lv_btnmatrix_create(lv_scr_act(), nullptr);
|
||||||
|
lv_btnmatrix_set_map(buttonMatrix, const_cast<const char **>(buttonMap1));
|
||||||
|
lv_obj_set_size(buttonMatrix, 240, 180);
|
||||||
|
lv_obj_set_pos(buttonMatrix, 0, 60);
|
||||||
|
lv_obj_set_style_local_pad_all(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 0);
|
||||||
|
buttonMatrix->user_data = this;
|
||||||
|
lv_obj_set_event_cb(buttonMatrix, eventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Calculator::eval() {
|
||||||
|
std::stack<char> input {};
|
||||||
|
for (int8_t i = position - 1; i >= 0; i--) {
|
||||||
|
input.push(text[i]);
|
||||||
|
}
|
||||||
|
std::stack<std::shared_ptr<CalcTreeNode>> output {};
|
||||||
|
std::stack<char> operators {};
|
||||||
|
bool expectingNumber = true;
|
||||||
|
int8_t sign = +1;
|
||||||
|
while (!input.empty()) {
|
||||||
|
if (input.top() == '.') {
|
||||||
|
input.push('0');
|
||||||
|
}
|
||||||
|
if (isdigit(input.top())) {
|
||||||
|
char numberStr[31];
|
||||||
|
uint8_t strln = 0;
|
||||||
|
uint8_t pointpos = 0;
|
||||||
|
while (!input.empty() && (isdigit(input.top()) || input.top() == '.')) {
|
||||||
|
if (input.top() == '.') {
|
||||||
|
if (pointpos != 0) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pointpos = strln;
|
||||||
|
} else {
|
||||||
|
numberStr[strln] = input.top();
|
||||||
|
strln++;
|
||||||
|
}
|
||||||
|
input.pop();
|
||||||
|
}
|
||||||
|
// replacement for strtod() since using that increased .txt by 76858 bzt
|
||||||
|
if (pointpos == 0) {
|
||||||
|
pointpos = strln;
|
||||||
|
}
|
||||||
|
double num = 0;
|
||||||
|
for (uint8_t i = 0; i < pointpos; i++) {
|
||||||
|
num += (numberStr[i] - '0') * pow(10, pointpos - i - 1);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < strln - pointpos; i++) {
|
||||||
|
num += (numberStr[i + pointpos] - '0') / pow(10, i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto number = std::make_shared<NumNode>();
|
||||||
|
number->value = sign * num;
|
||||||
|
output.push(number);
|
||||||
|
|
||||||
|
sign = +1;
|
||||||
|
expectingNumber = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectingNumber && input.top() == '+') {
|
||||||
|
input.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (expectingNumber && input.top() == '-') {
|
||||||
|
sign *= -1;
|
||||||
|
input.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char next = input.top();
|
||||||
|
input.pop();
|
||||||
|
|
||||||
|
switch (next) {
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
case '/':
|
||||||
|
case 'x':
|
||||||
|
case '^':
|
||||||
|
// while ((there is an operator at the top of the operator stack)
|
||||||
|
while (!operators.empty()
|
||||||
|
// and (the operator at the top of the operator stack is not a left parenthesis))
|
||||||
|
&& operators.top() != '('
|
||||||
|
// and ((the operator at the top of the operator stack has greater precedence)
|
||||||
|
&& (getPrecedence(operators.top()) > getPrecedence(next)
|
||||||
|
// or (the operator at the top of the operator stack has equal precedence and the token is left associative))
|
||||||
|
|| (getPrecedence(operators.top()) == getPrecedence(next) && leftAssociative(next)))) {
|
||||||
|
// need two elements on the output stack to add a binary operator
|
||||||
|
if (output.size() < 2) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto node = std::make_shared<BinOp>();
|
||||||
|
node->right = output.top();
|
||||||
|
output.pop();
|
||||||
|
node->left = output.top();
|
||||||
|
output.pop();
|
||||||
|
node->op = operators.top();
|
||||||
|
operators.pop();
|
||||||
|
output.push(node);
|
||||||
|
}
|
||||||
|
operators.push(next);
|
||||||
|
expectingNumber = true;
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
// we expect there to be a binary operator here but found a left parenthesis. this occurs in terms like this: a+b(c). This should be
|
||||||
|
// interpreted as a+b*(c)
|
||||||
|
if (!expectingNumber) {
|
||||||
|
operators.push('x');
|
||||||
|
}
|
||||||
|
operators.push(next);
|
||||||
|
expectingNumber = true;
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
while (operators.top() != '(') {
|
||||||
|
// need two elements on the output stack to add a binary operator
|
||||||
|
if (output.size() < 2) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto node = std::make_shared<BinOp>();
|
||||||
|
node->right = output.top();
|
||||||
|
output.pop();
|
||||||
|
node->left = output.top();
|
||||||
|
output.pop();
|
||||||
|
node->op = operators.top();
|
||||||
|
operators.pop();
|
||||||
|
output.push(node);
|
||||||
|
if (operators.empty()) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// discard the left parentheses
|
||||||
|
operators.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!operators.empty()) {
|
||||||
|
char op = operators.top();
|
||||||
|
if (op == ')' || op == '(') {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// need two elements on the output stack to add a binary operator
|
||||||
|
if (output.size() < 2) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto node = std::make_shared<BinOp>();
|
||||||
|
node->right = output.top();
|
||||||
|
output.pop();
|
||||||
|
node->left = output.top();
|
||||||
|
output.pop();
|
||||||
|
node->op = op;
|
||||||
|
operators.pop();
|
||||||
|
output.push(node);
|
||||||
|
}
|
||||||
|
// perform the calculation
|
||||||
|
errno = 0;
|
||||||
|
double resultFloat = output.top()->calculate();
|
||||||
|
if (errno != 0) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// make sure the result fits in a 32 bit int
|
||||||
|
if (INT32_MAX < resultFloat || INT32_MIN > resultFloat) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// weird workaround because sprintf crashes when trying to use a float
|
||||||
|
int32_t upper = resultFloat;
|
||||||
|
int32_t lower = round(std::abs(resultFloat - upper) * 10000);
|
||||||
|
// round up to the next int value
|
||||||
|
if (lower >= 10000) {
|
||||||
|
lower = 0;
|
||||||
|
upper++;
|
||||||
|
}
|
||||||
|
// see if decimal places have to be printed
|
||||||
|
if (lower != 0) {
|
||||||
|
if (upper == 0 && resultFloat < 0) {
|
||||||
|
position = sprintf(text, "-%ld.%ld", upper, lower);
|
||||||
|
} else {
|
||||||
|
position = sprintf(text, "%ld.%ld", upper, lower);
|
||||||
|
}
|
||||||
|
// remove extra zeros
|
||||||
|
while (text[position - 1] == '0') {
|
||||||
|
position--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
position = sprintf(text, "%ld", upper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
|
||||||
|
if (event == LV_EVENT_CLICKED) {
|
||||||
|
if (obj == buttonMatrix) {
|
||||||
|
const char* buttonstr = lv_btnmatrix_get_active_btn_text(obj);
|
||||||
|
if (*buttonstr == '=') {
|
||||||
|
eval();
|
||||||
|
} else {
|
||||||
|
if (position >= 30) {
|
||||||
|
motorController.RunForDuration(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
text[position] = *buttonstr;
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
} else if (obj == returnButton) {
|
||||||
|
if (position > 1) {
|
||||||
|
|
||||||
|
position--;
|
||||||
|
} else {
|
||||||
|
position = 0;
|
||||||
|
lv_label_set_text(result, "0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text[position] = '\0';
|
||||||
|
lv_label_set_text(result, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Calculator::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
|
if (event == Pinetime::Applications::TouchEvents::LongTap) {
|
||||||
|
position = 0;
|
||||||
|
lv_label_set_text(result, "0");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event == Pinetime::Applications::TouchEvents::SwipeLeft) {
|
||||||
|
lv_btnmatrix_set_map(buttonMatrix, const_cast<const char **>(buttonMap2));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event == Pinetime::Applications::TouchEvents::SwipeRight) {
|
||||||
|
lv_btnmatrix_set_map(buttonMatrix, const_cast<const char **>(buttonMap1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
43
src/displayapp/screens/Calculator.h
Normal file
43
src/displayapp/screens/Calculator.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.h"
|
||||||
|
#include "Symbols.h"
|
||||||
|
#include "components/motor/MotorController.h"
|
||||||
|
#include "systemtask/SystemTask.h"
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Pinetime::Applications {
|
||||||
|
namespace Screens {
|
||||||
|
class Calculator : public Screen {
|
||||||
|
public:
|
||||||
|
~Calculator() override;
|
||||||
|
|
||||||
|
Calculator(Controllers::MotorController& motorController);
|
||||||
|
|
||||||
|
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
|
||||||
|
|
||||||
|
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
lv_obj_t *result, *returnButton, *buttonMatrix;
|
||||||
|
|
||||||
|
char text[31];
|
||||||
|
uint8_t position = 0;
|
||||||
|
|
||||||
|
void eval();
|
||||||
|
|
||||||
|
Controllers::MotorController& motorController;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct AppTraits<Apps::Calculator> {
|
||||||
|
static constexpr Apps app = Apps::Calculator;
|
||||||
|
static constexpr const char* icon = Screens::Symbols::calculator;
|
||||||
|
|
||||||
|
static Screens::Screen* Create(AppControllers& controllers) {
|
||||||
|
return new Screens::Calculator(controllers.motorController);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Pinetime {
|
||||||
template <>
|
template <>
|
||||||
struct AppTraits<Apps::Motion> {
|
struct AppTraits<Apps::Motion> {
|
||||||
static constexpr Apps app = Apps::Motion;
|
static constexpr Apps app = Apps::Motion;
|
||||||
static constexpr const char* icon = "M";
|
static constexpr const char* icon = "XYZ";
|
||||||
|
|
||||||
static Screens::Screen* Create(AppControllers& controllers) {
|
static Screens::Screen* Create(AppControllers& controllers) {
|
||||||
return new Screens::Motion(controllers.motionController);
|
return new Screens::Motion(controllers.motionController);
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ namespace Pinetime {
|
||||||
static constexpr const char* eye = "\xEF\x81\xAE";
|
static constexpr const char* eye = "\xEF\x81\xAE";
|
||||||
static constexpr const char* home = "\xEF\x80\x95";
|
static constexpr const char* home = "\xEF\x80\x95";
|
||||||
static constexpr const char* sleep = "\xEE\xBD\x84";
|
static constexpr const char* sleep = "\xEE\xBD\x84";
|
||||||
|
static constexpr const char* calculator = "\xEF\x87\xAC";
|
||||||
|
|
||||||
// fontawesome_weathericons.c
|
// fontawesome_weathericons.c
|
||||||
// static constexpr const char* sun = "\xEF\x86\x85";
|
// static constexpr const char* sun = "\xEF\x86\x85";
|
||||||
|
|
|
||||||
|
|
@ -172,16 +172,16 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
|
||||||
|
|
||||||
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
|
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
|
||||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
|
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
lv_obj_align(heartbeatIcon, heartbeatValue, LV_ALIGN_OUT_TOP_LEFT, 0, 0);
|
lv_obj_align(heartbeatIcon, heartbeatValue, LV_ALIGN_OUT_TOP_LEFT, 0, 0);
|
||||||
|
|
||||||
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
||||||
lv_label_set_text_static(stepValue, "0");
|
lv_label_set_text_static(stepValue, "");
|
||||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
|
|
||||||
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
||||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_TOP_RIGHT, 0, 0);
|
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_TOP_RIGHT, 0, 0);
|
||||||
|
|
||||||
|
|
@ -309,15 +309,17 @@ void WatchFaceAnalog::Refresh() {
|
||||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
lv_label_set_text_static(heartbeatValue, "");
|
lv_label_set_text_static(heartbeatValue, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_obj_realign(heartbeatIcon);
|
|
||||||
lv_obj_realign(heartbeatValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stepCount = motionController.NbSteps();
|
stepCount = motionController.NbSteps();
|
||||||
if (stepCount.IsUpdated()) {
|
if (stepCount.IsUpdated()) {
|
||||||
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
|
if (stepCount.Get()) {
|
||||||
lv_obj_realign(stepValue);
|
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
||||||
lv_obj_realign(stepIcon);
|
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
|
||||||
|
lv_obj_realign(stepValue);
|
||||||
|
} else {
|
||||||
|
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
|
lv_label_set_text_static(stepValue, "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController,
|
||||||
|
|
||||||
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
|
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
|
||||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
|
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
|
|
||||||
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
|
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
|
@ -83,13 +83,13 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController,
|
||||||
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||||
|
|
||||||
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
||||||
lv_obj_align(stepIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
lv_obj_align(stepIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
|
|
||||||
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
||||||
lv_label_set_text_static(stepValue, "0");
|
lv_label_set_text_static(stepValue, "");
|
||||||
lv_obj_align(stepValue, stepIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
lv_obj_align(stepValue, stepIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||||
|
|
||||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
|
|
@ -171,16 +171,18 @@ void WatchFaceDigital::Refresh() {
|
||||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
lv_label_set_text_static(heartbeatValue, "");
|
lv_label_set_text_static(heartbeatValue, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_obj_realign(heartbeatIcon);
|
|
||||||
lv_obj_realign(heartbeatValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stepCount = motionController.NbSteps();
|
stepCount = motionController.NbSteps();
|
||||||
if (stepCount.IsUpdated()) {
|
if (stepCount.IsUpdated()) {
|
||||||
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
|
if (stepCount.Get()) {
|
||||||
lv_obj_realign(stepValue);
|
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
||||||
lv_obj_realign(stepIcon);
|
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
|
||||||
|
lv_obj_realign(stepValue);
|
||||||
|
} else {
|
||||||
|
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
|
||||||
|
lv_label_set_text_static(stepValue, "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentWeather = weatherService.Current();
|
currentWeather = weatherService.Current();
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,10 @@ void WatchFaceTerminal::Refresh() {
|
||||||
|
|
||||||
stepCount = motionController.NbSteps();
|
stepCount = motionController.NbSteps();
|
||||||
if (stepCount.IsUpdated()) {
|
if (stepCount.IsUpdated()) {
|
||||||
lv_label_set_text_fmt(stepValue, R_LTGREY("step=")"#ee3377 %lu steps#", stepCount.Get());
|
if (stepCount.Get()) {
|
||||||
|
lv_label_set_text_fmt(stepValue, R_LTGREY("step=")"#ee3377 %lu steps#", stepCount.Get());
|
||||||
|
} else {
|
||||||
|
lv_label_set_text_static(stepValue, R_LTGREY("step=---"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// QuickSettings is the screen with four icons:
|
||||||
|
//
|
||||||
|
// - brightness
|
||||||
|
// - torch
|
||||||
|
// - notifications mode
|
||||||
|
// - settings
|
||||||
|
//
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "displayapp/screens/Screen.h"
|
#include "displayapp/screens/Screen.h"
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue