Compare commits
48 Commits
Watch_Bina
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
77f1a3e230 | ||
|
11acaeadd3 | ||
4fa8e02289 | |||
0cc8017cbd | |||
d758394ce9 | |||
dd5d65d315 | |||
2bffcf99f0 | |||
|
9b8eb75f34 | ||
|
b191a30947 | ||
|
d930fd4fa2 | ||
|
e6b96c2863 | ||
|
77546c9fe2 | ||
e24323b454 | |||
79820669b6 | |||
1ff782cb0e | |||
5d7e1ae1f3 | |||
415ff6c05c | |||
2cb36d6e80 | |||
cbfd82959e | |||
ce136ea148 | |||
ab03504d0c | |||
e4b4fba5a1 | |||
2ffc63b1d8 | |||
31250fd579 | |||
94044d2fdc | |||
|
858bf4f96e | ||
|
1487a16f4a | ||
|
13af2bb96c | ||
e0e2126c29 | |||
6a772e7e8e | |||
191f99904c | |||
8ada9410a1 | |||
bbfef9ee5c | |||
886e425461 | |||
|
6bbdb581cc | ||
|
270d15a8ea | ||
|
bf8c4dfef8 | ||
|
ecbcce41d7 | ||
|
3d75a7dc9f | ||
|
9d749434b5 | ||
|
8ff6bd9cae | ||
|
eac460f030 | ||
|
46b664b528 | ||
|
b488811f7f | ||
|
e19e870290 | ||
cdd97b3871 | |||
b95823e745 | |||
292b7e3fb1 |
@ -11,6 +11,7 @@ RUN apt-get update -qq \
|
|||||||
make \
|
make \
|
||||||
python3 \
|
python3 \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
|
python3-pil \
|
||||||
tar \
|
tar \
|
||||||
unzip \
|
unzip \
|
||||||
wget \
|
wget \
|
||||||
|
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -31,6 +31,10 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
- name: Install resource build dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get -y install --no-install-recommends python3-pil
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: /opt/build.sh all
|
run: /opt/build.sh all
|
||||||
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
|
|
||||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release")
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release")
|
||||||
|
|
||||||
project(pinetime VERSION 1.13.0 LANGUAGES C CXX ASM)
|
project(pinetime VERSION 1.13.1.1 LANGUAGES C CXX ASM)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
18
README.md
18
README.md
@ -1,5 +1,8 @@
|
|||||||
# TODO
|
# TODO
|
||||||
## Completed
|
## Completed
|
||||||
|
### Pending version
|
||||||
|
|
||||||
|
### v1.13.1
|
||||||
- [x] Make $s in terminal watch face green
|
- [x] Make $s in terminal watch face green
|
||||||
- [x] Swipe left to access music control
|
- [x] Swipe left to access music control
|
||||||
- [x] Flashlight starts on
|
- [x] Flashlight starts on
|
||||||
@ -9,6 +12,8 @@
|
|||||||
- [x] Swipe left/right goes to watchface/another app
|
- [x] Swipe left/right goes to watchface/another app
|
||||||
- [x] Rearrange quick acces and apps
|
- [x] Rearrange quick acces and apps
|
||||||
- [x] Exponent button on calculator
|
- [x] Exponent button on calculator
|
||||||
|
- [x] Seconds on digital watchface
|
||||||
|
- [x] Add quick ring settings
|
||||||
|
|
||||||
## Pending merge
|
## Pending merge
|
||||||
|
|
||||||
@ -17,18 +22,17 @@
|
|||||||
- [ ] Countdown timer presistant buzz
|
- [ ] Countdown timer presistant buzz
|
||||||
|
|
||||||
### Josh
|
### Josh
|
||||||
- [ ] Seconds on digital watchface
|
- [ ] Smiley face watchface :)
|
||||||
- [ ] Battery on digital watchface
|
- [ ] Remap button double click
|
||||||
- [ ] Remap button double click (to music app)
|
|
||||||
|
|
||||||
### Moses
|
### Moses
|
||||||
|
|
||||||
|
|
||||||
- [ ] Add quick ring settings
|
|
||||||
|
|
||||||
## Medium priority
|
## Medium priority
|
||||||
- [ ] Temp sensor w/ arduino
|
- [ ] Battery on digital watchface
|
||||||
- [ ] Homeassistant control
|
- [ ] More watchfaces!
|
||||||
|
|
||||||
## Lower priority
|
## Lower priority
|
||||||
- [ ] Maybe some prank watchfaces
|
- [ ] Temp sensor w/ arduino
|
||||||
|
- [ ] Homeassistant control
|
||||||
|
@ -42,7 +42,7 @@ CMake configures the project according to variables you specify the command line
|
|||||||
**NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
|
**NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
|
||||||
**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`
|
**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`
|
||||||
**BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1`
|
**BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1`
|
||||||
**BUILD_RESOURCES (\*\*)**| Generate external resource while building (needs [lv_font_conv](https://github.com/lvgl/lv_font_conv) and [lv_img_conv](https://github.com/lvgl/lv_img_conv). |`-DBUILD_RESOURCES=1`
|
**BUILD_RESOURCES (\*\*)**| Generate external resource while building (needs [lv_font_conv](https://github.com/lvgl/lv_font_conv) and [python3-pil/pillow](https://pillow.readthedocs.io) module). |`-DBUILD_RESOURCES=1`
|
||||||
**TARGET_DEVICE**|Target device, used for hardware configuration. Allowed: `PINETIME, MOY-TFK5, MOY-TIN5, MOY-TON5, MOY-UNK`|`-DTARGET_DEVICE=PINETIME` (Default)
|
**TARGET_DEVICE**|Target device, used for hardware configuration. Allowed: `PINETIME, MOY-TFK5, MOY-TIN5, MOY-TON5, MOY-UNK`|`-DTARGET_DEVICE=PINETIME` (Default)
|
||||||
|
|
||||||
#### (\*) Note about **CMAKE_BUILD_TYPE**
|
#### (\*) Note about **CMAKE_BUILD_TYPE**
|
||||||
@ -98,4 +98,4 @@ Binary files are generated into the folder `src`:
|
|||||||
- **pinetime-mcuboot-app-image** : MCUBoot image of the firmware
|
- **pinetime-mcuboot-app-image** : MCUBoot image of the firmware
|
||||||
- **pinetime-mcuboot-app-dfu** : DFU file of the firmware
|
- **pinetime-mcuboot-app-dfu** : DFU file of the firmware
|
||||||
|
|
||||||
The same files are generated for **pinetime-recovery** and **pinetime-recoveryloader**
|
The same files are generated for **pinetime-recovery** and **pinetime-recovery-loader**
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
FROM ubuntu:22.04
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
ARG NODE_MAJOR=20
|
||||||
RUN apt-get update -qq \
|
RUN apt-get update -qq \
|
||||||
|
&& apt-get install -y ca-certificates curl gnupg \
|
||||||
|
&& mkdir -p /etc/apt/keyrings \
|
||||||
|
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
|
||||||
|
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \
|
||||||
|
&& apt-get update -qq \
|
||||||
&& apt-get install -y \
|
&& apt-get install -y \
|
||||||
# x86_64 / generic packages
|
# x86_64 / generic packages
|
||||||
bash \
|
bash \
|
||||||
@ -9,13 +15,14 @@ RUN apt-get update -qq \
|
|||||||
cmake \
|
cmake \
|
||||||
git \
|
git \
|
||||||
make \
|
make \
|
||||||
|
nodejs \
|
||||||
python3 \
|
python3 \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
|
python3-pil \
|
||||||
python-is-python3 \
|
python-is-python3 \
|
||||||
tar \
|
tar \
|
||||||
unzip \
|
unzip \
|
||||||
wget \
|
wget \
|
||||||
curl \
|
|
||||||
# aarch64 packages
|
# aarch64 packages
|
||||||
libffi-dev \
|
libffi-dev \
|
||||||
libssl-dev \
|
libssl-dev \
|
||||||
@ -28,8 +35,6 @@ RUN apt-get update -qq \
|
|||||||
libpango-1.0-0 \
|
libpango-1.0-0 \
|
||||||
ibpango1.0-dev \
|
ibpango1.0-dev \
|
||||||
libpangocairo-1.0-0 \
|
libpangocairo-1.0-0 \
|
||||||
&& curl -sL https://deb.nodesource.com/setup_18.x | bash - \
|
|
||||||
&& apt-get install -y nodejs \
|
|
||||||
&& rm -rf /var/cache/apt/* /var/lib/apt/lists/*;
|
&& rm -rf /var/cache/apt/* /var/lib/apt/lists/*;
|
||||||
|
|
||||||
# Git needed for PROJECT_GIT_COMMIT_HASH variable setting
|
# Git needed for PROJECT_GIT_COMMIT_HASH variable setting
|
||||||
@ -39,10 +44,6 @@ RUN pip3 install -Iv cryptography==3.3
|
|||||||
RUN pip3 install cbor
|
RUN pip3 install cbor
|
||||||
RUN npm i lv_font_conv@1.5.2 -g
|
RUN npm i lv_font_conv@1.5.2 -g
|
||||||
|
|
||||||
RUN npm i ts-node@10.9.1 -g
|
|
||||||
RUN npm i @swc/core -g
|
|
||||||
RUN npm i lv_img_conv@0.3.0 -g
|
|
||||||
|
|
||||||
# build.sh knows how to compile
|
# build.sh knows how to compile
|
||||||
COPY build.sh /opt/
|
COPY build.sh /opt/
|
||||||
|
|
||||||
|
@ -426,6 +426,7 @@ list(APPEND SOURCE_FILES
|
|||||||
displayapp/screens/settings/SettingChimes.cpp
|
displayapp/screens/settings/SettingChimes.cpp
|
||||||
displayapp/screens/settings/SettingShakeThreshold.cpp
|
displayapp/screens/settings/SettingShakeThreshold.cpp
|
||||||
displayapp/screens/settings/SettingBluetooth.cpp
|
displayapp/screens/settings/SettingBluetooth.cpp
|
||||||
|
displayapp/screens/settings/SettingQuickR.cpp
|
||||||
|
|
||||||
## Watch faces
|
## Watch faces
|
||||||
displayapp/screens/WatchFaceAnalog.cpp
|
displayapp/screens/WatchFaceAnalog.cpp
|
||||||
@ -434,6 +435,7 @@ list(APPEND SOURCE_FILES
|
|||||||
displayapp/screens/WatchFaceTerminal.cpp
|
displayapp/screens/WatchFaceTerminal.cpp
|
||||||
displayapp/screens/WatchFacePineTimeStyle.cpp
|
displayapp/screens/WatchFacePineTimeStyle.cpp
|
||||||
displayapp/screens/WatchFaceCasioStyleG7710.cpp
|
displayapp/screens/WatchFaceCasioStyleG7710.cpp
|
||||||
|
displayapp/screens/WatchFaceFace.cpp
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
||||||
|
@ -404,7 +404,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Clouds>& WeatherService::GetCurrentClouds() {
|
std::unique_ptr<WeatherData::Clouds>& WeatherService::GetCurrentClouds() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Clouds && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Clouds && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Clouds>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Clouds>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,7 +416,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Obscuration>& WeatherService::GetCurrentObscuration() {
|
std::unique_ptr<WeatherData::Obscuration>& WeatherService::GetCurrentObscuration() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Obscuration && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Obscuration && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Obscuration>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Obscuration>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -426,7 +428,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Precipitation>& WeatherService::GetCurrentPrecipitation() {
|
std::unique_ptr<WeatherData::Precipitation>& WeatherService::GetCurrentPrecipitation() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Precipitation && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Precipitation && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Precipitation>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Precipitation>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,7 +440,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Wind>& WeatherService::GetCurrentWind() {
|
std::unique_ptr<WeatherData::Wind>& WeatherService::GetCurrentWind() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Wind && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Wind && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Wind>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Wind>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,7 +452,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Temperature>& WeatherService::GetCurrentTemperature() {
|
std::unique_ptr<WeatherData::Temperature>& WeatherService::GetCurrentTemperature() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Temperature && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Temperature>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Temperature>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,7 +464,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Humidity>& WeatherService::GetCurrentHumidity() {
|
std::unique_ptr<WeatherData::Humidity>& WeatherService::GetCurrentHumidity() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Humidity && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Humidity && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Humidity>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Humidity>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,7 +476,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Pressure>& WeatherService::GetCurrentPressure() {
|
std::unique_ptr<WeatherData::Pressure>& WeatherService::GetCurrentPressure() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Pressure && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Pressure && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Pressure>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Pressure>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,7 +488,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::Location>& WeatherService::GetCurrentLocation() {
|
std::unique_ptr<WeatherData::Location>& WeatherService::GetCurrentLocation() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::Location && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::Location && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::Location>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::Location>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -492,7 +500,8 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<WeatherData::AirQuality>& WeatherService::GetCurrentQuality() {
|
std::unique_ptr<WeatherData::AirQuality>& WeatherService::GetCurrentQuality() {
|
||||||
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
|
||||||
for (auto&& header : this->timeline) {
|
for (auto&& header : this->timeline) {
|
||||||
if (header->eventType == WeatherData::eventtype::AirQuality && IsEventStillValid(header, currentTimestamp)) {
|
if (header->eventType == WeatherData::eventtype::AirQuality && currentTimestamp >= header->timestamp &&
|
||||||
|
IsEventStillValid(header, currentTimestamp)) {
|
||||||
return reinterpret_cast<std::unique_ptr<WeatherData::AirQuality>&>(header);
|
return reinterpret_cast<std::unique_ptr<WeatherData::AirQuality>&>(header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,58 @@
|
|||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
TimerHandle_t vibTimer;
|
||||||
|
|
||||||
|
void PatternStep(TimerHandle_t xTimer) {
|
||||||
|
/* Vibration pattern format:
|
||||||
|
* {
|
||||||
|
* durationOfVibration,
|
||||||
|
* durationOfPause,
|
||||||
|
* durationOfVibration,
|
||||||
|
* durationOfPause,
|
||||||
|
* ...,
|
||||||
|
* durationOfVibration,
|
||||||
|
* zeroTerminator
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Patterns can be any length
|
||||||
|
* The pattern must end with a duration of vibration and a terminator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static constexpr uint8_t vibrationPattern[] = {10, 100, 50, 200, 10, 0};
|
||||||
|
|
||||||
|
static size_t patternPosition = 0;
|
||||||
|
if (vibrationPattern[patternPosition] != 0 && xTimerChangePeriod(vibTimer, vibrationPattern[patternPosition] << 1, 0) == pdPASS &&
|
||||||
|
xTimerStart(vibTimer, 0) == pdPASS) {
|
||||||
|
if (patternPosition % 2 == 0) {
|
||||||
|
nrf_gpio_pin_clear(Pinetime::PinMap::Motor);
|
||||||
|
} else {
|
||||||
|
nrf_gpio_pin_set(Pinetime::PinMap::Motor);
|
||||||
|
}
|
||||||
|
patternPosition++;
|
||||||
|
} else {
|
||||||
|
patternPosition = 0;
|
||||||
|
nrf_gpio_pin_set(Pinetime::PinMap::Motor);
|
||||||
|
auto* motorController = static_cast<MotorController*>(pvTimerGetTimerID(xTimer));
|
||||||
|
motorController->PatternFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MotorController::Init() {
|
void MotorController::Init() {
|
||||||
nrf_gpio_cfg_output(PinMap::Motor);
|
nrf_gpio_cfg_output(PinMap::Motor);
|
||||||
nrf_gpio_pin_set(PinMap::Motor);
|
nrf_gpio_pin_set(PinMap::Motor);
|
||||||
|
|
||||||
|
vibTimer = xTimerCreate("vibration", 1, pdFALSE, this, PatternStep);
|
||||||
shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor);
|
shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor);
|
||||||
longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring);
|
longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MotorController::PatternFinished() {
|
||||||
|
patternPlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
void MotorController::Ring(TimerHandle_t xTimer) {
|
void MotorController::Ring(TimerHandle_t xTimer) {
|
||||||
auto* motorController = static_cast<MotorController*>(pvTimerGetTimerID(xTimer));
|
auto* motorController = static_cast<MotorController*>(pvTimerGetTimerID(xTimer));
|
||||||
motorController->RunForDuration(50);
|
motorController->RunForDuration(50);
|
||||||
@ -24,6 +68,15 @@ void MotorController::RunForDuration(uint8_t motorDuration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MotorController::StartPattern() {
|
||||||
|
if (!patternPlaying) {
|
||||||
|
patternPlaying = true;
|
||||||
|
PatternStep(vibTimer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void MotorController::StartRinging() {
|
void MotorController::StartRinging() {
|
||||||
RunForDuration(50);
|
RunForDuration(50);
|
||||||
xTimerStart(longVib, 0);
|
xTimerStart(longVib, 0);
|
||||||
|
@ -15,10 +15,13 @@ namespace Pinetime {
|
|||||||
void RunForDuration(uint8_t motorDuration);
|
void RunForDuration(uint8_t motorDuration);
|
||||||
void StartRinging();
|
void StartRinging();
|
||||||
void StopRinging();
|
void StopRinging();
|
||||||
|
void PatternFinished();
|
||||||
|
bool StartPattern();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void Ring(TimerHandle_t xTimer);
|
static void Ring(TimerHandle_t xTimer);
|
||||||
static void StopMotor(TimerHandle_t xTimer);
|
static void StopMotor(TimerHandle_t xTimer);
|
||||||
|
bool patternPlaying;
|
||||||
TimerHandle_t shortVib;
|
TimerHandle_t shortVib;
|
||||||
TimerHandle_t longVib;
|
TimerHandle_t longVib;
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ namespace Pinetime {
|
|||||||
enum class Notification : uint8_t { On, Off, Sleep };
|
enum class Notification : uint8_t { On, Off, Sleep };
|
||||||
enum class ChimesOption : uint8_t { None, Hours, HalfHours };
|
enum class ChimesOption : uint8_t { None, Hours, HalfHours };
|
||||||
enum class WakeUpMode : uint8_t { SingleTap = 0, DoubleTap = 1, RaiseWrist = 2, Shake = 3, LowerWrist = 4 };
|
enum class WakeUpMode : uint8_t { SingleTap = 0, DoubleTap = 1, RaiseWrist = 2, Shake = 3, LowerWrist = 4 };
|
||||||
|
enum class QuickApp : uint8_t { MusicPlayer = 0, Calculator = 1, Alarm = 2, Timer = 3, HeartRate = 4 }; //, Alarm = 5, Timer = 6, Stopwatch = 7 };
|
||||||
enum class Colors : uint8_t {
|
enum class Colors : uint8_t {
|
||||||
White,
|
White,
|
||||||
Silver,
|
Silver,
|
||||||
@ -241,6 +242,14 @@ namespace Pinetime {
|
|||||||
return getWakeUpModes()[static_cast<size_t>(mode)];
|
return getWakeUpModes()[static_cast<size_t>(mode)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SetBrightness(Controllers::BrightnessController::Levels level) {
|
void SetBrightness(Controllers::BrightnessController::Levels level) {
|
||||||
if (level != settings.brightLevel) {
|
if (level != settings.brightLevel) {
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
@ -271,6 +280,26 @@ namespace Pinetime {
|
|||||||
return bleRadioEnabled;
|
return bleRadioEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// New Settings
|
||||||
|
void SetQuickRModes(QuickApp App_now, bool enabled) {
|
||||||
|
if (enabled != isQuickROn(App_now)) {
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
settings.quickApp.set(static_cast<size_t>(App_now), enabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::bitset<5> getQuickRModes() const {
|
||||||
|
return settings.quickApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isQuickROn(const QuickApp app_holder) const {
|
||||||
|
return getQuickRModes()[static_cast<size_t>(app_holder)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pinetime::Controllers::FS& fs;
|
Pinetime::Controllers::FS& fs;
|
||||||
|
|
||||||
@ -279,6 +308,7 @@ namespace Pinetime {
|
|||||||
struct SettingsData {
|
struct SettingsData {
|
||||||
uint32_t version = settingsVersion;
|
uint32_t version = settingsVersion;
|
||||||
uint32_t stepsGoal = 10000;
|
uint32_t stepsGoal = 10000;
|
||||||
|
uint32_t setquickr = 10000;
|
||||||
uint32_t screenTimeOut = 15000;
|
uint32_t screenTimeOut = 15000;
|
||||||
|
|
||||||
ClockType clockType = ClockType::H24;
|
ClockType clockType = ClockType::H24;
|
||||||
@ -292,6 +322,7 @@ namespace Pinetime {
|
|||||||
WatchFaceInfineat watchFaceInfineat;
|
WatchFaceInfineat watchFaceInfineat;
|
||||||
|
|
||||||
std::bitset<5> wakeUpMode {0};
|
std::bitset<5> wakeUpMode {0};
|
||||||
|
std::bitset<5> quickApp {0};
|
||||||
uint16_t shakeWakeThreshold = 150;
|
uint16_t shakeWakeThreshold = 150;
|
||||||
|
|
||||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||||
|
@ -38,7 +38,8 @@ namespace Pinetime {
|
|||||||
SettingShakeThreshold,
|
SettingShakeThreshold,
|
||||||
SettingBluetooth,
|
SettingBluetooth,
|
||||||
Error,
|
Error,
|
||||||
Calculator
|
Calculator,
|
||||||
|
SettingQuickR
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "displayapp/screens/settings/SettingChimes.h"
|
#include "displayapp/screens/settings/SettingChimes.h"
|
||||||
#include "displayapp/screens/settings/SettingShakeThreshold.h"
|
#include "displayapp/screens/settings/SettingShakeThreshold.h"
|
||||||
#include "displayapp/screens/settings/SettingBluetooth.h"
|
#include "displayapp/screens/settings/SettingBluetooth.h"
|
||||||
|
#include "displayapp/screens/settings/SettingQuickR.h"
|
||||||
|
|
||||||
#include "libs/lv_conf.h"
|
#include "libs/lv_conf.h"
|
||||||
|
|
||||||
@ -294,7 +295,7 @@ void DisplayApp::Refresh() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!currentScreen->OnTouchEvent(gesture)) {
|
if (!currentScreen->OnTouchEvent(gesture)) {
|
||||||
if (currentApp == Apps::Clock || currentApp == Apps::Music || currentApp == Apps::Calculator || currentApp == Apps::QuickSettings) {
|
if (currentApp == Apps::Clock || currentApp == Apps::QuickSettings || (currentApp == Apps::Music && quick_app[0]) || (currentApp == Apps::Calculator && quick_app[1]) || (currentApp == Apps::Alarm && quick_app[2]) || (currentApp == Apps::Timer && quick_app[3]) || (currentApp == Apps::HeartRate && quick_app[4])) {
|
||||||
switch (gesture) {
|
switch (gesture) {
|
||||||
case TouchEvents::SwipeUp:
|
case TouchEvents::SwipeUp:
|
||||||
if (currentApp == Apps::Clock) {
|
if (currentApp == Apps::Clock) {
|
||||||
@ -311,26 +312,10 @@ void DisplayApp::Refresh() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TouchEvents::SwipeRight:
|
case TouchEvents::SwipeRight:
|
||||||
if (currentApp == Apps::Clock) {
|
gotoquickapp(-1);
|
||||||
LoadNewScreen(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim);
|
|
||||||
} else if (currentApp == Apps::QuickSettings) {
|
|
||||||
LoadNewScreen(Apps::Calculator, DisplayApp::FullRefreshDirections::RightAnim);
|
|
||||||
} else if (currentApp == Apps::Calculator) {
|
|
||||||
LoadNewScreen(Apps::Music, DisplayApp::FullRefreshDirections::RightAnim);
|
|
||||||
} else {
|
|
||||||
LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::RightAnim);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case TouchEvents::SwipeLeft:
|
case TouchEvents::SwipeLeft:
|
||||||
if (currentApp == Apps::Clock) {
|
gotoquickapp(1);
|
||||||
LoadNewScreen(Apps::Music, DisplayApp::FullRefreshDirections::LeftAnim);
|
|
||||||
} else if (currentApp == Apps::Music) {
|
|
||||||
LoadNewScreen(Apps::Calculator, DisplayApp::FullRefreshDirections::LeftAnim);
|
|
||||||
} else if (currentApp == Apps::Calculator) {
|
|
||||||
LoadNewScreen(Apps::QuickSettings, DisplayApp::FullRefreshDirections::LeftAnim);
|
|
||||||
} else {
|
|
||||||
LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case TouchEvents::DoubleTap:
|
case TouchEvents::DoubleTap:
|
||||||
PushMessageToSystemTask(System::Messages::GoToSleep);
|
PushMessageToSystemTask(System::Messages::GoToSleep);
|
||||||
@ -349,6 +334,7 @@ void DisplayApp::Refresh() {
|
|||||||
if (!currentScreen->OnButtonPushed()) {
|
if (!currentScreen->OnButtonPushed()) {
|
||||||
if (currentApp == Apps::Clock) {
|
if (currentApp == Apps::Clock) {
|
||||||
PushMessageToSystemTask(System::Messages::GoToSleep);
|
PushMessageToSystemTask(System::Messages::GoToSleep);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LoadPreviousScreen();
|
LoadPreviousScreen();
|
||||||
}
|
}
|
||||||
@ -388,8 +374,19 @@ void DisplayApp::Refresh() {
|
|||||||
// What should happen here?
|
// What should happen here?
|
||||||
break;
|
break;
|
||||||
case Messages::Chime:
|
case Messages::Chime:
|
||||||
LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
|
||||||
motorController.RunForDuration(35);
|
time_var = dateTimeController.Minutes();
|
||||||
|
if (time_var == 30){
|
||||||
|
//NRF_LOG_INFO("Short: %d", time_var);
|
||||||
|
motorController.StartPattern();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//NRF_LOG_INFO("Long: %d", time_var);
|
||||||
|
motorController.RunForDuration(200);
|
||||||
|
}
|
||||||
|
//LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Messages::OnChargingEvent:
|
case Messages::OnChargingEvent:
|
||||||
RestoreBrightness();
|
RestoreBrightness();
|
||||||
@ -442,6 +439,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
|
|||||||
// break;
|
// break;
|
||||||
case Apps::None:
|
case Apps::None:
|
||||||
case Apps::Clock:
|
case Apps::Clock:
|
||||||
|
currentQ_app = 2;
|
||||||
currentScreen = std::make_unique<Screens::Clock>(dateTimeController,
|
currentScreen = std::make_unique<Screens::Clock>(dateTimeController,
|
||||||
batteryController,
|
batteryController,
|
||||||
bleController,
|
bleController,
|
||||||
@ -583,6 +581,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
|
|||||||
case Apps::Calculator:
|
case Apps::Calculator:
|
||||||
currentScreen = std::make_unique<Screens::Calculator>();
|
currentScreen = std::make_unique<Screens::Calculator>();
|
||||||
break;
|
break;
|
||||||
|
case Apps::SettingQuickR:
|
||||||
|
currentScreen = std::make_unique<Screens::SettingQuickR>(settingsController);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
currentApp = app;
|
currentApp = app;
|
||||||
}
|
}
|
||||||
@ -642,3 +643,84 @@ void DisplayApp::ApplyBrightness() {
|
|||||||
}
|
}
|
||||||
brightnessController.Set(brightness);
|
brightnessController.Set(brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayApp::gotoquickapp(int app_step){
|
||||||
|
NRF_LOG_INFO("QuickRing Swiped");
|
||||||
|
currentQ_app += app_step;
|
||||||
|
|
||||||
|
quick_app = settingsController.getQuickRModes();
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
if(currentQ_app > 7)
|
||||||
|
{
|
||||||
|
currentQ_app = 1;
|
||||||
|
} else if(currentQ_app < 1)
|
||||||
|
{
|
||||||
|
currentQ_app = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentQ_app != 1 && currentQ_app != 2)
|
||||||
|
{
|
||||||
|
if(quick_app[currentQ_app-3])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentQ_app += (app_step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int quickringtotal = 2;
|
||||||
|
for(int i = 0; i < 5; i++){
|
||||||
|
quickringtotal += (quick_app[i] ? 1 : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NRF_LOG_INFO("case number current Q: %i", currentQ_app);
|
||||||
|
Apps app = Apps::Clock;
|
||||||
|
switch (currentQ_app) {
|
||||||
|
case 1:
|
||||||
|
app = Apps::QuickSettings;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
app = Apps::Clock;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
app = Apps::Music;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
app = Apps::Calculator;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
app = Apps::Alarm;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
app = Apps::Timer;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
app = Apps::HeartRate;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(app_step < 0){
|
||||||
|
LoadNewScreen(app, DisplayApp::FullRefreshDirections::RightAnim);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoadNewScreen(app, DisplayApp::FullRefreshDirections::LeftAnim);
|
||||||
|
}
|
||||||
|
//appStackDirections.Pop();
|
||||||
|
//returnAppStack.Pop();
|
||||||
|
}
|
@ -118,6 +118,8 @@ namespace Pinetime {
|
|||||||
void LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction);
|
void LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||||
void LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction);
|
void LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||||
void PushMessageToSystemTask(Pinetime::System::Messages message);
|
void PushMessageToSystemTask(Pinetime::System::Messages message);
|
||||||
|
void gotoquickapp(int app_step);
|
||||||
|
|
||||||
|
|
||||||
Apps nextApp = Apps::None;
|
Apps nextApp = Apps::None;
|
||||||
DisplayApp::FullRefreshDirections nextDirection;
|
DisplayApp::FullRefreshDirections nextDirection;
|
||||||
@ -128,7 +130,10 @@ namespace Pinetime {
|
|||||||
Utility::StaticStack<Apps, returnAppStackSize> returnAppStack;
|
Utility::StaticStack<Apps, returnAppStackSize> returnAppStack;
|
||||||
Utility::StaticStack<FullRefreshDirections, returnAppStackSize> appStackDirections;
|
Utility::StaticStack<FullRefreshDirections, returnAppStackSize> appStackDirections;
|
||||||
|
|
||||||
|
int time_var;
|
||||||
bool isDimmed = false;
|
bool isDimmed = false;
|
||||||
|
int currentQ_app = 2;
|
||||||
|
std::bitset<5> quick_app;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ namespace Pinetime {
|
|||||||
Terminal = 3,
|
Terminal = 3,
|
||||||
Infineat = 4,
|
Infineat = 4,
|
||||||
CasioStyleG7710 = 5,
|
CasioStyleG7710 = 5,
|
||||||
|
FaceFace = 6,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"file": "JetBrainsMono-Regular.ttf",
|
"file": "JetBrainsMono-Regular.ttf",
|
||||||
"range": "0x25, 0x2b, 0x2d, 0x30-0x3a"
|
"range": "0x25, 0x2b, 0x2d, 0x30-0x3a, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"bpp": 1,
|
"bpp": 1,
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "displayapp/screens/WatchFaceAnalog.h"
|
#include "displayapp/screens/WatchFaceAnalog.h"
|
||||||
#include "displayapp/screens/WatchFacePineTimeStyle.h"
|
#include "displayapp/screens/WatchFacePineTimeStyle.h"
|
||||||
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
|
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
|
||||||
|
#include "displayapp/screens/WatchFaceFace.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
using namespace Pinetime::Applications;
|
using namespace Pinetime::Applications;
|
||||||
@ -55,6 +56,9 @@ Clock::Clock(Controllers::DateTime& dateTimeController,
|
|||||||
case WatchFace::CasioStyleG7710:
|
case WatchFace::CasioStyleG7710:
|
||||||
return WatchFaceCasioStyleG7710();
|
return WatchFaceCasioStyleG7710();
|
||||||
break;
|
break;
|
||||||
|
case WatchFace::FaceFace:
|
||||||
|
return WatchFaceFaceScreen();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return WatchFaceDigitalScreen();
|
return WatchFaceDigitalScreen();
|
||||||
}()} {
|
}()} {
|
||||||
@ -127,7 +131,15 @@ std::unique_ptr<Screen> Clock::WatchFaceCasioStyleG7710() {
|
|||||||
bleController,
|
bleController,
|
||||||
notificationManager,
|
notificationManager,
|
||||||
settingsController,
|
settingsController,
|
||||||
heartRateController,
|
|
||||||
motionController,
|
motionController,
|
||||||
filesystem);
|
filesystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<Screen> Clock::WatchFaceFaceScreen() {
|
||||||
|
return std::make_unique<Screens::WatchFaceFace>(dateTimeController,
|
||||||
|
batteryController,
|
||||||
|
bleController,
|
||||||
|
notificationManager,
|
||||||
|
settingsController);
|
||||||
|
}
|
||||||
|
@ -54,6 +54,7 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<Screen> WatchFaceTerminalScreen();
|
std::unique_ptr<Screen> WatchFaceTerminalScreen();
|
||||||
std::unique_ptr<Screen> WatchFaceInfineatScreen();
|
std::unique_ptr<Screen> WatchFaceInfineatScreen();
|
||||||
std::unique_ptr<Screen> WatchFaceCasioStyleG7710();
|
std::unique_ptr<Screen> WatchFaceCasioStyleG7710();
|
||||||
|
std::unique_ptr<Screen> WatchFaceFaceScreen();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
#include "displayapp/InfiniTimeTheme.h"
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
#include <libraries/log/nrf_log.h>
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
@ -58,8 +59,17 @@ FlashLight::~FlashLight() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlashLight::SetColors() {
|
void FlashLight::SetColors() {
|
||||||
lv_color_t bgColor = isOn ? LV_COLOR_WHITE : LV_COLOR_BLACK;
|
lv_color_t bgColor = LV_COLOR_BLACK;
|
||||||
lv_color_t fgColor = isOn ? Colors::lightGray : LV_COLOR_WHITE;
|
if(State_l == 0){
|
||||||
|
bgColor = LV_COLOR_BLACK;
|
||||||
|
} else if (State_l == 1){
|
||||||
|
bgColor = LV_COLOR_WHITE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bgColor = lv_color_hex(0xff0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_color_t fgColor = State_l ? Colors::lightGray : LV_COLOR_WHITE;
|
||||||
|
|
||||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, bgColor);
|
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, bgColor);
|
||||||
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fgColor);
|
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fgColor);
|
||||||
@ -86,9 +96,11 @@ void FlashLight::SetIndicators() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlashLight::Toggle() {
|
void FlashLight::Toggle() {
|
||||||
isOn = !isOn;
|
State_l++;
|
||||||
|
if(State_l > 2)
|
||||||
|
State_l = 0;
|
||||||
SetColors();
|
SetColors();
|
||||||
if (isOn) {
|
if (State_l) {
|
||||||
brightnessController.Set(brightnessLevel);
|
brightnessController.Set(brightnessLevel);
|
||||||
} else {
|
} else {
|
||||||
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
||||||
@ -99,7 +111,7 @@ bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
auto SetState = [this]() {
|
auto SetState = [this]() {
|
||||||
if (isOn) {
|
if (State_l) {
|
||||||
brightnessController.Set(brightnessLevel);
|
brightnessController.Set(brightnessLevel);
|
||||||
}
|
}
|
||||||
SetIndicators();
|
SetIndicators();
|
||||||
|
@ -26,12 +26,13 @@ namespace Pinetime {
|
|||||||
Pinetime::System::SystemTask& systemTask;
|
Pinetime::System::SystemTask& systemTask;
|
||||||
Controllers::BrightnessController& brightnessController;
|
Controllers::BrightnessController& brightnessController;
|
||||||
|
|
||||||
|
|
||||||
Controllers::BrightnessController::Levels brightnessLevel = Controllers::BrightnessController::Levels::High;
|
Controllers::BrightnessController::Levels brightnessLevel = Controllers::BrightnessController::Levels::High;
|
||||||
|
|
||||||
lv_obj_t* flashLight;
|
lv_obj_t* flashLight;
|
||||||
lv_obj_t* backgroundAction;
|
lv_obj_t* backgroundAction;
|
||||||
lv_obj_t* indicators[3];
|
lv_obj_t* indicators[3];
|
||||||
bool isOn = false;
|
int State_l = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,19 +203,21 @@ Navigation::Navigation(Pinetime::Controllers::NavigationService& nav) : navServi
|
|||||||
lv_obj_align(imgFlag, nullptr, LV_ALIGN_CENTER, 0, -60);
|
lv_obj_align(imgFlag, nullptr, LV_ALIGN_CENTER, 0, -60);
|
||||||
|
|
||||||
txtNarrative = lv_label_create(lv_scr_act(), nullptr);
|
txtNarrative = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_long_mode(txtNarrative, LV_LABEL_LONG_BREAK);
|
lv_label_set_long_mode(txtNarrative, LV_LABEL_LONG_DOT);
|
||||||
lv_obj_set_width(txtNarrative, LV_HOR_RES);
|
lv_obj_set_width(txtNarrative, LV_HOR_RES);
|
||||||
|
lv_obj_set_height(txtNarrative, 80);
|
||||||
lv_label_set_text_static(txtNarrative, "Navigation");
|
lv_label_set_text_static(txtNarrative, "Navigation");
|
||||||
lv_label_set_align(txtNarrative, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(txtNarrative, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(txtNarrative, nullptr, LV_ALIGN_CENTER, 0, 10);
|
lv_obj_align(txtNarrative, nullptr, LV_ALIGN_CENTER, 0, 30);
|
||||||
|
|
||||||
txtManDist = lv_label_create(lv_scr_act(), nullptr);
|
txtManDist = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_long_mode(txtManDist, LV_LABEL_LONG_BREAK);
|
lv_label_set_long_mode(txtManDist, LV_LABEL_LONG_BREAK);
|
||||||
lv_obj_set_style_local_text_color(txtManDist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
lv_obj_set_style_local_text_color(txtManDist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||||
|
lv_obj_set_style_local_text_font(txtManDist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
|
||||||
lv_obj_set_width(txtManDist, LV_HOR_RES);
|
lv_obj_set_width(txtManDist, LV_HOR_RES);
|
||||||
lv_label_set_text_static(txtManDist, "--M");
|
lv_label_set_text_static(txtManDist, "--M");
|
||||||
lv_label_set_align(txtManDist, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(txtManDist, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(txtManDist, nullptr, LV_ALIGN_CENTER, 0, 60);
|
lv_obj_align(txtManDist, nullptr, LV_ALIGN_CENTER, 0, 90);
|
||||||
|
|
||||||
// Route Progress
|
// Route Progress
|
||||||
barProgress = lv_bar_create(lv_scr_act(), nullptr);
|
barProgress = lv_bar_create(lv_scr_act(), nullptr);
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "components/battery/BatteryController.h"
|
#include "components/battery/BatteryController.h"
|
||||||
#include "components/ble/BleController.h"
|
#include "components/ble/BleController.h"
|
||||||
#include "components/ble/NotificationManager.h"
|
#include "components/ble/NotificationManager.h"
|
||||||
#include "components/heartrate/HeartRateController.h"
|
|
||||||
#include "components/motion/MotionController.h"
|
#include "components/motion/MotionController.h"
|
||||||
#include "components/settings/Settings.h"
|
#include "components/settings/Settings.h"
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
@ -19,7 +18,6 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi
|
|||||||
const Controllers::Ble& bleController,
|
const Controllers::Ble& bleController,
|
||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
|
||||||
Controllers::MotionController& motionController,
|
Controllers::MotionController& motionController,
|
||||||
Controllers::FS& filesystem)
|
Controllers::FS& filesystem)
|
||||||
: currentDateTime {{}},
|
: currentDateTime {{}},
|
||||||
@ -29,7 +27,6 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi
|
|||||||
bleController {bleController},
|
bleController {bleController},
|
||||||
notificatioManager {notificatioManager},
|
notificatioManager {notificatioManager},
|
||||||
settingsController {settingsController},
|
settingsController {settingsController},
|
||||||
heartRateController {heartRateController},
|
|
||||||
motionController {motionController} {
|
motionController {motionController} {
|
||||||
|
|
||||||
lfs_file f = {};
|
lfs_file f = {};
|
||||||
@ -148,25 +145,20 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi
|
|||||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||||
lv_label_set_text_static(backgroundLabel, "");
|
lv_label_set_text_static(backgroundLabel, "");
|
||||||
|
|
||||||
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
|
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
||||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||||
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
|
lv_obj_align(stepIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
|
||||||
|
|
||||||
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
|
|
||||||
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
|
||||||
lv_label_set_text_static(heartbeatValue, "");
|
|
||||||
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 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, color_text);
|
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||||
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, -5, -2);
|
lv_obj_align(stepValue, stepIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||||
|
|
||||||
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
label_seconds = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
lv_obj_set_style_local_text_color(label_seconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||||
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
lv_label_set_text_static(label_seconds, "0");
|
||||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
lv_obj_align(label_seconds, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -9, -2);
|
||||||
|
|
||||||
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);
|
||||||
Refresh();
|
Refresh();
|
||||||
@ -222,10 +214,11 @@ void WatchFaceCasioStyleG7710::Refresh() {
|
|||||||
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDateTime = std::chrono::time_point_cast<std::chrono::minutes>(dateTimeController.CurrentDateTime());
|
currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime());
|
||||||
if (currentDateTime.IsUpdated()) {
|
if (currentDateTime.IsUpdated()) {
|
||||||
uint8_t hour = dateTimeController.Hours();
|
uint8_t hour = dateTimeController.Hours();
|
||||||
uint8_t minute = dateTimeController.Minutes();
|
uint8_t minute = dateTimeController.Minutes();
|
||||||
|
uint8_t second = dateTimeController.Seconds();
|
||||||
|
|
||||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
||||||
char ampmChar[2] = "A";
|
char ampmChar[2] = "A";
|
||||||
@ -244,6 +237,9 @@ void WatchFaceCasioStyleG7710::Refresh() {
|
|||||||
}
|
}
|
||||||
lv_obj_realign(label_time);
|
lv_obj_realign(label_time);
|
||||||
|
|
||||||
|
lv_label_set_text_fmt(label_seconds, "%02d", second);
|
||||||
|
lv_obj_realign(label_seconds);
|
||||||
|
|
||||||
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
|
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
|
||||||
if (currentDate.IsUpdated()) {
|
if (currentDate.IsUpdated()) {
|
||||||
const char* weekNumberFormat = "%V";
|
const char* weekNumberFormat = "%V";
|
||||||
@ -289,26 +285,11 @@ void WatchFaceCasioStyleG7710::Refresh() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
heartbeat = heartRateController.HeartRate();
|
|
||||||
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
|
|
||||||
if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
|
|
||||||
if (heartbeatRunning.Get()) {
|
|
||||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
|
||||||
lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get());
|
|
||||||
} else {
|
|
||||||
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_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());
|
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
|
||||||
lv_obj_realign(stepValue);
|
lv_obj_realign(stepValue);
|
||||||
lv_obj_realign(stepIcon);
|
lv_obj_realign(stepValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ namespace Pinetime {
|
|||||||
class Battery;
|
class Battery;
|
||||||
class Ble;
|
class Ble;
|
||||||
class NotificationManager;
|
class NotificationManager;
|
||||||
class HeartRateController;
|
|
||||||
class MotionController;
|
class MotionController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +29,6 @@ namespace Pinetime {
|
|||||||
const Controllers::Ble& bleController,
|
const Controllers::Ble& bleController,
|
||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
|
||||||
Controllers::MotionController& motionController,
|
Controllers::MotionController& motionController,
|
||||||
Controllers::FS& filesystem);
|
Controllers::FS& filesystem);
|
||||||
~WatchFaceCasioStyleG7710() override;
|
~WatchFaceCasioStyleG7710() override;
|
||||||
@ -44,10 +42,8 @@ namespace Pinetime {
|
|||||||
Utility::DirtyValue<bool> powerPresent {};
|
Utility::DirtyValue<bool> powerPresent {};
|
||||||
Utility::DirtyValue<bool> bleState {};
|
Utility::DirtyValue<bool> bleState {};
|
||||||
Utility::DirtyValue<bool> bleRadioEnabled {};
|
Utility::DirtyValue<bool> bleRadioEnabled {};
|
||||||
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
|
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> currentDateTime {};
|
||||||
Utility::DirtyValue<uint32_t> stepCount {};
|
Utility::DirtyValue<uint32_t> stepCount {};
|
||||||
Utility::DirtyValue<uint8_t> heartbeat {};
|
|
||||||
Utility::DirtyValue<bool> heartbeatRunning {};
|
|
||||||
Utility::DirtyValue<bool> notificationState {};
|
Utility::DirtyValue<bool> notificationState {};
|
||||||
using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
|
using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
|
||||||
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
|
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
|
||||||
@ -64,6 +60,7 @@ namespace Pinetime {
|
|||||||
lv_style_t style_border;
|
lv_style_t style_border;
|
||||||
|
|
||||||
lv_obj_t* label_time;
|
lv_obj_t* label_time;
|
||||||
|
lv_obj_t* label_seconds;
|
||||||
lv_obj_t* line_time;
|
lv_obj_t* line_time;
|
||||||
lv_obj_t* label_time_ampm;
|
lv_obj_t* label_time_ampm;
|
||||||
lv_obj_t* label_date;
|
lv_obj_t* label_date;
|
||||||
@ -77,8 +74,6 @@ namespace Pinetime {
|
|||||||
lv_obj_t* bleIcon;
|
lv_obj_t* bleIcon;
|
||||||
lv_obj_t* batteryPlug;
|
lv_obj_t* batteryPlug;
|
||||||
lv_obj_t* label_battery_value;
|
lv_obj_t* label_battery_value;
|
||||||
lv_obj_t* heartbeatIcon;
|
|
||||||
lv_obj_t* heartbeatValue;
|
|
||||||
lv_obj_t* stepIcon;
|
lv_obj_t* stepIcon;
|
||||||
lv_obj_t* stepValue;
|
lv_obj_t* stepValue;
|
||||||
lv_obj_t* notificationIcon;
|
lv_obj_t* notificationIcon;
|
||||||
@ -91,7 +86,6 @@ namespace Pinetime {
|
|||||||
const Controllers::Ble& bleController;
|
const Controllers::Ble& bleController;
|
||||||
Controllers::NotificationManager& notificatioManager;
|
Controllers::NotificationManager& notificatioManager;
|
||||||
Controllers::Settings& settingsController;
|
Controllers::Settings& settingsController;
|
||||||
Controllers::HeartRateController& heartRateController;
|
|
||||||
Controllers::MotionController& motionController;
|
Controllers::MotionController& motionController;
|
||||||
|
|
||||||
lv_task_t* taskRefresh;
|
lv_task_t* taskRefresh;
|
||||||
|
@ -35,6 +35,10 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController,
|
|||||||
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
|
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
|
||||||
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||||
|
|
||||||
|
label_seconds = lv_label_create(lv_scr_act(), nullptr); // for secs
|
||||||
|
lv_obj_align(label_seconds, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, -55);
|
||||||
|
lv_obj_set_style_local_text_color(label_seconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
||||||
|
|
||||||
label_date = lv_label_create(lv_scr_act(), nullptr);
|
label_date = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
|
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
|
||||||
lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
||||||
@ -44,10 +48,6 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController,
|
|||||||
|
|
||||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
|
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
|
||||||
|
|
||||||
label_time_ampm = lv_label_create(lv_scr_act(), nullptr);
|
|
||||||
lv_label_set_text_static(label_time_ampm, "");
|
|
||||||
lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -30, -55);
|
|
||||||
|
|
||||||
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(0xCE1B1B));
|
||||||
@ -85,23 +85,19 @@ void WatchFaceDigital::Refresh() {
|
|||||||
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDateTime = std::chrono::time_point_cast<std::chrono::minutes>(dateTimeController.CurrentDateTime());
|
currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime());
|
||||||
|
|
||||||
if (currentDateTime.IsUpdated()) {
|
if (currentDateTime.IsUpdated()) {
|
||||||
uint8_t hour = dateTimeController.Hours();
|
uint8_t hour = dateTimeController.Hours();
|
||||||
uint8_t minute = dateTimeController.Minutes();
|
uint8_t minute = dateTimeController.Minutes();
|
||||||
|
uint8_t second = dateTimeController.Seconds();
|
||||||
|
|
||||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
||||||
char ampmChar[3] = "AM";
|
|
||||||
if (hour == 0) {
|
if (hour == 0) {
|
||||||
hour = 12;
|
hour = 12;
|
||||||
} else if (hour == 12) {
|
|
||||||
ampmChar[0] = 'P';
|
|
||||||
} else if (hour > 12) {
|
} else if (hour > 12) {
|
||||||
hour = hour - 12;
|
hour = hour - 12;
|
||||||
ampmChar[0] = 'P';
|
|
||||||
}
|
}
|
||||||
lv_label_set_text(label_time_ampm, ampmChar);
|
|
||||||
lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute);
|
lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute);
|
||||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
|
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
@ -109,6 +105,8 @@ void WatchFaceDigital::Refresh() {
|
|||||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lv_label_set_text_fmt(label_seconds, "%02d", second); // for secs
|
||||||
|
|
||||||
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
|
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
|
||||||
if (currentDate.IsUpdated()) {
|
if (currentDate.IsUpdated()) {
|
||||||
uint16_t year = dateTimeController.Year();
|
uint16_t year = dateTimeController.Year();
|
||||||
|
@ -44,7 +44,7 @@ namespace Pinetime {
|
|||||||
Utility::DirtyValue<bool> powerPresent {};
|
Utility::DirtyValue<bool> powerPresent {};
|
||||||
Utility::DirtyValue<bool> bleState {};
|
Utility::DirtyValue<bool> bleState {};
|
||||||
Utility::DirtyValue<bool> bleRadioEnabled {};
|
Utility::DirtyValue<bool> bleRadioEnabled {};
|
||||||
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
|
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> currentDateTime {};
|
||||||
Utility::DirtyValue<uint32_t> stepCount {};
|
Utility::DirtyValue<uint32_t> stepCount {};
|
||||||
Utility::DirtyValue<uint8_t> heartbeat {};
|
Utility::DirtyValue<uint8_t> heartbeat {};
|
||||||
Utility::DirtyValue<bool> heartbeatRunning {};
|
Utility::DirtyValue<bool> heartbeatRunning {};
|
||||||
@ -53,7 +53,8 @@ namespace Pinetime {
|
|||||||
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
|
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
|
||||||
|
|
||||||
lv_obj_t* label_time;
|
lv_obj_t* label_time;
|
||||||
lv_obj_t* label_time_ampm;
|
lv_obj_t* label_seconds; //for secs
|
||||||
|
lv_obj_t* batteryValue;
|
||||||
lv_obj_t* label_date;
|
lv_obj_t* label_date;
|
||||||
lv_obj_t* heartbeatIcon;
|
lv_obj_t* heartbeatIcon;
|
||||||
lv_obj_t* heartbeatValue;
|
lv_obj_t* heartbeatValue;
|
||||||
|
274
src/displayapp/screens/WatchFaceFace.cpp
Normal file
274
src/displayapp/screens/WatchFaceFace.cpp
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
#include "displayapp/screens/WatchFaceFace.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <lvgl/lvgl.h>
|
||||||
|
#include "displayapp/screens/BatteryIcon.h"
|
||||||
|
#include "displayapp/screens/BleIcon.h"
|
||||||
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/screens/NotificationIcon.h"
|
||||||
|
#include "components/settings/Settings.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int16_t HourLength = 100;
|
||||||
|
constexpr int16_t MinuteLength = 90;
|
||||||
|
constexpr int16_t SecondLength = 110;
|
||||||
|
|
||||||
|
// sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor
|
||||||
|
const auto LV_TRIG_SCALE = _lv_trigo_sin(90);
|
||||||
|
|
||||||
|
int16_t Cosine(int16_t angle) {
|
||||||
|
return _lv_trigo_sin(angle + 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t Sine(int16_t angle) {
|
||||||
|
return _lv_trigo_sin(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t CoordinateXRelocate(int16_t x) {
|
||||||
|
return (x + LV_HOR_RES / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t CoordinateYRelocate(int16_t y) {
|
||||||
|
return std::abs(y - LV_HOR_RES / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_point_t CoordinateRelocate(int16_t radius, int16_t angle) {
|
||||||
|
return lv_point_t {.x = CoordinateXRelocate(radius * static_cast<int32_t>(Sine(angle)) / LV_TRIG_SCALE),
|
||||||
|
.y = CoordinateYRelocate(radius * static_cast<int32_t>(Cosine(angle)) / LV_TRIG_SCALE)};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
WatchFaceFace::WatchFaceFace(Controllers::DateTime& dateTimeController,
|
||||||
|
const Controllers::Battery& batteryController,
|
||||||
|
const Controllers::Ble& bleController,
|
||||||
|
Controllers::NotificationManager& notificationManager,
|
||||||
|
Controllers::Settings& settingsController)
|
||||||
|
: currentDateTime {{}},
|
||||||
|
batteryIcon(true),
|
||||||
|
dateTimeController {dateTimeController},
|
||||||
|
batteryController {batteryController},
|
||||||
|
bleController {bleController},
|
||||||
|
notificationManager {notificationManager},
|
||||||
|
settingsController {settingsController} {
|
||||||
|
|
||||||
|
sHour = 99;
|
||||||
|
sMinute = 99;
|
||||||
|
sSecond = 99;
|
||||||
|
|
||||||
|
mouth = lv_arc_create(lv_scr_act(), nullptr);
|
||||||
|
lv_arc_set_angles(mouth, 30, 110);
|
||||||
|
lv_arc_set_bg_angles(mouth, 45, 135);
|
||||||
|
lv_obj_set_size(mouth, 130, 130);
|
||||||
|
lv_obj_align(mouth, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
|
||||||
|
leye = lv_arc_create(lv_scr_act(), nullptr);
|
||||||
|
lv_arc_set_angles(leye, 0, 360);
|
||||||
|
lv_obj_set_size(leye, 30, 30);
|
||||||
|
lv_obj_align(leye, nullptr, LV_ALIGN_CENTER, -35, -35);
|
||||||
|
|
||||||
|
reye = lv_arc_create(lv_scr_act(), nullptr);
|
||||||
|
lv_arc_set_angles(reye, 0, 360);
|
||||||
|
lv_obj_set_size(reye, 30, 30);
|
||||||
|
lv_obj_align(reye, nullptr, LV_ALIGN_CENTER, 35, -35);
|
||||||
|
|
||||||
|
|
||||||
|
minor_scales = lv_linemeter_create(lv_scr_act(), nullptr);
|
||||||
|
lv_linemeter_set_scale(minor_scales, 300, 51);
|
||||||
|
lv_linemeter_set_angle_offset(minor_scales, 180);
|
||||||
|
lv_obj_set_size(minor_scales, 240, 240);
|
||||||
|
lv_obj_align(minor_scales, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
lv_obj_set_style_local_bg_opa(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||||
|
lv_obj_set_style_local_scale_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4);
|
||||||
|
lv_obj_set_style_local_scale_end_line_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 1);
|
||||||
|
lv_obj_set_style_local_scale_end_color(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||||
|
|
||||||
|
major_scales = lv_linemeter_create(lv_scr_act(), nullptr);
|
||||||
|
lv_linemeter_set_scale(major_scales, 300, 11);
|
||||||
|
lv_linemeter_set_angle_offset(major_scales, 180);
|
||||||
|
lv_obj_set_size(major_scales, 240, 240);
|
||||||
|
lv_obj_align(major_scales, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
lv_obj_set_style_local_bg_opa(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||||
|
lv_obj_set_style_local_scale_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 6);
|
||||||
|
lv_obj_set_style_local_scale_end_line_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4);
|
||||||
|
lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
|
|
||||||
|
large_scales = lv_linemeter_create(lv_scr_act(), nullptr);
|
||||||
|
lv_linemeter_set_scale(large_scales, 180, 3);
|
||||||
|
lv_linemeter_set_angle_offset(large_scales, 180);
|
||||||
|
lv_obj_set_size(large_scales, 240, 240);
|
||||||
|
lv_obj_align(large_scales, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
lv_obj_set_style_local_bg_opa(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||||
|
lv_obj_set_style_local_scale_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 20);
|
||||||
|
lv_obj_set_style_local_scale_end_line_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4);
|
||||||
|
lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
||||||
|
|
||||||
|
twelve = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_label_set_align(twelve, LV_LABEL_ALIGN_CENTER);
|
||||||
|
lv_label_set_text_static(twelve, "12");
|
||||||
|
lv_obj_set_pos(twelve, 110, 10);
|
||||||
|
lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
||||||
|
|
||||||
|
batteryIcon.Create(lv_scr_act());
|
||||||
|
lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||||
|
|
||||||
|
plugIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_label_set_text_static(plugIcon, Symbols::plug);
|
||||||
|
lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||||
|
|
||||||
|
bleIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_label_set_text_static(bleIcon, "");
|
||||||
|
lv_obj_align(bleIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, -30, 0);
|
||||||
|
|
||||||
|
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME);
|
||||||
|
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
|
||||||
|
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||||
|
|
||||||
|
// Date - Day / Week day
|
||||||
|
|
||||||
|
label_date_day = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
|
||||||
|
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
|
||||||
|
lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER);
|
||||||
|
lv_obj_align(label_date_day, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
|
|
||||||
|
minute_body = lv_line_create(lv_scr_act(), nullptr);
|
||||||
|
minute_body_trace = lv_line_create(lv_scr_act(), nullptr);
|
||||||
|
hour_body = lv_line_create(lv_scr_act(), nullptr);
|
||||||
|
hour_body_trace = lv_line_create(lv_scr_act(), nullptr);
|
||||||
|
second_body = lv_line_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
|
lv_style_init(&second_line_style);
|
||||||
|
lv_style_set_line_width(&second_line_style, LV_STATE_DEFAULT, 3);
|
||||||
|
lv_style_set_line_color(&second_line_style, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||||
|
lv_style_set_line_rounded(&second_line_style, LV_STATE_DEFAULT, true);
|
||||||
|
lv_obj_add_style(second_body, LV_LINE_PART_MAIN, &second_line_style);
|
||||||
|
|
||||||
|
lv_style_init(&minute_line_style);
|
||||||
|
lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 3);
|
||||||
|
lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
|
lv_style_set_line_rounded(&minute_line_style, LV_STATE_DEFAULT, true);
|
||||||
|
lv_obj_add_style(minute_body, LV_LINE_PART_MAIN, &minute_line_style);
|
||||||
|
|
||||||
|
lv_style_init(&minute_line_style_trace);
|
||||||
|
lv_style_set_line_width(&minute_line_style_trace, LV_STATE_DEFAULT, 3);
|
||||||
|
lv_style_set_line_color(&minute_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
|
lv_style_set_line_rounded(&minute_line_style_trace, LV_STATE_DEFAULT, false);
|
||||||
|
lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_line_style_trace);
|
||||||
|
|
||||||
|
lv_style_init(&hour_line_style);
|
||||||
|
lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 7);
|
||||||
|
lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
|
lv_style_set_line_rounded(&hour_line_style, LV_STATE_DEFAULT, true);
|
||||||
|
lv_obj_add_style(hour_body, LV_LINE_PART_MAIN, &hour_line_style);
|
||||||
|
|
||||||
|
lv_style_init(&hour_line_style_trace);
|
||||||
|
lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 3);
|
||||||
|
lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
|
lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false);
|
||||||
|
lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace);
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
|
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
WatchFaceFace::~WatchFaceFace() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
|
|
||||||
|
lv_style_reset(&hour_line_style);
|
||||||
|
lv_style_reset(&hour_line_style_trace);
|
||||||
|
lv_style_reset(&minute_line_style);
|
||||||
|
lv_style_reset(&minute_line_style_trace);
|
||||||
|
lv_style_reset(&second_line_style);
|
||||||
|
|
||||||
|
lv_obj_clean(lv_scr_act());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchFaceFace::UpdateClock() {
|
||||||
|
uint8_t hour = dateTimeController.Hours();
|
||||||
|
uint8_t minute = dateTimeController.Minutes();
|
||||||
|
uint8_t second = dateTimeController.Seconds();
|
||||||
|
|
||||||
|
if (sMinute != minute) {
|
||||||
|
auto const angle = minute * 6;
|
||||||
|
minute_point[0] = CoordinateRelocate(10, angle - 90);
|
||||||
|
minute_point[1] = CoordinateRelocate(MinuteLength, angle);
|
||||||
|
minute_point[2] = CoordinateRelocate(10, angle + 90);
|
||||||
|
|
||||||
|
lv_line_set_points(minute_body, minute_point, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sHour != hour || sMinute != minute) {
|
||||||
|
sHour = hour;
|
||||||
|
sMinute = minute;
|
||||||
|
auto const angle = (hour * 30 + minute / 2);
|
||||||
|
|
||||||
|
hour_point[0] = CoordinateRelocate(90, angle);
|
||||||
|
hour_point[1] = CoordinateRelocate(HourLength, angle);
|
||||||
|
|
||||||
|
lv_line_set_points(hour_body, hour_point, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sSecond != second) {
|
||||||
|
sSecond = second;
|
||||||
|
auto const angle = second * 6;
|
||||||
|
|
||||||
|
second_point[0] = CoordinateRelocate(105, angle);
|
||||||
|
second_point[1] = CoordinateRelocate(SecondLength, angle);
|
||||||
|
lv_line_set_points(second_body, second_point, 2);
|
||||||
|
}//TODO: redo seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchFaceFace::SetBatteryIcon() {
|
||||||
|
auto batteryPercent = batteryPercentRemaining.Get();
|
||||||
|
batteryIcon.SetBatteryPercentage(batteryPercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchFaceFace::Refresh() {
|
||||||
|
isCharging = batteryController.IsCharging();
|
||||||
|
if (isCharging.IsUpdated()) {
|
||||||
|
if (isCharging.Get()) {
|
||||||
|
lv_obj_set_hidden(batteryIcon.GetObject(), true);
|
||||||
|
lv_obj_set_hidden(plugIcon, false);
|
||||||
|
} else {
|
||||||
|
lv_obj_set_hidden(batteryIcon.GetObject(), false);
|
||||||
|
lv_obj_set_hidden(plugIcon, true);
|
||||||
|
SetBatteryIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isCharging.Get()) {
|
||||||
|
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||||
|
if (batteryPercentRemaining.IsUpdated()) {
|
||||||
|
SetBatteryIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bleState = bleController.IsConnected();
|
||||||
|
if (bleState.IsUpdated()) {
|
||||||
|
if (bleState.Get()) {
|
||||||
|
lv_label_set_text_static(bleIcon, Symbols::bluetooth);
|
||||||
|
} else {
|
||||||
|
lv_label_set_text_static(bleIcon, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationState = notificationManager.AreNewNotificationsAvailable();
|
||||||
|
|
||||||
|
if (notificationState.IsUpdated()) {
|
||||||
|
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
currentDateTime = dateTimeController.CurrentDateTime();
|
||||||
|
if (currentDateTime.IsUpdated()) {
|
||||||
|
UpdateClock();
|
||||||
|
|
||||||
|
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
|
||||||
|
if (currentDate.IsUpdated()) {
|
||||||
|
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
src/displayapp/screens/WatchFaceFace.h
Normal file
95
src/displayapp/screens/WatchFaceFace.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lvgl/src/lv_core/lv_obj.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include "displayapp/screens/Screen.h"
|
||||||
|
#include "components/datetime/DateTimeController.h"
|
||||||
|
#include "components/battery/BatteryController.h"
|
||||||
|
#include "components/ble/BleController.h"
|
||||||
|
#include "components/ble/NotificationManager.h"
|
||||||
|
#include "displayapp/screens/BatteryIcon.h"
|
||||||
|
#include "utility/DirtyValue.h"
|
||||||
|
|
||||||
|
namespace Pinetime {
|
||||||
|
namespace Controllers {
|
||||||
|
class Settings;
|
||||||
|
class Battery;
|
||||||
|
class Ble;
|
||||||
|
class NotificationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Applications {
|
||||||
|
namespace Screens {
|
||||||
|
|
||||||
|
class WatchFaceFace : public Screen {
|
||||||
|
public:
|
||||||
|
WatchFaceFace(Controllers::DateTime& dateTimeController,
|
||||||
|
const Controllers::Battery& batteryController,
|
||||||
|
const Controllers::Ble& bleController,
|
||||||
|
Controllers::NotificationManager& notificationManager,
|
||||||
|
Controllers::Settings& settingsController);
|
||||||
|
|
||||||
|
~WatchFaceFace() override;
|
||||||
|
|
||||||
|
void Refresh() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t sHour, sMinute, sSecond;
|
||||||
|
|
||||||
|
Utility::DirtyValue<uint8_t> batteryPercentRemaining {0};
|
||||||
|
Utility::DirtyValue<bool> isCharging {};
|
||||||
|
Utility::DirtyValue<bool> bleState {};
|
||||||
|
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
|
||||||
|
Utility::DirtyValue<bool> notificationState {false};
|
||||||
|
using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
|
||||||
|
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
|
||||||
|
|
||||||
|
lv_obj_t* minor_scales;
|
||||||
|
lv_obj_t* major_scales;
|
||||||
|
lv_obj_t* large_scales;
|
||||||
|
lv_obj_t* twelve;
|
||||||
|
|
||||||
|
lv_obj_t* hour_body;
|
||||||
|
lv_obj_t* hour_body_trace;
|
||||||
|
lv_obj_t* minute_body;
|
||||||
|
lv_obj_t* minute_body_trace;
|
||||||
|
lv_obj_t* second_body;
|
||||||
|
|
||||||
|
lv_point_t hour_point[2];
|
||||||
|
lv_point_t minute_point[3];
|
||||||
|
lv_point_t second_point[2];
|
||||||
|
|
||||||
|
lv_style_t hour_line_style;
|
||||||
|
lv_style_t hour_line_style_trace;
|
||||||
|
lv_style_t minute_line_style;
|
||||||
|
lv_style_t minute_line_style_trace;
|
||||||
|
lv_style_t second_line_style;
|
||||||
|
|
||||||
|
lv_obj_t* label_date_day;
|
||||||
|
lv_obj_t* plugIcon;
|
||||||
|
lv_obj_t* notificationIcon;
|
||||||
|
lv_obj_t* bleIcon;
|
||||||
|
|
||||||
|
lv_obj_t* mouth;
|
||||||
|
lv_obj_t* leye;
|
||||||
|
lv_obj_t* reye;
|
||||||
|
|
||||||
|
|
||||||
|
BatteryIcon batteryIcon;
|
||||||
|
|
||||||
|
const Controllers::DateTime& dateTimeController;
|
||||||
|
const Controllers::Battery& batteryController;
|
||||||
|
const Controllers::Ble& bleController;
|
||||||
|
Controllers::NotificationManager& notificationManager;
|
||||||
|
Controllers::Settings& settingsController;
|
||||||
|
|
||||||
|
void UpdateClock();
|
||||||
|
void SetBatteryIcon();
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
src/displayapp/screens/settings/SettingQuickR.cpp
Normal file
77
src/displayapp/screens/settings/SettingQuickR.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "displayapp/screens/settings/SettingQuickR.h"
|
||||||
|
#include <lvgl/lvgl.h>
|
||||||
|
#include "displayapp/DisplayApp.h"
|
||||||
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
constexpr std::array<SettingQuickR::Option, 5> SettingQuickR::options;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||||
|
auto* screen = static_cast<SettingQuickR*>(obj->user_data);
|
||||||
|
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||||
|
screen->UpdateSelected(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingQuickR::SettingQuickR(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} {
|
||||||
|
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
|
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||||
|
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
||||||
|
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
||||||
|
lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
|
|
||||||
|
lv_obj_set_pos(container1, 10, 35);
|
||||||
|
lv_obj_set_width(container1, LV_HOR_RES - 20);
|
||||||
|
lv_obj_set_height(container1, LV_VER_RES - 20);
|
||||||
|
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
|
||||||
|
|
||||||
|
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_label_set_text_static(title, "Quick Ring");
|
||||||
|
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
|
||||||
|
lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15);
|
||||||
|
|
||||||
|
lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
|
||||||
|
lv_label_set_text_static(icon, Symbols::check);
|
||||||
|
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
|
||||||
|
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 5; i++) {
|
||||||
|
cbOption[i] = lv_checkbox_create(container1, nullptr);
|
||||||
|
lv_checkbox_set_text(cbOption[i], options[i].name);
|
||||||
|
if (settingsController.isQuickROn(static_cast<Controllers::Settings::QuickApp>(i))) {
|
||||||
|
lv_checkbox_set_checked(cbOption[i], true);
|
||||||
|
}
|
||||||
|
cbOption[i]->user_data = this;
|
||||||
|
lv_obj_set_event_cb(cbOption[i], event_handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingQuickR::~SettingQuickR() {
|
||||||
|
lv_obj_clean(lv_scr_act());
|
||||||
|
settingsController.SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingQuickR::UpdateSelected(lv_obj_t* object) {
|
||||||
|
// Find the index of the checkbox that triggered the event
|
||||||
|
for (size_t i = 0; i < 5; i++) {
|
||||||
|
if (cbOption[i] == object) {
|
||||||
|
bool currentState = settingsController.isQuickROn(options[i].quickApp);
|
||||||
|
settingsController.SetQuickRModes(options[i].quickApp, !currentState);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update checkbox according to current wakeup modes.
|
||||||
|
// This is needed because we can have extra logic when setting or unsetting wakeup modes,
|
||||||
|
// for example, when setting SingleTap, DoubleTap is unset and vice versa.
|
||||||
|
auto modes = settingsController.getQuickRModes();
|
||||||
|
for (size_t i = 0; i < 5; ++i) {
|
||||||
|
lv_checkbox_set_checked(cbOption[i], modes[i]);
|
||||||
|
}
|
||||||
|
}
|
39
src/displayapp/screens/settings/SettingQuickR.h
Normal file
39
src/displayapp/screens/settings/SettingQuickR.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <lvgl/lvgl.h>
|
||||||
|
#include "components/settings/Settings.h"
|
||||||
|
#include "displayapp/screens/Screen.h"
|
||||||
|
|
||||||
|
namespace Pinetime {
|
||||||
|
|
||||||
|
namespace Applications {
|
||||||
|
namespace Screens {
|
||||||
|
|
||||||
|
class SettingQuickR : public Screen {
|
||||||
|
public:
|
||||||
|
SettingQuickR(Pinetime::Controllers::Settings& settingsController);
|
||||||
|
~SettingQuickR() override;
|
||||||
|
void UpdateSelected(lv_obj_t* object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Option {
|
||||||
|
Controllers::Settings::QuickApp quickApp;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<Option, 5> options = {{
|
||||||
|
{Controllers::Settings::QuickApp::MusicPlayer, "Music Player"},
|
||||||
|
{Controllers::Settings::QuickApp::Calculator, "Calculator"},
|
||||||
|
{Controllers::Settings::QuickApp::Alarm, "Alarms"},
|
||||||
|
{Controllers::Settings::QuickApp::Timer, "Timer"},
|
||||||
|
{Controllers::Settings::QuickApp::HeartRate, "Heart Rate"},
|
||||||
|
}};
|
||||||
|
|
||||||
|
lv_obj_t* cbOption[5];
|
||||||
|
Controllers::Settings& settingsController;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
#include "displayapp/screens/CheckboxList.h"
|
#include "displayapp/screens/CheckboxList.h"
|
||||||
#include "displayapp/screens/WatchFaceInfineat.h"
|
#include "displayapp/screens/WatchFaceInfineat.h"
|
||||||
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
|
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
|
||||||
|
#include "displayapp/screens/WatchFaceFace.h"
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
|
|
||||||
@ -47,8 +48,9 @@ namespace Pinetime {
|
|||||||
{"Terminal", true},
|
{"Terminal", true},
|
||||||
{"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)},
|
{"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)},
|
||||||
{"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)},
|
{"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)},
|
||||||
{"", false},
|
{"Face face", true},
|
||||||
{"", false}}};
|
{"", false}
|
||||||
|
}};
|
||||||
ScreenList<nScreens> screens;
|
ScreenList<nScreens> screens;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ namespace Pinetime {
|
|||||||
static constexpr int entriesPerScreen = 4;
|
static constexpr int entriesPerScreen = 4;
|
||||||
|
|
||||||
// Increment this when more space is needed
|
// Increment this when more space is needed
|
||||||
static constexpr int nScreens = 3;
|
static constexpr int nScreens = 4;
|
||||||
|
|
||||||
static constexpr std::array<List::Applications, entriesPerScreen * nScreens> entries {{
|
static constexpr std::array<List::Applications, entriesPerScreen * nScreens> entries {{
|
||||||
{Symbols::sun, "Display", Apps::SettingDisplay},
|
{Symbols::sun, "Display", Apps::SettingDisplay},
|
||||||
@ -40,11 +40,14 @@ namespace Pinetime {
|
|||||||
{Symbols::shoe, "Steps", Apps::SettingSteps},
|
{Symbols::shoe, "Steps", Apps::SettingSteps},
|
||||||
{Symbols::clock, "Date&Time", Apps::SettingSetDateTime},
|
{Symbols::clock, "Date&Time", Apps::SettingSetDateTime},
|
||||||
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
|
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
|
||||||
{Symbols::clock, "Chimes", Apps::SettingChimes},
|
{Symbols::check, "QuickRing", Apps::SettingQuickR},
|
||||||
|
|
||||||
|
|
||||||
|
{Symbols::clock, "Chimes", Apps::SettingChimes},
|
||||||
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
|
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
|
||||||
{Symbols::check, "Firmware", Apps::FirmwareValidation},
|
{Symbols::check, "Firmware", Apps::FirmwareValidation},
|
||||||
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
|
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
|
||||||
|
|
||||||
{Symbols::list, "About", Apps::SysInfo},
|
{Symbols::list, "About", Apps::SysInfo},
|
||||||
|
|
||||||
// {Symbols::none, "None", Apps::None},
|
// {Symbols::none, "None", Apps::None},
|
||||||
|
@ -3,8 +3,8 @@ find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED
|
|||||||
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
|
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
|
||||||
message(STATUS "Using ${LV_FONT_CONV} to generate font files")
|
message(STATUS "Using ${LV_FONT_CONV} to generate font files")
|
||||||
|
|
||||||
find_program(LV_IMG_CONV "lv_img_conv" NO_CACHE REQUIRED
|
find_program(LV_IMG_CONV "lv_img_conv.py" NO_CACHE REQUIRED
|
||||||
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
|
HINTS "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
message(STATUS "Using ${LV_IMG_CONV} to generate font files")
|
message(STATUS "Using ${LV_IMG_CONV} to generate font files")
|
||||||
|
|
||||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
|
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
|
||||||
|
@ -11,6 +11,9 @@ import subprocess
|
|||||||
|
|
||||||
def gen_lvconv_line(lv_img_conv: str, dest: str, color_format: str, output_format: str, binary_format: str, sources: str):
|
def gen_lvconv_line(lv_img_conv: str, dest: str, color_format: str, output_format: str, binary_format: str, sources: str):
|
||||||
args = [lv_img_conv, sources, '--force', '--output-file', dest, '--color-format', color_format, '--output-format', output_format, '--binary-format', binary_format]
|
args = [lv_img_conv, sources, '--force', '--output-file', dest, '--color-format', color_format, '--output-format', output_format, '--binary-format', binary_format]
|
||||||
|
if lv_img_conv.endswith(".py"):
|
||||||
|
# lv_img_conv is a python script, call with current python executable
|
||||||
|
args = [sys.executable] + args
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
193
src/resources/lv_img_conv.py
Executable file
193
src/resources/lv_img_conv.py
Executable file
@ -0,0 +1,193 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import decimal
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
def classify_pixel(value, bits):
|
||||||
|
def round_half_up(v):
|
||||||
|
"""python3 implements "propper" "banker's rounding" by rounding to the nearest
|
||||||
|
even number. Javascript rounds to the nearest integer.
|
||||||
|
To have the same output as the original JavaScript implementation add a custom
|
||||||
|
rounding function, which does "school" rounding (to the nearest integer).
|
||||||
|
|
||||||
|
see: https://stackoverflow.com/questions/43851273/how-to-round-float-0-5-up-to-1-0-while-still-rounding-0-45-to-0-0-as-the-usual
|
||||||
|
"""
|
||||||
|
return int(decimal.Decimal(v).quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP))
|
||||||
|
tmp = 1 << (8 - bits)
|
||||||
|
val = round_half_up(value / tmp) * tmp
|
||||||
|
if val < 0:
|
||||||
|
val = 0
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
def test_classify_pixel():
|
||||||
|
# test difference between round() and round_half_up()
|
||||||
|
assert classify_pixel(18, 5) == 16
|
||||||
|
# school rounding 4.5 to 5, but banker's rounding 4.5 to 4
|
||||||
|
assert classify_pixel(18, 6) == 20
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument("img",
|
||||||
|
help="Path to image to convert to C header file")
|
||||||
|
parser.add_argument("-o", "--output-file",
|
||||||
|
help="output file path (for single-image conversion)",
|
||||||
|
required=True)
|
||||||
|
parser.add_argument("-f", "--force",
|
||||||
|
help="allow overwriting the output file",
|
||||||
|
action="store_true")
|
||||||
|
parser.add_argument("-i", "--image-name",
|
||||||
|
help="name of image structure (not implemented)")
|
||||||
|
parser.add_argument("-c", "--color-format",
|
||||||
|
help="color format of image",
|
||||||
|
default="CF_TRUE_COLOR_ALPHA",
|
||||||
|
choices=[
|
||||||
|
"CF_ALPHA_1_BIT", "CF_ALPHA_2_BIT", "CF_ALPHA_4_BIT",
|
||||||
|
"CF_ALPHA_8_BIT", "CF_INDEXED_1_BIT", "CF_INDEXED_2_BIT", "CF_INDEXED_4_BIT",
|
||||||
|
"CF_INDEXED_8_BIT", "CF_RAW", "CF_RAW_CHROMA", "CF_RAW_ALPHA",
|
||||||
|
"CF_TRUE_COLOR", "CF_TRUE_COLOR_ALPHA", "CF_TRUE_COLOR_CHROMA", "CF_RGB565A8",
|
||||||
|
],
|
||||||
|
required=True)
|
||||||
|
parser.add_argument("-t", "--output-format",
|
||||||
|
help="output format of image",
|
||||||
|
default="bin", # default in original is 'c'
|
||||||
|
choices=["c", "bin"])
|
||||||
|
parser.add_argument("--binary-format",
|
||||||
|
help="binary color format (needed if output-format is binary)",
|
||||||
|
default="ARGB8565_RBSWAP",
|
||||||
|
choices=["ARGB8332", "ARGB8565", "ARGB8565_RBSWAP", "ARGB8888"])
|
||||||
|
parser.add_argument("-s", "--swap-endian",
|
||||||
|
help="swap endian of image (not implemented)",
|
||||||
|
action="store_true")
|
||||||
|
parser.add_argument("-d", "--dither",
|
||||||
|
help="enable dither (not implemented)",
|
||||||
|
action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
img_path = pathlib.Path(args.img)
|
||||||
|
out = pathlib.Path(args.output_file)
|
||||||
|
if not img_path.is_file():
|
||||||
|
print(f"Input file is missing: '{args.img}'")
|
||||||
|
return 1
|
||||||
|
print(f"Beginning conversion of {args.img}")
|
||||||
|
if out.exists():
|
||||||
|
if args.force:
|
||||||
|
print(f"overwriting {args.output_file}")
|
||||||
|
else:
|
||||||
|
pritn(f"Error: refusing to overwrite {args.output_file} without -f specified.")
|
||||||
|
return 1
|
||||||
|
out.touch()
|
||||||
|
|
||||||
|
# only implemented the bare minimum, everything else is not implemented
|
||||||
|
if args.color_format not in ["CF_INDEXED_1_BIT", "CF_TRUE_COLOR_ALPHA"]:
|
||||||
|
raise NotImplementedError(f"argument --color-format '{args.color_format}' not implemented")
|
||||||
|
if args.output_format != "bin":
|
||||||
|
raise NotImplementedError(f"argument --output-format '{args.output_format}' not implemented")
|
||||||
|
if args.binary_format not in ["ARGB8565_RBSWAP", "ARGB8888"]:
|
||||||
|
raise NotImplementedError(f"argument --binary-format '{args.binary_format}' not implemented")
|
||||||
|
if args.image_name:
|
||||||
|
raise NotImplementedError(f"argument --image-name not implemented")
|
||||||
|
if args.swap_endian:
|
||||||
|
raise NotImplementedError(f"argument --swap-endian not implemented")
|
||||||
|
if args.dither:
|
||||||
|
raise NotImplementedError(f"argument --dither not implemented")
|
||||||
|
|
||||||
|
# open image using Pillow
|
||||||
|
img = Image.open(img_path)
|
||||||
|
img_height = img.height
|
||||||
|
img_width = img.width
|
||||||
|
if args.color_format == "CF_TRUE_COLOR_ALPHA" and args.binary_format == "ARGB8888":
|
||||||
|
buf = bytearray(img_height*img_width*4) # 4 bytes (32 bit) per pixel
|
||||||
|
for y in range(img_height):
|
||||||
|
for x in range(img_width):
|
||||||
|
i = (y*img_width + x)*4 # buffer-index
|
||||||
|
pixel = img.getpixel((x,y))
|
||||||
|
r, g, b, a = pixel
|
||||||
|
buf[i + 0] = r
|
||||||
|
buf[i + 1] = g
|
||||||
|
buf[i + 2] = b
|
||||||
|
buf[i + 3] = a
|
||||||
|
|
||||||
|
elif args.color_format == "CF_TRUE_COLOR_ALPHA" and args.binary_format == "ARGB8565_RBSWAP":
|
||||||
|
buf = bytearray(img_height*img_width*3) # 3 bytes (24 bit) per pixel
|
||||||
|
for y in range(img_height):
|
||||||
|
for x in range(img_width):
|
||||||
|
i = (y*img_width + x)*3 # buffer-index
|
||||||
|
pixel = img.getpixel((x,y))
|
||||||
|
r_act = classify_pixel(pixel[0], 5)
|
||||||
|
g_act = classify_pixel(pixel[1], 6)
|
||||||
|
b_act = classify_pixel(pixel[2], 5)
|
||||||
|
a = pixel[3]
|
||||||
|
r_act = min(r_act, 0xF8)
|
||||||
|
g_act = min(g_act, 0xFC)
|
||||||
|
b_act = min(b_act, 0xF8)
|
||||||
|
c16 = ((r_act) << 8) | ((g_act) << 3) | ((b_act) >> 3) # RGR565
|
||||||
|
buf[i + 0] = (c16 >> 8) & 0xFF
|
||||||
|
buf[i + 1] = c16 & 0xFF
|
||||||
|
buf[i + 2] = a
|
||||||
|
|
||||||
|
elif args.color_format == "CF_INDEXED_1_BIT": # ignore binary format, use color format as binary format
|
||||||
|
w = img_width >> 3
|
||||||
|
if img_width & 0x07:
|
||||||
|
w+=1
|
||||||
|
max_p = w * (img_height-1) + ((img_width-1) >> 3) + 8 # +8 for the palette
|
||||||
|
buf = bytearray(max_p+1)
|
||||||
|
|
||||||
|
for y in range(img_height):
|
||||||
|
for x in range(img_width):
|
||||||
|
c, a = img.getpixel((x,y))
|
||||||
|
p = w * y + (x >> 3) + 8 # +8 for the palette
|
||||||
|
buf[p] |= (c & 0x1) << (7 - (x & 0x7))
|
||||||
|
# write palette information, for indexed-1-bit we need palette with two values
|
||||||
|
# write 8 palette bytes
|
||||||
|
buf[0] = 0
|
||||||
|
buf[1] = 0
|
||||||
|
buf[2] = 0
|
||||||
|
buf[3] = 0
|
||||||
|
# Normally there is much math behind this, but for the current use case this is close enough
|
||||||
|
# only needs to be more complicated if we have more than 2 colors in the palette
|
||||||
|
buf[4] = 255
|
||||||
|
buf[5] = 255
|
||||||
|
buf[6] = 255
|
||||||
|
buf[7] = 255
|
||||||
|
else:
|
||||||
|
# raise just to be sure
|
||||||
|
raise NotImplementedError(f"args.color_format '{args.color_format}' with args.binary_format '{args.binary_format}' not implemented")
|
||||||
|
|
||||||
|
# write header
|
||||||
|
match args.color_format:
|
||||||
|
case "CF_TRUE_COLOR_ALPHA":
|
||||||
|
lv_cf = 5
|
||||||
|
case "CF_INDEXED_1_BIT":
|
||||||
|
lv_cf = 7
|
||||||
|
case _:
|
||||||
|
# raise just to be sure
|
||||||
|
raise NotImplementedError(f"args.color_format '{args.color_format}' not implemented")
|
||||||
|
header_32bit = lv_cf | (img_width << 10) | (img_height << 21)
|
||||||
|
buf_out = bytearray(4 + len(buf))
|
||||||
|
buf_out[0] = header_32bit & 0xFF
|
||||||
|
buf_out[1] = (header_32bit & 0xFF00) >> 8
|
||||||
|
buf_out[2] = (header_32bit & 0xFF0000) >> 16
|
||||||
|
buf_out[3] = (header_32bit & 0xFF000000) >> 24
|
||||||
|
buf_out[4:] = buf
|
||||||
|
|
||||||
|
# write byte buffer to file
|
||||||
|
with open(out, "wb") as f:
|
||||||
|
f.write(buf_out)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if "--test" in sys.argv:
|
||||||
|
# run small set of tests and exit
|
||||||
|
print("running tests")
|
||||||
|
test_classify_pixel()
|
||||||
|
print("success!")
|
||||||
|
sys.exit(0)
|
||||||
|
# run normal program
|
||||||
|
sys.exit(main())
|
Loading…
Reference in New Issue
Block a user