App improvements (#103)
This commit is contained in:
parent
c7314546fe
commit
f31c7f00ae
@ -1,7 +1,7 @@
|
||||
#include "lvgl.h"
|
||||
#include "lvgl/Toolbar.h"
|
||||
|
||||
static void app_show(tt::app::App& app, lv_obj_t* parent) {
|
||||
static void onShow(tt::app::App& app, lv_obj_t* parent) {
|
||||
lv_obj_t* toolbar = tt::lvgl::toolbar_create(parent, app);
|
||||
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
|
||||
|
||||
@ -13,5 +13,5 @@ static void app_show(tt::app::App& app, lv_obj_t* parent) {
|
||||
extern const tt::app::Manifest hello_world_app = {
|
||||
.id = "HelloWorld",
|
||||
.name = "Hello World",
|
||||
.onShow = &app_show,
|
||||
.onShow = onShow,
|
||||
};
|
||||
|
||||
@ -6,7 +6,7 @@ The app goes through these states:
|
||||
|
||||
Let's look at a scenario where an app launches another app:
|
||||
|
||||
1. `first` app starts: `first.on_create()` -> `first.on_show()`
|
||||
2. `second` app starts: `first.on_hide()` -> `second.on_create()` -> `second.on_show()`
|
||||
3. `second` app stops: `second.on_hide()` -> `second.on_destroy()` -> `first.on_show()`
|
||||
4. `first` app stops: `first.on_hide()` -> `first.on_destroy()`
|
||||
1. `first` app starts: `first.onStart()` -> `first.onShow()`
|
||||
2. `second` app starts: `first.onHide()` -> `second.onStart()` -> `second.onShow()`
|
||||
3. `second` app stops: `second.onHide()` -> `second.onStop()` -> `first.onShow()`
|
||||
4. `first` app stops: `first.onHide()` -> `first.onStop()`
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
# TODOs
|
||||
- Bug: sdcard file reading fails (due to `A:/` prefix?)
|
||||
- Publish firmwares with upload tool
|
||||
- Bug: When closing a top level app, there's often an error "can't stop root app"
|
||||
- Bug: I2C Scanner is on M5Stack devices is broken
|
||||
|
||||
@ -42,7 +42,7 @@ UI is created with [lvgl](https://github.com/lvgl/lvgl) which has lots of [widge
|
||||
Creating a touch-capable UI is [easy](https://docs.lvgl.io/9.0/get-started/quick-overview.html) and doesn't require your own render loop!
|
||||
|
||||
```C++
|
||||
static void app_show(tt::app::App app, lv_obj_t* parent) {
|
||||
static void onShow(tt::app::App app, lv_obj_t* parent) {
|
||||
// Default toolbar with app name and close button
|
||||
lv_obj_t* toolbar = tt::lvgl::toolbar_create(parent, app);
|
||||
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
|
||||
@ -57,7 +57,7 @@ static void app_show(tt::app::App app, lv_obj_t* parent) {
|
||||
extern const tt::app::Manifest manifest = {
|
||||
.id = "HelloWorld", // Used to identify and start an app
|
||||
.name = "Hello World", // Shown on the desktop and app's toolbar
|
||||
.onShow = &app_show // A minimal setup sets the on_show() function
|
||||
.onShow = onShow // A minimal setup sets the onShow() function
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
namespace tt::service::gui {
|
||||
|
||||
/** Process draw call. Calls on_show callback.
|
||||
/** Process draw call. Calls onShow callback.
|
||||
* To be used by GUI, called on redraw.
|
||||
*
|
||||
* @param view_port ViewPort instance
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include "hal/Display.h"
|
||||
#include "service/loader/Loader.h"
|
||||
#include "lvgl/Style.h"
|
||||
#include "app/display/DisplayPreferences.h"
|
||||
#include "app/display/DisplaySettings.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "sdkconfig.h"
|
||||
@ -33,7 +33,7 @@ static int32_t threadCallback(TT_UNUSED void* context) {
|
||||
auto* hal_display = (tt::hal::Display*)lv_display_get_user_data(lvgl_display);
|
||||
tt_assert(hal_display != nullptr);
|
||||
if (hal_display->supportsBacklightDuty()) {
|
||||
int32_t backlight_duty = app::display::preferences_get_backlight_duty();
|
||||
int32_t backlight_duty = app::display::getBacklightDuty();
|
||||
hal_display->setBacklightDuty(backlight_duty);
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace tt::app::desktop {
|
||||
|
||||
static void on_app_pressed(lv_event_t* e) {
|
||||
static void onAppPressed(lv_event_t* e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_CLICKED) {
|
||||
const auto* manifest = static_cast<const Manifest*>(lv_event_get_user_data(e));
|
||||
@ -15,15 +15,15 @@ static void on_app_pressed(lv_event_t* e) {
|
||||
}
|
||||
}
|
||||
|
||||
static void create_app_widget(const Manifest* manifest, void* parent) {
|
||||
static void createAppWidget(const Manifest* manifest, void* parent) {
|
||||
tt_check(parent);
|
||||
auto* list = static_cast<lv_obj_t*>(parent);
|
||||
const void* icon = !manifest->icon.empty() ? manifest->icon.c_str() : TT_ASSETS_APP_ICON_FALLBACK;
|
||||
lv_obj_t* btn = lv_list_add_button(list, icon, manifest->name.c_str());
|
||||
lv_obj_add_event_cb(btn, &on_app_pressed, LV_EVENT_CLICKED, (void*)manifest);
|
||||
lv_obj_add_event_cb(btn, &onAppPressed, LV_EVENT_CLICKED, (void*)manifest);
|
||||
}
|
||||
|
||||
static void desktop_show(TT_UNUSED App& app, lv_obj_t* parent) {
|
||||
static void onShow(TT_UNUSED App& app, lv_obj_t* parent) {
|
||||
lv_obj_t* list = lv_list_create(parent);
|
||||
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_center(list);
|
||||
@ -34,14 +34,14 @@ static void desktop_show(TT_UNUSED App& app, lv_obj_t* parent) {
|
||||
lv_list_add_text(list, "User");
|
||||
for (const auto& manifest: manifests) {
|
||||
if (manifest->type == TypeUser) {
|
||||
create_app_widget(manifest, list);
|
||||
createAppWidget(manifest, list);
|
||||
}
|
||||
}
|
||||
|
||||
lv_list_add_text(list, "System");
|
||||
for (const auto& manifest: manifests) {
|
||||
if (manifest->type == TypeSystem) {
|
||||
create_app_widget(manifest, list);
|
||||
createAppWidget(manifest, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,7 +50,7 @@ extern const Manifest manifest = {
|
||||
.id = "Desktop",
|
||||
.name = "Desktop",
|
||||
.type = TypeDesktop,
|
||||
.onShow = &desktop_show,
|
||||
.onShow = onShow,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "app/App.h"
|
||||
#include "Assets.h"
|
||||
#include "DisplayPreferences.h"
|
||||
#include "DisplaySettings.h"
|
||||
#include "Tactility.h"
|
||||
#include "lvgl/Toolbar.h"
|
||||
#include "lvgl.h"
|
||||
@ -13,7 +13,7 @@ namespace tt::app::display {
|
||||
static bool backlight_duty_set = false;
|
||||
static uint8_t backlight_duty = 255;
|
||||
|
||||
static void slider_event_cb(lv_event_t* event) {
|
||||
static void onSliderEvent(lv_event_t* event) {
|
||||
auto* slider = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
auto* lvgl_display = lv_display_get_default();
|
||||
tt_assert(lvgl_display != nullptr);
|
||||
@ -35,7 +35,7 @@ static void slider_event_cb(lv_event_t* event) {
|
||||
#define ORIENTATION_PORTRAIT_LEFT 2
|
||||
#define ORIENTATION_PORTRAIT_RIGHT 3
|
||||
|
||||
static lv_display_rotation_t orientation_setting_to_display_rotation(uint32_t setting) {
|
||||
static lv_display_rotation_t orientationSettingToDisplayOrientation(uint32_t setting) {
|
||||
if (setting == ORIENTATION_LANDSCAPE_FLIPPED) {
|
||||
return LV_DISPLAY_ROTATION_180;
|
||||
} else if (setting == ORIENTATION_PORTRAIT_LEFT) {
|
||||
@ -47,7 +47,7 @@ static lv_display_rotation_t orientation_setting_to_display_rotation(uint32_t se
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t display_rotation_to_orientation_setting(lv_display_rotation_t orientation) {
|
||||
static uint32_t dipslayOrientationToOrientationSetting(lv_display_rotation_t orientation) {
|
||||
if (orientation == LV_DISPLAY_ROTATION_90) {
|
||||
return ORIENTATION_PORTRAIT_RIGHT;
|
||||
} else if (orientation == LV_DISPLAY_ROTATION_180) {
|
||||
@ -59,18 +59,18 @@ static uint32_t display_rotation_to_orientation_setting(lv_display_rotation_t or
|
||||
}
|
||||
}
|
||||
|
||||
static void on_orientation_set(lv_event_t* event) {
|
||||
static void onOrientationSet(lv_event_t* event) {
|
||||
auto* dropdown = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
uint32_t selected = lv_dropdown_get_selected(dropdown);
|
||||
TT_LOG_I(TAG, "Selected %ld", selected);
|
||||
lv_display_rotation_t rotation = orientation_setting_to_display_rotation(selected);
|
||||
lv_display_rotation_t rotation = orientationSettingToDisplayOrientation(selected);
|
||||
if (lv_display_get_rotation(lv_display_get_default()) != rotation) {
|
||||
lv_display_set_rotation(lv_display_get_default(), rotation);
|
||||
preferences_set_rotation(rotation);
|
||||
setRotation(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
static void app_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
lvgl::toolbar_create(parent, app);
|
||||
@ -92,7 +92,7 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_width(brightness_slider, LV_PCT(50));
|
||||
lv_obj_align(brightness_slider, LV_ALIGN_TOP_RIGHT, -8, 0);
|
||||
lv_slider_set_range(brightness_slider, 0, 255);
|
||||
lv_obj_add_event_cb(brightness_slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
lv_obj_add_event_cb(brightness_slider, onSliderEvent, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
|
||||
auto* lvgl_display = lv_display_get_default();
|
||||
tt_assert(lvgl_display != nullptr);
|
||||
@ -103,7 +103,7 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
lv_slider_set_value(brightness_slider, 255, LV_ANIM_OFF);
|
||||
lv_obj_add_state(brightness_slider, LV_STATE_DISABLED);
|
||||
} else {
|
||||
uint8_t value = preferences_get_backlight_duty();
|
||||
uint8_t value = getBacklightDuty();
|
||||
lv_slider_set_value(brightness_slider, value, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
@ -114,16 +114,16 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_t* orientation_dropdown = lv_dropdown_create(wrapper);
|
||||
lv_dropdown_set_options(orientation_dropdown, "Landscape\nLandscape (flipped)\nPortrait Left\nPortrait Right");
|
||||
lv_obj_align(orientation_dropdown, LV_ALIGN_TOP_RIGHT, 0, 32);
|
||||
lv_obj_add_event_cb(orientation_dropdown, on_orientation_set, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
uint32_t orientation_selected = display_rotation_to_orientation_setting(
|
||||
lv_obj_add_event_cb(orientation_dropdown, onOrientationSet, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
uint32_t orientation_selected = dipslayOrientationToOrientationSetting(
|
||||
lv_display_get_rotation(lv_display_get_default())
|
||||
);
|
||||
lv_dropdown_set_selected(orientation_dropdown, orientation_selected);
|
||||
}
|
||||
|
||||
static void app_hide(TT_UNUSED App& app) {
|
||||
static void onHide(TT_UNUSED App& app) {
|
||||
if (backlight_duty_set) {
|
||||
preferences_set_backlight_duty(backlight_duty);
|
||||
setBacklightDuty(backlight_duty);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,8 +134,8 @@ extern const Manifest manifest = {
|
||||
.type = TypeSettings,
|
||||
.onStart = nullptr,
|
||||
.onStop = nullptr,
|
||||
.onShow = &app_show,
|
||||
.onHide = &app_hide
|
||||
.onShow = onShow,
|
||||
.onHide = onHide
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <src/display/lv_display.h>
|
||||
|
||||
namespace tt::app::display {
|
||||
|
||||
void preferences_set_backlight_duty(uint8_t value);
|
||||
uint8_t preferences_get_backlight_duty();
|
||||
void preferences_set_rotation(lv_display_rotation_t rotation);
|
||||
lv_display_rotation_t preferences_get_rotation();
|
||||
|
||||
} // namespace
|
||||
@ -1,4 +1,4 @@
|
||||
#include "DisplayPreferences.h"
|
||||
#include "DisplaySettings.h"
|
||||
#include "Preferences.h"
|
||||
|
||||
namespace tt::app::display {
|
||||
@ -8,11 +8,11 @@ tt::Preferences preferences("display");
|
||||
#define BACKLIGHT_DUTY_KEY "backlight_duty"
|
||||
#define ROTATION_KEY "rotation"
|
||||
|
||||
void preferences_set_backlight_duty(uint8_t value) {
|
||||
void setBacklightDuty(uint8_t value) {
|
||||
preferences.putInt32(BACKLIGHT_DUTY_KEY, (int32_t)value);
|
||||
}
|
||||
|
||||
uint8_t preferences_get_backlight_duty() {
|
||||
uint8_t getBacklightDuty() {
|
||||
int32_t result;
|
||||
if (preferences.optInt32(BACKLIGHT_DUTY_KEY, result)) {
|
||||
return (uint8_t)(result % 255);
|
||||
@ -21,11 +21,11 @@ uint8_t preferences_get_backlight_duty() {
|
||||
}
|
||||
}
|
||||
|
||||
void preferences_set_rotation(lv_display_rotation_t rotation) {
|
||||
void setRotation(lv_display_rotation_t rotation) {
|
||||
preferences.putInt32(ROTATION_KEY, (int32_t)rotation);
|
||||
}
|
||||
|
||||
lv_display_rotation_t preferences_get_rotation() {
|
||||
lv_display_rotation_t getRotation() {
|
||||
int32_t rotation;
|
||||
if (preferences.optInt32(ROTATION_KEY, rotation)) {
|
||||
return (lv_display_rotation_t)rotation;
|
||||
12
Tactility/Source/app/display/DisplaySettings.h
Normal file
12
Tactility/Source/app/display/DisplaySettings.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <src/display/lv_display.h>
|
||||
|
||||
namespace tt::app::display {
|
||||
|
||||
void setBacklightDuty(uint8_t value);
|
||||
uint8_t getBacklightDuty();
|
||||
void setRotation(lv_display_rotation_t rotation);
|
||||
lv_display_rotation_t getRotation();
|
||||
|
||||
} // namespace
|
||||
@ -7,23 +7,23 @@ namespace tt::app::files {
|
||||
/** File types for `dirent`'s `d_type`. */
|
||||
enum {
|
||||
TT_DT_UNKNOWN = 0,
|
||||
#define TT_DT_UNKNOWN TT_DT_UNKNOWN
|
||||
#define TT_DT_UNKNOWN TT_DT_UNKNOWN // Unknown type
|
||||
TT_DT_FIFO = 1,
|
||||
#define TT_DT_FIFO TT_DT_FIFO
|
||||
#define TT_DT_FIFO TT_DT_FIFO // Named pipe or FIFO
|
||||
TT_DT_CHR = 2,
|
||||
#define TT_DT_CHR TT_DT_CHR
|
||||
#define TT_DT_CHR TT_DT_CHR // Character device
|
||||
TT_DT_DIR = 4,
|
||||
#define TT_DT_DIR TT_DT_DIR
|
||||
#define TT_DT_DIR TT_DT_DIR // Directory
|
||||
TT_DT_BLK = 6,
|
||||
#define TT_DT_BLK TT_DT_BLK
|
||||
#define TT_DT_BLK TT_DT_BLK // Block device
|
||||
TT_DT_REG = 8,
|
||||
#define TT_DT_REG TT_DT_REG
|
||||
#define TT_DT_REG TT_DT_REG // Regular file
|
||||
TT_DT_LNK = 10,
|
||||
#define TT_DT_LNK TT_DT_LNK
|
||||
#define TT_DT_LNK TT_DT_LNK // Symbolic link
|
||||
TT_DT_SOCK = 12,
|
||||
#define TT_DT_SOCK TT_DT_SOCK
|
||||
#define TT_DT_SOCK TT_DT_SOCK // Local-domain socket
|
||||
TT_DT_WHT = 14
|
||||
#define TT_DT_WHT TT_DT_WHT
|
||||
#define TT_DT_WHT TT_DT_WHT // Whiteout inodes
|
||||
};
|
||||
|
||||
typedef int (*ScandirFilter)(const struct dirent*);
|
||||
|
||||
@ -23,7 +23,7 @@ namespace tt::app::files {
|
||||
* @param extension the extension to look for, including the period symbol, in lower case
|
||||
* @return true on match
|
||||
*/
|
||||
static bool has_file_extension(const char* path, const char* extension) {
|
||||
static bool hasFileExtension(const char* path, const char* extension) {
|
||||
size_t postfix_len = strlen(extension);
|
||||
size_t base_len = strlen(path);
|
||||
if (base_len < postfix_len) {
|
||||
@ -39,27 +39,27 @@ static bool has_file_extension(const char* path, const char* extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_supported_image_file(const char* filename) {
|
||||
static bool isSupportedImageFile(const char* filename) {
|
||||
// Currently only the PNG library is built into Tactility
|
||||
return has_file_extension(filename, ".png");
|
||||
return hasFileExtension(filename, ".png");
|
||||
}
|
||||
|
||||
static bool is_supported_text_file(const char* filename) {
|
||||
return has_file_extension(filename, ".txt") ||
|
||||
has_file_extension(filename, ".ini") ||
|
||||
has_file_extension(filename, ".json") ||
|
||||
has_file_extension(filename, ".yaml") ||
|
||||
has_file_extension(filename, ".yml") ||
|
||||
has_file_extension(filename, ".lua") ||
|
||||
has_file_extension(filename, ".js") ||
|
||||
has_file_extension(filename, ".properties");
|
||||
static bool isSupportedTextFile(const char* filename) {
|
||||
return hasFileExtension(filename, ".txt") ||
|
||||
hasFileExtension(filename, ".ini") ||
|
||||
hasFileExtension(filename, ".json") ||
|
||||
hasFileExtension(filename, ".yaml") ||
|
||||
hasFileExtension(filename, ".yml") ||
|
||||
hasFileExtension(filename, ".lua") ||
|
||||
hasFileExtension(filename, ".js") ||
|
||||
hasFileExtension(filename, ".properties");
|
||||
}
|
||||
|
||||
// region Views
|
||||
|
||||
static void update_views(Data* data);
|
||||
static void updateViews(Data* data);
|
||||
|
||||
static void on_navigate_up_pressed(lv_event_t* event) {
|
||||
static void onNavigateUpPressed(lv_event_t* event) {
|
||||
auto* files_data = (Data*)lv_event_get_user_data(event);
|
||||
if (strcmp(files_data->current_path, "/") != 0) {
|
||||
TT_LOG_I(TAG, "Navigating upwards");
|
||||
@ -68,14 +68,14 @@ static void on_navigate_up_pressed(lv_event_t* event) {
|
||||
data_set_entries_for_path(files_data, new_absolute_path);
|
||||
}
|
||||
}
|
||||
update_views(files_data);
|
||||
updateViews(files_data);
|
||||
}
|
||||
|
||||
static void on_exit_app_pressed(TT_UNUSED lv_event_t* event) {
|
||||
static void onExitAppPressed(TT_UNUSED lv_event_t* event) {
|
||||
service::loader::stopApp();
|
||||
}
|
||||
|
||||
static void view_file(const char* path, const char* filename) {
|
||||
static void viewFile(const char* path, const char* filename) {
|
||||
size_t path_len = strlen(path);
|
||||
size_t filename_len = strlen(filename);
|
||||
char* filepath = static_cast<char*>(malloc(path_len + filename_len + 2));
|
||||
@ -102,11 +102,11 @@ static void view_file(const char* path, const char* filename) {
|
||||
|
||||
TT_LOG_I(TAG, "Clicked %s", filepath);
|
||||
|
||||
if (is_supported_image_file(filename)) {
|
||||
if (isSupportedImageFile(filename)) {
|
||||
Bundle bundle;
|
||||
bundle.putString(IMAGE_VIEWER_FILE_ARGUMENT, processed_filepath);
|
||||
service::loader::startApp("ImageViewer", false, bundle);
|
||||
} else if (is_supported_text_file(filename)) {
|
||||
} else if (isSupportedTextFile(filename)) {
|
||||
Bundle bundle;
|
||||
if (get_platform() == PlatformEsp) {
|
||||
bundle.putString(TEXT_VIEWER_FILE_ARGUMENT, processed_filepath);
|
||||
@ -122,7 +122,7 @@ static void view_file(const char* path, const char* filename) {
|
||||
free(filepath);
|
||||
}
|
||||
|
||||
static void on_file_pressed(lv_event_t* event) {
|
||||
static void onFilePressed(lv_event_t* event) {
|
||||
lv_event_code_t code = lv_event_get_code(event);
|
||||
if (code == LV_EVENT_CLICKED) {
|
||||
lv_obj_t* button = lv_event_get_current_target_obj(event);
|
||||
@ -134,30 +134,30 @@ static void on_file_pressed(lv_event_t* event) {
|
||||
switch (dir_entry->d_type) {
|
||||
case TT_DT_DIR:
|
||||
data_set_entries_for_child_path(files_data, dir_entry->d_name);
|
||||
update_views(files_data);
|
||||
updateViews(files_data);
|
||||
break;
|
||||
case TT_DT_LNK:
|
||||
TT_LOG_W(TAG, "opening links is not supported");
|
||||
break;
|
||||
case TT_DT_REG:
|
||||
view_file(files_data->current_path, dir_entry->d_name);
|
||||
viewFile(files_data->current_path, dir_entry->d_name);
|
||||
break;
|
||||
default:
|
||||
// Assume it's a file
|
||||
// TODO: Find a better way to identify a file
|
||||
view_file(files_data->current_path, dir_entry->d_name);
|
||||
viewFile(files_data->current_path, dir_entry->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void create_file_widget(Data* files_data, lv_obj_t* parent, struct dirent* dir_entry) {
|
||||
static void createFileWidget(Data* files_data, lv_obj_t* parent, struct dirent* dir_entry) {
|
||||
tt_check(parent);
|
||||
auto* list = (lv_obj_t*)parent;
|
||||
const char* symbol;
|
||||
if (dir_entry->d_type == TT_DT_DIR) {
|
||||
symbol = LV_SYMBOL_DIRECTORY;
|
||||
} else if (is_supported_image_file(dir_entry->d_name)) {
|
||||
} else if (isSupportedImageFile(dir_entry->d_name)) {
|
||||
symbol = LV_SYMBOL_IMAGE;
|
||||
} else if (dir_entry->d_type == TT_DT_LNK) {
|
||||
symbol = LV_SYMBOL_LOOP;
|
||||
@ -166,13 +166,14 @@ static void create_file_widget(Data* files_data, lv_obj_t* parent, struct dirent
|
||||
}
|
||||
lv_obj_t* button = lv_list_add_button(list, symbol, dir_entry->d_name);
|
||||
lv_obj_set_user_data(button, files_data);
|
||||
lv_obj_add_event_cb(button, &on_file_pressed, LV_EVENT_CLICKED, (void*)dir_entry);
|
||||
lv_obj_add_event_cb(button, &onFilePressed, LV_EVENT_CLICKED, (void*)dir_entry);
|
||||
}
|
||||
|
||||
static void update_views(Data* data) {
|
||||
static void updateViews(Data* data) {
|
||||
lv_obj_clean(data->list);
|
||||
for (int i = 0; i < data->dir_entries_count; ++i) {
|
||||
create_file_widget(data, data->list, data->dir_entries[i]);
|
||||
TT_LOG_I(TAG, "Entry: %s %d", data->dir_entries[i]->d_name, data->dir_entries[i]->d_type);
|
||||
createFileWidget(data, data->list, data->dir_entries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,23 +181,23 @@ static void update_views(Data* data) {
|
||||
|
||||
// region Lifecycle
|
||||
|
||||
static void on_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
auto* data = static_cast<Data*>(app.getData());
|
||||
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
lv_obj_t* toolbar = lvgl::toolbar_create(parent, "Files");
|
||||
lvgl::toolbar_set_nav_action(toolbar, LV_SYMBOL_CLOSE, &on_exit_app_pressed, nullptr);
|
||||
lvgl::toolbar_add_action(toolbar, LV_SYMBOL_UP, &on_navigate_up_pressed, data);
|
||||
lvgl::toolbar_set_nav_action(toolbar, LV_SYMBOL_CLOSE, &onExitAppPressed, nullptr);
|
||||
lvgl::toolbar_add_action(toolbar, LV_SYMBOL_UP, &onNavigateUpPressed, data);
|
||||
|
||||
data->list = lv_list_create(parent);
|
||||
lv_obj_set_width(data->list, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(data->list, 1);
|
||||
|
||||
update_views(data);
|
||||
updateViews(data);
|
||||
}
|
||||
|
||||
static void on_start(App& app) {
|
||||
static void onStart(App& app) {
|
||||
auto* data = data_alloc();
|
||||
// PC platform is bound to current work directory because of the LVGL file system mapping
|
||||
if (get_platform() == PlatformSimulator) {
|
||||
@ -214,7 +215,7 @@ static void on_start(App& app) {
|
||||
app.setData(data);
|
||||
}
|
||||
|
||||
static void on_stop(App& app) {
|
||||
static void onStop(App& app) {
|
||||
auto* data = static_cast<Data*>(app.getData());
|
||||
data_free(data);
|
||||
}
|
||||
@ -226,9 +227,9 @@ extern const Manifest manifest = {
|
||||
.name = "Files",
|
||||
.icon = TT_ASSETS_APP_ICON_FILES,
|
||||
.type = TypeSystem,
|
||||
.onStart = &on_start,
|
||||
.onStop = &on_stop,
|
||||
.onShow = &on_show,
|
||||
.onStart = onStart,
|
||||
.onStop = onStop,
|
||||
.onShow = onShow,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -9,41 +9,57 @@
|
||||
|
||||
namespace tt::app::gpio {
|
||||
|
||||
typedef struct {
|
||||
lv_obj_t* lv_pins[GPIO_NUM_MAX];
|
||||
uint8_t pin_states[GPIO_NUM_MAX];
|
||||
Thread* thread;
|
||||
Mutex* mutex;
|
||||
bool thread_interrupted;
|
||||
} Gpio;
|
||||
class Gpio {
|
||||
|
||||
static void lock(Gpio* gpio) {
|
||||
tt_check(tt_mutex_acquire(gpio->mutex, 1000) == TtStatusOk);
|
||||
}
|
||||
private:
|
||||
|
||||
static void unlock(Gpio* gpio) {
|
||||
tt_check(tt_mutex_release(gpio->mutex) == TtStatusOk);
|
||||
}
|
||||
lv_obj_t* lvPins[GPIO_NUM_MAX] = {0 };
|
||||
uint8_t pinStates[GPIO_NUM_MAX] = {0 };
|
||||
Thread* thread = nullptr;
|
||||
Mutex mutex;
|
||||
bool interruptTask = true;
|
||||
|
||||
static void update_pin_states(Gpio* gpio) {
|
||||
lock(gpio);
|
||||
public:
|
||||
|
||||
void lock() {
|
||||
tt_check(mutex.acquire(1000) == TtStatusOk);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
tt_check(mutex.release() == TtStatusOk);
|
||||
}
|
||||
|
||||
void onShow(App& app, lv_obj_t* parent);
|
||||
void onHide(App& app);
|
||||
|
||||
void startTask();
|
||||
void stopTask();
|
||||
bool shouldInterruptTask() { return interruptTask; };
|
||||
|
||||
void updatePinStates();
|
||||
void updatePinWidgets();
|
||||
};
|
||||
|
||||
|
||||
void Gpio::updatePinStates() {
|
||||
lock();
|
||||
// Update pin states
|
||||
for (int i = 0; i < GPIO_NUM_MAX; ++i) {
|
||||
#ifdef ESP_PLATFORM
|
||||
gpio->pin_states[i] = gpio_get_level((gpio_num_t)i);
|
||||
pinStates[i] = gpio_get_level((gpio_num_t)i);
|
||||
#else
|
||||
gpio->pin_states[i] = gpio_get_level(i);
|
||||
pinStates[i] = gpio_get_level(i);
|
||||
#endif
|
||||
}
|
||||
unlock(gpio);
|
||||
unlock();
|
||||
}
|
||||
|
||||
static void update_pin_widgets(Gpio* gpio) {
|
||||
void Gpio::updatePinWidgets() {
|
||||
if (lvgl::lock(100)) {
|
||||
lock(gpio);
|
||||
lock();
|
||||
for (int j = 0; j < GPIO_NUM_MAX; ++j) {
|
||||
int level = gpio->pin_states[j];
|
||||
lv_obj_t* label = gpio->lv_pins[j];
|
||||
int level = pinStates[j];
|
||||
lv_obj_t* label = lvPins[j];
|
||||
void* label_user_data = lv_obj_get_user_data(label);
|
||||
// The user data stores the state, so we can avoid unnecessary updates
|
||||
if ((void*)level != label_user_data) {
|
||||
@ -56,11 +72,11 @@ static void update_pin_widgets(Gpio* gpio) {
|
||||
}
|
||||
}
|
||||
lvgl::unlock();
|
||||
unlock(gpio);
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
static lv_obj_t* create_gpio_row_wrapper(lv_obj_t* parent) {
|
||||
static lv_obj_t* createGpioRowWrapper(lv_obj_t* parent) {
|
||||
lv_obj_t* wrapper = lv_obj_create(parent);
|
||||
lv_obj_set_style_pad_all(wrapper, 0, 0);
|
||||
lv_obj_set_style_border_width(wrapper, 0, 0);
|
||||
@ -70,57 +86,56 @@ static lv_obj_t* create_gpio_row_wrapper(lv_obj_t* parent) {
|
||||
|
||||
// region Task
|
||||
|
||||
static int32_t gpio_task(void* context) {
|
||||
static int32_t taskMain(void* context) {
|
||||
Gpio* gpio = (Gpio*)context;
|
||||
bool interrupted = false;
|
||||
|
||||
while (!interrupted) {
|
||||
delay_ms(100);
|
||||
|
||||
update_pin_states(gpio);
|
||||
update_pin_widgets(gpio);
|
||||
gpio->updatePinStates();
|
||||
gpio->updatePinWidgets();
|
||||
|
||||
lock(gpio);
|
||||
interrupted = gpio->thread_interrupted;
|
||||
unlock(gpio);
|
||||
gpio->lock();
|
||||
interrupted = gpio->shouldInterruptTask();
|
||||
gpio->unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void task_start(Gpio* gpio) {
|
||||
tt_assert(gpio->thread == nullptr);
|
||||
lock(gpio);
|
||||
gpio->thread = new Thread(
|
||||
void Gpio::startTask() {
|
||||
lock();
|
||||
tt_assert(thread == nullptr);
|
||||
thread = new Thread(
|
||||
"gpio",
|
||||
4096,
|
||||
&gpio_task,
|
||||
gpio
|
||||
&taskMain,
|
||||
this
|
||||
);
|
||||
gpio->thread_interrupted = false;
|
||||
gpio->thread->start();
|
||||
unlock(gpio);
|
||||
interruptTask = false;
|
||||
thread->start();
|
||||
unlock();
|
||||
}
|
||||
|
||||
static void task_stop(Gpio* gpio) {
|
||||
tt_assert(gpio->thread);
|
||||
lock(gpio);
|
||||
gpio->thread_interrupted = true;
|
||||
unlock(gpio);
|
||||
void Gpio::stopTask() {
|
||||
tt_assert(thread);
|
||||
lock();
|
||||
interruptTask = true;
|
||||
unlock();
|
||||
|
||||
gpio->thread->join();
|
||||
thread->join();
|
||||
|
||||
lock(gpio);
|
||||
delete gpio->thread;
|
||||
gpio->thread = nullptr;
|
||||
unlock(gpio);
|
||||
lock();
|
||||
delete thread;
|
||||
thread = nullptr;
|
||||
unlock();
|
||||
}
|
||||
|
||||
// endregion Task
|
||||
|
||||
// region App lifecycle
|
||||
|
||||
static void app_show(App& app, lv_obj_t* parent) {
|
||||
void Gpio::onShow(App& app, lv_obj_t* parent) {
|
||||
auto* gpio = (Gpio*)app.getData();
|
||||
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
@ -137,10 +152,10 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
uint8_t column_limit = 10;
|
||||
int32_t x_spacing = 20;
|
||||
|
||||
lv_obj_t* row_wrapper = create_gpio_row_wrapper(wrapper);
|
||||
lv_obj_t* row_wrapper = createGpioRowWrapper(wrapper);
|
||||
lv_obj_align(row_wrapper, LV_ALIGN_TOP_MID, 0, 0);
|
||||
|
||||
lock(gpio);
|
||||
gpio->lock();
|
||||
for (int i = GPIO_NUM_MIN; i < GPIO_NUM_MAX; ++i) {
|
||||
|
||||
// Add the GPIO number before the first item on a row
|
||||
@ -153,7 +168,7 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_t* status_label = lv_label_create(row_wrapper);
|
||||
lv_obj_set_pos(status_label, (int32_t)((column+1) * x_spacing), 0);
|
||||
lv_label_set_text_fmt(status_label, "%s", LV_SYMBOL_STOP);
|
||||
gpio->lv_pins[i] = status_label;
|
||||
gpio->lvPins[i] = status_label;
|
||||
|
||||
column++;
|
||||
|
||||
@ -164,37 +179,43 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_pos(postfix, (int32_t)((column+1) * x_spacing), 0);
|
||||
|
||||
// Add a new row wrapper underneath the last one
|
||||
lv_obj_t* new_row_wrapper = create_gpio_row_wrapper(wrapper);
|
||||
lv_obj_t* new_row_wrapper = createGpioRowWrapper(wrapper);
|
||||
lv_obj_align_to(new_row_wrapper, row_wrapper, LV_ALIGN_BOTTOM_LEFT, 0, 4);
|
||||
row_wrapper = new_row_wrapper;
|
||||
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
unlock(gpio);
|
||||
gpio->unlock();
|
||||
|
||||
task_start(gpio);
|
||||
gpio->startTask();
|
||||
}
|
||||
|
||||
static void on_hide(App& app) {
|
||||
void Gpio::onHide(App& app) {
|
||||
auto* gpio = (Gpio*)app.getData();
|
||||
task_stop(gpio);
|
||||
gpio->stopTask();
|
||||
}
|
||||
|
||||
static void on_start(App& app) {
|
||||
auto* gpio = new Gpio {
|
||||
.lv_pins = { nullptr },
|
||||
.pin_states = { 0 },
|
||||
.thread = nullptr,
|
||||
.mutex = tt_mutex_alloc(MutexTypeNormal),
|
||||
.thread_interrupted = true,
|
||||
};
|
||||
|
||||
// region App lifecycle
|
||||
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
auto* gpio = (Gpio*)app.getData();
|
||||
gpio->onShow(app, parent);
|
||||
}
|
||||
|
||||
static void onHide(App& app) {
|
||||
auto* gpio = (Gpio*)app.getData();
|
||||
gpio->onHide(app);
|
||||
}
|
||||
|
||||
static void onStart(App& app) {
|
||||
auto* gpio = new Gpio();
|
||||
app.setData(gpio);
|
||||
}
|
||||
|
||||
static void on_stop(App& app) {
|
||||
static void onStop(App& app) {
|
||||
auto* gpio = (Gpio*)app.getData();
|
||||
tt_mutex_free(gpio->mutex);
|
||||
delete gpio;
|
||||
}
|
||||
|
||||
@ -204,10 +225,10 @@ extern const Manifest manifest = {
|
||||
.id = "Gpio",
|
||||
.name = "GPIO",
|
||||
.type = TypeSystem,
|
||||
.onStart = &on_start,
|
||||
.onStop = &on_stop,
|
||||
.onShow = &app_show,
|
||||
.onHide = &on_hide
|
||||
.onStart = onStart,
|
||||
.onStop = onStop,
|
||||
.onShow = onShow,
|
||||
.onHide = onHide
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace tt::app::i2csettings {
|
||||
|
||||
static void on_switch_toggle(lv_event_t* event) {
|
||||
static void onSwitchToggled(lv_event_t* event) {
|
||||
lv_event_code_t code = lv_event_get_code(event);
|
||||
auto* state_switch = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
const hal::i2c::Configuration* configuration = static_cast<hal::i2c::Configuration*>(lv_event_get_user_data(event));
|
||||
@ -46,7 +46,7 @@ static void show(lv_obj_t* parent, const hal::i2c::Configuration& configuration)
|
||||
lv_obj_add_state(state_switch, LV_STATE_CHECKED);
|
||||
}
|
||||
|
||||
lv_obj_add_event_cb(state_switch, on_switch_toggle, LV_EVENT_VALUE_CHANGED, (void*)&configuration);
|
||||
lv_obj_add_event_cb(state_switch, onSwitchToggled, LV_EVENT_VALUE_CHANGED, (void*) &configuration);
|
||||
}
|
||||
|
||||
// SDA label
|
||||
@ -69,7 +69,7 @@ static void show(lv_obj_t* parent, const hal::i2c::Configuration& configuration)
|
||||
}
|
||||
}
|
||||
|
||||
static void on_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lvgl::toolbar_create(parent, app);
|
||||
|
||||
@ -90,7 +90,7 @@ extern const Manifest manifest = {
|
||||
.name = "I2C",
|
||||
.icon = TT_ASSETS_APP_ICON_I2C_SETTINGS,
|
||||
.type = TypeSettings,
|
||||
.onShow = &on_show
|
||||
.onShow = onShow
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -8,7 +8,7 @@ namespace tt::app::imageviewer {
|
||||
|
||||
#define TAG "image_viewer"
|
||||
|
||||
static void on_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lvgl::toolbar_create(parent, app);
|
||||
|
||||
@ -35,7 +35,7 @@ extern const Manifest manifest = {
|
||||
.id = "ImageViewer",
|
||||
.name = "Image Viewer",
|
||||
.type = TypeHidden,
|
||||
.onShow = &on_show
|
||||
.onShow = onShow
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -18,10 +18,10 @@ typedef struct {
|
||||
lv_obj_t* charge_state;
|
||||
lv_obj_t* charge_level;
|
||||
lv_obj_t* current;
|
||||
} AppData;
|
||||
} Data;
|
||||
|
||||
static void app_update_ui(void* callbackContext) {
|
||||
auto* data = (AppData*)callbackContext;
|
||||
static void updateUi(void* callbackContext) {
|
||||
auto* data = (Data*)callbackContext;
|
||||
bool charging_enabled = data->power->isChargingEnabled();
|
||||
const char* charge_state = data->power->isCharging() ? "yes" : "no";
|
||||
uint8_t charge_level = data->power->getChargeLevel();
|
||||
@ -40,20 +40,20 @@ static void app_update_ui(void* callbackContext) {
|
||||
lvgl::unlock();
|
||||
}
|
||||
|
||||
static void on_power_enabled_change(lv_event_t* event) {
|
||||
static void onPowerEnabledChanged(lv_event_t* event) {
|
||||
lv_event_code_t code = lv_event_get_code(event);
|
||||
auto* enable_switch = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
bool is_on = lv_obj_has_state(enable_switch, LV_STATE_CHECKED);
|
||||
auto* data = static_cast<AppData*>(lv_event_get_user_data(event));
|
||||
auto* data = static_cast<Data*>(lv_event_get_user_data(event));
|
||||
if (data->power->isChargingEnabled() != is_on) {
|
||||
data->power->setChargingEnabled(is_on);
|
||||
app_update_ui(data);
|
||||
updateUi(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void app_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
lvgl::toolbar_create(parent, app);
|
||||
@ -64,7 +64,7 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_grow(wrapper, 1);
|
||||
lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
auto* data = static_cast<AppData*>(app.getData());
|
||||
auto* data = static_cast<Data*>(app.getData());
|
||||
|
||||
// Top row: enable/disable
|
||||
lv_obj_t* switch_container = lv_obj_create(wrapper);
|
||||
@ -78,7 +78,7 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_align(enable_label, LV_ALIGN_LEFT_MID);
|
||||
|
||||
lv_obj_t* enable_switch = lv_switch_create(switch_container);
|
||||
lv_obj_add_event_cb(enable_switch, on_power_enabled_change, LV_EVENT_ALL, data);
|
||||
lv_obj_add_event_cb(enable_switch, onPowerEnabledChanged, LV_EVENT_ALL, data);
|
||||
lv_obj_set_align(enable_switch, LV_ALIGN_RIGHT_MID);
|
||||
|
||||
data->enable_switch = enable_switch;
|
||||
@ -86,25 +86,25 @@ static void app_show(App& app, lv_obj_t* parent) {
|
||||
data->charge_level = lv_label_create(wrapper);
|
||||
data->current = lv_label_create(wrapper);
|
||||
|
||||
app_update_ui(data);
|
||||
updateUi(data);
|
||||
data->update_timer->start(ms_to_ticks(1000));
|
||||
}
|
||||
|
||||
static void app_hide(TT_UNUSED App& app) {
|
||||
auto* data = static_cast<AppData*>(app.getData());
|
||||
static void onHide(TT_UNUSED App& app) {
|
||||
auto* data = static_cast<Data*>(app.getData());
|
||||
data->update_timer->stop();
|
||||
}
|
||||
|
||||
static void app_start(App& app) {
|
||||
auto* data = new AppData();
|
||||
data->update_timer = new Timer(Timer::TypePeriodic, &app_update_ui, data);
|
||||
static void onStart(App& app) {
|
||||
auto* data = new Data();
|
||||
data->update_timer = new Timer(Timer::TypePeriodic, &updateUi, data);
|
||||
data->power = getConfiguration()->hardware->power;
|
||||
assert(data->power != nullptr); // The Power app only shows up on supported devices
|
||||
app.setData(data);
|
||||
}
|
||||
|
||||
static void app_stop(App& app) {
|
||||
auto* data = static_cast<AppData*>(app.getData());
|
||||
static void onStop(App& app) {
|
||||
auto* data = static_cast<Data*>(app.getData());
|
||||
delete data->update_timer;
|
||||
delete data;
|
||||
}
|
||||
@ -114,10 +114,10 @@ extern const Manifest manifest = {
|
||||
.name = "Power",
|
||||
.icon = TT_ASSETS_APP_ICON_POWER_SETTINGS,
|
||||
.type = TypeSettings,
|
||||
.onStart = &app_start,
|
||||
.onStop = &app_stop,
|
||||
.onShow = &app_show,
|
||||
.onHide = &app_hide
|
||||
.onStart = onStart,
|
||||
.onStop = onStop,
|
||||
.onShow = onShow,
|
||||
.onHide = onHide
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -2,17 +2,17 @@
|
||||
|
||||
namespace tt::app::screenshot {
|
||||
|
||||
static void on_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
auto* ui = static_cast<ScreenshotUi*>(app.getData());
|
||||
create_ui(app, ui, parent);
|
||||
}
|
||||
|
||||
static void on_start(App& app) {
|
||||
static void onStart(App& app) {
|
||||
auto* ui = static_cast<ScreenshotUi*>(malloc(sizeof(ScreenshotUi)));
|
||||
app.setData(ui);
|
||||
}
|
||||
|
||||
static void on_stop(App& app) {
|
||||
static void onStop(App& app) {
|
||||
auto* ui = static_cast<ScreenshotUi*>(app.getData());
|
||||
free(ui);
|
||||
}
|
||||
@ -22,9 +22,9 @@ extern const Manifest manifest = {
|
||||
.name = "_Screenshot", // So it gets put at the bottom of the desktop and becomes less visible on small screen devices
|
||||
.icon = LV_SYMBOL_IMAGE,
|
||||
.type = TypeSystem,
|
||||
.onStart = &on_start,
|
||||
.onStop = &on_stop,
|
||||
.onShow = &on_show,
|
||||
.onStart = onStart,
|
||||
.onStop = onStop,
|
||||
.onShow = onShow,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -103,7 +103,7 @@ extern const Manifest manifest = {
|
||||
.id = "SelectionDialog",
|
||||
.name = "Selection Dialog",
|
||||
.type = TypeHidden,
|
||||
.onShow = &onShow
|
||||
.onShow = onShow
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
namespace tt::app::settings {
|
||||
|
||||
static void on_app_pressed(lv_event_t* e) {
|
||||
static void onAppPressed(lv_event_t* e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_CLICKED) {
|
||||
const auto* manifest = static_cast<const Manifest*>(lv_event_get_user_data(e));
|
||||
@ -16,15 +16,15 @@ static void on_app_pressed(lv_event_t* e) {
|
||||
}
|
||||
}
|
||||
|
||||
static void create_app_widget(const Manifest* manifest, void* parent) {
|
||||
static void createWidget(const Manifest* manifest, void* parent) {
|
||||
tt_check(parent);
|
||||
auto* list = (lv_obj_t*)parent;
|
||||
const void* icon = !manifest->icon.empty() ? manifest->icon.c_str() : TT_ASSETS_APP_ICON_FALLBACK;
|
||||
lv_obj_t* btn = lv_list_add_button(list, icon, manifest->name.c_str());
|
||||
lv_obj_add_event_cb(btn, &on_app_pressed, LV_EVENT_CLICKED, (void*)manifest);
|
||||
lv_obj_add_event_cb(btn, &onAppPressed, LV_EVENT_CLICKED, (void*)manifest);
|
||||
}
|
||||
|
||||
static void on_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
lvgl::toolbar_create(parent, app);
|
||||
@ -37,7 +37,7 @@ static void on_show(App& app, lv_obj_t* parent) {
|
||||
std::sort(manifests.begin(), manifests.end(), SortAppManifestByName);
|
||||
for (const auto& manifest: manifests) {
|
||||
if (manifest->type == TypeSettings) {
|
||||
create_app_widget(manifest, list);
|
||||
createWidget(manifest, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -47,10 +47,7 @@ extern const Manifest manifest = {
|
||||
.name = "Settings",
|
||||
.icon = TT_ASSETS_APP_ICON_SETTINGS,
|
||||
.type = TypeSystem,
|
||||
.onStart = nullptr,
|
||||
.onStop = nullptr,
|
||||
.onShow = &on_show,
|
||||
.onHide = nullptr
|
||||
.onShow = onShow,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
namespace tt::app::systeminfo {
|
||||
|
||||
static size_t get_heap_free() {
|
||||
static size_t getHeapFree() {
|
||||
#ifdef ESP_PLATFORM
|
||||
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
#else
|
||||
@ -13,7 +13,7 @@ static size_t get_heap_free() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t get_heap_total() {
|
||||
static size_t getHeapTotal() {
|
||||
#ifdef ESP_PLATFORM
|
||||
return heap_caps_get_total_size(MALLOC_CAP_INTERNAL);
|
||||
#else
|
||||
@ -21,7 +21,7 @@ static size_t get_heap_total() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t get_spi_free() {
|
||||
static size_t getSpiFree() {
|
||||
#ifdef ESP_PLATFORM
|
||||
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
#else
|
||||
@ -29,7 +29,7 @@ static size_t get_spi_free() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t get_spi_total() {
|
||||
static size_t getSpiTotal() {
|
||||
#ifdef ESP_PLATFORM
|
||||
return heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
|
||||
#else
|
||||
@ -37,7 +37,7 @@ static size_t get_spi_total() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void add_memory_bar(lv_obj_t* parent, const char* label, size_t used, size_t total) {
|
||||
static void addMemoryBar(lv_obj_t* parent, const char* label, size_t used, size_t total) {
|
||||
lv_obj_t* container = lv_obj_create(parent);
|
||||
lv_obj_set_size(container, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_all(container, 0, 0);
|
||||
@ -65,7 +65,7 @@ static void add_memory_bar(lv_obj_t* parent, const char* label, size_t used, siz
|
||||
lv_obj_set_style_text_align(bottom_label, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
}
|
||||
|
||||
static void on_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lvgl::toolbar_create(parent, app);
|
||||
|
||||
@ -83,8 +83,8 @@ static void on_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(memory_wrapper, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_size(memory_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
|
||||
add_memory_bar(memory_wrapper, "Heap", get_heap_total() - get_heap_free(), get_heap_total());
|
||||
add_memory_bar(memory_wrapper, "SPI", get_spi_total() - get_spi_free(), get_spi_total());
|
||||
addMemoryBar(memory_wrapper, "Heap", getHeapTotal() - getHeapFree(), getHeapTotal());
|
||||
addMemoryBar(memory_wrapper, "SPI", getSpiTotal() - getSpiFree(), getSpiTotal());
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
// Build info
|
||||
@ -97,8 +97,6 @@ static void on_show(App& app, lv_obj_t* parent) {
|
||||
lv_obj_t* esp_idf_version = lv_label_create(build_info_wrapper);
|
||||
lv_label_set_text_fmt(esp_idf_version, "IDF version: %d.%d.%d", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR, ESP_IDF_VERSION_PATCH);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
extern const Manifest manifest = {
|
||||
@ -108,7 +106,7 @@ extern const Manifest manifest = {
|
||||
.type = TypeSystem,
|
||||
.onStart = nullptr,
|
||||
.onStop = nullptr,
|
||||
.onShow = &on_show
|
||||
.onShow = onShow
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
namespace tt::app::textviewer {
|
||||
|
||||
static void on_show(App& app, lv_obj_t* parent) {
|
||||
static void onShow(App& app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lvgl::toolbar_create(parent, app);
|
||||
|
||||
@ -35,7 +35,7 @@ extern const Manifest manifest = {
|
||||
.id = "TextViewer",
|
||||
.name = "Text Viewer",
|
||||
.type = TypeHidden,
|
||||
.onShow = &on_show
|
||||
.onShow = onShow
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "app/display/DisplayPreferences.h"
|
||||
#include "app/display/DisplaySettings.h"
|
||||
#include "lvgl.h"
|
||||
#include "hal/Configuration.h"
|
||||
#include "hal/Display.h"
|
||||
@ -32,7 +32,7 @@ bool initDisplay(const hal::Configuration& config) {
|
||||
tt_assert(existing_display_user_data == nullptr);
|
||||
lv_display_set_user_data(lvgl_display, display);
|
||||
|
||||
lv_display_rotation_t rotation = app::display::preferences_get_rotation();
|
||||
lv_display_rotation_t rotation = app::display::getRotation();
|
||||
if (rotation != lv_disp_get_rotation(lv_disp_get_default())) {
|
||||
lv_disp_set_rotation(lv_disp_get_default(), static_cast<lv_display_rotation_t>(rotation));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user