mirror of
https://github.com/InfiniTimeOrg/InfiniTime.git
synced 2025-01-08 19:21:20 +03:00
Merge branch 'develop' into bootloader-doc
# Conflicts: # README.md # doc/gettingStarted/updating-software.md
This commit is contained in:
commit
1bfb128617
@ -60,7 +60,6 @@ CmakeGenerate() {
|
||||
|
||||
cmake -G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DUSE_OPENOCD=1 \
|
||||
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_VER" \
|
||||
-DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \
|
||||
"$SOURCES_DIR"
|
||||
|
72
.github/workflows/lv_sim.yml
vendored
72
.github/workflows/lv_sim.yml
vendored
@ -1,72 +0,0 @@
|
||||
# GitHub Actions Workflow to build Simulator for PineTime Smart Watch LVGL Interface
|
||||
|
||||
name: Build PineTime LVGL Simulator
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
pull_request:
|
||||
branches: [ develop ]
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
#########################################################################################
|
||||
# Download and Install Dependencies
|
||||
|
||||
- name: Install cmake
|
||||
uses: lukka/get-cmake@v3.18.3
|
||||
|
||||
- name: Install SDL2 development package
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install libsdl2-dev
|
||||
|
||||
- name: Install lv_font_conv
|
||||
run:
|
||||
npm i -g lv_font_conv@1.5.2
|
||||
|
||||
#########################################################################################
|
||||
# Checkout
|
||||
|
||||
- name: Checkout source files
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
#########################################################################################
|
||||
# get InfiniSim repo
|
||||
|
||||
- name: Get InfiniSim repo
|
||||
run: |
|
||||
git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main
|
||||
git -C InfiniSim submodule update --init lv_drivers libpng
|
||||
|
||||
#########################################################################################
|
||||
# CMake
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -G Ninja -S InfiniSim -B build_lv_sim -DInfiniTime_DIR="${PWD}"
|
||||
|
||||
#########################################################################################
|
||||
# Build and Upload simulator
|
||||
|
||||
- name: Build simulator executable
|
||||
run: |
|
||||
cmake --build build_lv_sim
|
||||
|
||||
- name: Upload simulator executable
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: infinisim-${{ github.head_ref }}
|
||||
path: build_lv_sim/infinisim
|
54
.github/workflows/main.yml
vendored
54
.github/workflows/main.yml
vendored
@ -1,24 +1,21 @@
|
||||
# GitHub Actions Workflow to build FreeRTOS Firmware for PineTime Smart Watch
|
||||
# See https://lupyuen.github.io/pinetime-rust-mynewt/articles/cloud
|
||||
# Based on https://github.com/JF002/InfiniTime/blob/master/doc/buildAndProgram.md
|
||||
# and https://github.com/JF002/InfiniTime/blob/master/bootloader/README.md
|
||||
|
||||
name: Build PineTime Firmware
|
||||
name: CI
|
||||
|
||||
# Run this workflow whenever the build may be affected
|
||||
on:
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches: [ develop ]
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
- '**.md'
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-firmware:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: infinitime/infinitime-build
|
||||
@ -51,3 +48,42 @@ jobs:
|
||||
with:
|
||||
name: InfiniTime MCUBoot image ${{ github.head_ref }}
|
||||
path: ./build/output/pinetime-mcuboot-app-image-*.bin
|
||||
|
||||
build-simulator:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install cmake
|
||||
uses: lukka/get-cmake@v3.18.3
|
||||
|
||||
- name: Install SDL2 development package
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install libsdl2-dev
|
||||
|
||||
- name: Install lv_font_conv
|
||||
run:
|
||||
npm i -g lv_font_conv@1.5.2
|
||||
|
||||
- name: Checkout source files
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Get InfiniSim repo
|
||||
run: |
|
||||
git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main
|
||||
git -C InfiniSim submodule update --init lv_drivers libpng
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -G Ninja -S InfiniSim -B build_lv_sim -DInfiniTime_DIR="${PWD}"
|
||||
|
||||
- name: Build simulator executable
|
||||
run: |
|
||||
cmake --build build_lv_sim
|
||||
|
||||
- name: Upload simulator executable
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: infinisim-${{ github.head_ref }}
|
||||
path: build_lv_sim/infinisim
|
||||
|
@ -24,28 +24,6 @@ if (NOT NRF5_SDK_PATH)
|
||||
message(FATAL_ERROR "The path to the NRF52 SDK must be specified on the command line (add -DNRF5_SDK_PATH=<path>")
|
||||
endif ()
|
||||
|
||||
if(USE_JLINK)
|
||||
if (NOT NRFJPROG)
|
||||
message(FATAL_ERROR "the path to the tool nrfjprog must be specified on the command line (add -DNRFJPROG=<path>")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if(USE_GDB_CLIENT)
|
||||
if(NOT GDB_CLIENT_BIN_PATH)
|
||||
set(GDB_CLIENT_BIN_PATH "arm-none-eabi-gdb")
|
||||
endif()
|
||||
|
||||
if(NOT GDB_CLIENT_TARGET_REMOTE)
|
||||
message(FATAL_ERROR "The GDB target must be specified (add -DGDB_CLIENT_TARGET_REMOTE=<target>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_OPENOCD)
|
||||
if(NOT OPENOCD_BIN_PATH)
|
||||
set(OPENOCD_BIN_PATH "openocd")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DEFINED USE_DEBUG_PINS AND USE_DEBUG_PINS)
|
||||
add_definitions(-DUSE_DEBUG_PINS)
|
||||
endif()
|
||||
@ -54,6 +32,10 @@ if(BUILD_DFU)
|
||||
set(BUILD_DFU true)
|
||||
endif()
|
||||
|
||||
if(BUILD_RESOURCES)
|
||||
set(BUILD_RESOURCES true)
|
||||
endif()
|
||||
|
||||
set(TARGET_DEVICE "PINETIME" CACHE STRING "Target device")
|
||||
set_property(CACHE TARGET_DEVICE PROPERTY STRINGS PINETIME MOY-TFK5 MOY-TIN5 MOY-TON5 MOY-UNK)
|
||||
|
||||
@ -77,17 +59,6 @@ message(" * Toolchain : " ${ARM_NONE_EABI_TOOLCHAIN_PATH})
|
||||
message(" * GitRef(S) : " ${PROJECT_GIT_COMMIT_HASH})
|
||||
message(" * NRF52 SDK : " ${NRF5_SDK_PATH})
|
||||
message(" * Target device : " ${TARGET_DEVICE})
|
||||
set(PROGRAMMER "???")
|
||||
if(USE_JLINK)
|
||||
message(" * Programmer/debugger : JLINK")
|
||||
message(" * NrfJprog : " ${NRFJPROG})
|
||||
elseif(USE_GDB_CLIENT)
|
||||
message(" * Programmer/debugger : GDB Client")
|
||||
message(" * GDB Client path : " ${GDB_CLIENT_BIN_PATH})
|
||||
message(" * GDB Target : " ${GDB_CLIENT_TARGET_REMOTE})
|
||||
elseif(USE_OPENOCD)
|
||||
message(" * Programmer/debugger : OpenOCD Client")
|
||||
endif()
|
||||
if(USE_DEBUG_PINS)
|
||||
message(" * Debug pins : Enabled")
|
||||
else()
|
||||
@ -98,6 +69,11 @@ if(BUILD_DFU)
|
||||
else()
|
||||
message(" * Build DFU (using adafruit-nrfutil) : Disabled")
|
||||
endif()
|
||||
if(BUILD_RESOURCES)
|
||||
message(" * Build resources : Enabled")
|
||||
else()
|
||||
message(" * Build resources : Disabled")
|
||||
endif()
|
||||
|
||||
set(VERSION_EDIT_WARNING "// Do not edit this file, it is automatically generated by CMAKE!")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/Version.h)
|
||||
|
@ -28,6 +28,7 @@ Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/p
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
||||
- [Tips on designing an app UI](doc/ui_guidelines.md)
|
||||
- [Bootloader, OTA and DFU](doc/bootloader/README.md)
|
||||
- [External resources](doc/ExternalResources.md)
|
||||
- [Versioning](doc/versioning.md)
|
||||
- [Project branches](doc/branches.md)
|
||||
- [Files included in the release notes](doc/filesInReleaseNotes.md)
|
||||
|
@ -229,24 +229,6 @@ macro(nRF5x_setup)
|
||||
"${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_twi.c"
|
||||
)
|
||||
|
||||
# adds target for erasing
|
||||
if(USE_JLINK)
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${NRFJPROG} --eraseall -f ${NRF_TARGET}
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
elseif(USE_GDB_CLIENT)
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'mon erase_mass'
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
elseif(USE_OPENOCD)
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${OPENOCD_BIN_PATH} -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c init -c halt -c 'nrf5 mass_erase' -c reset -c shutdown
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
set(TERMINAL "open")
|
||||
elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows")
|
||||
@ -255,16 +237,6 @@ macro(nRF5x_setup)
|
||||
set(TERMINAL "gnome-terminal")
|
||||
endif()
|
||||
|
||||
if(USE_JLINK)
|
||||
add_custom_target(START_JLINK
|
||||
COMMAND ${TERMINAL} "${DIR_OF_nRF5x_CMAKE}/runJLinkGDBServer-${NRF_TARGET}"
|
||||
COMMAND ${TERMINAL} "${DIR_OF_nRF5x_CMAKE}/runJLinkExe-${NRF_TARGET}"
|
||||
COMMAND sleep 2s
|
||||
COMMAND ${TERMINAL} "${DIR_OF_nRF5x_CMAKE}/runJLinkRTTClient"
|
||||
COMMENT "started JLink commands"
|
||||
)
|
||||
endif()
|
||||
|
||||
endmacro(nRF5x_setup)
|
||||
|
||||
# adds a target for comiling and flashing an executable
|
||||
@ -282,29 +254,6 @@ macro(nRF5x_addExecutable EXECUTABLE_NAME SOURCE_FILES)
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_NAME}.out "${EXECUTABLE_NAME}.hex"
|
||||
COMMENT "post build steps for ${EXECUTABLE_NAME}")
|
||||
|
||||
# custom target for flashing the board
|
||||
if(USE_JLINK)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${NRFJPROG} --program ${EXECUTABLE_NAME}.hex -f ${NRF_TARGET} --sectorerase
|
||||
COMMAND sleep 0.5s
|
||||
COMMAND ${NRFJPROG} --reset -f ${NRF_TARGET}
|
||||
COMMENT "flashing ${EXECUTABLE_NAME}.hex"
|
||||
)
|
||||
elseif(USE_GDB_CLIENT)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'load' -ex 'kill' ${EXECUTABLE_NAME}.hex
|
||||
COMMENT "flashing ${EXECUTABLE_NAME}.hex"
|
||||
)
|
||||
elseif(USE_OPENOCD)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${OPENOCD_BIN_PATH} -c "tcl_port disabled" -c "gdb_port 3333" -c "telnet_port 4444" -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c "program \"${EXECUTABLE_NAME}.hex\"" -c reset -c shutdown
|
||||
COMMENT "flashing ${EXECUTABLE_NAME}.hex"
|
||||
)
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
||||
# adds app-level scheduler library
|
||||
|
70
doc/ExternalResources.md
Normal file
70
doc/ExternalResources.md
Normal file
@ -0,0 +1,70 @@
|
||||
# External resources
|
||||
Since InfiniTime 1.11 apps and watchfaces can benefit from the external flash memory to store images and fonts.
|
||||
This external memory is a lot bigger (4MB) than the internal memory that contains the firmware (512KB).
|
||||
|
||||
This page describes how the resources are integrated in InfiniTime from a developer perspective. [This page](gettingStarted/updating-software.md) explains how to install and update the external resources using companion apps.
|
||||
|
||||
## Resources generation
|
||||
|
||||
Resources are generated at build time via the [CMake target `Generate Resources`](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/src/resources/CMakeLists.txt#L19).
|
||||
It runs 3 Python scripts that respectively convert the fonts to binary format, convert the images to binary format and package everything in a .zip file.
|
||||
|
||||
The resulting file `infinitime-resources-x.y.z.zip` contains the images and fonts converted in binary `.bin` files and a JSON file `resources.json`.
|
||||
|
||||
Companion apps use this file to upload the files to the watch.
|
||||
|
||||
```
|
||||
{
|
||||
"resources": [
|
||||
{
|
||||
"filename": "lv_font_dots_40.bin",
|
||||
"path": "/fonts/lv_font_dots_40.bin"
|
||||
}
|
||||
],
|
||||
"obsolete_files": [
|
||||
{
|
||||
"path": "/example-of-obsolete-file.bin",
|
||||
"since": "1.11.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The resource JSON file describes an array of resources and an array of obsolete files :
|
||||
|
||||
- `resources` : a resource is a file that must be flashed to the watch
|
||||
- `filename`: name of the resources in the zip file.
|
||||
- `path` : file path and name where the file must be flashed in the watch FS.
|
||||
|
||||
- `obsolete_files` : files that are not needed anymore in the memory of the watch that can be deleted during the update procedure.
|
||||
- `path` : path of the file in the watch FS
|
||||
- `since` : version of InfiniTime that made this file obsolete.
|
||||
|
||||
## Resources update procedure
|
||||
|
||||
The update procedure is based on the [BLE FS API](BLEFS.md). The companion app simply write the binary files to the watch FS using information from the file `resources.json`.
|
||||
|
||||
## Working with external resources in the code
|
||||
|
||||
Load a picture from the external resources:
|
||||
|
||||
```
|
||||
lv_obj_t* logo = lv_img_create(lv_scr_act(), nullptr);
|
||||
lv_img_set_src(logo, "F:/images/logo.bin");
|
||||
```
|
||||
|
||||
Load a font from the external resources: you first need to check that the file actually exists. LVGL will crash when trying to open a font that doesn't exist.
|
||||
|
||||
```
|
||||
lv_font_t* font_teko = nullptr;
|
||||
if (filesystem.FileOpen(&f, "/fonts/font.bin", LFS_O_RDONLY) >= 0) {
|
||||
filesystem.FileClose(&f);
|
||||
font_teko = lv_font_load("F:/fonts/font.bin");
|
||||
}
|
||||
|
||||
if(font != nullptr) {
|
||||
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -17,7 +17,7 @@ InfiniTime is not to be used for medical or other health tracking purposes.
|
||||
- Easy and simple navigation
|
||||
- Behaviour should be predictable and easy to understand
|
||||
- Prefer solid default experience over customization
|
||||
- Personalization is achieved through custom watchfaces.
|
||||
- Personalization is achieved through custom watch faces.
|
||||
More options may be available through a companion app.
|
||||
- Use standard protocols and methods
|
||||
|
||||
@ -25,7 +25,7 @@ InfiniTime is not to be used for medical or other health tracking purposes.
|
||||
|
||||
The perfect version of InfiniTime would include:
|
||||
|
||||
- Capability to sideload apps and watchfaces
|
||||
- Capability to sideload apps and watch faces
|
||||
- Only a minimal feature set in the flashed firmware.
|
||||
Users would add the features they want.
|
||||
- Ports to other devices
|
||||
|
@ -245,7 +245,7 @@ void* __wrap_malloc(size_t size) {
|
||||
|
||||
Now, your function `__wrap_malloc()` will be called instead of `malloc()`. You can call the actual malloc from the stdlib by calling `__real_malloc()`.
|
||||
|
||||
Using this technique, I was able to trace all malloc calls at boot (boot -> digital watchface):
|
||||
Using this technique, I was able to trace all malloc calls at boot (boot -> digital watch face):
|
||||
|
||||
- system task = 3464 bytes (SystemTask could potentially be declared as a global variable to avoid heap allocation here)
|
||||
- string music = 31 (maybe we should not use std::string when not needed, as it does heap allocation)
|
||||
|
@ -40,12 +40,9 @@ CMake configures the project according to variables you specify the command line
|
||||
----------|-------------|--------|
|
||||
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-10.3-2021.10/`|
|
||||
**NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
|
||||
**USE_JLINK, USE_GDB_CLIENT and USE_OPENOCD**|Enable *JLink* mode, *GDB Client* (Black Magic Probe) mode or *OpenOCD* mode (set the one you want to use to `1`)|`-DUSE_JLINK=1`
|
||||
**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`
|
||||
**NRFJPROG**|Path to the NRFJProg executable. Used only if `USE_JLINK` is 1.|`-DNRFJPROG=/opt/nrfjprog/nrfjprog`
|
||||
**GDB_CLIENT_BIN_PATH**|Path to arm-none-eabi-gdb executable. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_BIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb`
|
||||
**GDB_CLIENT_TARGET_REMOTE**|Target remote connection string. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_TARGET_REMOTE=/dev/ttyACM0`
|
||||
**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`
|
||||
**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**
|
||||
@ -56,30 +53,16 @@ The *Debug* mode disables all optimizations, which makes the code easier to debu
|
||||
#### (\*\*) Note about **BUILD_DFU**
|
||||
DFU files are the files you'll need to install your build of InfiniTime using OTA (over-the-air) mechanism. To generate the DFU file, the Python tool [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) is needed on your system. Check that this tool is properly installed before enabling this option.
|
||||
|
||||
#### CMake command line for JLink
|
||||
#### CMake command
|
||||
|
||||
```
|
||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_JLINK=1 -DNRFJPROG=... ../
|
||||
```
|
||||
|
||||
#### CMake command line for GDB Client (Black Magic Probe)
|
||||
|
||||
```
|
||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_GDB_CLIENT=1 -DGDB_CLIENT_BIN_PATH=... -DGDB_CLIENT_TARGET_REMOTE=... ../
|
||||
```
|
||||
|
||||
#### CMake command line for OpenOCD
|
||||
|
||||
```
|
||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_OPENOCD=1 -DGDB_CLIENT_BIN_PATH=[optional] ../
|
||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=...
|
||||
```
|
||||
|
||||
### Build the project
|
||||
|
||||
During the project generation, CMake created the following targets:
|
||||
|
||||
- **FLASH_ERASE** : mass erase the flash memory of the NRF52.
|
||||
- **FLASH_pinetime-app** : flash the firmware into the NRF52.
|
||||
- **pinetime-app** : build the standalone (without bootloader support) version of the firmware.
|
||||
- **pinetime-recovery** : build the standalone recovery version of infinitime (light firmware that only supports OTA and basic UI)
|
||||
- **pinetime-recovery-loader** : build the standalone tool that flashes the recovery firmware into the external SPI flash
|
||||
@ -107,24 +90,6 @@ Binary files are generated into the folder `src`:
|
||||
|
||||
The same files are generated for **pinetime-recovery** and **pinetime-recoveryloader**
|
||||
|
||||
### Program and run
|
||||
|
||||
#### Using CMake targets
|
||||
|
||||
These target have been configured during the project generation by CMake according to the parameters you provided to the command line.
|
||||
|
||||
Mass erase:
|
||||
|
||||
```
|
||||
make FLASH_ERASE
|
||||
```
|
||||
|
||||
Flash the application:
|
||||
|
||||
```
|
||||
make FLASH_pinetime-app
|
||||
```
|
||||
|
||||
### How to generate files needed by the factory
|
||||
|
||||
These files are needed by the Pine64 factory to flash InfiniTime as the default firmware on the PineTimes.
|
||||
|
@ -99,7 +99,7 @@ Now, go to the function `DisplayApp::LoadApp` and add another case to the switch
|
||||
The case will be the id you gave your app earlier.
|
||||
If your app needs any additional arguments, this is the place to pass them.
|
||||
|
||||
If you want to add your app in the app launcher, add your app in [displayapp/screens/ApplicationList.cpp](/src/displayapp/screens/ApplicationList.cpp) to one of the `CreateScreen` functions, or add another `CreateScreen` function if there are no empty spaces for your app. If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.cpp](/src/displayapp/screens/settings/Settings.cpp).
|
||||
If you want to add your app in the app launcher, add your app in [displayapp/screens/ApplicationList.h](/src/displayapp/screens/ApplicationList.h) to the array containing the applications and their corresponding symbol. If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.h](/src/displayapp/screens/settings/Settings.h).
|
||||
|
||||
You should now be able to [build](../buildAndProgram.md) the firmware
|
||||
and flash it to your PineTime. Yay!
|
||||
|
BIN
doc/gettingStarted/amazfish-external-resources-1.png
Normal file
BIN
doc/gettingStarted/amazfish-external-resources-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
BIN
doc/gettingStarted/amazfish-external-resources-2.png
Normal file
BIN
doc/gettingStarted/amazfish-external-resources-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
@ -8,7 +8,7 @@ It is highly recommended to update the firmware to the latest version when you r
|
||||
|
||||
### Setting the time
|
||||
|
||||
By default, InfiniTime starts on the digital watchface. It'll probably display the epoch time (1 Jan 1970, 00:00).
|
||||
By default, InfiniTime starts on the digital watch face. It'll probably display the epoch time (1 Jan 1970, 00:00).
|
||||
|
||||
You can sync the time using companion apps.
|
||||
|
||||
|
BIN
doc/gettingStarted/itd-external-resources.png
Normal file
BIN
doc/gettingStarted/itd-external-resources.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -4,7 +4,7 @@ If you just want to flash or upgrade InfiniTime on your PineTime, this page is f
|
||||
|
||||
## Checking the version of InfiniTime
|
||||
|
||||
You can check the InfiniTime version by first swiping right on the watchface to open quick settings, tapping the cogwheel to open settings, swipe up until you find an entry named "About" and tap on it.
|
||||
You can check the InfiniTime version by first swiping right on the watch face to open quick settings, tapping the cogwheel to open settings, swipe up until you find an entry named "About" and tap on it.
|
||||
|
||||
![InfiniTime 1.0 version](version-1.0.jpg)
|
||||
|
||||
@ -37,6 +37,11 @@ If the new firmware is working correctly, open the settings and select the "Firm
|
||||
|
||||
Firmware validation setting:
|
||||
|
||||
- From the watch face, swipe **right** to display the *quick settings menu*
|
||||
- Open settings by tapping the cogwheel on the bottom right
|
||||
- Swipe up until you find an entry named **Firmware** and tap on it
|
||||
- If the firmware is not validated yet, you can either validate the running firmware, or reset and revert to the previous firmware version
|
||||
|
||||
![Firmware Validation setting](firmwareValidationSetting.png)
|
||||
|
||||
The firmware is not validated yet. Tap 'Validate' to validate it, or 'Reset' to rollback to the previous version.
|
||||
@ -46,3 +51,35 @@ The firmware is not validated yet. Tap 'Validate' to validate it, or 'Reset' to
|
||||
The firmware is validated!
|
||||
|
||||
![Firmware Validated](firmwareValidated.png)
|
||||
|
||||
# Updating resources
|
||||
|
||||
Since InfiniTime 1.11 apps and watchfaces can take benefit of the external flash memory to store their pictures and fonts.
|
||||
This external memory is a lot bigger (4MB) than the internal memory where the firmware is flashed (512KB).
|
||||
Since those resources are not part of the firmware, they need to be flashed and updated separately.
|
||||
|
||||
Resources are packaged into a single .zip file named `infinitime-resources-x.y.z.zip` (where `x`, `y` and `z` are the version numbers of InfiniTime).
|
||||
You can use the companion app of your choice to flash the resources.
|
||||
|
||||
**Note : at the time of writing this page, [Amazfish](https://github.com/piggz/harbour-amazfish) and [ITD](https://gitea.arsenm.dev/Arsen6331/itd) have already integrated this functionality. Other companion apps will hopefully implement it soon!*
|
||||
|
||||
## Amazfish
|
||||
Use the `Download file` functionality of Amazfish.
|
||||
|
||||
![Update resources with Amazfish - Download file](amazfish-external-resources-1.png)
|
||||
|
||||
Amazfish automatically detects the file type (firmware or resources) and apply the corresponding flash procedure when you hit the button **Send file**.
|
||||
|
||||
![Update resources with Amazfish](amazfish-external-resources-2.png)
|
||||
|
||||
## ITD
|
||||
|
||||
Run `itctl` with the `res` command:
|
||||
|
||||
```
|
||||
itctl res load infinitime-resources-1.10.0.zip
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
![Update resources using itctl](itd-external-resources.png)
|
||||
|
@ -22,6 +22,12 @@ RUN apt-get update -qq \
|
||||
python3-dev \
|
||||
git \
|
||||
apt-utils \
|
||||
pkg-config \
|
||||
libpixman-1-dev \
|
||||
libcairo2-dev \
|
||||
libpango-1.0-0 \
|
||||
ibpango1.0-dev \
|
||||
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/*;
|
||||
@ -33,6 +39,10 @@ RUN pip3 install -Iv cryptography==3.3
|
||||
RUN pip3 install cbor
|
||||
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
|
||||
COPY build.sh /opt/
|
||||
|
||||
|
@ -11,6 +11,10 @@ export SOURCES_DIR="${SOURCES_DIR:=/sources}"
|
||||
export BUILD_DIR="${BUILD_DIR:=$SOURCES_DIR/build}"
|
||||
export OUTPUT_DIR="${OUTPUT_DIR:=$SOURCES_DIR/build/output}"
|
||||
|
||||
# Specify a folder with read/write access to NPM
|
||||
export NPM_DIR="$BUILD_DIR/npm"
|
||||
export npm_config_cache="${NPM_DIR}"
|
||||
|
||||
export BUILD_TYPE=${BUILD_TYPE:=Release}
|
||||
export GCC_ARM_VER=${GCC_ARM_VER:="10.3-2021.10"}
|
||||
export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"}
|
||||
@ -59,10 +63,10 @@ CmakeGenerate() {
|
||||
-S "$SOURCES_DIR" \
|
||||
-B "$BUILD_DIR" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DUSE_OPENOCD=1 \
|
||||
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_PATH" \
|
||||
-DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \
|
||||
-DBUILD_DFU=1
|
||||
-DBUILD_DFU=1 \
|
||||
-DBUILD_RESOURCES=1
|
||||
}
|
||||
|
||||
CmakeBuild() {
|
||||
|
@ -15,6 +15,8 @@ cp "$BUILD_DIR/src/pinetime-mcuboot-app-dfu-$PROJECT_VERSION.zip" "$OUTPUT_DIR/p
|
||||
cp "$BUILD_DIR/src/pinetime-mcuboot-recovery-loader-image-$PROJECT_VERSION.bin" "$OUTPUT_DIR/pinetime-mcuboot-recovery-loader-image-$PROJECT_VERSION.bin"
|
||||
cp "$BUILD_DIR/src/pinetime-mcuboot-recovery-loader-dfu-$PROJECT_VERSION.zip" "$OUTPUT_DIR/pinetime-mcuboot-recovery-loader-dfu-$PROJECT_VERSION.zip"
|
||||
|
||||
cp "$BUILD_DIR/src/resources/infinitime-resources-$PROJECT_VERSION.zip" "$OUTPUT_DIR/infinitime-resources-$PROJECT_VERSION.zip"
|
||||
|
||||
mkdir -p "$OUTPUT_DIR/src"
|
||||
cp $BUILD_DIR/src/*.bin "$OUTPUT_DIR/src/"
|
||||
cp $BUILD_DIR/src/*.hex "$OUTPUT_DIR/src/"
|
||||
|
@ -396,6 +396,7 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/screens/Motion.cpp
|
||||
displayapp/screens/FlashLight.cpp
|
||||
displayapp/screens/List.cpp
|
||||
displayapp/screens/CheckboxList.cpp
|
||||
displayapp/screens/BatteryInfo.cpp
|
||||
displayapp/screens/Steps.cpp
|
||||
displayapp/screens/Timer.cpp
|
||||
@ -426,8 +427,10 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/icons/bg_clock.c
|
||||
displayapp/screens/WatchFaceAnalog.cpp
|
||||
displayapp/screens/WatchFaceDigital.cpp
|
||||
displayapp/screens/WatchFaceInfineat.cpp
|
||||
displayapp/screens/WatchFaceTerminal.cpp
|
||||
displayapp/screens/WatchFacePineTimeStyle.cpp
|
||||
displayapp/screens/WatchFaceCasioStyleG7710.cpp
|
||||
|
||||
##
|
||||
|
||||
@ -602,6 +605,7 @@ set(INCLUDE_FILES
|
||||
displayapp/screens/FirmwareUpdate.h
|
||||
displayapp/screens/FirmwareValidation.h
|
||||
displayapp/screens/ApplicationList.h
|
||||
displayapp/screens/CheckboxList.h
|
||||
displayapp/Apps.h
|
||||
displayapp/screens/Notifications.h
|
||||
displayapp/screens/HeartRate.h
|
||||
@ -940,6 +944,10 @@ add_custom_command(TARGET ${EXECUTABLE_NAME}
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_FILE_NAME}.out "${EXECUTABLE_FILE_NAME}.hex"
|
||||
COMMENT "post build steps for ${EXECUTABLE_FILE_NAME}")
|
||||
|
||||
if(BUILD_RESOURCES)
|
||||
add_dependencies(${EXECUTABLE_NAME} GenerateResources)
|
||||
endif()
|
||||
|
||||
# Build binary intended to be used by bootloader
|
||||
set(EXECUTABLE_MCUBOOT_NAME "pinetime-mcuboot-app")
|
||||
set(EXECUTABLE_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
@ -973,6 +981,10 @@ add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
|
||||
COMMENT "post build steps for ${EXECUTABLE_MCUBOOT_FILE_NAME}"
|
||||
)
|
||||
|
||||
if(BUILD_RESOURCES)
|
||||
add_dependencies(${EXECUTABLE_MCUBOOT_NAME} GenerateResources)
|
||||
endif()
|
||||
|
||||
if(BUILD_DFU)
|
||||
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
|
||||
POST_BUILD
|
||||
@ -1127,68 +1139,7 @@ if(BUILD_DFU)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_RESOURCES)
|
||||
add_subdirectory(resources)
|
||||
endif()
|
||||
|
||||
# FLASH
|
||||
if (USE_JLINK)
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${NRFJPROG} --eraseall -f ${NRF_TARGET}
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${NRFJPROG} --program ${EXECUTABLE_FILE_NAME}.hex -f ${NRF_TARGET} --sectorerase
|
||||
COMMAND sleep 0.5s
|
||||
COMMAND ${NRFJPROG} --reset -f ${NRF_TARGET}
|
||||
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
|
||||
)
|
||||
|
||||
elseif (USE_GDB_CLIENT)
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'mon erase_mass'
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'load' -ex 'kill' ${EXECUTABLE_FILE_NAME}.hex
|
||||
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
|
||||
)
|
||||
elseif (USE_OPENOCD)
|
||||
if (USE_CMSIS_DAP)
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${OPENOCD_BIN_PATH} -c 'source [find interface/cmsis-dap.cfg]' -c 'transport select swd'
|
||||
-c 'source [find target/nrf52.cfg]'
|
||||
-c 'init'
|
||||
-c 'halt'
|
||||
-c 'nrf5 mass_erase'
|
||||
-c 'halt'
|
||||
-c 'reset'
|
||||
-c 'exit'
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${OPENOCD_BIN_PATH}
|
||||
-c 'tcl_port disabled'
|
||||
-c 'gdb_port 3333'
|
||||
-c 'telnet_port 4444'
|
||||
-c 'source [find interface/cmsis-dap.cfg]'
|
||||
-c 'transport select swd'
|
||||
-c 'source [find target/nrf52.cfg]'
|
||||
-c 'halt'
|
||||
-c "program \"${EXECUTABLE_FILE_NAME}.hex\""
|
||||
-c 'reset'
|
||||
-c 'shutdown'
|
||||
COMMENT "flashing ${EXECUTABLE_BIN_NAME}.hex"
|
||||
)
|
||||
else ()
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${OPENOCD_BIN_PATH} -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c init -c halt -c 'nrf5 mass_erase' -c reset -c shutdown
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${OPENOCD_BIN_PATH} -c "tcl_port disabled" -c "gdb_port 3333" -c "telnet_port 4444" -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c "program \"${EXECUTABLE_FILE_NAME}.hex\"" -c reset -c shutdown
|
||||
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
@ -82,7 +82,7 @@ void AlarmController::ScheduleAlarm() {
|
||||
state = AlarmState::Set;
|
||||
}
|
||||
|
||||
uint32_t AlarmController::SecondsToAlarm() {
|
||||
uint32_t AlarmController::SecondsToAlarm() const {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(alarmTime - dateTimeController.CurrentDateTime()).count();
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace Pinetime {
|
||||
void ScheduleAlarm();
|
||||
void DisableAlarm();
|
||||
void SetOffAlarmNow();
|
||||
uint32_t SecondsToAlarm();
|
||||
uint32_t SecondsToAlarm() const;
|
||||
void StopAlerting();
|
||||
enum class AlarmState { Not_Set, Set, Alerting };
|
||||
enum class RecurType { None, Daily, Weekdays };
|
||||
|
@ -239,7 +239,7 @@ namespace Pinetime {
|
||||
* In order to represent bursts of wind instead of constant wind,
|
||||
* you have minimum and maximum speeds.
|
||||
*
|
||||
* As direction can fluctuate wildly and some watchfaces might wish to display it nicely,
|
||||
* As direction can fluctuate wildly and some watch faces might wish to display it nicely,
|
||||
* we're following the aerospace industry weather report option of specifying a range.
|
||||
*/
|
||||
class Wind : public TimelineHeader {
|
||||
@ -283,7 +283,7 @@ namespace Pinetime {
|
||||
* as it usually is, but it could change during a trip for ex.
|
||||
* so we allow changing it dynamically.
|
||||
*
|
||||
* Location info can be for some kind of map watchface
|
||||
* Location info can be for some kind of map watch face
|
||||
* or daylight calculations, should those be required.
|
||||
*
|
||||
*/
|
||||
@ -331,7 +331,7 @@ namespace Pinetime {
|
||||
*
|
||||
* These events are a bit more complex because the topic is not simple,
|
||||
* the intention is to heavy-lift the annoying preprocessing from the watch
|
||||
* this allows watchface or watchapp makers to generate accurate alerts and graphics
|
||||
* this allows watch face or watchapp makers to generate accurate alerts and graphics
|
||||
*
|
||||
* If this needs further enforced standardization, pull requests are welcome
|
||||
*/
|
||||
|
@ -7,6 +7,7 @@ using namespace Pinetime::Controllers;
|
||||
|
||||
namespace {
|
||||
char const* DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
char const* DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||
char const* MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
|
||||
char const* MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
}
|
||||
@ -126,6 +127,10 @@ const char* DateTime::MonthShortToStringLow(Months month) {
|
||||
return MonthsStringLow[static_cast<uint8_t>(month)];
|
||||
}
|
||||
|
||||
const char* DateTime::DayOfWeekShortToStringLow() const {
|
||||
return DaysStringShortLow[static_cast<uint8_t>(dayOfWeek)];
|
||||
}
|
||||
|
||||
void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
|
||||
this->systemTask = systemTask;
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ namespace Pinetime {
|
||||
const char* MonthShortToString() const;
|
||||
const char* DayOfWeekShortToString() const;
|
||||
static const char* MonthShortToStringLow(Months month);
|
||||
const char* DayOfWeekShortToStringLow() const;
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
|
||||
return currentDateTime;
|
||||
|
@ -19,7 +19,7 @@ void MotorController::Ring(TimerHandle_t xTimer) {
|
||||
}
|
||||
|
||||
void MotorController::RunForDuration(uint8_t motorDuration) {
|
||||
if (xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) {
|
||||
if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) {
|
||||
nrf_gpio_pin_clear(PinMap::Motor);
|
||||
}
|
||||
}
|
||||
|
@ -34,12 +34,20 @@ namespace Pinetime {
|
||||
Navy,
|
||||
Magenta,
|
||||
Purple,
|
||||
Orange
|
||||
Orange,
|
||||
Pink
|
||||
};
|
||||
enum class PTSGaugeStyle : uint8_t { Full, Half, Numeric };
|
||||
|
||||
struct PineTimeStyle {
|
||||
Colors ColorTime = Colors::Teal;
|
||||
Colors ColorBar = Colors::Teal;
|
||||
Colors ColorBG = Colors::Black;
|
||||
PTSGaugeStyle gaugeStyle = PTSGaugeStyle::Full;
|
||||
};
|
||||
struct WatchFaceInfineat {
|
||||
bool showSideCover = true;
|
||||
int colorIndex = 0;
|
||||
};
|
||||
|
||||
Settings(Pinetime::Controllers::FS& fs);
|
||||
@ -94,10 +102,47 @@ namespace Pinetime {
|
||||
return settings.PTS.ColorBG;
|
||||
};
|
||||
|
||||
void SetInfineatShowSideCover(bool show) {
|
||||
if (show != settings.watchFaceInfineat.showSideCover) {
|
||||
settings.watchFaceInfineat.showSideCover = show;
|
||||
settingsChanged = true;
|
||||
}
|
||||
};
|
||||
bool GetInfineatShowSideCover() const {
|
||||
return settings.watchFaceInfineat.showSideCover;
|
||||
};
|
||||
|
||||
void SetInfineatColorIndex(int index) {
|
||||
if (index != settings.watchFaceInfineat.colorIndex) {
|
||||
settings.watchFaceInfineat.colorIndex = index;
|
||||
settingsChanged = true;
|
||||
}
|
||||
};
|
||||
int GetInfineatColorIndex() const {
|
||||
return settings.watchFaceInfineat.colorIndex;
|
||||
};
|
||||
|
||||
void SetPTSGaugeStyle(PTSGaugeStyle gaugeStyle) {
|
||||
if (gaugeStyle != settings.PTS.gaugeStyle)
|
||||
settingsChanged = true;
|
||||
settings.PTS.gaugeStyle = gaugeStyle;
|
||||
};
|
||||
PTSGaugeStyle GetPTSGaugeStyle() const {
|
||||
return settings.PTS.gaugeStyle;
|
||||
};
|
||||
|
||||
void SetAppMenu(uint8_t menu) {
|
||||
appMenu = menu;
|
||||
};
|
||||
|
||||
void SetWatchfacesMenu(uint8_t menu) {
|
||||
watchFacesMenu = menu;
|
||||
};
|
||||
|
||||
uint8_t GetWatchfacesMenu() const {
|
||||
return watchFacesMenu;
|
||||
};
|
||||
|
||||
uint8_t GetAppMenu() const {
|
||||
return appMenu;
|
||||
};
|
||||
@ -212,7 +257,7 @@ namespace Pinetime {
|
||||
private:
|
||||
Pinetime::Controllers::FS& fs;
|
||||
|
||||
static constexpr uint32_t settingsVersion = 0x0003;
|
||||
static constexpr uint32_t settingsVersion = 0x0004;
|
||||
struct SettingsData {
|
||||
uint32_t version = settingsVersion;
|
||||
uint32_t stepsGoal = 10000;
|
||||
@ -226,6 +271,8 @@ namespace Pinetime {
|
||||
|
||||
PineTimeStyle PTS;
|
||||
|
||||
WatchFaceInfineat watchFaceInfineat;
|
||||
|
||||
std::bitset<4> wakeUpMode {0};
|
||||
uint16_t shakeWakeThreshold = 150;
|
||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||
@ -236,6 +283,7 @@ namespace Pinetime {
|
||||
|
||||
uint8_t appMenu = 0;
|
||||
uint8_t settingsMenu = 0;
|
||||
uint8_t watchFacesMenu = 0;
|
||||
/* ble state is intentionally not saved with the other watch settings and initialized
|
||||
* to off (false) on every boot because we always want ble to be enabled on startup
|
||||
*/
|
||||
|
@ -39,6 +39,8 @@ lv_color_t Pinetime::Applications::Convert(Pinetime::Controllers::Settings::Colo
|
||||
return LV_COLOR_MAKE(0xb0, 0x0, 0xb0);
|
||||
case Pinetime::Controllers::Settings::Colors::Orange:
|
||||
return LV_COLOR_ORANGE;
|
||||
case Pinetime::Controllers::Settings::Colors::Pink:
|
||||
return LV_COLOR_MAKE(0xFF, 0xAE, 0xC9);
|
||||
default:
|
||||
return LV_COLOR_WHITE;
|
||||
}
|
||||
|
@ -75,7 +75,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::BrightnessController& brightnessController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler)
|
||||
Pinetime::Controllers::TouchHandler& touchHandler,
|
||||
Pinetime::Controllers::FS& filesystem)
|
||||
: lcd {lcd},
|
||||
lvgl {lvgl},
|
||||
touchPanel {touchPanel},
|
||||
@ -91,7 +92,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
timerController {timerController},
|
||||
alarmController {alarmController},
|
||||
brightnessController {brightnessController},
|
||||
touchHandler {touchHandler} {
|
||||
touchHandler {touchHandler},
|
||||
filesystem {filesystem} {
|
||||
}
|
||||
|
||||
void DisplayApp::Start(System::BootErrors error) {
|
||||
@ -125,7 +127,7 @@ void DisplayApp::Process(void* instance) {
|
||||
|
||||
void DisplayApp::InitHw() {
|
||||
brightnessController.Init();
|
||||
brightnessController.Set(settingsController.GetBrightness());
|
||||
ApplyBrightness();
|
||||
}
|
||||
|
||||
void DisplayApp::Refresh() {
|
||||
@ -156,7 +158,7 @@ void DisplayApp::Refresh() {
|
||||
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
||||
break;
|
||||
case Messages::RestoreBrightness:
|
||||
brightnessController.Set(settingsController.GetBrightness());
|
||||
ApplyBrightness();
|
||||
break;
|
||||
case Messages::GoToSleep:
|
||||
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
@ -167,7 +169,7 @@ void DisplayApp::Refresh() {
|
||||
state = States::Idle;
|
||||
break;
|
||||
case Messages::GoToRunning:
|
||||
brightnessController.Set(settingsController.GetBrightness());
|
||||
ApplyBrightness();
|
||||
state = States::Running;
|
||||
break;
|
||||
case Messages::UpdateTimeOut:
|
||||
@ -301,7 +303,7 @@ void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction
|
||||
|
||||
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||
touchHandler.CancelTap();
|
||||
brightnessController.Set(settingsController.GetBrightness());
|
||||
ApplyBrightness();
|
||||
|
||||
currentScreen.reset(nullptr);
|
||||
SetFullRefresh(direction);
|
||||
@ -324,7 +326,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||
notificationManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
motionController,
|
||||
filesystem);
|
||||
break;
|
||||
|
||||
case Apps::Error:
|
||||
@ -527,3 +530,12 @@ void DisplayApp::PushMessageToSystemTask(Pinetime::System::Messages message) {
|
||||
void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) {
|
||||
this->systemTask = systemTask;
|
||||
}
|
||||
void DisplayApp::ApplyBrightness() {
|
||||
auto brightness = settingsController.GetBrightness();
|
||||
if(brightness != Controllers::BrightnessController::Levels::Low &&
|
||||
brightness != Controllers::BrightnessController::Levels::Medium &&
|
||||
brightness != Controllers::BrightnessController::Levels::High) {
|
||||
brightness = Controllers::BrightnessController::Levels::High;
|
||||
}
|
||||
brightnessController.Set(brightness);
|
||||
}
|
||||
|
@ -62,7 +62,8 @@ namespace Pinetime {
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::BrightnessController& brightnessController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler);
|
||||
Pinetime::Controllers::TouchHandler& touchHandler,
|
||||
Pinetime::Controllers::FS& filesystem);
|
||||
void Start(System::BootErrors error);
|
||||
void PushMessage(Display::Messages msg);
|
||||
|
||||
@ -90,6 +91,7 @@ namespace Pinetime {
|
||||
Pinetime::Controllers::AlarmController& alarmController;
|
||||
Pinetime::Controllers::BrightnessController& brightnessController;
|
||||
Pinetime::Controllers::TouchHandler& touchHandler;
|
||||
Pinetime::Controllers::FS& filesystem;
|
||||
|
||||
Pinetime::Controllers::FirmwareValidator validator;
|
||||
|
||||
@ -119,6 +121,7 @@ namespace Pinetime {
|
||||
Apps nextApp = Apps::None;
|
||||
DisplayApp::FullRefreshDirections nextDirection;
|
||||
System::BootErrors bootError;
|
||||
void ApplyBrightness();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include "components/fs/FS.h"
|
||||
#include "components/rle/RleDecoder.h"
|
||||
#include "touchhandler/TouchHandler.h"
|
||||
#include "displayapp/icons/infinitime/infinitime-nb.c"
|
||||
@ -24,7 +25,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::BrightnessController& brightnessController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler)
|
||||
Pinetime::Controllers::TouchHandler& touchHandler,
|
||||
Pinetime::Controllers::FS& filesystem)
|
||||
: lcd {lcd}, bleController {bleController} {
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ namespace Pinetime {
|
||||
class TimerController;
|
||||
class AlarmController;
|
||||
class BrightnessController;
|
||||
class FS;
|
||||
}
|
||||
|
||||
namespace System {
|
||||
@ -59,7 +60,8 @@ namespace Pinetime {
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::BrightnessController& brightnessController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler);
|
||||
Pinetime::Controllers::TouchHandler& touchHandler,
|
||||
Pinetime::Controllers::FS& filesystem);
|
||||
void Start();
|
||||
void Start(Pinetime::System::BootErrors) {
|
||||
Start();
|
||||
|
@ -58,7 +58,7 @@
|
||||
"sources": [
|
||||
{
|
||||
"file": "material-design-icons/MaterialIcons-Regular.ttf",
|
||||
"range": "0xf00b, 0xe3aa-0xe3ac, 0xe7f6-0xe7f7, 0xe8b8, 0xef44"
|
||||
"range": "0xf00b, 0xe3aa-0xe3ac, 0xe7f6-0xe7f7, 0xe8b8, 0xef44, 0xe40a"
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
|
116
src/displayapp/screens/CheckboxList.cpp
Normal file
116
src/displayapp/screens/CheckboxList.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "displayapp/screens/CheckboxList.h"
|
||||
#include "displayapp/DisplayApp.h"
|
||||
#include "displayapp/screens/Styles.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
static void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
CheckboxList* screen = static_cast<CheckboxList*>(obj->user_data);
|
||||
screen->UpdateSelected(obj, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CheckboxList::CheckboxList(const uint8_t screenID,
|
||||
const uint8_t numScreens,
|
||||
DisplayApp* app,
|
||||
Controllers::Settings& settingsController,
|
||||
const char* optionsTitle,
|
||||
const char* optionsSymbol,
|
||||
void (Controllers::Settings::*SetOptionIndex)(uint8_t),
|
||||
uint8_t (Controllers::Settings::*GetOptionIndex)() const,
|
||||
std::array<const char*, MaxItems> options)
|
||||
: Screen(app),
|
||||
screenID {screenID},
|
||||
settingsController {settingsController},
|
||||
SetOptionIndex {SetOptionIndex},
|
||||
GetOptionIndex {GetOptionIndex},
|
||||
options {options} {
|
||||
|
||||
settingsController.SetWatchfacesMenu(screenID);
|
||||
|
||||
// Set the background to Black
|
||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
|
||||
if (numScreens > 1) {
|
||||
pageIndicatorBasePoints[0].x = LV_HOR_RES - 1;
|
||||
pageIndicatorBasePoints[0].y = 0;
|
||||
pageIndicatorBasePoints[1].x = LV_HOR_RES - 1;
|
||||
pageIndicatorBasePoints[1].y = LV_VER_RES;
|
||||
|
||||
pageIndicatorBase = lv_line_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||
lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
||||
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints.data(), 2);
|
||||
|
||||
const uint16_t indicatorSize = LV_VER_RES / numScreens;
|
||||
const uint16_t indicatorPos = indicatorSize * screenID;
|
||||
|
||||
pageIndicatorPoints[0].x = LV_HOR_RES - 1;
|
||||
pageIndicatorPoints[0].y = indicatorPos;
|
||||
pageIndicatorPoints[1].x = LV_HOR_RES - 1;
|
||||
pageIndicatorPoints[1].y = indicatorPos + indicatorSize;
|
||||
|
||||
pageIndicator = lv_line_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||
lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
lv_line_set_points(pageIndicator, pageIndicatorPoints.data(), 2);
|
||||
}
|
||||
|
||||
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, 60);
|
||||
lv_obj_set_width(container1, LV_HOR_RES - 20);
|
||||
lv_obj_set_height(container1, LV_VER_RES - 50);
|
||||
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, optionsTitle);
|
||||
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 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, optionsSymbol);
|
||||
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 < options.size(); i++) {
|
||||
if (strcmp(options[i], "")) {
|
||||
cbOption[i] = lv_checkbox_create(container1, nullptr);
|
||||
lv_checkbox_set_text(cbOption[i], options[i]);
|
||||
cbOption[i]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[i], event_handler);
|
||||
SetRadioButtonStyle(cbOption[i]);
|
||||
|
||||
if (static_cast<unsigned int>((settingsController.*GetOptionIndex)() - MaxItems * screenID) == i) {
|
||||
lv_checkbox_set_checked(cbOption[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckboxList::~CheckboxList() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void CheckboxList::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
||||
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||
for (unsigned int i = 0; i < options.size(); i++) {
|
||||
if (strcmp(options[i], "")) {
|
||||
if (object == cbOption[i]) {
|
||||
lv_checkbox_set_checked(cbOption[i], true);
|
||||
(settingsController.*SetOptionIndex)(MaxItems * screenID + i);
|
||||
} else {
|
||||
lv_checkbox_set_checked(cbOption[i], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
src/displayapp/screens/CheckboxList.h
Normal file
48
src/displayapp/screens/CheckboxList.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "displayapp/Apps.h"
|
||||
#include "components/settings/Settings.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
class CheckboxList : public Screen {
|
||||
public:
|
||||
static constexpr size_t MaxItems = 4;
|
||||
|
||||
CheckboxList(const uint8_t screenID,
|
||||
const uint8_t numScreens,
|
||||
DisplayApp* app,
|
||||
Controllers::Settings& settingsController,
|
||||
const char* optionsTitle,
|
||||
const char* optionsSymbol,
|
||||
void (Controllers::Settings::*SetOptionIndex)(uint8_t),
|
||||
uint8_t (Controllers::Settings::*GetOptionIndex)() const,
|
||||
std::array<const char*, MaxItems> options);
|
||||
|
||||
~CheckboxList() override;
|
||||
|
||||
void UpdateSelected(lv_obj_t* object, lv_event_t event);
|
||||
|
||||
private:
|
||||
const uint8_t screenID;
|
||||
Controllers::Settings& settingsController;
|
||||
const char* optionsTitle;
|
||||
const char* optionsSymbol;
|
||||
void (Controllers::Settings::*SetOptionIndex)(uint8_t);
|
||||
uint8_t (Controllers::Settings::*GetOptionIndex)() const;
|
||||
std::array<const char*, MaxItems> options;
|
||||
std::array<lv_obj_t*, MaxItems> cbOption;
|
||||
std::array<lv_point_t, 2> pageIndicatorBasePoints;
|
||||
std::array<lv_point_t, 2> pageIndicatorPoints;
|
||||
lv_obj_t* pageIndicatorBase;
|
||||
lv_obj_t* pageIndicator;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -10,8 +10,10 @@
|
||||
#include "displayapp/DisplayApp.h"
|
||||
#include "displayapp/screens/WatchFaceDigital.h"
|
||||
#include "displayapp/screens/WatchFaceTerminal.h"
|
||||
#include "displayapp/screens/WatchFaceInfineat.h"
|
||||
#include "displayapp/screens/WatchFaceAnalog.h"
|
||||
#include "displayapp/screens/WatchFacePineTimeStyle.h"
|
||||
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
@ -19,18 +21,20 @@ Clock::Clock(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController)
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::FS& filesystem)
|
||||
: Screen(app),
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificatioManager {notificatioManager},
|
||||
notificationManager {notificationManager},
|
||||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController},
|
||||
filesystem {filesystem},
|
||||
screen {[this, &settingsController]() {
|
||||
switch (settingsController.GetClockFace()) {
|
||||
case 0:
|
||||
@ -45,6 +49,12 @@ Clock::Clock(DisplayApp* app,
|
||||
case 3:
|
||||
return WatchFaceTerminalScreen();
|
||||
break;
|
||||
case 4:
|
||||
return WatchFaceInfineatScreen();
|
||||
break;
|
||||
case 5:
|
||||
return WatchFaceCasioStyleG7710();
|
||||
break;
|
||||
}
|
||||
return WatchFaceDigitalScreen();
|
||||
}()} {
|
||||
@ -68,7 +78,7 @@ std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificatioManager,
|
||||
notificationManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
@ -79,7 +89,7 @@ std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificatioManager,
|
||||
notificationManager,
|
||||
settingsController);
|
||||
}
|
||||
|
||||
@ -88,7 +98,7 @@ std::unique_ptr<Screen> Clock::WatchFacePineTimeStyleScreen() {
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificatioManager,
|
||||
notificationManager,
|
||||
settingsController,
|
||||
motionController);
|
||||
}
|
||||
@ -98,8 +108,31 @@ std::unique_ptr<Screen> Clock::WatchFaceTerminalScreen() {
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificatioManager,
|
||||
notificationManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceInfineatScreen() {
|
||||
return std::make_unique<Screens::WatchFaceInfineat>(app,
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificationManager,
|
||||
settingsController,
|
||||
motionController,
|
||||
filesystem);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceCasioStyleG7710() {
|
||||
return std::make_unique<Screens::WatchFaceCasioStyleG7710>(app,
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificationManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController,
|
||||
filesystem);
|
||||
}
|
||||
|
@ -25,10 +25,11 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController);
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::FS& filesystem);
|
||||
~Clock() override;
|
||||
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
@ -38,16 +39,19 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::NotificationManager& notificationManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Controllers::MotionController& motionController;
|
||||
Controllers::FS& filesystem;
|
||||
|
||||
std::unique_ptr<Screen> screen;
|
||||
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
||||
std::unique_ptr<Screen> WatchFaceAnalogScreen();
|
||||
std::unique_ptr<Screen> WatchFacePineTimeStyleScreen();
|
||||
std::unique_ptr<Screen> WatchFaceTerminalScreen();
|
||||
std::unique_ptr<Screen> WatchFaceInfineatScreen();
|
||||
std::unique_ptr<Screen> WatchFaceCasioStyleG7710();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,8 @@ Error::Error(Pinetime::Applications::DisplayApp* app, System::BootErrors error)
|
||||
lv_obj_set_event_cb(btnOk, ButtonEventCallback);
|
||||
lv_obj_set_size(btnOk, LV_HOR_RES, 50);
|
||||
lv_obj_align(btnOk, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_style_local_value_str(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Proceed");
|
||||
lv_obj_t* lblOk = lv_label_create(btnOk, nullptr);
|
||||
lv_label_set_text_static(lblOk, "Proceed");
|
||||
lv_obj_set_style_local_bg_color(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,8 @@ Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorControl
|
||||
lv_obj_set_event_cb(playPause, eventHandler);
|
||||
lv_obj_set_size(playPause, 115, 50);
|
||||
lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||
lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play);
|
||||
lblPlayPause = lv_label_create(playPause, nullptr);
|
||||
lv_label_set_text_static(lblPlayPause, Symbols::play);
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
}
|
||||
@ -126,12 +127,12 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
|
||||
if (obj == playPause) {
|
||||
metronomeStarted = !metronomeStarted;
|
||||
if (metronomeStarted) {
|
||||
lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::pause);
|
||||
lv_label_set_text_static(lblPlayPause, Symbols::pause);
|
||||
systemTask.PushMessage(System::Messages::DisableSleeping);
|
||||
startTime = xTaskGetTickCount();
|
||||
counter = 1;
|
||||
} else {
|
||||
lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play);
|
||||
lv_label_set_text_static(lblPlayPause, Symbols::play);
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ namespace Pinetime {
|
||||
lv_obj_t *bpmArc, *bpmTap, *bpmValue;
|
||||
lv_obj_t *bpbDropdown, *currentBpbText;
|
||||
lv_obj_t* playPause;
|
||||
lv_obj_t* lblPlayPause;
|
||||
|
||||
lv_task_t* taskRefresh;
|
||||
};
|
||||
|
@ -50,6 +50,7 @@ namespace Pinetime {
|
||||
static constexpr const char* notificationsOn = "\xEE\x9F\xB7";
|
||||
|
||||
static constexpr const char* flashlight = "\xEF\x80\x8B";
|
||||
static constexpr const char* paintbrushLg = "\xEE\x90\x8A";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,53 +7,34 @@ using namespace Pinetime::Applications::Screens;
|
||||
|
||||
Twos::Twos(Pinetime::Applications::DisplayApp* app) : Screen(app) {
|
||||
|
||||
// create styles to apply to different valued tiles
|
||||
lv_style_init(&style_cell1);
|
||||
lv_style_init(&style_cell2);
|
||||
lv_style_init(&style_cell3);
|
||||
lv_style_init(&style_cell4);
|
||||
lv_style_init(&style_cell5);
|
||||
struct colorPair {
|
||||
lv_color_t bg;
|
||||
lv_color_t fg;
|
||||
};
|
||||
|
||||
lv_style_set_border_color(&style_cell1, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
|
||||
lv_style_set_border_width(&style_cell1, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_bg_opa(&style_cell1, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_cell1, LV_STATE_DEFAULT, lv_color_hex(0xcdc0b4));
|
||||
lv_style_set_pad_top(&style_cell1, LV_STATE_DEFAULT, 29);
|
||||
lv_style_set_text_color(&style_cell1, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
|
||||
lv_style_set_border_color(&style_cell2, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
|
||||
lv_style_set_border_width(&style_cell2, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_bg_opa(&style_cell2, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_cell2, LV_STATE_DEFAULT, lv_color_hex(0xefdfc6));
|
||||
lv_style_set_pad_top(&style_cell2, LV_STATE_DEFAULT, 29);
|
||||
lv_style_set_text_color(&style_cell2, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
|
||||
lv_style_set_border_color(&style_cell3, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
|
||||
lv_style_set_border_width(&style_cell3, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_bg_opa(&style_cell3, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_cell3, LV_STATE_DEFAULT, lv_color_hex(0xef9263));
|
||||
lv_style_set_pad_top(&style_cell3, LV_STATE_DEFAULT, 29);
|
||||
|
||||
lv_style_set_border_color(&style_cell4, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
|
||||
lv_style_set_border_width(&style_cell4, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_bg_opa(&style_cell4, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_cell4, LV_STATE_DEFAULT, lv_color_hex(0xf76142));
|
||||
lv_style_set_pad_top(&style_cell4, LV_STATE_DEFAULT, 29);
|
||||
|
||||
lv_style_set_border_color(&style_cell5, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
|
||||
lv_style_set_border_width(&style_cell5, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_bg_opa(&style_cell5, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_cell5, LV_STATE_DEFAULT, lv_color_hex(0x007dc5));
|
||||
lv_style_set_pad_top(&style_cell5, LV_STATE_DEFAULT, 29);
|
||||
|
||||
// format grid display
|
||||
static constexpr colorPair colors[nColors] = {
|
||||
{LV_COLOR_MAKE(0xcd, 0xc0, 0xb4), LV_COLOR_BLACK},
|
||||
{LV_COLOR_MAKE(0xef, 0xdf, 0xc6), LV_COLOR_BLACK},
|
||||
{LV_COLOR_MAKE(0xef, 0x92, 0x63), LV_COLOR_WHITE},
|
||||
{LV_COLOR_MAKE(0xf7, 0x61, 0x42), LV_COLOR_WHITE},
|
||||
{LV_COLOR_MAKE(0x00, 0x7d, 0xc5), LV_COLOR_WHITE},
|
||||
};
|
||||
|
||||
gridDisplay = lv_table_create(lv_scr_act(), nullptr);
|
||||
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL1, &style_cell1);
|
||||
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL2, &style_cell2);
|
||||
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL3, &style_cell3);
|
||||
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL4, &style_cell4);
|
||||
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL4 + 1, &style_cell5);
|
||||
|
||||
for (size_t i = 0; i < nColors; i++) {
|
||||
lv_style_init(&cellStyles[i]);
|
||||
|
||||
lv_style_set_border_color(&cellStyles[i], LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
|
||||
lv_style_set_border_width(&cellStyles[i], LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_bg_opa(&cellStyles[i], LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&cellStyles[i], LV_STATE_DEFAULT, colors[i].bg);
|
||||
lv_style_set_pad_top(&cellStyles[i], LV_STATE_DEFAULT, 29);
|
||||
lv_style_set_text_color(&cellStyles[i], LV_STATE_DEFAULT, colors[i].fg);
|
||||
|
||||
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL1 + i, &cellStyles[i]);
|
||||
}
|
||||
|
||||
lv_table_set_col_cnt(gridDisplay, nCols);
|
||||
lv_table_set_row_cnt(gridDisplay, nRows);
|
||||
for (int col = 0; col < nCols; col++) {
|
||||
@ -83,11 +64,9 @@ Twos::Twos(Pinetime::Applications::DisplayApp* app) : Screen(app) {
|
||||
}
|
||||
|
||||
Twos::~Twos() {
|
||||
lv_style_reset(&style_cell1);
|
||||
lv_style_reset(&style_cell2);
|
||||
lv_style_reset(&style_cell3);
|
||||
lv_style_reset(&style_cell4);
|
||||
lv_style_reset(&style_cell5);
|
||||
for (lv_style_t cellStyle : cellStyles) {
|
||||
lv_style_reset(&cellStyle);
|
||||
}
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
|
@ -18,11 +18,8 @@ namespace Pinetime {
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
lv_style_t style_cell1;
|
||||
lv_style_t style_cell2;
|
||||
lv_style_t style_cell3;
|
||||
lv_style_t style_cell4;
|
||||
lv_style_t style_cell5;
|
||||
static constexpr int nColors = 5;
|
||||
lv_style_t cellStyles[nColors];
|
||||
|
||||
lv_obj_t* scoreText;
|
||||
lv_obj_t* gridDisplay;
|
||||
|
@ -70,7 +70,6 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
|
||||
|
||||
plugIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_static(plugIcon, Symbols::plug);
|
||||
lv_obj_set_style_local_text_color(plugIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||
|
||||
notificationIcon = lv_label_create(lv_scr_act(), NULL);
|
||||
|
335
src/displayapp/screens/WatchFaceCasioStyleG7710.cpp
Normal file
335
src/displayapp/screens/WatchFaceCasioStyleG7710.cpp
Normal file
@ -0,0 +1,335 @@
|
||||
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
|
||||
|
||||
#include <date/date.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <cstdio>
|
||||
#include "displayapp/screens/BatteryIcon.h"
|
||||
#include "displayapp/screens/BleIcon.h"
|
||||
#include "displayapp/screens/NotificationIcon.h"
|
||||
#include "displayapp/screens/Symbols.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/heartrate/HeartRateController.h"
|
||||
#include "components/motion/MotionController.h"
|
||||
#include "components/settings/Settings.h"
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::FS& filesystem)
|
||||
: Screen(app),
|
||||
currentDateTime {{}},
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificatioManager {notificatioManager},
|
||||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController} {
|
||||
|
||||
lfs_file f = {};
|
||||
if (filesystem.FileOpen(&f, "/fonts/lv_font_dots_40.bin", LFS_O_RDONLY) >= 0) {
|
||||
filesystem.FileClose(&f);
|
||||
font_dot40 = lv_font_load("F:/fonts/lv_font_dots_40.bin");
|
||||
}
|
||||
|
||||
if (filesystem.FileOpen(&f, "/fonts/7segments_40.bin", LFS_O_RDONLY) >= 0) {
|
||||
filesystem.FileClose(&f);
|
||||
font_segment40 = lv_font_load("F:/fonts/7segments_40.bin");
|
||||
}
|
||||
|
||||
if (filesystem.FileOpen(&f, "/fonts/7segments_115.bin", LFS_O_RDONLY) >= 0) {
|
||||
filesystem.FileClose(&f);
|
||||
font_segment115 = lv_font_load("F:/fonts/7segments_115.bin");
|
||||
}
|
||||
|
||||
label_battery_vallue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(label_battery_vallue, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||
lv_obj_set_style_local_text_color(label_battery_vallue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_label_set_text_static(label_battery_vallue, "00%");
|
||||
|
||||
batteryIcon.Create(lv_scr_act());
|
||||
batteryIcon.SetColor(color_text);
|
||||
lv_obj_align(batteryIcon.GetObject(), label_battery_vallue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_label_set_text_static(batteryPlug, Symbols::plug);
|
||||
lv_obj_align(batteryPlug, batteryIcon.GetObject(), LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
bleIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_label_set_text_static(bleIcon, Symbols::bluetooth);
|
||||
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
lv_obj_align(notificationIcon, bleIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
label_day_of_week = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(label_day_of_week, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, 64);
|
||||
lv_obj_set_style_local_text_color(label_day_of_week, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_obj_set_style_local_text_font(label_day_of_week, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_dot40);
|
||||
lv_label_set_text_static(label_day_of_week, "SUN");
|
||||
|
||||
label_week_number = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(label_week_number, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 22);
|
||||
lv_obj_set_style_local_text_color(label_week_number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_obj_set_style_local_text_font(label_week_number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_dot40);
|
||||
lv_label_set_text_static(label_week_number, "WK26");
|
||||
|
||||
label_day_of_year = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(label_day_of_year, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 100, 30);
|
||||
lv_obj_set_style_local_text_color(label_day_of_year, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_obj_set_style_local_text_font(label_day_of_year, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40);
|
||||
lv_label_set_text_static(label_day_of_year, "181-184");
|
||||
|
||||
lv_style_init(&style_line);
|
||||
lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_line_color(&style_line, LV_STATE_DEFAULT, color_text);
|
||||
lv_style_set_line_rounded(&style_line, LV_STATE_DEFAULT, true);
|
||||
|
||||
lv_style_init(&style_border);
|
||||
lv_style_set_line_width(&style_border, LV_STATE_DEFAULT, 6);
|
||||
lv_style_set_line_color(&style_border, LV_STATE_DEFAULT, color_text);
|
||||
lv_style_set_line_rounded(&style_border, LV_STATE_DEFAULT, true);
|
||||
|
||||
line_icons = lv_line_create(lv_scr_act(), nullptr);
|
||||
lv_line_set_points(line_icons, line_icons_points, 3);
|
||||
lv_obj_add_style(line_icons, LV_LINE_PART_MAIN, &style_line);
|
||||
lv_obj_align(line_icons, nullptr, LV_ALIGN_IN_TOP_RIGHT, -10, 18);
|
||||
|
||||
line_day_of_week_number = lv_line_create(lv_scr_act(), nullptr);
|
||||
lv_line_set_points(line_day_of_week_number, line_day_of_week_number_points, 4);
|
||||
lv_obj_add_style(line_day_of_week_number, LV_LINE_PART_MAIN, &style_border);
|
||||
lv_obj_align(line_day_of_week_number, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 8);
|
||||
|
||||
line_day_of_year = lv_line_create(lv_scr_act(), nullptr);
|
||||
lv_line_set_points(line_day_of_year, line_day_of_year_points, 3);
|
||||
lv_obj_add_style(line_day_of_year, LV_LINE_PART_MAIN, &style_line);
|
||||
lv_obj_align(line_day_of_year, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 60);
|
||||
|
||||
label_date = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 100, 70);
|
||||
lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_obj_set_style_local_text_font(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40);
|
||||
lv_label_set_text_static(label_date, "6-30");
|
||||
|
||||
line_date = lv_line_create(lv_scr_act(), nullptr);
|
||||
lv_line_set_points(line_date, line_date_points, 3);
|
||||
lv_obj_add_style(line_date, LV_LINE_PART_MAIN, &style_line);
|
||||
lv_obj_align(line_date, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 100);
|
||||
|
||||
label_time = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment115);
|
||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
|
||||
|
||||
line_time = lv_line_create(lv_scr_act(), nullptr);
|
||||
lv_line_set_points(line_time, line_time_points, 3);
|
||||
lv_obj_add_style(line_time, LV_LINE_PART_MAIN, &style_line);
|
||||
lv_obj_align(line_time, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, -25);
|
||||
|
||||
label_time_ampm = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(label_time_ampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_label_set_text_static(label_time_ampm, "");
|
||||
lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 5, -5);
|
||||
|
||||
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_click(backgroundLabel, true);
|
||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
lv_label_set_text_static(backgroundLabel, "");
|
||||
|
||||
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
|
||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
|
||||
lv_obj_align(heartbeatIcon, 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);
|
||||
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_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
|
||||
|
||||
stepIcon = 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_label_set_text_static(stepIcon, Symbols::shoe);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
WatchFaceCasioStyleG7710::~WatchFaceCasioStyleG7710() {
|
||||
lv_task_del(taskRefresh);
|
||||
|
||||
lv_style_reset(&style_line);
|
||||
lv_style_reset(&style_border);
|
||||
|
||||
if (font_dot40 != nullptr) {
|
||||
lv_font_free(font_dot40);
|
||||
}
|
||||
|
||||
if (font_segment40 != nullptr) {
|
||||
lv_font_free(font_segment40);
|
||||
}
|
||||
|
||||
if (font_segment115 != nullptr) {
|
||||
lv_font_free(font_segment115);
|
||||
}
|
||||
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void WatchFaceCasioStyleG7710::Refresh() {
|
||||
powerPresent = batteryController.IsPowerPresent();
|
||||
if (powerPresent.IsUpdated()) {
|
||||
lv_label_set_text_static(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
|
||||
}
|
||||
|
||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||
if (batteryPercentRemaining.IsUpdated()) {
|
||||
auto batteryPercent = batteryPercentRemaining.Get();
|
||||
batteryIcon.SetBatteryPercentage(batteryPercent);
|
||||
lv_label_set_text_fmt(label_battery_vallue, "%d%%", batteryPercent);
|
||||
}
|
||||
|
||||
bleState = bleController.IsConnected();
|
||||
bleRadioEnabled = bleController.IsRadioEnabled();
|
||||
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
|
||||
lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
|
||||
}
|
||||
lv_obj_realign(label_battery_vallue);
|
||||
lv_obj_realign(batteryIcon.GetObject());
|
||||
lv_obj_realign(batteryPlug);
|
||||
lv_obj_realign(bleIcon);
|
||||
lv_obj_realign(notificationIcon);
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
if (notificationState.IsUpdated()) {
|
||||
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
||||
}
|
||||
|
||||
currentDateTime = dateTimeController.CurrentDateTime();
|
||||
|
||||
if (currentDateTime.IsUpdated()) {
|
||||
auto newDateTime = currentDateTime.Get();
|
||||
|
||||
auto dp = date::floor<date::days>(newDateTime);
|
||||
auto time = date::make_time(newDateTime - dp);
|
||||
auto yearMonthDay = date::year_month_day(dp);
|
||||
|
||||
auto year = static_cast<int>(yearMonthDay.year());
|
||||
auto month = static_cast<Pinetime::Controllers::DateTime::Months>(static_cast<unsigned>(yearMonthDay.month()));
|
||||
auto day = static_cast<unsigned>(yearMonthDay.day());
|
||||
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||
|
||||
uint8_t hour = time.hours().count();
|
||||
uint8_t minute = time.minutes().count();
|
||||
auto weekNumberFormat = "%V";
|
||||
|
||||
if (displayedHour != hour || displayedMinute != minute) {
|
||||
displayedHour = hour;
|
||||
displayedMinute = minute;
|
||||
|
||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
||||
char ampmChar[2] = "A";
|
||||
if (hour == 0) {
|
||||
hour = 12;
|
||||
} else if (hour == 12) {
|
||||
ampmChar[0] = 'P';
|
||||
} else if (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_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
|
||||
} else {
|
||||
lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute);
|
||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
|
||||
}
|
||||
}
|
||||
|
||||
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
|
||||
// 24h mode: ddmmyyyy, first DOW=Monday;
|
||||
lv_label_set_text_fmt(label_date, "%3d-%2d", day, month);
|
||||
weekNumberFormat = "%V"; // Replaced by the week number of the year (Monday as the first day of the week) as a decimal number
|
||||
// [01,53]. If the week containing 1 January has four or more days in the new year, then it is considered
|
||||
// week 1. Otherwise, it is the last week of the previous year, and the next week is week 1. Both January
|
||||
// 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
|
||||
} else {
|
||||
// 12h mode: mmddyyyy, first DOW=Sunday;
|
||||
lv_label_set_text_fmt(label_date, "%3d-%2d", month, day);
|
||||
weekNumberFormat = "%U"; // Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the
|
||||
// first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
|
||||
}
|
||||
|
||||
uint8_t weekNumber;
|
||||
uint16_t dayOfYearNumber, daysTillEndOfYearNumber;
|
||||
|
||||
time_t ttTime =
|
||||
std::chrono::system_clock::to_time_t(std::chrono::time_point_cast<std::chrono::system_clock::duration>(currentDateTime.Get()));
|
||||
tm* tmTime = std::localtime(&ttTime);
|
||||
|
||||
dayOfYearNumber = tmTime->tm_yday + 1; // tm_yday day of year [0,365] => yday+1
|
||||
daysTillEndOfYearNumber = (yearMonthDay.year().is_leap() ? 366 : 365) - dayOfYearNumber;
|
||||
|
||||
char buffer[8];
|
||||
strftime(buffer, 8, weekNumberFormat, tmTime);
|
||||
weekNumber = atoi(buffer);
|
||||
|
||||
lv_label_set_text_fmt(label_day_of_week, "%s", dateTimeController.DayOfWeekShortToString());
|
||||
lv_label_set_text_fmt(label_day_of_year, "%3d-%3d", dayOfYearNumber, daysTillEndOfYearNumber);
|
||||
lv_label_set_text_fmt(label_week_number, "WK%02d", weekNumber);
|
||||
|
||||
lv_obj_realign(label_day_of_week);
|
||||
lv_obj_realign(label_day_of_year);
|
||||
lv_obj_realign(label_week_number);
|
||||
lv_obj_realign(label_date);
|
||||
|
||||
currentYear = year;
|
||||
currentMonth = month;
|
||||
currentDayOfWeek = dayOfWeek;
|
||||
currentDay = day;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
motionSensorOk = motionController.IsSensorOk();
|
||||
if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
|
||||
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
|
||||
lv_obj_realign(stepValue);
|
||||
lv_obj_realign(stepIcon);
|
||||
}
|
||||
}
|
109
src/displayapp/screens/WatchFaceCasioStyleG7710.h
Normal file
109
src/displayapp/screens/WatchFaceCasioStyleG7710.h
Normal file
@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
#include <displayapp/screens/BatteryIcon.h>
|
||||
#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/ble/BleController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Settings;
|
||||
class Battery;
|
||||
class Ble;
|
||||
class NotificationManager;
|
||||
class HeartRateController;
|
||||
class MotionController;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class WatchFaceCasioStyleG7710 : public Screen {
|
||||
public:
|
||||
WatchFaceCasioStyleG7710(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::FS& filesystem);
|
||||
~WatchFaceCasioStyleG7710() override;
|
||||
|
||||
void Refresh() override;
|
||||
|
||||
private:
|
||||
uint8_t displayedHour = -1;
|
||||
uint8_t displayedMinute = -1;
|
||||
|
||||
uint16_t currentYear = 1970;
|
||||
Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
|
||||
Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
|
||||
uint8_t currentDay = 0;
|
||||
|
||||
DirtyValue<uint8_t> batteryPercentRemaining {};
|
||||
DirtyValue<bool> powerPresent {};
|
||||
DirtyValue<bool> bleState {};
|
||||
DirtyValue<bool> bleRadioEnabled {};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
|
||||
DirtyValue<bool> motionSensorOk {};
|
||||
DirtyValue<uint32_t> stepCount {};
|
||||
DirtyValue<uint8_t> heartbeat {};
|
||||
DirtyValue<bool> heartbeatRunning {};
|
||||
DirtyValue<bool> notificationState {};
|
||||
|
||||
lv_point_t line_icons_points[3] {{0, 5}, {117, 5}, {122, 0}};
|
||||
lv_point_t line_day_of_week_number_points[4] {{0, 0}, {100, 0}, {95, 95}, {0, 95}};
|
||||
lv_point_t line_day_of_year_points[3] {{0, 5}, {130, 5}, {135, 0}};
|
||||
lv_point_t line_date_points[3] {{0, 5}, {135, 5}, {140, 0}};
|
||||
lv_point_t line_time_points[3] {{0, 0}, {230, 0}, {235, 5}};
|
||||
|
||||
lv_color_t color_text = lv_color_hex(0x98B69A);
|
||||
|
||||
lv_style_t style_line;
|
||||
lv_style_t style_border;
|
||||
|
||||
lv_obj_t* label_time;
|
||||
lv_obj_t* line_time;
|
||||
lv_obj_t* label_time_ampm;
|
||||
lv_obj_t* label_date;
|
||||
lv_obj_t* line_date;
|
||||
lv_obj_t* label_day_of_week;
|
||||
lv_obj_t* label_week_number;
|
||||
lv_obj_t* line_day_of_week_number;
|
||||
lv_obj_t* label_day_of_year;
|
||||
lv_obj_t* line_day_of_year;
|
||||
lv_obj_t* backgroundLabel;
|
||||
lv_obj_t* bleIcon;
|
||||
lv_obj_t* batteryPlug;
|
||||
lv_obj_t* label_battery_vallue;
|
||||
lv_obj_t* heartbeatIcon;
|
||||
lv_obj_t* heartbeatValue;
|
||||
lv_obj_t* stepIcon;
|
||||
lv_obj_t* stepValue;
|
||||
lv_obj_t* notificationIcon;
|
||||
lv_obj_t* line_icons;
|
||||
|
||||
BatteryIcon batteryIcon;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Controllers::MotionController& motionController;
|
||||
|
||||
lv_task_t* taskRefresh;
|
||||
lv_font_t* font_dot40 = nullptr;
|
||||
lv_font_t* font_segment40 = nullptr;
|
||||
lv_font_t* font_segment115 = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -18,14 +18,14 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController)
|
||||
: Screen(app),
|
||||
currentDateTime {{}},
|
||||
dateTimeController {dateTimeController},
|
||||
notificatioManager {notificatioManager},
|
||||
notificationManager {notificationManager},
|
||||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController},
|
||||
@ -83,7 +83,7 @@ WatchFaceDigital::~WatchFaceDigital() {
|
||||
void WatchFaceDigital::Refresh() {
|
||||
statusIcons.Update();
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
notificationState = notificationManager.AreNewNotificationsAvailable();
|
||||
if (notificationState.IsUpdated()) {
|
||||
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController);
|
||||
@ -66,7 +66,7 @@ namespace Pinetime {
|
||||
lv_obj_t* notificationIcon;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::NotificationManager& notificationManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Controllers::MotionController& motionController;
|
||||
|
611
src/displayapp/screens/WatchFaceInfineat.cpp
Normal file
611
src/displayapp/screens/WatchFaceInfineat.cpp
Normal file
@ -0,0 +1,611 @@
|
||||
#include "displayapp/screens/WatchFaceInfineat.h"
|
||||
|
||||
#include <date/date.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <cstdio>
|
||||
#include "displayapp/screens/Symbols.h"
|
||||
#include "displayapp/screens/BleIcon.h"
|
||||
#include "components/settings/Settings.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/motion/MotionController.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
auto* screen = static_cast<WatchFaceInfineat*>(obj->user_data);
|
||||
screen->UpdateSelected(obj, event);
|
||||
}
|
||||
}
|
||||
|
||||
WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::FS& filesystem)
|
||||
: Screen(app),
|
||||
currentDateTime {{}},
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificationManager {notificationManager},
|
||||
settingsController {settingsController},
|
||||
motionController {motionController} {
|
||||
lfs_file f = {};
|
||||
if (filesystem.FileOpen(&f, "/fonts/teko.bin", LFS_O_RDONLY) >= 0) {
|
||||
filesystem.FileClose(&f);
|
||||
font_teko = lv_font_load("F:/fonts/teko.bin");
|
||||
}
|
||||
|
||||
if (filesystem.FileOpen(&f, "/fonts/bebas.bin", LFS_O_RDONLY) >= 0) {
|
||||
filesystem.FileClose(&f);
|
||||
font_bebas = lv_font_load("F:/fonts/bebas.bin");
|
||||
}
|
||||
|
||||
// Black background covering the whole screen
|
||||
background = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_obj_set_size(background, 240, 240);
|
||||
lv_obj_align(background, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||
|
||||
// Side Cover
|
||||
line0 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line1 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line2 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line3 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line4 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line5 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line6 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line7 = lv_line_create(lv_scr_act(), nullptr);
|
||||
line8 = lv_line_create(lv_scr_act(), nullptr);
|
||||
lineBattery = lv_line_create(lv_scr_act(), nullptr);
|
||||
|
||||
lv_style_init(&line0Style);
|
||||
lv_style_set_line_width(&line0Style, LV_STATE_DEFAULT, 18);
|
||||
lv_style_set_line_color(&line0Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines]));
|
||||
lv_obj_add_style(line0, LV_LINE_PART_MAIN, &line0Style);
|
||||
line0Points[0] = {30, 25};
|
||||
line0Points[1] = {68, -8};
|
||||
lv_line_set_points(line0, line0Points, 2);
|
||||
|
||||
lv_style_init(&line1Style);
|
||||
lv_style_set_line_width(&line1Style, LV_STATE_DEFAULT, 15);
|
||||
lv_style_set_line_color(&line1Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 1]));
|
||||
lv_obj_add_style(line1, LV_LINE_PART_MAIN, &line1Style);
|
||||
line1Points[0] = {26, 167};
|
||||
line1Points[1] = {43, 216};
|
||||
lv_line_set_points(line1, line1Points, 2);
|
||||
|
||||
lv_style_init(&line2Style);
|
||||
lv_style_set_line_width(&line2Style, LV_STATE_DEFAULT, 14);
|
||||
lv_style_set_line_color(&line2Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 2]));
|
||||
lv_obj_add_style(line2, LV_LINE_PART_MAIN, &line2Style);
|
||||
line2Points[0] = {27, 40};
|
||||
line2Points[1] = {27, 196};
|
||||
lv_line_set_points(line2, line2Points, 2);
|
||||
|
||||
lv_style_init(&line3Style);
|
||||
lv_style_set_line_width(&line3Style, LV_STATE_DEFAULT, 22);
|
||||
lv_style_set_line_color(&line3Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 3]));
|
||||
lv_obj_add_style(line3, LV_LINE_PART_MAIN, &line3Style);
|
||||
line3Points[0] = {12, 182};
|
||||
line3Points[1] = {65, 249};
|
||||
lv_line_set_points(line3, line3Points, 2);
|
||||
|
||||
lv_style_init(&line4Style);
|
||||
lv_style_set_line_width(&line4Style, LV_STATE_DEFAULT, 20);
|
||||
lv_style_set_line_color(&line4Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4]));
|
||||
lv_obj_add_style(line4, LV_LINE_PART_MAIN, &line4Style);
|
||||
line4Points[0] = {17, 99};
|
||||
line4Points[1] = {17, 144};
|
||||
lv_line_set_points(line4, line4Points, 2);
|
||||
|
||||
lv_style_init(&line5Style);
|
||||
lv_style_set_line_width(&line5Style, LV_STATE_DEFAULT, 18);
|
||||
lv_style_set_line_color(&line5Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 5]));
|
||||
lv_obj_add_style(line5, LV_LINE_PART_MAIN, &line5Style);
|
||||
line5Points[0] = {14, 81};
|
||||
line5Points[1] = {40, 127};
|
||||
lv_line_set_points(line5, line5Points, 2);
|
||||
|
||||
lv_style_init(&line6Style);
|
||||
lv_style_set_line_width(&line6Style, LV_STATE_DEFAULT, 18);
|
||||
lv_style_set_line_color(&line6Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 6]));
|
||||
lv_obj_add_style(line6, LV_LINE_PART_MAIN, &line6Style);
|
||||
line6Points[0] = {14, 163};
|
||||
line6Points[1] = {40, 118};
|
||||
lv_line_set_points(line6, line6Points, 2);
|
||||
|
||||
lv_style_init(&line7Style);
|
||||
lv_style_set_line_width(&line7Style, LV_STATE_DEFAULT, 52);
|
||||
lv_style_set_line_color(&line7Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 7]));
|
||||
lv_obj_add_style(line7, LV_LINE_PART_MAIN, &line7Style);
|
||||
line7Points[0] = {-20, 124};
|
||||
line7Points[1] = {25, -11};
|
||||
lv_line_set_points(line7, line7Points, 2);
|
||||
|
||||
lv_style_init(&line8Style);
|
||||
lv_style_set_line_width(&line8Style, LV_STATE_DEFAULT, 48);
|
||||
lv_style_set_line_color(&line8Style,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 8]));
|
||||
lv_obj_add_style(line8, LV_LINE_PART_MAIN, &line8Style);
|
||||
line8Points[0] = {-29, 89};
|
||||
line8Points[1] = {27, 254};
|
||||
lv_line_set_points(line8, line8Points, 2);
|
||||
|
||||
logoPine = lv_img_create(lv_scr_act(), nullptr);
|
||||
lv_img_set_src(logoPine, "F:/images/pine_small.bin");
|
||||
lv_obj_set_pos(logoPine, 15, 106);
|
||||
|
||||
lv_style_init(&lineBatteryStyle);
|
||||
lv_style_set_line_width(&lineBatteryStyle, LV_STATE_DEFAULT, 24);
|
||||
lv_style_set_line_color(&lineBatteryStyle,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4]));
|
||||
lv_style_set_line_opa(&lineBatteryStyle, LV_STATE_DEFAULT, 190);
|
||||
lv_obj_add_style(lineBattery, LV_LINE_PART_MAIN, &lineBatteryStyle);
|
||||
lineBatteryPoints[0] = {27, 105};
|
||||
lineBatteryPoints[1] = {27, 106};
|
||||
lv_line_set_points(lineBattery, lineBatteryPoints, 2);
|
||||
lv_obj_move_foreground(lineBattery);
|
||||
|
||||
notificationIcon = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_color(notificationIcon,
|
||||
LV_BTN_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 7]));
|
||||
lv_obj_set_style_local_radius(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_obj_set_size(notificationIcon, 13, 13);
|
||||
lv_obj_set_hidden(notificationIcon, true);
|
||||
|
||||
if (!settingsController.GetInfineatShowSideCover()) {
|
||||
ToggleBatteryIndicatorColor(false);
|
||||
lv_obj_set_hidden(line0, true);
|
||||
lv_obj_set_hidden(line1, true);
|
||||
lv_obj_set_hidden(line2, true);
|
||||
lv_obj_set_hidden(line3, true);
|
||||
lv_obj_set_hidden(line4, true);
|
||||
lv_obj_set_hidden(line5, true);
|
||||
lv_obj_set_hidden(line6, true);
|
||||
lv_obj_set_hidden(line7, true);
|
||||
lv_obj_set_hidden(line8, true);
|
||||
}
|
||||
|
||||
timeContainer = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_opa(timeContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
if (font_bebas != nullptr) {
|
||||
lv_obj_set_size(timeContainer, 185, 185);
|
||||
lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
|
||||
} else {
|
||||
lv_obj_set_size(timeContainer, 110, 145);
|
||||
lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
labelHour = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
|
||||
lv_label_set_text(labelHour, "01");
|
||||
if (font_bebas != nullptr) {
|
||||
lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas);
|
||||
lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 0);
|
||||
} else {
|
||||
lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
|
||||
lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 5);
|
||||
}
|
||||
|
||||
labelMinutes = lv_label_create(lv_scr_act(), nullptr);
|
||||
if (font_bebas != nullptr) {
|
||||
lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas);
|
||||
} else {
|
||||
lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
|
||||
}
|
||||
lv_label_set_text(labelMinutes, "00");
|
||||
lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
|
||||
labelTimeAmPm = lv_label_create(lv_scr_act(), nullptr);
|
||||
if (font_teko != nullptr) {
|
||||
lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
|
||||
} else {
|
||||
lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
|
||||
}
|
||||
|
||||
lv_label_set_text(labelTimeAmPm, "");
|
||||
lv_obj_align(labelTimeAmPm, timeContainer, LV_ALIGN_OUT_RIGHT_TOP, 0, 15);
|
||||
|
||||
dateContainer = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_opa(dateContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_obj_set_size(dateContainer, 60, 30);
|
||||
lv_obj_align(dateContainer, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 5);
|
||||
|
||||
labelDate = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
||||
if (font_teko != nullptr) {
|
||||
lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
|
||||
} else {
|
||||
lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
|
||||
}
|
||||
lv_obj_align(labelDate, dateContainer, LV_ALIGN_IN_TOP_MID, 0, 0);
|
||||
lv_label_set_text(labelDate, "Mon 01");
|
||||
|
||||
bleIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
||||
lv_label_set_text(bleIcon, Symbols::bluetooth);
|
||||
lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
|
||||
|
||||
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
||||
if (font_teko != nullptr) {
|
||||
lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
|
||||
} else {
|
||||
lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
|
||||
}
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 10, 0);
|
||||
lv_label_set_text(stepValue, "0");
|
||||
|
||||
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
||||
lv_label_set_text(stepIcon, Symbols::shoe);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
// Setting buttons
|
||||
btnClose = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnClose->user_data = this;
|
||||
lv_obj_set_size(btnClose, 60, 60);
|
||||
lv_obj_align(btnClose, lv_scr_act(), LV_ALIGN_CENTER, 0, -80);
|
||||
lv_obj_set_style_local_bg_opa(btnClose, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
|
||||
lv_obj_t* lblClose = lv_label_create(btnClose, nullptr);
|
||||
lv_label_set_text_static(lblClose, "X");
|
||||
lv_obj_set_event_cb(btnClose, event_handler);
|
||||
lv_obj_set_hidden(btnClose, true);
|
||||
|
||||
btnNextColor = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnNextColor->user_data = this;
|
||||
lv_obj_set_size(btnNextColor, 60, 60);
|
||||
lv_obj_align(btnNextColor, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 0);
|
||||
lv_obj_set_style_local_bg_opa(btnNextColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
|
||||
lv_obj_t* lblNextColor = lv_label_create(btnNextColor, nullptr);
|
||||
lv_label_set_text_static(lblNextColor, ">");
|
||||
lv_obj_set_event_cb(btnNextColor, event_handler);
|
||||
lv_obj_set_hidden(btnNextColor, true);
|
||||
|
||||
btnPrevColor = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnPrevColor->user_data = this;
|
||||
lv_obj_set_size(btnPrevColor, 60, 60);
|
||||
lv_obj_align(btnPrevColor, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 0);
|
||||
lv_obj_set_style_local_bg_opa(btnPrevColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
|
||||
lv_obj_t* lblPrevColor = lv_label_create(btnPrevColor, nullptr);
|
||||
lv_label_set_text_static(lblPrevColor, "<");
|
||||
lv_obj_set_event_cb(btnPrevColor, event_handler);
|
||||
lv_obj_set_hidden(btnPrevColor, true);
|
||||
|
||||
btnToggleCover = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnToggleCover->user_data = this;
|
||||
lv_obj_set_size(btnToggleCover, 60, 60);
|
||||
lv_obj_align(btnToggleCover, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);
|
||||
lv_obj_set_style_local_bg_opa(btnToggleCover, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
|
||||
const char* labelToggle = settingsController.GetInfineatShowSideCover() ? "ON" : "OFF";
|
||||
lblToggle = lv_label_create(btnToggleCover, nullptr);
|
||||
lv_label_set_text_static(lblToggle, labelToggle);
|
||||
lv_obj_set_event_cb(btnToggleCover, event_handler);
|
||||
lv_obj_set_hidden(btnToggleCover, true);
|
||||
|
||||
// Button to access the settings
|
||||
btnSettings = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnSettings->user_data = this;
|
||||
lv_obj_set_size(btnSettings, 150, 150);
|
||||
lv_obj_align(btnSettings, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_style_local_radius(btnSettings, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 30);
|
||||
lv_obj_set_style_local_bg_opa(btnSettings, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
|
||||
lv_obj_set_event_cb(btnSettings, event_handler);
|
||||
labelBtnSettings = lv_label_create(btnSettings, nullptr);
|
||||
lv_obj_set_style_local_text_font(labelBtnSettings, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
|
||||
lv_label_set_text_static(labelBtnSettings, Symbols::settings);
|
||||
lv_obj_set_hidden(btnSettings, true);
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
WatchFaceInfineat::~WatchFaceInfineat() {
|
||||
lv_task_del(taskRefresh);
|
||||
|
||||
lv_style_reset(&line0Style);
|
||||
lv_style_reset(&line1Style);
|
||||
lv_style_reset(&line2Style);
|
||||
lv_style_reset(&line3Style);
|
||||
lv_style_reset(&line4Style);
|
||||
lv_style_reset(&line5Style);
|
||||
lv_style_reset(&line6Style);
|
||||
lv_style_reset(&line7Style);
|
||||
lv_style_reset(&line8Style);
|
||||
lv_style_reset(&lineBatteryStyle);
|
||||
|
||||
if (font_bebas != nullptr) {
|
||||
lv_font_free(font_bebas);
|
||||
}
|
||||
if (font_teko != nullptr) {
|
||||
lv_font_free(font_teko);
|
||||
}
|
||||
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool WatchFaceInfineat::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
if ((event == Pinetime::Applications::TouchEvents::LongTap) && lv_obj_get_hidden(btnSettings)) {
|
||||
lv_obj_set_hidden(btnSettings, false);
|
||||
savedTick = lv_tick_get();
|
||||
return true;
|
||||
}
|
||||
// Prevent screen from sleeping when double tapping with settings on
|
||||
if ((event == Pinetime::Applications::TouchEvents::DoubleTap) && !lv_obj_get_hidden(btnClose)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WatchFaceInfineat::CloseMenu() {
|
||||
settingsController.SaveSettings();
|
||||
lv_obj_set_hidden(btnClose, true);
|
||||
lv_obj_set_hidden(btnNextColor, true);
|
||||
lv_obj_set_hidden(btnPrevColor, true);
|
||||
lv_obj_set_hidden(btnToggleCover, true);
|
||||
}
|
||||
|
||||
bool WatchFaceInfineat::OnButtonPushed() {
|
||||
if (!lv_obj_get_hidden(btnClose)) {
|
||||
CloseMenu();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WatchFaceInfineat::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
bool showSideCover = settingsController.GetInfineatShowSideCover();
|
||||
int colorIndex = settingsController.GetInfineatColorIndex();
|
||||
|
||||
if (object == btnSettings) {
|
||||
lv_obj_set_hidden(btnSettings, true);
|
||||
lv_obj_set_hidden(btnClose, false);
|
||||
lv_obj_set_hidden(btnNextColor, !showSideCover);
|
||||
lv_obj_set_hidden(btnPrevColor, !showSideCover);
|
||||
lv_obj_set_hidden(btnToggleCover, false);
|
||||
}
|
||||
if (object == btnClose) {
|
||||
CloseMenu();
|
||||
}
|
||||
if (object == btnToggleCover) {
|
||||
settingsController.SetInfineatShowSideCover(!showSideCover);
|
||||
ToggleBatteryIndicatorColor(!showSideCover);
|
||||
lv_obj_set_hidden(line0, showSideCover);
|
||||
lv_obj_set_hidden(line1, showSideCover);
|
||||
lv_obj_set_hidden(line2, showSideCover);
|
||||
lv_obj_set_hidden(line3, showSideCover);
|
||||
lv_obj_set_hidden(line4, showSideCover);
|
||||
lv_obj_set_hidden(line5, showSideCover);
|
||||
lv_obj_set_hidden(line6, showSideCover);
|
||||
lv_obj_set_hidden(line7, showSideCover);
|
||||
lv_obj_set_hidden(line8, showSideCover);
|
||||
lv_obj_set_hidden(btnNextColor, showSideCover);
|
||||
lv_obj_set_hidden(btnPrevColor, showSideCover);
|
||||
const char* labelToggle = showSideCover ? "OFF" : "ON";
|
||||
lv_label_set_text_static(lblToggle, labelToggle);
|
||||
}
|
||||
if (object == btnNextColor) {
|
||||
colorIndex = (colorIndex + 1) % nColors;
|
||||
settingsController.SetInfineatColorIndex(colorIndex);
|
||||
}
|
||||
if (object == btnPrevColor) {
|
||||
colorIndex -= 1;
|
||||
if (colorIndex < 0)
|
||||
colorIndex = nColors - 1;
|
||||
settingsController.SetInfineatColorIndex(colorIndex);
|
||||
}
|
||||
if (object == btnNextColor || object == btnPrevColor) {
|
||||
lv_obj_set_style_local_line_color(line0,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 0]));
|
||||
lv_obj_set_style_local_line_color(line1,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 1]));
|
||||
lv_obj_set_style_local_line_color(line2,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 2]));
|
||||
lv_obj_set_style_local_line_color(line3,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 3]));
|
||||
lv_obj_set_style_local_line_color(line4,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 4]));
|
||||
lv_obj_set_style_local_line_color(line5,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 5]));
|
||||
lv_obj_set_style_local_line_color(line6,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 6]));
|
||||
lv_obj_set_style_local_line_color(line7,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 7]));
|
||||
lv_obj_set_style_local_line_color(line8,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 8]));
|
||||
lv_obj_set_style_local_line_color(lineBattery,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 4]));
|
||||
lv_obj_set_style_local_bg_color(notificationIcon,
|
||||
LV_BTN_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[colorIndex * nLines + 7]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WatchFaceInfineat::Refresh() {
|
||||
notificationState = notificationManager.AreNewNotificationsAvailable();
|
||||
if (notificationState.IsUpdated()) {
|
||||
lv_obj_set_hidden(notificationIcon, !notificationState.Get());
|
||||
lv_obj_align(notificationIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||
}
|
||||
|
||||
currentDateTime = dateTimeController.CurrentDateTime();
|
||||
|
||||
if (currentDateTime.IsUpdated()) {
|
||||
auto newDateTime = currentDateTime.Get();
|
||||
|
||||
auto dp = date::floor<date::days>(newDateTime);
|
||||
auto time = date::make_time(newDateTime - dp);
|
||||
auto yearMonthDay = date::year_month_day(dp);
|
||||
|
||||
auto year = static_cast<int>(yearMonthDay.year());
|
||||
auto month = static_cast<Pinetime::Controllers::DateTime::Months>(static_cast<unsigned>(yearMonthDay.month()));
|
||||
auto day = static_cast<unsigned>(yearMonthDay.day());
|
||||
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||
|
||||
int hour = time.hours().count();
|
||||
auto minute = time.minutes().count();
|
||||
|
||||
char minutesChar[3];
|
||||
sprintf(minutesChar, "%02d", static_cast<int>(minute));
|
||||
|
||||
char hoursChar[3];
|
||||
char ampmChar[3];
|
||||
|
||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
||||
if (hour < 12) {
|
||||
if (hour == 0) {
|
||||
hour = 12;
|
||||
}
|
||||
sprintf(ampmChar, "AM");
|
||||
} else { // hour >= 12
|
||||
if (hour != 12) {
|
||||
hour = hour - 12;
|
||||
}
|
||||
sprintf(ampmChar, "PM");
|
||||
}
|
||||
}
|
||||
sprintf(hoursChar, "%02d", hour);
|
||||
|
||||
if ((hoursChar[0] != displayedChar[0]) || (hoursChar[1] != displayedChar[1]) || (minutesChar[0] != displayedChar[2]) ||
|
||||
(minutesChar[1] != displayedChar[3])) {
|
||||
displayedChar[0] = hoursChar[0];
|
||||
displayedChar[1] = hoursChar[1];
|
||||
displayedChar[2] = minutesChar[0];
|
||||
displayedChar[3] = minutesChar[1];
|
||||
|
||||
lv_label_set_text_fmt(labelHour, "%s", hoursChar);
|
||||
lv_label_set_text_fmt(labelMinutes, "%s", minutesChar);
|
||||
}
|
||||
|
||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
||||
lv_label_set_text(labelTimeAmPm, ampmChar);
|
||||
lv_obj_align(labelTimeAmPm, timeContainer, LV_ALIGN_OUT_RIGHT_TOP, 0, 10);
|
||||
lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 5);
|
||||
lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
}
|
||||
|
||||
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||
lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(), day);
|
||||
lv_obj_realign(labelDate);
|
||||
|
||||
currentYear = year;
|
||||
currentMonth = month;
|
||||
currentDayOfWeek = dayOfWeek;
|
||||
currentDay = day;
|
||||
}
|
||||
}
|
||||
|
||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||
isCharging = batteryController.IsCharging();
|
||||
// We store if battery and charging are updated before calling Get(),
|
||||
// since Get() sets isUpdated to false.
|
||||
bool isBatteryUpdated = batteryPercentRemaining.IsUpdated();
|
||||
bool isChargingUpdated = isCharging.IsUpdated();
|
||||
if (isCharging.Get()) { // Charging battery animation
|
||||
chargingBatteryPercent += 1;
|
||||
if (chargingBatteryPercent > 100) {
|
||||
chargingBatteryPercent = batteryPercentRemaining.Get();
|
||||
}
|
||||
SetBatteryLevel(chargingBatteryPercent);
|
||||
} else if (isChargingUpdated || isBatteryUpdated) {
|
||||
chargingBatteryPercent = batteryPercentRemaining.Get();
|
||||
SetBatteryLevel(chargingBatteryPercent);
|
||||
}
|
||||
|
||||
bleState = bleController.IsConnected();
|
||||
bleRadioEnabled = bleController.IsRadioEnabled();
|
||||
if (bleState.IsUpdated()) {
|
||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get()));
|
||||
lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 3);
|
||||
}
|
||||
|
||||
stepCount = motionController.NbSteps();
|
||||
motionSensorOk = motionController.IsSensorOk();
|
||||
if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
|
||||
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 10, 0);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
}
|
||||
|
||||
if (!lv_obj_get_hidden(btnSettings)) {
|
||||
if ((savedTick > 0) && (lv_tick_get() - savedTick > 3000)) {
|
||||
lv_obj_set_hidden(btnSettings, true);
|
||||
savedTick = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WatchFaceInfineat::SetBatteryLevel(uint8_t batteryPercent) {
|
||||
// starting point (y) + Pine64 logo height * (100 - batteryPercent) / 100
|
||||
lineBatteryPoints[1] = {27, static_cast<lv_coord_t>(105 + 32 * (100 - batteryPercent) / 100)};
|
||||
lv_line_set_points(lineBattery, lineBatteryPoints, 2);
|
||||
}
|
||||
|
||||
void WatchFaceInfineat::ToggleBatteryIndicatorColor(bool showSideCover) {
|
||||
if (!showSideCover) { // make indicator and notification icon color white
|
||||
lv_obj_set_style_local_image_recolor_opa(logoPine, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_100);
|
||||
lv_obj_set_style_local_image_recolor(logoPine, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_set_style_local_line_color(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_obj_set_style_local_bg_color(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
} else {
|
||||
lv_obj_set_style_local_image_recolor_opa(logoPine, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
|
||||
lv_obj_set_style_local_line_color(lineBattery,
|
||||
LV_LINE_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4]));
|
||||
lv_obj_set_style_local_bg_color(notificationIcon,
|
||||
LV_BTN_PART_MAIN,
|
||||
LV_STATE_DEFAULT,
|
||||
lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 7]));
|
||||
}
|
||||
}
|
145
src/displayapp/screens/WatchFaceInfineat.h
Normal file
145
src/displayapp/screens/WatchFaceInfineat.h
Normal file
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Settings;
|
||||
class Battery;
|
||||
class Ble;
|
||||
class NotificationManager;
|
||||
class MotionController;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class WatchFaceInfineat : public Screen {
|
||||
public:
|
||||
WatchFaceInfineat(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::FS& fs);
|
||||
|
||||
~WatchFaceInfineat() override;
|
||||
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
bool OnButtonPushed() override;
|
||||
void UpdateSelected(lv_obj_t* object, lv_event_t event);
|
||||
void CloseMenu();
|
||||
|
||||
void Refresh() override;
|
||||
|
||||
private:
|
||||
char displayedChar[5] {};
|
||||
|
||||
uint16_t currentYear = 1970;
|
||||
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
|
||||
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
|
||||
uint8_t currentDay = 0;
|
||||
uint32_t savedTick = 0;
|
||||
uint8_t chargingBatteryPercent = 101; // not a mistake ;)
|
||||
|
||||
DirtyValue<uint8_t> batteryPercentRemaining {};
|
||||
DirtyValue<bool> isCharging {};
|
||||
DirtyValue<bool> bleState {};
|
||||
DirtyValue<bool> bleRadioEnabled {};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
|
||||
DirtyValue<bool> motionSensorOk {};
|
||||
DirtyValue<uint32_t> stepCount {};
|
||||
DirtyValue<bool> notificationState {};
|
||||
|
||||
lv_obj_t* background;
|
||||
|
||||
// Lines making up the side cover
|
||||
lv_obj_t* line0;
|
||||
lv_obj_t* line1;
|
||||
lv_obj_t* line2;
|
||||
lv_obj_t* line3;
|
||||
lv_obj_t* line4;
|
||||
lv_obj_t* line5;
|
||||
lv_obj_t* line6;
|
||||
lv_obj_t* line7;
|
||||
lv_obj_t* line8;
|
||||
lv_obj_t* lineBattery;
|
||||
|
||||
lv_style_t line0Style;
|
||||
lv_style_t line1Style;
|
||||
lv_style_t line2Style;
|
||||
lv_style_t line3Style;
|
||||
lv_style_t line4Style;
|
||||
lv_style_t line5Style;
|
||||
lv_style_t line6Style;
|
||||
lv_style_t line7Style;
|
||||
lv_style_t line8Style;
|
||||
lv_style_t lineBatteryStyle;
|
||||
|
||||
lv_point_t line0Points[2];
|
||||
lv_point_t line1Points[2];
|
||||
lv_point_t line2Points[2];
|
||||
lv_point_t line3Points[2];
|
||||
lv_point_t line4Points[2];
|
||||
lv_point_t line5Points[2];
|
||||
lv_point_t line6Points[2];
|
||||
lv_point_t line7Points[2];
|
||||
lv_point_t line8Points[2];
|
||||
lv_point_t lineBatteryPoints[2];
|
||||
|
||||
lv_obj_t* logoPine;
|
||||
|
||||
lv_obj_t* timeContainer;
|
||||
lv_obj_t* labelHour;
|
||||
lv_obj_t* labelMinutes;
|
||||
lv_obj_t* labelTimeAmPm;
|
||||
lv_obj_t* dateContainer;
|
||||
lv_obj_t* labelDate;
|
||||
lv_obj_t* bleIcon;
|
||||
lv_obj_t* stepIcon;
|
||||
lv_obj_t* stepValue;
|
||||
lv_obj_t* notificationIcon;
|
||||
lv_obj_t* btnClose;
|
||||
lv_obj_t* btnNextColor;
|
||||
lv_obj_t* btnToggleCover;
|
||||
lv_obj_t* btnPrevColor;
|
||||
lv_obj_t* btnSettings;
|
||||
lv_obj_t* labelBtnSettings;
|
||||
lv_obj_t* lblToggle;
|
||||
|
||||
static constexpr int nLines = 9;
|
||||
static constexpr int nColors = 7; // must match number of colors in InfineatColors
|
||||
struct InfineatColors {
|
||||
int orange[nLines] = {0xfd872b, 0xdb3316, 0x6f1000, 0xfd7a0a, 0xffffff, 0xffffff, 0xffffff, 0xe85102, 0xea1c00};
|
||||
int blue[nLines] = {0xe7f8ff, 0x2232d0, 0x182a8b, 0xe7f8ff, 0xffffff, 0xffffff, 0xffffff, 0x5991ff, 0x1636ff};
|
||||
int green[nLines] = {0xb8ff9b, 0x088608, 0x004a00, 0xb8ff9b, 0xffffff, 0xffffff, 0xffffff, 0x62d515, 0x007400};
|
||||
int rainbow[nLines] = {0x2da400, 0xac09c4, 0xfe0303, 0x0d57ff, 0xffffff, 0xffffff, 0xffffff, 0xe0b900, 0xe85102};
|
||||
int gray[nLines] = {0xeeeeee, 0x98959b, 0x191919, 0xeeeeee, 0xffffff, 0xffffff, 0xffffff, 0x919191, 0x3a3a3a};
|
||||
int nordBlue[nLines] = {0xc3daf2, 0x4d78ce, 0x153451, 0xc3daf2, 0xffffff, 0xffffff, 0xffffff, 0x5d8ad2, 0x21518a};
|
||||
int nordGreen[nLines] = {0xd5f0e9, 0x238373, 0x1d413f, 0xd5f0e9, 0xffffff, 0xffffff, 0xffffff, 0x2fb8a2, 0x11705a};
|
||||
} infineatColors;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificationManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::MotionController& motionController;
|
||||
|
||||
void SetBatteryLevel(uint8_t batteryPercent);
|
||||
void ToggleBatteryIndicatorColor(bool showSideCover);
|
||||
|
||||
lv_task_t* taskRefresh;
|
||||
lv_font_t* font_teko = nullptr;
|
||||
lv_font_t* font_bebas = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* PineTimeStyle watchface for Infinitime created by Kieran Cawthray
|
||||
* PineTimeStyle watch face for Infinitime created by Kieran Cawthray
|
||||
* Based on WatchFaceDigital
|
||||
* Style/layout copied from TimeStyle for Pebble by Dan Tilden (github.com/tilden)
|
||||
*/
|
||||
@ -48,7 +48,7 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::MotionController& motionController)
|
||||
: Screen(app),
|
||||
@ -56,7 +56,7 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificatioManager {notificatioManager},
|
||||
notificationManager {notificationManager},
|
||||
settingsController {settingsController},
|
||||
motionController {motionController} {
|
||||
|
||||
@ -172,13 +172,23 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
}
|
||||
stepGauge = lv_gauge_create(lv_scr_act(), nullptr);
|
||||
lv_gauge_set_needle_count(stepGauge, 1, needle_colors);
|
||||
lv_obj_set_size(stepGauge, 40, 40);
|
||||
lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_gauge_set_scale(stepGauge, 360, 11, 0);
|
||||
lv_gauge_set_angle_offset(stepGauge, 180);
|
||||
lv_gauge_set_critical_value(stepGauge, 100);
|
||||
lv_gauge_set_range(stepGauge, 0, 100);
|
||||
lv_gauge_set_value(stepGauge, 0, 0);
|
||||
if (settingsController.GetPTSGaugeStyle() == Pinetime::Controllers::Settings::PTSGaugeStyle::Full) {
|
||||
lv_obj_set_size(stepGauge, 40, 40);
|
||||
lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_gauge_set_scale(stepGauge, 360, 11, 0);
|
||||
lv_gauge_set_angle_offset(stepGauge, 180);
|
||||
lv_gauge_set_critical_value(stepGauge, 100);
|
||||
} else if (settingsController.GetPTSGaugeStyle() == Pinetime::Controllers::Settings::PTSGaugeStyle::Half) {
|
||||
lv_obj_set_size(stepGauge, 37, 37);
|
||||
lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, -10);
|
||||
lv_gauge_set_scale(stepGauge, 180, 5, 0);
|
||||
lv_gauge_set_angle_offset(stepGauge, 0);
|
||||
lv_gauge_set_critical_value(stepGauge, 120);
|
||||
} else if (settingsController.GetPTSGaugeStyle() == Pinetime::Controllers::Settings::PTSGaugeStyle::Numeric) {
|
||||
lv_obj_set_hidden(stepGauge, true);
|
||||
}
|
||||
|
||||
lv_obj_set_style_local_pad_right(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||
lv_obj_set_style_local_pad_left(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||
@ -191,12 +201,44 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 3);
|
||||
lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
|
||||
|
||||
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_label_set_text_static(stepValue, "0");
|
||||
lv_obj_align(stepValue, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
if (settingsController.GetPTSGaugeStyle() == Pinetime::Controllers::Settings::PTSGaugeStyle::Numeric) {
|
||||
lv_obj_set_hidden(stepValue, false);
|
||||
} else {
|
||||
lv_obj_set_hidden(stepValue, true);
|
||||
}
|
||||
|
||||
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_TOP_MID, 0, 0);
|
||||
if (settingsController.GetPTSGaugeStyle() == Pinetime::Controllers::Settings::PTSGaugeStyle::Numeric) {
|
||||
lv_obj_set_hidden(stepIcon, false);
|
||||
} else {
|
||||
lv_obj_set_hidden(stepIcon, true);
|
||||
}
|
||||
|
||||
// Display seconds
|
||||
timeDD3 = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(timeDD3, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_label_set_text_static(timeDD3, ":00");
|
||||
lv_obj_align(timeDD3, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
if (settingsController.GetPTSGaugeStyle() == Pinetime::Controllers::Settings::PTSGaugeStyle::Half) {
|
||||
lv_obj_set_hidden(timeDD3, false);
|
||||
} else {
|
||||
lv_obj_set_hidden(timeDD3, true);
|
||||
}
|
||||
|
||||
btnNextTime = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnNextTime->user_data = this;
|
||||
lv_obj_set_size(btnNextTime, 60, 60);
|
||||
lv_obj_align(btnNextTime, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, -80);
|
||||
lv_obj_set_style_local_bg_opa(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
|
||||
lv_obj_t* lblNextTime = lv_label_create(btnNextTime, nullptr);
|
||||
lv_label_set_text_static(lblNextTime, ">");
|
||||
lv_obj_set_event_cb(btnNextTime, event_handler);
|
||||
lv_obj_set_hidden(btnNextTime, true);
|
||||
|
||||
@ -205,7 +247,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnPrevTime, 60, 60);
|
||||
lv_obj_align(btnPrevTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, -80);
|
||||
lv_obj_set_style_local_bg_opa(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
|
||||
lv_obj_t* lblPrevTime = lv_label_create(btnPrevTime, nullptr);
|
||||
lv_label_set_text_static(lblPrevTime, "<");
|
||||
lv_obj_set_event_cb(btnPrevTime, event_handler);
|
||||
lv_obj_set_hidden(btnPrevTime, true);
|
||||
|
||||
@ -214,7 +257,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnNextBar, 60, 60);
|
||||
lv_obj_align(btnNextBar, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 0);
|
||||
lv_obj_set_style_local_bg_opa(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
|
||||
lv_obj_t* lblNextBar = lv_label_create(btnNextBar, nullptr);
|
||||
lv_label_set_text_static(lblNextBar, ">");
|
||||
lv_obj_set_event_cb(btnNextBar, event_handler);
|
||||
lv_obj_set_hidden(btnNextBar, true);
|
||||
|
||||
@ -223,7 +267,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnPrevBar, 60, 60);
|
||||
lv_obj_align(btnPrevBar, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 0);
|
||||
lv_obj_set_style_local_bg_opa(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
|
||||
lv_obj_t* lblPrevBar = lv_label_create(btnPrevBar, nullptr);
|
||||
lv_label_set_text_static(lblPrevBar, "<");
|
||||
lv_obj_set_event_cb(btnPrevBar, event_handler);
|
||||
lv_obj_set_hidden(btnPrevBar, true);
|
||||
|
||||
@ -232,7 +277,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnNextBG, 60, 60);
|
||||
lv_obj_align(btnNextBG, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 80);
|
||||
lv_obj_set_style_local_bg_opa(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
|
||||
lv_obj_t* lblNextBG = lv_label_create(btnNextBG, nullptr);
|
||||
lv_label_set_text_static(lblNextBG, ">");
|
||||
lv_obj_set_event_cb(btnNextBG, event_handler);
|
||||
lv_obj_set_hidden(btnNextBG, true);
|
||||
|
||||
@ -241,7 +287,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnPrevBG, 60, 60);
|
||||
lv_obj_align(btnPrevBG, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 80);
|
||||
lv_obj_set_style_local_bg_opa(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
|
||||
lv_obj_t* lblPrevBG = lv_label_create(btnPrevBG, nullptr);
|
||||
lv_label_set_text_static(lblPrevBG, "<");
|
||||
lv_obj_set_event_cb(btnPrevBG, event_handler);
|
||||
lv_obj_set_hidden(btnPrevBG, true);
|
||||
|
||||
@ -250,7 +297,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnReset, 60, 60);
|
||||
lv_obj_align(btnReset, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);
|
||||
lv_obj_set_style_local_bg_opa(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rst");
|
||||
lv_obj_t* lblReset = lv_label_create(btnReset, nullptr);
|
||||
lv_label_set_text_static(lblReset, "Rst");
|
||||
lv_obj_set_event_cb(btnReset, event_handler);
|
||||
lv_obj_set_hidden(btnReset, true);
|
||||
|
||||
@ -259,7 +307,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnRandom, 60, 60);
|
||||
lv_obj_align(btnRandom, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_style_local_bg_opa(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rnd");
|
||||
lv_obj_t* lblRandom = lv_label_create(btnRandom, nullptr);
|
||||
lv_label_set_text_static(lblRandom, "Rnd");
|
||||
lv_obj_set_event_cb(btnRandom, event_handler);
|
||||
lv_obj_set_hidden(btnRandom, true);
|
||||
|
||||
@ -268,22 +317,44 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||
lv_obj_set_size(btnClose, 60, 60);
|
||||
lv_obj_align(btnClose, lv_scr_act(), LV_ALIGN_CENTER, 0, -80);
|
||||
lv_obj_set_style_local_bg_opa(btnClose, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_style_local_value_str(btnClose, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "X");
|
||||
lv_obj_t* lblClose = lv_label_create(btnClose, nullptr);
|
||||
lv_label_set_text_static(lblClose, "X");
|
||||
lv_obj_set_event_cb(btnClose, event_handler);
|
||||
lv_obj_set_hidden(btnClose, true);
|
||||
|
||||
btnSet = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnSet->user_data = this;
|
||||
lv_obj_set_height(btnSet, 150);
|
||||
lv_obj_set_width(btnSet, 150);
|
||||
lv_obj_align(btnSet, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_style_local_radius(btnSet, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 30);
|
||||
lv_obj_set_style_local_bg_opa(btnSet, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_event_cb(btnSet, event_handler);
|
||||
lbl_btnSet = lv_label_create(btnSet, nullptr);
|
||||
lv_obj_set_style_local_text_font(lbl_btnSet, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
|
||||
lv_label_set_text_static(lbl_btnSet, Symbols::settings);
|
||||
lv_obj_set_hidden(btnSet, true);
|
||||
btnSteps = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnSteps->user_data = this;
|
||||
lv_obj_set_size(btnSteps, 160, 60);
|
||||
lv_obj_align(btnSteps, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_style_local_bg_opa(btnSteps, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_t* lblSteps = lv_label_create(btnSteps, nullptr);
|
||||
lv_label_set_text_static(lblSteps, "Steps style");
|
||||
lv_obj_set_event_cb(btnSteps, event_handler);
|
||||
lv_obj_set_hidden(btnSteps, true);
|
||||
|
||||
btnSetColor = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnSetColor->user_data = this;
|
||||
lv_obj_set_size(btnSetColor, 150, 60);
|
||||
lv_obj_align(btnSetColor, lv_scr_act(), LV_ALIGN_CENTER, 0, -40);
|
||||
lv_obj_set_style_local_radius(btnSetColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
||||
lv_obj_set_style_local_bg_opa(btnSetColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_event_cb(btnSetColor, event_handler);
|
||||
lbl_btnSetColor = lv_label_create(btnSetColor, nullptr);
|
||||
lv_obj_set_style_local_text_font(lbl_btnSetColor, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
|
||||
lv_label_set_text_static(lbl_btnSetColor, Symbols::paintbrushLg);
|
||||
lv_obj_set_hidden(btnSetColor, true);
|
||||
|
||||
btnSetOpts = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnSetOpts->user_data = this;
|
||||
lv_obj_set_size(btnSetOpts, 150, 60);
|
||||
lv_obj_align(btnSetOpts, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
|
||||
lv_obj_set_style_local_radius(btnSetOpts, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
||||
lv_obj_set_style_local_bg_opa(btnSetOpts, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
|
||||
lv_obj_set_event_cb(btnSetOpts, event_handler);
|
||||
lbl_btnSetOpts = lv_label_create(btnSetOpts, nullptr);
|
||||
lv_obj_set_style_local_text_font(lbl_btnSetOpts, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
|
||||
lv_label_set_text_static(lbl_btnSetOpts, Symbols::settings);
|
||||
lv_obj_set_hidden(btnSetOpts, true);
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
Refresh();
|
||||
@ -296,7 +367,8 @@ WatchFacePineTimeStyle::~WatchFacePineTimeStyle() {
|
||||
|
||||
bool WatchFacePineTimeStyle::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
if ((event == Pinetime::Applications::TouchEvents::LongTap) && lv_obj_get_hidden(btnRandom)) {
|
||||
lv_obj_set_hidden(btnSet, false);
|
||||
lv_obj_set_hidden(btnSetColor, false);
|
||||
lv_obj_set_hidden(btnSetOpts, false);
|
||||
savedTick = lv_tick_get();
|
||||
return true;
|
||||
}
|
||||
@ -317,6 +389,7 @@ void WatchFacePineTimeStyle::CloseMenu() {
|
||||
lv_obj_set_hidden(btnReset, true);
|
||||
lv_obj_set_hidden(btnRandom, true);
|
||||
lv_obj_set_hidden(btnClose, true);
|
||||
lv_obj_set_hidden(btnSteps, true);
|
||||
}
|
||||
|
||||
bool WatchFacePineTimeStyle::OnButtonPushed() {
|
||||
@ -369,7 +442,7 @@ void WatchFacePineTimeStyle::Refresh() {
|
||||
AlignIcons();
|
||||
}
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
notificationState = notificationManager.AreNewNotificationsAvailable();
|
||||
if (notificationState.IsUpdated()) {
|
||||
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
||||
AlignIcons();
|
||||
@ -390,6 +463,7 @@ void WatchFacePineTimeStyle::Refresh() {
|
||||
|
||||
uint8_t hour = time.hours().count();
|
||||
uint8_t minute = time.minutes().count();
|
||||
uint8_t second = time.seconds().count();
|
||||
|
||||
if (displayedHour != hour || displayedMinute != minute) {
|
||||
displayedHour = hour;
|
||||
@ -415,6 +489,11 @@ void WatchFacePineTimeStyle::Refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
if (displayedSecond != second) {
|
||||
displayedSecond = second;
|
||||
lv_label_set_text_fmt(timeDD3, ":%02d", second);
|
||||
}
|
||||
|
||||
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||
lv_label_set_text_static(dateDayOfWeek, dateTimeController.DayOfWeekShortToString());
|
||||
lv_label_set_text_fmt(dateDay, "%d", day);
|
||||
@ -431,16 +510,19 @@ void WatchFacePineTimeStyle::Refresh() {
|
||||
stepCount = motionController.NbSteps();
|
||||
motionSensorOk = motionController.IsSensorOk();
|
||||
if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
|
||||
lv_gauge_set_value(stepGauge, 0, (stepCount.Get() / (settingsController.GetStepsGoal() / 100)));
|
||||
lv_gauge_set_value(stepGauge, 0, (stepCount.Get() / (settingsController.GetStepsGoal() / 100)) % 100);
|
||||
lv_obj_realign(stepGauge);
|
||||
lv_label_set_text_fmt(stepValue, "%luK", (stepCount.Get() / 1000));
|
||||
lv_obj_realign(stepValue);
|
||||
if (stepCount.Get() > settingsController.GetStepsGoal()) {
|
||||
lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
if (!lv_obj_get_hidden(btnSet)) {
|
||||
if (!lv_obj_get_hidden(btnSetColor)) {
|
||||
if ((savedTick > 0) && (lv_tick_get() - savedTick > 3000)) {
|
||||
lv_obj_set_hidden(btnSet, true);
|
||||
lv_obj_set_hidden(btnSetColor, true);
|
||||
lv_obj_set_hidden(btnSetOpts, true);
|
||||
savedTick = 0;
|
||||
}
|
||||
}
|
||||
@ -552,8 +634,39 @@ void WatchFacePineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event)
|
||||
if (object == btnClose) {
|
||||
CloseMenu();
|
||||
}
|
||||
if (object == btnSet) {
|
||||
lv_obj_set_hidden(btnSet, true);
|
||||
if (object == btnSteps) {
|
||||
if (!lv_obj_get_hidden(stepGauge) && (lv_obj_get_hidden(timeDD3))) {
|
||||
// show half gauge & seconds
|
||||
lv_obj_set_hidden(timeDD3, false);
|
||||
lv_obj_set_size(stepGauge, 37, 37);
|
||||
lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, -10);
|
||||
lv_gauge_set_scale(stepGauge, 180, 5, 0);
|
||||
lv_gauge_set_angle_offset(stepGauge, 0);
|
||||
lv_gauge_set_critical_value(stepGauge, 120);
|
||||
settingsController.SetPTSGaugeStyle(Controllers::Settings::PTSGaugeStyle::Half);
|
||||
} else if (!lv_obj_get_hidden(timeDD3) && (lv_obj_get_hidden(stepValue))) {
|
||||
// show step count & icon
|
||||
lv_obj_set_hidden(timeDD3, true);
|
||||
lv_obj_set_hidden(stepGauge, true);
|
||||
lv_obj_set_hidden(stepValue, false);
|
||||
lv_obj_set_hidden(stepIcon, false);
|
||||
settingsController.SetPTSGaugeStyle(Controllers::Settings::PTSGaugeStyle::Numeric);
|
||||
} else {
|
||||
// show full gauge
|
||||
lv_obj_set_hidden(stepGauge, false);
|
||||
lv_obj_set_hidden(stepValue, true);
|
||||
lv_obj_set_hidden(stepIcon, true);
|
||||
lv_obj_set_size(stepGauge, 40, 40);
|
||||
lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_gauge_set_scale(stepGauge, 360, 11, 0);
|
||||
lv_gauge_set_angle_offset(stepGauge, 180);
|
||||
lv_gauge_set_critical_value(stepGauge, 100);
|
||||
settingsController.SetPTSGaugeStyle(Controllers::Settings::PTSGaugeStyle::Full);
|
||||
}
|
||||
}
|
||||
if (object == btnSetColor) {
|
||||
lv_obj_set_hidden(btnSetColor, true);
|
||||
lv_obj_set_hidden(btnSetOpts, true);
|
||||
lv_obj_set_hidden(btnNextTime, false);
|
||||
lv_obj_set_hidden(btnPrevTime, false);
|
||||
lv_obj_set_hidden(btnNextBar, false);
|
||||
@ -564,13 +677,19 @@ void WatchFacePineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event)
|
||||
lv_obj_set_hidden(btnRandom, false);
|
||||
lv_obj_set_hidden(btnClose, false);
|
||||
}
|
||||
if (object == btnSetOpts) {
|
||||
lv_obj_set_hidden(btnSetColor, true);
|
||||
lv_obj_set_hidden(btnSetOpts, true);
|
||||
lv_obj_set_hidden(btnSteps, false);
|
||||
lv_obj_set_hidden(btnClose, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pinetime::Controllers::Settings::Colors WatchFacePineTimeStyle::GetNext(Pinetime::Controllers::Settings::Colors color) {
|
||||
auto colorAsInt = static_cast<uint8_t>(color);
|
||||
Pinetime::Controllers::Settings::Colors nextColor;
|
||||
if (colorAsInt < 16) {
|
||||
if (colorAsInt < 17) {
|
||||
nextColor = static_cast<Controllers::Settings::Colors>(colorAsInt + 1);
|
||||
} else {
|
||||
nextColor = static_cast<Controllers::Settings::Colors>(0);
|
||||
@ -585,7 +704,7 @@ Pinetime::Controllers::Settings::Colors WatchFacePineTimeStyle::GetPrevious(Pine
|
||||
if (colorAsInt > 0) {
|
||||
prevColor = static_cast<Controllers::Settings::Colors>(colorAsInt - 1);
|
||||
} else {
|
||||
prevColor = static_cast<Controllers::Settings::Colors>(16);
|
||||
prevColor = static_cast<Controllers::Settings::Colors>(17);
|
||||
}
|
||||
return prevColor;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::MotionController& motionController);
|
||||
~WatchFacePineTimeStyle() override;
|
||||
@ -43,6 +43,7 @@ namespace Pinetime {
|
||||
private:
|
||||
uint8_t displayedHour = -1;
|
||||
uint8_t displayedMinute = -1;
|
||||
uint8_t displayedSecond = -1;
|
||||
|
||||
uint16_t currentYear = 1970;
|
||||
Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
|
||||
@ -71,10 +72,12 @@ namespace Pinetime {
|
||||
lv_obj_t* btnReset;
|
||||
lv_obj_t* btnRandom;
|
||||
lv_obj_t* btnClose;
|
||||
lv_obj_t* btnSteps;
|
||||
lv_obj_t* timebar;
|
||||
lv_obj_t* sidebar;
|
||||
lv_obj_t* timeDD1;
|
||||
lv_obj_t* timeDD2;
|
||||
lv_obj_t* timeDD3;
|
||||
lv_obj_t* timeAMPM;
|
||||
lv_obj_t* dateDayOfWeek;
|
||||
lv_obj_t* dateDay;
|
||||
@ -89,8 +92,12 @@ namespace Pinetime {
|
||||
lv_obj_t* calendarCrossBar2;
|
||||
lv_obj_t* notificationIcon;
|
||||
lv_obj_t* stepGauge;
|
||||
lv_obj_t* btnSet;
|
||||
lv_obj_t* lbl_btnSet;
|
||||
lv_obj_t* btnSetColor;
|
||||
lv_obj_t* btnSetOpts;
|
||||
lv_obj_t* lbl_btnSetColor;
|
||||
lv_obj_t* lbl_btnSetOpts;
|
||||
lv_obj_t* stepIcon;
|
||||
lv_obj_t* stepValue;
|
||||
lv_color_t needle_colors[1];
|
||||
|
||||
BatteryIcon batteryIcon;
|
||||
@ -98,7 +105,7 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::NotificationManager& notificationManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::MotionController& motionController;
|
||||
|
||||
|
@ -17,7 +17,7 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController)
|
||||
@ -26,7 +26,7 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app,
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificatioManager {notificatioManager},
|
||||
notificationManager {notificationManager},
|
||||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController} {
|
||||
@ -100,7 +100,7 @@ void WatchFaceTerminal::Refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
notificationState = notificationManager.AreNewNotificationsAvailable();
|
||||
if (notificationState.IsUpdated()) {
|
||||
if (notificationState.Get()) {
|
||||
lv_label_set_text_static(notificationIcon, "You have mail.");
|
||||
|
@ -26,7 +26,7 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController);
|
||||
@ -68,7 +68,7 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::NotificationManager& notificationManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Controllers::MotionController& motionController;
|
||||
|
@ -79,9 +79,11 @@ SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, Pinetime
|
||||
lv_obj_set_size(btnSetTime, 120, 48);
|
||||
lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38));
|
||||
lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
|
||||
lblSetTime = lv_label_create(btnSetTime, nullptr);
|
||||
lv_label_set_text_static(lblSetTime, "Set");
|
||||
lv_obj_set_event_cb(btnSetTime, event_handler);
|
||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
|
||||
lv_obj_set_state(lblSetTime, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
SettingSetDate::~SettingSetDate() {
|
||||
@ -102,10 +104,12 @@ void SettingSetDate::HandleButtonPress() {
|
||||
dateTimeController.Seconds(),
|
||||
nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
|
||||
lv_obj_set_state(lblSetTime, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
void SettingSetDate::CheckDay() {
|
||||
const int maxDay = MaximumDayOfMonth(monthCounter.GetValue(), yearCounter.GetValue());
|
||||
dayCounter.SetMax(maxDay);
|
||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
||||
lv_obj_set_state(lblSetTime, LV_STATE_DEFAULT);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController;
|
||||
|
||||
lv_obj_t* btnSetTime;
|
||||
lv_obj_t* lblSetTime;
|
||||
|
||||
Widgets::Counter dayCounter = Widgets::Counter(1, 31, jetbrains_mono_bold_20);
|
||||
Widgets::Counter monthCounter = Widgets::Counter(1, 12, jetbrains_mono_bold_20);
|
||||
|
@ -67,13 +67,15 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app,
|
||||
btnSetTime->user_data = this;
|
||||
lv_obj_set_size(btnSetTime, 120, 50);
|
||||
lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
|
||||
lblSetTime = lv_label_create(btnSetTime, nullptr);
|
||||
lv_label_set_text_static(lblSetTime, "Set");
|
||||
lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
|
||||
lv_obj_set_style_local_value_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_GRAY);
|
||||
lv_obj_set_style_local_text_color(lblSetTime, LV_LABEL_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_GRAY);
|
||||
lv_obj_set_event_cb(btnSetTime, SetTimeEventHandler);
|
||||
|
||||
UpdateScreen();
|
||||
lv_obj_set_state(btnSetTime, LV_STATE_DISABLED);
|
||||
lv_obj_set_state(lblSetTime, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
SettingSetTime::~SettingSetTime() {
|
||||
@ -89,6 +91,7 @@ void SettingSetTime::UpdateScreen() {
|
||||
}
|
||||
}
|
||||
lv_obj_set_state(btnSetTime, LV_STATE_DEFAULT);
|
||||
lv_obj_set_state(lblSetTime, LV_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
void SettingSetTime::SetTime() {
|
||||
@ -104,4 +107,5 @@ void SettingSetTime::SetTime() {
|
||||
0,
|
||||
nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
lv_obj_set_state(btnSetTime, LV_STATE_DISABLED);
|
||||
lv_obj_set_state(lblSetTime, LV_STATE_DISABLED);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ namespace Pinetime {
|
||||
|
||||
lv_obj_t* lblampm;
|
||||
lv_obj_t* btnSetTime;
|
||||
lv_obj_t* lblSetTime;
|
||||
Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_42);
|
||||
Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_42);
|
||||
};
|
||||
|
@ -48,7 +48,8 @@ SettingSteps::SettingSteps(Pinetime::Applications::DisplayApp* app, Pinetime::Co
|
||||
btnPlus->user_data = this;
|
||||
lv_obj_set_size(btnPlus, 80, 50);
|
||||
lv_obj_align(btnPlus, lv_scr_act(), LV_ALIGN_CENTER, 55, 80);
|
||||
lv_obj_set_style_local_value_str(btnPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
|
||||
lv_obj_t* lblPlus = lv_label_create(btnPlus, nullptr);
|
||||
lv_label_set_text_static(lblPlus, "+");
|
||||
lv_obj_set_event_cb(btnPlus, event_handler);
|
||||
|
||||
btnMinus = lv_btn_create(lv_scr_act(), nullptr);
|
||||
@ -56,7 +57,8 @@ SettingSteps::SettingSteps(Pinetime::Applications::DisplayApp* app, Pinetime::Co
|
||||
lv_obj_set_size(btnMinus, 80, 50);
|
||||
lv_obj_set_event_cb(btnMinus, event_handler);
|
||||
lv_obj_align(btnMinus, lv_scr_act(), LV_ALIGN_CENTER, -55, 80);
|
||||
lv_obj_set_style_local_value_str(btnMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
|
||||
lv_obj_t* lblMinus = lv_label_create(btnMinus, nullptr);
|
||||
lv_label_set_text_static(lblMinus, "-");
|
||||
}
|
||||
|
||||
SettingSteps::~SettingSteps() {
|
||||
|
@ -1,58 +1,29 @@
|
||||
#include "displayapp/screens/settings/SettingWatchFace.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
#include "displayapp/DisplayApp.h"
|
||||
#include "displayapp/screens/CheckboxList.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "displayapp/screens/Styles.h"
|
||||
#include "displayapp/screens/Symbols.h"
|
||||
#include "components/settings/Settings.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
auto* screen = static_cast<SettingWatchFace*>(obj->user_data);
|
||||
screen->UpdateSelected(obj, event);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr std::array<const char*, 4> SettingWatchFace::options;
|
||||
constexpr const char* SettingWatchFace::title;
|
||||
constexpr const char* SettingWatchFace::symbol;
|
||||
|
||||
SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
|
||||
: Screen(app), 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, 60);
|
||||
lv_obj_set_width(container1, LV_HOR_RES - 20);
|
||||
lv_obj_set_height(container1, LV_VER_RES - 50);
|
||||
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, "Watch face");
|
||||
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 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::home);
|
||||
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 < options.size(); i++) {
|
||||
cbOption[i] = lv_checkbox_create(container1, nullptr);
|
||||
lv_checkbox_set_text(cbOption[i], options[i]);
|
||||
cbOption[i]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[i], event_handler);
|
||||
SetRadioButtonStyle(cbOption[i]);
|
||||
|
||||
if (settingsController.GetClockFace() == i) {
|
||||
lv_checkbox_set_checked(cbOption[i], true);
|
||||
}
|
||||
}
|
||||
: Screen(app),
|
||||
settingsController {settingsController},
|
||||
screens {app,
|
||||
settingsController.GetWatchfacesMenu(),
|
||||
{[this]() -> std::unique_ptr<Screen> {
|
||||
return CreateScreen1();
|
||||
},
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return CreateScreen2();
|
||||
}},
|
||||
Screens::ScreenListModes::UpDown} {
|
||||
}
|
||||
|
||||
SettingWatchFace::~SettingWatchFace() {
|
||||
@ -60,15 +31,32 @@ SettingWatchFace::~SettingWatchFace() {
|
||||
settingsController.SaveSettings();
|
||||
}
|
||||
|
||||
void SettingWatchFace::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
||||
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||
for (unsigned int i = 0; i < options.size(); i++) {
|
||||
if (object == cbOption[i]) {
|
||||
lv_checkbox_set_checked(cbOption[i], true);
|
||||
settingsController.SetClockFace(i);
|
||||
} else {
|
||||
lv_checkbox_set_checked(cbOption[i], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool SettingWatchFace::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return screens.OnTouchEvent(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> SettingWatchFace::CreateScreen1() {
|
||||
std::array<const char*, 4> watchfaces {"Digital face", "Analog face", "PineTimeStyle", "Terminal"};
|
||||
return std::make_unique<Screens::CheckboxList>(0,
|
||||
2,
|
||||
app,
|
||||
settingsController,
|
||||
title,
|
||||
symbol,
|
||||
&Controllers::Settings::SetClockFace,
|
||||
&Controllers::Settings::GetClockFace,
|
||||
watchfaces);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> SettingWatchFace::CreateScreen2() {
|
||||
std::array<const char*, 4> watchfaces {"Infineat face", "Casio G7710", "", ""};
|
||||
return std::make_unique<Screens::CheckboxList>(1,
|
||||
2,
|
||||
app,
|
||||
settingsController,
|
||||
title,
|
||||
symbol,
|
||||
&Controllers::Settings::SetClockFace,
|
||||
&Controllers::Settings::GetClockFace,
|
||||
watchfaces);
|
||||
}
|
||||
|
@ -4,8 +4,10 @@
|
||||
#include <cstdint>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "displayapp/screens/ScreenList.h"
|
||||
#include "components/settings/Settings.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "displayapp/screens/Symbols.h"
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
@ -17,13 +19,16 @@ namespace Pinetime {
|
||||
SettingWatchFace(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
|
||||
~SettingWatchFace() override;
|
||||
|
||||
void UpdateSelected(lv_obj_t* object, lv_event_t event);
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
static constexpr std::array<const char*, 4> options = {"Digital face", "Analog face", "PineTimeStyle", "Terminal"};
|
||||
Controllers::Settings& settingsController;
|
||||
ScreenList<2> screens;
|
||||
|
||||
lv_obj_t* cbOption[options.size()];
|
||||
static constexpr const char* title = "Watch face";
|
||||
static constexpr const char* symbol = Symbols::home;
|
||||
std::unique_ptr<Screen> CreateScreen1();
|
||||
std::unique_ptr<Screen> CreateScreen2();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,9 @@ void StatusIcons::Create() {
|
||||
lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
|
||||
bleIcon = lv_label_create(container, nullptr);
|
||||
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC));
|
||||
lv_label_set_text_static(bleIcon, Screens::Symbols::bluetooth);
|
||||
|
||||
batteryPlug = lv_label_create(container, nullptr);
|
||||
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_label_set_text_static(batteryPlug, Screens::Symbols::plug);
|
||||
|
||||
batteryIcon.Create(container);
|
||||
|
@ -164,7 +164,7 @@ typedef void* lv_anim_user_data_t;
|
||||
#define LV_USE_PATTERN 1
|
||||
|
||||
/*1: enable value string drawing on rectangles*/
|
||||
#define LV_USE_VALUE_STR 1
|
||||
#define LV_USE_VALUE_STR 0
|
||||
|
||||
/* 1: Use other blend modes than normal (`LV_BLEND_MODE_...`)*/
|
||||
#define LV_USE_BLEND_MODES 0
|
||||
|
@ -131,7 +131,8 @@ Pinetime::Applications::DisplayApp displayApp(lcd,
|
||||
timerController,
|
||||
alarmController,
|
||||
brightnessController,
|
||||
touchHandler);
|
||||
touchHandler,
|
||||
fs);
|
||||
|
||||
Pinetime::System::SystemTask systemTask(spi,
|
||||
lcd,
|
||||
|
29
src/resources/CMakeLists.txt
Normal file
29
src/resources/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED
|
||||
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
|
||||
message(STATUS "Using ${LV_FONT_CONV} to generate font files")
|
||||
|
||||
find_program(LV_IMG_CONV "lv_img_conv" NO_CACHE REQUIRED
|
||||
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
|
||||
message(STATUS "Using ${LV_IMG_CONV} to generate font files")
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
|
||||
# FindPython3 module introduces with CMake 3.12
|
||||
# https://cmake.org/cmake/help/latest/module/FindPython3.html
|
||||
find_package(Python3 REQUIRED)
|
||||
else()
|
||||
set(Python3_EXECUTABLE "python")
|
||||
endif()
|
||||
|
||||
# generate fonts
|
||||
add_custom_target(GenerateResources
|
||||
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/generate-fonts.py --lv-font-conv "${LV_FONT_CONV}" ${CMAKE_CURRENT_SOURCE_DIR}/fonts.json
|
||||
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/generate-img.py --lv-img-conv "${LV_IMG_CONV}" ${CMAKE_CURRENT_SOURCE_DIR}/images.json
|
||||
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/generate-package.py --config ${CMAKE_CURRENT_SOURCE_DIR}/fonts.json --config ${CMAKE_CURRENT_SOURCE_DIR}/images.json --obsolete obsolete_files.json --output infinitime-resources-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/fonts.json
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/images.json
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
|
||||
COMMENT "Generate fonts and images for resource package"
|
||||
)
|
||||
|
62
src/resources/fonts.json
Normal file
62
src/resources/fonts.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"teko" : {
|
||||
"sources": [
|
||||
{
|
||||
"file": "fonts/Teko-Light.ttf",
|
||||
"symbols": "0123456789:/ampMonTueWdhFriSt "
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
"size": 28,
|
||||
"format": "bin",
|
||||
"target_path": "/fonts/"
|
||||
},
|
||||
"bebas" : {
|
||||
"sources": [
|
||||
{
|
||||
"file": "fonts/BebasNeue-Regular.ttf",
|
||||
"symbols": "0123456789:"
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
"size": 120,
|
||||
"format": "bin",
|
||||
"target_path": "/fonts/"
|
||||
},
|
||||
"lv_font_dots_40": {
|
||||
"sources": [
|
||||
{
|
||||
"file": "fonts/repetitionscrolling.ttf",
|
||||
"symbols": "0123456789-MONTUEWEDTHUFRISATSUN WK"
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
"size": 40,
|
||||
"format": "bin",
|
||||
"target_path": "/fonts/"
|
||||
},
|
||||
"7segments_40" : {
|
||||
"sources": [
|
||||
{
|
||||
"file": "fonts/7segment.woff",
|
||||
"symbols": "0123456789: -"
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
"size": 40,
|
||||
"format": "bin",
|
||||
"target_path": "/fonts/"
|
||||
},
|
||||
"7segments_115" : {
|
||||
"sources": [
|
||||
{
|
||||
"file": "fonts/7segment.woff",
|
||||
"symbols": "0123456789: -"
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
"size": 115,
|
||||
"format": "bin",
|
||||
"target_path": "/fonts/"
|
||||
}
|
||||
}
|
BIN
src/resources/fonts/7segment.woff
Normal file
BIN
src/resources/fonts/7segment.woff
Normal file
Binary file not shown.
BIN
src/resources/fonts/BebasNeue-Regular.ttf
Normal file
BIN
src/resources/fonts/BebasNeue-Regular.ttf
Normal file
Binary file not shown.
BIN
src/resources/fonts/Teko-Light.ttf
Normal file
BIN
src/resources/fonts/Teko-Light.ttf
Normal file
Binary file not shown.
BIN
src/resources/fonts/repetitionscrolling.ttf
Normal file
BIN
src/resources/fonts/repetitionscrolling.ttf
Normal file
Binary file not shown.
80
src/resources/generate-fonts.py
Executable file
80
src/resources/generate-fonts.py
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import io
|
||||
import sys
|
||||
import json
|
||||
import shutil
|
||||
import typing
|
||||
import os.path
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
class Source(object):
|
||||
def __init__(self, d):
|
||||
self.file = d['file']
|
||||
if not os.path.exists(self.file):
|
||||
self.file = os.path.join(os.path.dirname(sys.argv[0]), self.file)
|
||||
self.range = d.get('range')
|
||||
self.symbols = d.get('symbols')
|
||||
|
||||
|
||||
def gen_lvconv_line(lv_font_conv: str, dest: str, size: int, bpp: int, format: str, sources: typing.List[Source], compress:bool=False):
|
||||
if format != "lvgl" and format != "bin":
|
||||
format = "bin" if dest.lower().endswith(".bin") else "lvgl"
|
||||
|
||||
args = [lv_font_conv, '--size', str(size), '--output', dest, '--bpp', str(bpp), '--format', format]
|
||||
if not compress:
|
||||
args.append('--no-compress')
|
||||
for source in sources:
|
||||
args.extend(['--font', source.file])
|
||||
if source.range:
|
||||
args.extend(['--range', source.range])
|
||||
if source.symbols:
|
||||
args.extend(['--symbols', source.symbols])
|
||||
|
||||
return args
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description='auto generate LVGL font files from fonts')
|
||||
ap.add_argument('config', type=str, help='config file to use')
|
||||
ap.add_argument('-f', '--font', type=str, action='append', help='Choose specific fonts to generate (default: all)', default=[])
|
||||
ap.add_argument('--lv-font-conv', type=str, help='Path to "lv_font_conf" executable', default="lv_font_conv")
|
||||
args = ap.parse_args()
|
||||
|
||||
if not shutil.which(args.lv_font_conv):
|
||||
sys.exit(f"Missing lv_font_conv. Make sure it's findable (in PATH) or specify it manually")
|
||||
if not os.path.exists(args.config):
|
||||
sys.exit(f'Error: the config file {args.config} does not exist.')
|
||||
if not os.access(args.config, os.R_OK):
|
||||
sys.exit(f'Error: the config file {args.config} is not accessible (permissions?).')
|
||||
with open(args.config, 'r') as fd:
|
||||
data = json.load(fd)
|
||||
|
||||
fonts_to_run = set(data.keys())
|
||||
|
||||
if args.font:
|
||||
enabled_fonts = set()
|
||||
for font in args.font:
|
||||
enabled_fonts.add(font[:-2] if font.endswith('.c') else font)
|
||||
d = enabled_fonts.difference(fonts_to_run)
|
||||
if d:
|
||||
print(f'Warning: requested font{"s" if len(d)>1 else ""} missing: {" ".join(d)}')
|
||||
fonts_to_run = fonts_to_run.intersection(enabled_fonts)
|
||||
|
||||
for name in fonts_to_run:
|
||||
font = data[name]
|
||||
sources = font.pop('sources')
|
||||
patches = font.pop('patches') if 'patches' in font else []
|
||||
font['sources'] = [Source(thing) for thing in sources]
|
||||
extension = 'c' if font['format'] != 'bin' else 'bin'
|
||||
font.pop('target_path')
|
||||
line = gen_lvconv_line(args.lv_font_conv, f'{name}.{extension}', **font)
|
||||
subprocess.check_call(line)
|
||||
if patches:
|
||||
for patch in patches:
|
||||
subprocess.check_call(['/usr/bin/env', 'patch', name+'.'+extension, patch])
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
56
src/resources/generate-img.py
Executable file
56
src/resources/generate-img.py
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import io
|
||||
import sys
|
||||
import json
|
||||
import shutil
|
||||
import typing
|
||||
import os.path
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
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]
|
||||
|
||||
return args
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description='auto generate LVGL font files from fonts')
|
||||
ap.add_argument('config', type=str, help='config file to use')
|
||||
ap.add_argument('-i', '--image', type=str, action='append', help='Choose specific images to generate (default: all)', default=[])
|
||||
ap.add_argument('--lv-img-conv', type=str, help='Path to "lv_img_conf" executable', default="lv_img_conv")
|
||||
args = ap.parse_args()
|
||||
|
||||
if not shutil.which(args.lv_img_conv):
|
||||
sys.exit(f"Missing lv_img_conv. Make sure it's findable (in PATH) or specify it manually")
|
||||
if not os.path.exists(args.config):
|
||||
sys.exit(f'Error: the config file {args.config} does not exist.')
|
||||
if not os.access(args.config, os.R_OK):
|
||||
sys.exit(f'Error: the config file {args.config} is not accessible (permissions?).')
|
||||
with open(args.config, 'r') as fd:
|
||||
data = json.load(fd)
|
||||
|
||||
images_to_run = set(data.keys())
|
||||
|
||||
if args.image:
|
||||
enabled_images = set()
|
||||
for image in args.image:
|
||||
enabled_images.add(image[:-2] if image.endswith('.c') else image)
|
||||
d = enabled_images.difference(images_to_run)
|
||||
if d:
|
||||
print(f'Warning: requested image{"s" if len(d)>1 else ""} missing: {" ".join(d)}')
|
||||
images_to_run = images_to_run.intersection(enabled_images)
|
||||
|
||||
for name in images_to_run:
|
||||
image = data[name]
|
||||
if not os.path.exists(image['sources']):
|
||||
image['sources'] = os.path.join(os.path.dirname(sys.argv[0]), image['sources'])
|
||||
extension = 'bin'
|
||||
image.pop('target_path')
|
||||
line = gen_lvconv_line(args.lv_img_conv, f'{name}.{extension}', **image)
|
||||
subprocess.check_call(line)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
72
src/resources/generate-package.py
Executable file
72
src/resources/generate-package.py
Executable file
@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import io
|
||||
import sys
|
||||
import json
|
||||
import shutil
|
||||
import typing
|
||||
import os.path
|
||||
import argparse
|
||||
import subprocess
|
||||
from zipfile import ZipFile
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description='auto generate LVGL font files from fonts')
|
||||
ap.add_argument('--config', '-c', type=str, action='append', help='config file to use')
|
||||
ap.add_argument('--obsolete', type=str, help='List of obsolete files')
|
||||
ap.add_argument('--output', type=str, help='output file name')
|
||||
args = ap.parse_args()
|
||||
|
||||
for config_file in args.config:
|
||||
if not os.path.exists(config_file):
|
||||
sys.exit(f'Error: the config file {config_file} does not exist.')
|
||||
if not os.access(config_file, os.R_OK):
|
||||
sys.exit(f'Error: the config file {config_file} is not accessible (permissions?).')
|
||||
|
||||
if args.obsolete:
|
||||
obsolete_file_path = os.path.join(os.path.dirname(sys.argv[0]), args.obsolete)
|
||||
if not os.path.exists(obsolete_file_path):
|
||||
sys.exit(f'Error: the "obsolete" file {args.obsolete} does not exist.')
|
||||
if not os.access(obsolete_file_path, os.R_OK):
|
||||
sys.exit(f'Error: the "obsolete" file {args.obsolete} is not accessible (permissions?).')
|
||||
|
||||
zf = ZipFile(args.output, mode='w')
|
||||
resource_files = []
|
||||
|
||||
for config_file in args.config:
|
||||
with open(config_file, 'r') as fd:
|
||||
data = json.load(fd)
|
||||
|
||||
resource_names = set(data.keys())
|
||||
for name in resource_names:
|
||||
resource = data[name]
|
||||
resource_files.append({
|
||||
"filename": name+'.bin',
|
||||
"path": resource['target_path'] + name+'.bin'
|
||||
})
|
||||
|
||||
path = name + '.bin'
|
||||
if not os.path.exists(path):
|
||||
path = os.path.join(os.path.dirname(sys.argv[0]), path)
|
||||
zf.write(path)
|
||||
|
||||
if args.obsolete:
|
||||
obsolete_file_path = os.path.join(os.path.dirname(sys.argv[0]), args.obsolete)
|
||||
with open(obsolete_file_path, 'r') as fd:
|
||||
obsolete_data = json.load(fd)
|
||||
else:
|
||||
obsolete_data = {}
|
||||
output = {
|
||||
'resources': resource_files,
|
||||
'obsolete_files': obsolete_data
|
||||
}
|
||||
|
||||
|
||||
with open("resources.json", 'w') as fd:
|
||||
json.dump(output, fd, indent=4)
|
||||
|
||||
zf.write('resources.json')
|
||||
zf.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
9
src/resources/images.json
Normal file
9
src/resources/images.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"pine_small" : {
|
||||
"sources": "images/pine_logo.png",
|
||||
"color_format": "CF_TRUE_COLOR_ALPHA",
|
||||
"output_format": "bin",
|
||||
"binary_format": "ARGB8565_RBSWAP",
|
||||
"target_path": "/images/"
|
||||
}
|
||||
}
|
BIN
src/resources/images/pine_logo.png
Normal file
BIN
src/resources/images/pine_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
253
src/resources/images/pine_logo.svg
Normal file
253
src/resources/images/pine_logo.svg
Normal file
@ -0,0 +1,253 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="110.49872"
|
||||
height="150.24246"
|
||||
viewBox="0 0 29.236118 39.751652"
|
||||
version="1.1"
|
||||
id="svg2418"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
|
||||
sodipodi:docname="pine_logo.svg"
|
||||
inkscape:export-filename="/home/diegomiguel/Syncthing/Watchface/pine_logo_new_2_transparent.png"
|
||||
inkscape:export-xdpi="19.807983"
|
||||
inkscape:export-ydpi="19.807983"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview2420"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
units="px"
|
||||
inkscape:zoom="4.1424077"
|
||||
inkscape:cx="69.886892"
|
||||
inkscape:cy="73.387272"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1026"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g972"
|
||||
inkscape:snap-page="true" />
|
||||
<defs
|
||||
id="defs2415" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
id="layer1"
|
||||
transform="translate(-91.35232,-110.1768)"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="display:none;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:0"
|
||||
id="rect2129"
|
||||
width="29.236118"
|
||||
height="39.751652"
|
||||
x="91.352318"
|
||||
y="110.1768"
|
||||
inkscape:label="bg" />
|
||||
<g
|
||||
id="g32004"
|
||||
style="display:none;stroke:none"
|
||||
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
|
||||
inkscape:export-xdpi="19.965168"
|
||||
inkscape:export-ydpi="19.965168"
|
||||
inkscape:label="pine_logo"
|
||||
transform="translate(75.060638,-5.5438717)">
|
||||
<g
|
||||
id="g13016"
|
||||
inkscape:label="pine"
|
||||
style="display:inline;fill:#6f2d00;fill-opacity:1;stroke:none"
|
||||
transform="matrix(1.1631294,0,0,1.1631294,-5.0422885,-22.11978)"
|
||||
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
|
||||
inkscape:export-xdpi="31.276381"
|
||||
inkscape:export-ydpi="31.276381"
|
||||
sodipodi:insensitive="true">
|
||||
<path
|
||||
id="path5716"
|
||||
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:2.34917;stroke-linecap:round"
|
||||
inkscape:transform-center-x="1.2687941"
|
||||
d="M 116.82422,535.70898 102.4375,542.5 l -14.386719,6.78906 14.386719,6.78906 11,5.19141 v 15.80664 h 3.38672 v -14.20703 -3.93555 -9.64453 z"
|
||||
transform="scale(0.26458333)" />
|
||||
<path
|
||||
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 18.341872,136.77692 3.331558,7.57837 7.029221,-3.22172 z"
|
||||
id="path5936"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
|
||||
id="path7773"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="116.64632"
|
||||
sodipodi:cy="501.86975"
|
||||
sodipodi:r1="14.699218"
|
||||
sodipodi:r2="7.3496094"
|
||||
sodipodi:arg1="1.0471976"
|
||||
sodipodi:arg2="2.0943951"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
transform="matrix(0.39243637,0,0,0.31059853,-17.750778,-19.228227)"
|
||||
inkscape:transform-center-x="1.4421265"
|
||||
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
|
||||
id="path7877"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="116.64632"
|
||||
sodipodi:cy="501.86975"
|
||||
sodipodi:r1="14.699218"
|
||||
sodipodi:r2="7.3496094"
|
||||
sodipodi:arg1="1.0471976"
|
||||
sodipodi:arg2="2.0943951"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
transform="matrix(-0.3940968,0,0,-0.29190487,69.062729,278.57074)"
|
||||
inkscape:transform-center-x="-1.4482278"
|
||||
inkscape:transform-center-y="3.6892669e-06"
|
||||
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
|
||||
id="path7929"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="116.64632"
|
||||
sodipodi:cy="501.86975"
|
||||
sodipodi:r1="14.699218"
|
||||
sodipodi:r2="7.3496094"
|
||||
sodipodi:arg1="1.0471976"
|
||||
sodipodi:arg2="2.0943951"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
transform="matrix(0.34926521,0,0,0.27033526,-12.397729,-7.5515591)"
|
||||
inkscape:transform-center-x="1.28348"
|
||||
inkscape:transform-center-y="1.7340579e-06"
|
||||
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
|
||||
<path
|
||||
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 24.903849,122.34368 -1.378447,3.99721 5.0395,-2.31516 z"
|
||||
id="path7964"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 30.909733,118.50827 v 4.63122 l -3.122345,-1.29967 z"
|
||||
id="path11445" />
|
||||
</g>
|
||||
<g
|
||||
id="g13032"
|
||||
transform="matrix(-1.1631294,0,0,1.1631294,66.861771,-22.11978)"
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none"
|
||||
inkscape:label="pine"
|
||||
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
|
||||
inkscape:export-xdpi="31.276381"
|
||||
inkscape:export-ydpi="31.276381">
|
||||
<path
|
||||
id="path13018"
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:2.34917;stroke-linecap:round"
|
||||
inkscape:transform-center-x="1.2687941"
|
||||
d="M 116.82422,535.70898 102.4375,542.5 l -14.386719,6.78906 14.386719,6.78906 11,5.19141 v 15.80664 h 3.38672 v -14.20703 -3.93555 -9.64453 z"
|
||||
transform="scale(0.26458333)" />
|
||||
<path
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 18.341872,136.77692 3.331558,7.57837 7.029221,-3.22172 z"
|
||||
id="path13020"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
|
||||
id="path13022"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="116.64632"
|
||||
sodipodi:cy="501.86975"
|
||||
sodipodi:r1="14.699218"
|
||||
sodipodi:r2="7.3496094"
|
||||
sodipodi:arg1="1.0471976"
|
||||
sodipodi:arg2="2.0943951"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
transform="matrix(0.39243637,0,0,0.31059853,-17.750778,-19.228227)"
|
||||
inkscape:transform-center-x="1.4421265"
|
||||
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
|
||||
id="path13024"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="116.64632"
|
||||
sodipodi:cy="501.86975"
|
||||
sodipodi:r1="14.699218"
|
||||
sodipodi:r2="7.3496094"
|
||||
sodipodi:arg1="1.0471976"
|
||||
sodipodi:arg2="2.0943951"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
transform="matrix(-0.3940968,0,0,-0.29190487,69.062729,278.57074)"
|
||||
inkscape:transform-center-x="-1.4482278"
|
||||
inkscape:transform-center-y="3.6892669e-06"
|
||||
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
|
||||
id="path13026"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="116.64632"
|
||||
sodipodi:cy="501.86975"
|
||||
sodipodi:r1="14.699218"
|
||||
sodipodi:r2="7.3496094"
|
||||
sodipodi:arg1="1.0471976"
|
||||
sodipodi:arg2="2.0943951"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
transform="matrix(0.34926521,0,0,0.27033526,-12.397729,-7.5515591)"
|
||||
inkscape:transform-center-x="1.28348"
|
||||
inkscape:transform-center-y="1.7340579e-06"
|
||||
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
|
||||
<path
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 24.903849,122.34368 -1.378447,3.99721 5.0395,-2.31516 z"
|
||||
id="path13028"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 30.909733,118.50827 v 4.63122 l -3.122345,-1.29967 z"
|
||||
id="path13030" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g972"
|
||||
style="display:inline;stroke:none"
|
||||
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
|
||||
inkscape:export-xdpi="19.965168"
|
||||
inkscape:export-ydpi="19.965168"
|
||||
inkscape:label="pine_logo"
|
||||
transform="translate(75.060638,-5.5438717)">
|
||||
<path
|
||||
id="path952"
|
||||
style="fill:#0f0f0f;fill-opacity:1;stroke:none;stroke-width:0.307744px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 30.909731,115.72067 v 5.38671 l -3.631692,-1.51168 z m -6.985621,4.46108 -1.603312,4.64927 5.861591,-2.69283 z m 6.98562,10.72311 -4.478564,-2.00136 -4.478563,-2.00136 4.478563,-2.00136 4.478568,-2.00137 v 4.00273 z m -12.461069,-3.7293 5.05343,2.16104 5.053431,2.16105 -5.053431,2.16105 -5.053434,2.16104 v -4.32209 z m 12.461067,14.24725 -5.032139,-2.29945 -5.032139,-2.29944 5.032139,-2.29943 5.032144,-2.29945 v 4.59888 z m -14.618046,-4.45333 3.875033,8.81462 8.175894,-3.74728 z m 14.618058,5.77232 -4.427436,2.0899 -4.427436,2.08929 4.427436,2.0893 3.385191,1.59762 v 4.86441 h 1.042245 v -4.37214 -1.21114 -2.96805 z"
|
||||
inkscape:label="left" />
|
||||
<path
|
||||
id="path968"
|
||||
style="fill:#575757;fill-opacity:1;stroke:none;stroke-width:0.307744px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 30.909752,115.72067 v 5.38671 l 3.631691,-1.51168 z m 6.98562,4.46108 1.603312,4.64927 -5.86159,-2.69283 z m -6.985619,10.72311 4.478564,-2.00136 4.478563,-2.00136 -4.478563,-2.00136 -4.478568,-2.00136 v 4.00272 z m 12.461067,-3.72931 -5.05343,2.16105 -5.05343,2.16105 5.05343,2.16104 5.053435,2.16105 v -4.32209 z m -12.461065,14.24726 5.032139,-2.29945 5.032139,-2.29944 -5.032139,-2.29944 -5.032144,-2.29944 v 4.59888 z m 14.618045,-4.45333 -3.875033,8.81462 -8.175893,-3.74728 z m -14.618058,5.77231 4.427436,2.0899 4.427436,2.0893 -4.427436,2.0893 -3.385191,1.59763 v 4.8644 h -1.042245 v -4.37213 -1.21115 -2.96805 z"
|
||||
inkscape:label="right" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
6
src/resources/obsolete_files.json
Normal file
6
src/resources/obsolete_files.json
Normal file
@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"path": "/example-of-obsolete-file.bin",
|
||||
"since": "1.11.0"
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user