Migrate TactilityC and LVGL functionality (#588)

lvgl-module

- Move and rename source and include files
- Fix bug with missing lvgl unlock
- New widgets: spinner, toolbar, sliderbox

TactilityC

- Removed tt_lock, tt_lvgl_\*
This commit is contained in:
Ken Van Hoeylandt
2026-07-26 15:58:35 +02:00
committed by GitHub
parent cd2d9d6158
commit b98a813f3c
84 changed files with 586 additions and 831 deletions
@@ -1,36 +0,0 @@
#pragma once
#include <lvgl.h>
namespace tt::lvgl {
/**
* Create a SliderBox: a slider flanked by "-" and "+" buttons with a value label.
* @param parent the parent object
* @param min minimum value (inclusive)
* @param max maximum value (inclusive)
* @param step the amount each +/- button press changes the value by
* @param value the initial value
* @return the created SliderBox instance
*/
lv_obj_t* sliderbox_create(lv_obj_t* parent, int32_t min, int32_t max, int32_t step, int32_t value);
/** @return the current value of the SliderBox */
int32_t sliderbox_get_value(lv_obj_t* obj);
/**
* Set the current value of the SliderBox (clamped to its [min, max] range).
* Updates the slider position and the value label.
*/
void sliderbox_set_value(lv_obj_t* obj, int32_t value, lv_anim_enable_t anim);
/**
* Register a callback that is fired with LV_EVENT_VALUE_CHANGED whenever the value
* changes, whether the change came from the slider or from the +/- buttons.
* @param obj the SliderBox instance
* @param callback the callback to invoke
* @param userData user data that is attached to the event
*/
void sliderbox_add_value_changed_cb(lv_obj_t* obj, lv_event_cb_t callback, void* userData);
} // namespace tt::lvgl
@@ -1,12 +0,0 @@
#include <lvgl.h>
namespace tt::lvgl {
/**
* Create the Tactility spinner widget
* @param parent pointer to an object, it will be the parent of the new spinner.
* @return the created spinner
*/
lv_obj_t* spinner_create(lv_obj_t* parent);
}
+1 -57
View File
@@ -2,67 +2,11 @@
#include "../app/AppContext.h"
#include <lvgl.h>
#include <lvgl/widgets/toolbar.h>
namespace tt::lvgl {
#define TOOLBAR_ACTION_LIMIT 4
/** Create a toolbar widget that shows the app name as title */
lv_obj_t* toolbar_create(lv_obj_t* parent, const app::AppContext& app);
/** Create a toolbar widget with the provided title*/
lv_obj_t* toolbar_create(lv_obj_t* parent, const std::string& title);
/** Sets the toolbar title */
void toolbar_set_title(lv_obj_t* obj, const std::string& title);
/** Sets the navigation action of the toolbar (button on the top-left)
* @param[in] obj the toolbar instance
* @param[in] icon the icon to set on the button
* @param[in] callback the callback for the click action of the button
* @param[in] callbackEventUserData the user data that is attached to the callback event object
*/
void toolbar_set_nav_action(lv_obj_t* obj, const char* icon, lv_event_cb_t callback, void* userData);
/**
* Create and add an action button with an image to the toolbar (aligned to the right of the toolbar)
* @param[in] obj the toolbar instance
* @param[in] imagePath the path to an image file to shown on the button
* @param[in] callback the callback for the click action of the button
* @param[in] callbackUserData the user data that is passed to the callback
* @return an lv_button instance
*/
lv_obj_t* toolbar_add_image_button_action(lv_obj_t* obj, const char* imagePath, lv_event_cb_t callback, void* callbackUserData);
/**
* Create and add an action button with text to the toolbar (aligned to the right of the toolbar)
* @param[in] obj the toolbar instance
* @param[in] text the button text
* @param[in] callback the callback for the click action of the button
* @param[in] callbackUserData the user data that is passed to the callback
* @return an lv_button instance
*/
lv_obj_t* toolbar_add_text_button_action(lv_obj_t* obj, const char* text, lv_event_cb_t callback, void* callbackUserData);
/**
* Create and add a switch to the toolbar actions.
* @param[in] obj the toolbar instance
* @return an instance created by lv_switch_create()
*/
lv_obj_t* toolbar_add_switch_action(lv_obj_t* obj);
/**
* Create and add a spinner to the toolbar actions.
* @param[in] obj the toolbar instance
* @return an instance created by Tactility's spinner_create()
*/
lv_obj_t* toolbar_add_spinner_action(lv_obj_t* obj);
/**
* Remove all actions from the toolbar
* @param[in] obj the toolbar instance
*/
void toolbar_clear_actions(lv_obj_t* obj);
} // namespace
+8
View File
@@ -25,6 +25,7 @@
#include <crypt/module.h>
#include <lvgl/module.h>
#include <lvgl/widgets/toolbar.h>
#include <tactility/concurrent/thread.h>
#include <tactility/drivers/audio_stream.h>
#include <tactility/drivers/display.h>
@@ -350,7 +351,14 @@ void registerApps() {
registerInstalledAppsFromFileSystems();
}
static void stopAppFromToolbar(lv_event_t*) {
app::stop();
}
static void onLvglStarted() {
ToolbarConfig toolbar_config = { .nav_action_callback = stopAppFromToolbar };
lvgl_toolbar_configure(&toolbar_config);
addService(service::gui::manifest);
addService(service::statusbar::manifest);
addService(service::memorychecker::manifest);
+1 -1
View File
@@ -4,9 +4,9 @@
#include <Tactility/lvgl/Style.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/icons/shared.h>
#include <tactility/drivers/uart_controller.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
#include <gps/gps.h>
#include <gps/gps_settings.h>
@@ -1,6 +1,6 @@
#include "Tactility/app/alertdialog/AlertDialog.h"
#include "Tactility/lvgl/Toolbar.h"
#include <lvgl/widgets/toolbar.h>
#include "Tactility/service/loader/Loader.h"
#include <Tactility/StringUtils.h>
@@ -98,7 +98,7 @@ public:
check(parameters != nullptr, "Parameters missing");
std::string title = getTitleParameter(app.getParameters());
lv_obj_t* toolbar = lvgl::toolbar_create(parent, title);
lv_obj_t* toolbar = lvgl_toolbar_create(parent, title.c_str());
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_t* message_label = lv_label_create(parent);
@@ -6,7 +6,7 @@
#include <Tactility/app/alertdialog/AlertDialog.h>
#include <tactility/check.h>
#include <Tactility/lvgl/Style.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/widgets/toolbar.h>
#include <lvgl.h>
#include <format>
@@ -51,7 +51,7 @@ public:
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
auto title = std::format("{} details", manifest->appName);
lvgl::toolbar_create(parent, title);
lvgl_toolbar_create(parent, title.c_str());
auto* wrapper = lv_obj_create(parent);
lv_obj_set_width(wrapper, LV_PCT(100));
+6 -6
View File
@@ -3,18 +3,18 @@
#include <Tactility/app/apphubdetails/AppHubDetailsApp.h>
#include <Tactility/file/File.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/lvgl/Spinner.h>
#include <lvgl/widgets/spinner.h>
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/network/Http.h>
#include <Tactility/Paths.h>
#include <Tactility/service/loader/Loader.h>
#include <Tactility/service/wifi/Wifi.h>
#include <lvgl.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <algorithm>
#include <format>
#include <lvgl.h>
#include <tactility/log.h>
namespace tt::app::apphub {
@@ -125,7 +125,7 @@ class AppHubApp final : public App {
void refresh() {
lv_obj_clean(contentWrapper);
auto* spinner = lvgl::spinner_create(contentWrapper);
auto* spinner = lvgl_spinner_create(contentWrapper);
lv_obj_align(spinner, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_flag(refreshButton, LV_OBJ_FLAG_HIDDEN);
@@ -165,7 +165,7 @@ public:
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
auto* toolbar = lvgl::toolbar_create(parent, app);
refreshButton = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_REFRESH, onRefreshPressed, this);
refreshButton = lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_REFRESH, onRefreshPressed, this);
lv_obj_add_flag(refreshButton, LV_OBJ_FLAG_HIDDEN);
contentWrapper = lv_obj_create(parent);
@@ -4,7 +4,7 @@
#include <Tactility/app/AppRegistration.h>
#include <Tactility/file/File.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/widgets/toolbar.h>
#include <Tactility/network/Http.h>
#include <Tactility/Paths.h>
#include <Tactility/service/loader/Loader.h>
@@ -154,19 +154,19 @@ class AppHubDetailsApp final : public App {
}
void updateViews() {
lvgl::toolbar_clear_actions(toolbar);
lvgl_toolbar_clear_actions(toolbar);
const auto manifest = findAppManifestById(entry.appId);
spinner = lvgl::toolbar_add_spinner_action(toolbar);
spinner = lvgl_toolbar_add_spinner_action(toolbar);
lv_obj_add_flag(spinner, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(updateLabel, LV_OBJ_FLAG_HIDDEN);
if (manifest != nullptr) {
if (manifest->appVersionCode < entry.appVersionCode) {
updateButton = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_DOWNLOAD, onUpdatePressed, this);
updateButton = lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_DOWNLOAD, onUpdatePressed, this);
lv_obj_remove_flag(updateLabel, LV_OBJ_FLAG_HIDDEN);
}
lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_TRASH, onUninstallPressed, this);
lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_TRASH, onUninstallPressed, this);
} else {
lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_DOWNLOAD, onInstallPressed, this);
lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_DOWNLOAD, onInstallPressed, this);
}
}
@@ -190,7 +190,7 @@ public:
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
toolbar = lvgl::toolbar_create(parent, entry.appName.c_str());
toolbar = lvgl_toolbar_create(parent, entry.appName.c_str());
auto* wrapper = lv_obj_create(parent);
lv_obj_set_width(wrapper, LV_PCT(100));
lv_obj_set_flex_grow(wrapper, 1);
+2 -2
View File
@@ -5,8 +5,8 @@
#include <lvgl.h>
#include <algorithm>
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl/fonts.h>
namespace tt::app::applist {
@@ -1,10 +1,10 @@
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl/fonts.h>
#include <Tactility/app/AppRegistration.h>
#include <Tactility/app/appdetails/AppDetails.h>
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/service/loader/Loader.h>
#include <lvgl/widgets/toolbar.h>
#include <lvgl.h>
#include <algorithm>
@@ -29,7 +29,7 @@ class AppSettingsApp final : public App {
public:
void onShow(AppContext& app, lv_obj_t* parent) override {
auto* toolbar = lvgl::toolbar_create(parent, "Installed Apps");
auto* toolbar = lvgl_toolbar_create(parent, "Installed Apps");
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_t* list = lv_list_create(parent);
@@ -1,13 +1,13 @@
#include <Tactility/Tactility.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <Tactility/PubSub.h>
#include <Tactility/app/App.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/lvgl/SliderBox.h>
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/service/audio/Audio.h>
#include <lvgl/widgets/sliderbox.h>
#include <lvgl.h>
#include <lvgl/lvgl.h>
@@ -52,13 +52,13 @@ class AudioSettingsApp final : public App {
static void onInputVolumeSlider(lv_event_t* event) {
auto* sliderBox = static_cast<lv_obj_t*>(lv_event_get_target(event));
float percent = static_cast<float>(lvgl::sliderbox_get_value(sliderBox));
float percent = static_cast<float>(lvgl_sliderbox_get_value(sliderBox));
service::audio::setInputVolume(percent);
}
static void onOutputVolumeSlider(lv_event_t* event) {
auto* sliderBox = static_cast<lv_obj_t*>(lv_event_get_target(event));
float percent = static_cast<float>(lvgl::sliderbox_get_value(sliderBox));
float percent = static_cast<float>(lvgl_sliderbox_get_value(sliderBox));
service::audio::setOutputVolume(percent);
}
@@ -102,10 +102,10 @@ class AudioSettingsApp final : public App {
lv_label_set_text(row_label, label);
lv_obj_align(row_label, LV_ALIGN_LEFT_MID, 0, 0);
auto* sliderBox = lvgl::sliderbox_create(row, 0, 100, 10, initialValue);
auto* sliderBox = lvgl_sliderbox_create(row, 0, 100, 10, initialValue);
lv_obj_set_width(sliderBox, LV_PCT(50));
lv_obj_align(sliderBox, LV_ALIGN_RIGHT_MID, 0, 0);
lvgl::sliderbox_add_value_changed_cb(sliderBox, cb, userData);
lvgl_sliderbox_add_value_changed_cb(sliderBox, cb, userData);
return sliderBox;
}
@@ -192,7 +192,7 @@ public:
else lv_obj_remove_state(inputMuteSwitch, LV_STATE_CHECKED);
}
if (inputVolumeSlider) {
lvgl::sliderbox_set_value(inputVolumeSlider, static_cast<int32_t>(service::audio::getInputVolume()), LV_ANIM_OFF);
lvgl_sliderbox_set_value(inputVolumeSlider, static_cast<int32_t>(service::audio::getInputVolume()), LV_ANIM_OFF);
}
if (outputEnabledSwitch) {
@@ -204,7 +204,7 @@ public:
else lv_obj_remove_state(outputMuteSwitch, LV_STATE_CHECKED);
}
if (outputVolumeSlider) {
lvgl::sliderbox_set_value(outputVolumeSlider, static_cast<int32_t>(service::audio::getOutputVolume()), LV_ANIM_OFF);
lvgl_sliderbox_set_value(outputVolumeSlider, static_cast<int32_t>(service::audio::getOutputVolume()), LV_ANIM_OFF);
}
}
};
+1 -1
View File
@@ -7,8 +7,8 @@
#include <Tactility/app/AppManifest.h>
#include <Tactility/lvgl/LvglSync.h>
#include <lvgl/icons/shared.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
namespace tt::app::btmanage {
+2 -2
View File
@@ -222,9 +222,9 @@ void View::init(const AppContext& app, lv_obj_t* parent) {
// Toolbar
auto* toolbar = lvgl::toolbar_create(parent, app);
scanning_spinner = lvgl::toolbar_add_spinner_action(toolbar);
scanning_spinner = lvgl_toolbar_add_spinner_action(toolbar);
enable_switch = lvgl::toolbar_add_switch_action(toolbar);
enable_switch = lvgl_toolbar_add_switch_action(toolbar);
lv_obj_add_event_cb(enable_switch, onEnableSwitchChanged, LV_EVENT_VALUE_CHANGED, nullptr);
// Peer list
@@ -11,7 +11,7 @@
#include <Tactility/bluetooth/BluetoothPairedDevice.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/lvgl/Style.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/widgets/toolbar.h>
#include <tactility/check.h>
#include <tactility/drivers/bluetooth.h>
#include <tactility/log.h>
@@ -138,7 +138,7 @@ public:
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
lvgl::toolbar_create(parent, title);
lvgl_toolbar_create(parent, title.c_str());
auto* wrapper = lv_obj_create(parent);
lv_obj_set_width(wrapper, LV_PCT(100));
+1 -1
View File
@@ -10,11 +10,11 @@
#include <Tactility/app/AppManifest.h>
#include <Tactility/lvgl/LvglSync.h>
#include <lvgl/icons/shared.h>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
#include <vector>
namespace tt::app::chat {
+3 -3
View File
@@ -34,7 +34,7 @@ void ChatView::updateToolbarTitle() {
if (!state || !toolbar) return;
std::string channel = state->getCurrentChannel();
std::string title = "Chat: " + channel;
lvgl::toolbar_set_title(toolbar, title);
lvgl_toolbar_set_title(toolbar, title.c_str());
}
void ChatView::createInputBar(lv_obj_t* parent) {
@@ -149,8 +149,8 @@ void ChatView::init(AppContext& appContext, lv_obj_t* parent) {
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
toolbar = lvgl::toolbar_create(parent, appContext);
lvgl::toolbar_add_text_button_action(toolbar, LV_SYMBOL_LIST, onChannelClicked, this);
lvgl::toolbar_add_text_button_action(toolbar, LV_SYMBOL_SETTINGS, onSettingsClicked, this);
lvgl_toolbar_add_text_button_action(toolbar, LV_SYMBOL_LIST, onChannelClicked, this);
lvgl_toolbar_add_text_button_action(toolbar, LV_SYMBOL_SETTINGS, onSettingsClicked, this);
updateToolbarTitle();
// Message list
@@ -11,9 +11,9 @@
#include <Tactility/service/loader/Loader.h>
#include <Tactility/service/wifi/Wifi.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl/lvgl.h>
#include <tactility/log.h>
#include <cstring>
#include <lvgl.h>
@@ -98,7 +98,7 @@ public:
lv_obj_t* toolbar = lvgl::toolbar_create(parent, app);
enableSwitch = lvgl::toolbar_add_switch_action(toolbar);
enableSwitch = lvgl_toolbar_add_switch_action(toolbar);
lv_obj_add_event_cb(enableSwitch, onEnableSwitchChanged, LV_EVENT_VALUE_CHANGED, this);
if (service->isEnabled()) {
+4 -4
View File
@@ -523,10 +523,10 @@ void View::init(const AppContext& appContext, lv_obj_t* parent) {
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
auto* toolbar = lvgl::toolbar_create(parent, appContext);
navigate_up_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_UP, &onNavigateUpPressedCallback, this);
new_file_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_FILE, &onNewFilePressedCallback, this);
new_folder_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_DIRECTORY, &onNewFolderPressedCallback, this);
paste_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_PASTE, &onPastePressedCallback, this);
navigate_up_button = lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_UP, &onNavigateUpPressedCallback, this);
new_file_button = lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_FILE, &onNewFilePressedCallback, this);
new_folder_button = lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_DIRECTORY, &onNewFolderPressedCallback, this);
paste_button = lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_PASTE, &onPastePressedCallback, this);
lv_obj_add_flag(lv_obj_get_parent(paste_button), LV_OBJ_FLAG_HIDDEN);
auto* wrapper = lv_obj_create(parent);
+3 -3
View File
@@ -7,7 +7,7 @@
#include <Tactility/file/File.h>
#include <Tactility/Platform.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/widgets/toolbar.h>
#include <tactility/check.h>
#include <tactility/log.h>
@@ -181,8 +181,8 @@ void View::init(lv_obj_t* parent, Mode mode) {
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
auto* toolbar = lvgl::toolbar_create(parent, "Select File");
navigate_up_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_UP, &onNavigateUpPressedCallback, this);
auto* toolbar = lvgl_toolbar_create(parent, "Select File");
navigate_up_button = lvgl_toolbar_add_image_button_action(toolbar, LV_SYMBOL_UP, &onNavigateUpPressedCallback, this);
auto* wrapper = lv_obj_create(parent);
lv_obj_set_width(wrapper, LV_PCT(100));
@@ -1,5 +1,5 @@
#include <lvgl/icons/shared.h>
#include <lvgl/lvgl.h>
#include <lvgl/lvgl_icon_shared.h>
#include <Tactility/Tactility.h>
#include <Tactility/Timer.h>
@@ -223,7 +223,7 @@ public:
uint8_t margin = (lvgl_get_ui_density() == LVGL_UI_DENSITY_COMPACT) ? 2 : 8;
auto* toolbar = lvgl::toolbar_create(parent, app);
lvgl::toolbar_add_text_button_action(toolbar, LV_SYMBOL_PLUS, onAddGpsCallback, this);
lvgl_toolbar_add_text_button_action(toolbar, LV_SYMBOL_PLUS, onAddGpsCallback, this);
lv_obj_set_style_margin_bottom(toolbar, margin, LV_STATE_DEFAULT);
deviceListWrapper = lv_obj_create(parent);
@@ -2,9 +2,9 @@
#include <lvgl.h>
#include <lvgl/icons/shared.h>
#include <tactility/device.h>
#include <tactility/drivers/grove.h>
#include <lvgl/lvgl_icon_shared.h>
#include <Tactility/Tactility.h>
#include <Tactility/lvgl/Toolbar.h>
@@ -13,8 +13,8 @@
#include <format>
#include <lvgl/icons/shared.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
namespace tt::app::i2cscanner {
@@ -1,6 +1,6 @@
#include <Tactility/app/inputdialog/InputDialog.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/widgets/toolbar.h>
#include <Tactility/service/loader/Loader.h>
#include <Tactility/TactilityCore.h>
#include <tactility/log.h>
@@ -83,7 +83,7 @@ public:
check(parameters != nullptr, "Parameters missing");
std::string title = getTitleParameter(app.getParameters());
auto* toolbar = lvgl::toolbar_create(parent, title);
auto* toolbar = lvgl_toolbar_create(parent, title.c_str());
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
auto* message_label = lv_label_create(parent);
@@ -1,10 +1,10 @@
#include <tactility/drivers/display.h>
#include <tactility/error.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl/lvgl.h>
#include <tactility/device.h>
#include <tactility/drivers/backlight.h>
#include <tactility/drivers/display.h>
#include <tactility/error.h>
#include <tactility/log.h>
#include <lvgl/lvgl.h>
#include <Tactility/Tactility.h>
#ifdef ESP_PLATFORM
@@ -5,9 +5,9 @@
#include <Tactility/settings/KeyboardSettings.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/icons/shared.h>
#include <tactility/device.h>
#include <tactility/drivers/backlight.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl.h>
+3 -3
View File
@@ -10,12 +10,12 @@
#include <cstring>
#include <lvgl.h>
#include <lvgl/icons/launcher.h>
#include <lvgl/fonts.h>
#include <lvgl/lvgl.h>
#include <tactility/device.h>
#include <tactility/drivers/power_supply.h>
#include <tactility/log.h>
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl_icon_launcher.h>
#include <lvgl/lvgl.h>
namespace tt::app::launcher {
@@ -8,7 +8,7 @@
#include <Tactility/settings/Language.h>
#include <Tactility/settings/SystemSettings.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl.h>
#include <map>
+1 -1
View File
@@ -7,9 +7,9 @@
#include <Tactility/file/File.h>
#include <lvgl/icons/shared.h>
#include <lvgl.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
namespace tt::app::notes {
+1 -1
View File
@@ -6,9 +6,9 @@
#include <Tactility/Timer.h>
#include <lvgl/icons/shared.h>
#include <tactility/device.h>
#include <tactility/drivers/power_supply.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl.h>
+2 -2
View File
@@ -6,11 +6,11 @@
#include <Tactility/app/AppRegistration.h>
#include <Tactility/service/loader/Loader.h>
#include <lvgl/icons/shared.h>
#include <lvgl.h>
#include <lvgl/fonts.h>
#include <tactility/device.h>
#include <tactility/drivers/power_supply.h>
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl_icon_shared.h>
namespace tt::app::poweroff {
@@ -14,8 +14,8 @@
#include <Tactility/Paths.h>
#include <Tactility/Timer.h>
#include <lvgl/icons/shared.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
namespace tt::app::screenshot {
@@ -1,6 +1,6 @@
#include <Tactility/app/selectiondialog/SelectionDialog.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/widgets/toolbar.h>
#include <Tactility/service/loader/Loader.h>
#include <Tactility/StringUtils.h>
#include <tactility/log.h>
@@ -73,7 +73,7 @@ public:
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
std::string title = getTitleParameter(app.getParameters());
lvgl::toolbar_create(parent, title);
lvgl_toolbar_create(parent, title.c_str());
auto* list = lv_list_create(parent);
lv_obj_set_width(list, LV_PCT(100));
+2 -2
View File
@@ -2,9 +2,9 @@
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/service/loader/Loader.h>
#include <lvgl/icons/shared.h>
#include <lvgl/fonts.h>
#include <tactility/check.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/lvgl_fonts.h>
#include <lvgl.h>
+1 -1
View File
@@ -1,4 +1,4 @@
#include <lvgl/lvgl_fonts.h>
#include <lvgl/fonts.h>
#include <lvgl/lvgl.h>
#include <Tactility/app/App.h>
@@ -11,8 +11,8 @@
#include <lvgl.h>
#include <utility>
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl/fonts.h>
#include <lvgl/lvgl.h>
#ifdef ESP_PLATFORM
@@ -12,8 +12,8 @@
#include <lvgl.h>
#include <lvgl/icons/shared.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
namespace tt::app::timedatesettings {
+2 -2
View File
@@ -1,5 +1,5 @@
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl/fonts.h>
#include <Tactility/app/AppContext.h>
#include <Tactility/app/AppManifest.h>
@@ -7,7 +7,7 @@
#include <tactility/log.h>
#include <lvgl/lvgl.h>
#include <lvgl/lvgl_pointer.h>
#include <lvgl/devices/pointer.h>
#include <algorithm>
#include <lvgl.h>
@@ -2,7 +2,7 @@
#include <lvgl.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#include <lvgl/lvgl.h>
#include <Tactility/Tactility.h>
@@ -117,7 +117,7 @@ public:
lv_obj_t* toolbar = lvgl::toolbar_create(parent, app);
switchTrackball = lvgl::toolbar_add_switch_action(toolbar);
switchTrackball = lvgl_toolbar_add_switch_action(toolbar);
lv_obj_add_event_cb(switchTrackball, onTrackballSwitch, LV_EVENT_VALUE_CHANGED, this);
if (tbSettings.trackballEnabled) lv_obj_add_state(switchTrackball, LV_STATE_CHECKED);
@@ -5,7 +5,7 @@
#include <lvgl.h>
#include <lvgl/lvgl_icon_shared.h>
#include <lvgl/icons/shared.h>
#define TAG "usb_settings"
@@ -10,9 +10,9 @@
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/lvgl/LvglSync.h>
#include <lvgl/icons/shared.h>
#include <lvgl.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
#include <esp_netif.h>
#include <esp_wifi.h>
@@ -192,7 +192,7 @@ public:
lv_obj_t* toolbar = lvgl::toolbar_create(parent, app);
// Web Server Enable toggle
switchWebServerEnabled = lvgl::toolbar_add_switch_action(toolbar);
switchWebServerEnabled = lvgl_toolbar_add_switch_action(toolbar);
if (wsSettings.webServerEnabled) {
lv_obj_add_state(switchWebServerEnabled, LV_STATE_CHECKED);
}
@@ -6,7 +6,7 @@
#include <Tactility/app/AppManifest.h>
#include <Tactility/app/alertdialog/AlertDialog.h>
#include <Tactility/lvgl/Style.h>
#include <Tactility/lvgl/Toolbar.h>
#include <lvgl/widgets/toolbar.h>
#include <Tactility/service/wifi/Wifi.h>
#include <Tactility/service/wifi/WifiApSettings.h>
@@ -138,8 +138,8 @@ public:
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
auto* toolbar = lvgl::toolbar_create(parent, ssid);
busySpinner = lvgl::toolbar_add_spinner_action(toolbar);
auto* toolbar = lvgl_toolbar_create(parent, ssid.c_str());
busySpinner = lvgl_toolbar_add_spinner_action(toolbar);
auto* wrapper = lv_obj_create(parent);
lv_obj_set_width(wrapper, LV_PCT(100));
+2 -2
View File
@@ -3,7 +3,7 @@
#include <Tactility/app/wificonnect/View.h>
#include <Tactility/app/wificonnect/WifiConnect.h>
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/lvgl/Spinner.h>
#include <lvgl/widgets/spinner.h>
#include <Tactility/service/wifi/WifiApSettings.h>
#include <Tactility/service/wifi/WifiGlobals.h>
@@ -98,7 +98,7 @@ void View::createBottomButtons(lv_obj_t* parent) {
lv_obj_align(remember_label, LV_ALIGN_CENTER, 0, 0);
lv_obj_align_to(remember_label, remember_switch, LV_ALIGN_OUT_RIGHT_MID, 4, 0);
connecting_spinner = tt::lvgl::spinner_create(button_container);
connecting_spinner = lvgl_spinner_create(button_container);
lv_obj_align(connecting_spinner, LV_ALIGN_RIGHT_MID, 0, 0);
lv_obj_add_flag(connecting_spinner, LV_OBJ_FLAG_HIDDEN);
+2 -2
View File
@@ -302,9 +302,9 @@ void View::init(const AppContext& app, lv_obj_t* parent) {
lv_obj_t* toolbar = lvgl::toolbar_create(parent, app);
scanning_spinner = lvgl::toolbar_add_spinner_action(toolbar);
scanning_spinner = lvgl_toolbar_add_spinner_action(toolbar);
enable_switch = lvgl::toolbar_add_switch_action(toolbar);
enable_switch = lvgl_toolbar_add_switch_action(toolbar);
lv_obj_add_event_cb(enable_switch, onEnableSwitchChanged, LV_EVENT_VALUE_CHANGED, bindings);
// Networks
@@ -8,8 +8,8 @@
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/service/loader/Loader.h>
#include <lvgl/icons/shared.h>
#include <tactility/log.h>
#include <lvgl/lvgl_icon_shared.h>
namespace tt::app::wifimanage {
-207
View File
@@ -1,207 +0,0 @@
#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration
#include <Tactility/lvgl/SliderBox.h>
#include <lvgl/lvgl_fonts.h>
namespace tt::lvgl {
typedef struct {
lv_obj_t obj;
lv_obj_t* minusButton;
lv_obj_t* slider;
lv_obj_t* valueLabel;
lv_obj_t* plusButton;
int32_t min;
int32_t max;
int32_t step;
} SliderBox;
static void sliderbox_constructor(const lv_obj_class_t* classPointer, lv_obj_t* obj);
static lv_obj_class_t sliderbox_class = {
.base_class = &lv_obj_class,
.constructor_cb = &sliderbox_constructor,
.destructor_cb = nullptr,
.event_cb = nullptr,
.user_data = nullptr,
.name = "tt_sliderbox",
.width_def = LV_PCT(100),
.height_def = LV_SIZE_CONTENT,
.editable = false,
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
.instance_size = sizeof(SliderBox),
.theme_inheritable = false
};
static void sliderbox_constructor(const lv_obj_class_t* classPointer, lv_obj_t* obj) {
LV_UNUSED(classPointer);
lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_all(obj, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_column(obj, 4, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(obj, 0, LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(obj, 0, LV_STATE_DEFAULT);
}
static void update_value_label(SliderBox* sliderBox) {
auto value = lv_slider_get_value(sliderBox->slider);
lv_label_set_text_fmt(sliderBox->valueLabel, "%" LV_PRId32, value);
}
static void update_button_states(SliderBox* sliderBox) {
auto value = lv_slider_get_value(sliderBox->slider);
if (value <= sliderBox->min) {
lv_obj_add_state(sliderBox->minusButton, LV_STATE_DISABLED);
} else {
lv_obj_remove_state(sliderBox->minusButton, LV_STATE_DISABLED);
}
if (value >= sliderBox->max) {
lv_obj_add_state(sliderBox->plusButton, LV_STATE_DISABLED);
} else {
lv_obj_remove_state(sliderBox->plusButton, LV_STATE_DISABLED);
}
}
static void notify_value_changed(lv_obj_t* obj) {
lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, nullptr);
}
static void on_slider_value_changed(lv_event_t* event) {
auto* obj = static_cast<lv_obj_t*>(lv_event_get_user_data(event));
auto* sliderBox = reinterpret_cast<SliderBox*>(obj);
auto raw_value = lv_slider_get_value(sliderBox->slider);
auto steps_from_min = (raw_value - sliderBox->min + sliderBox->step / 2) / sliderBox->step;
auto snapped_value = sliderBox->min + steps_from_min * sliderBox->step;
if (snapped_value > sliderBox->max) {
snapped_value = sliderBox->max;
}
if (snapped_value != raw_value) {
lv_slider_set_value(sliderBox->slider, snapped_value, LV_ANIM_OFF);
}
update_value_label(sliderBox);
update_button_states(sliderBox);
notify_value_changed(obj);
}
static void on_step_button_clicked(lv_event_t* event, int32_t direction) {
auto* obj = static_cast<lv_obj_t*>(lv_event_get_user_data(event));
auto* sliderBox = reinterpret_cast<SliderBox*>(obj);
auto value = lv_slider_get_value(sliderBox->slider);
auto new_value = value + direction * sliderBox->step;
if (new_value < sliderBox->min) {
new_value = sliderBox->min;
} else if (new_value > sliderBox->max) {
new_value = sliderBox->max;
}
if (new_value != value) {
lv_slider_set_value(sliderBox->slider, new_value, LV_ANIM_ON);
update_value_label(sliderBox);
notify_value_changed(obj);
}
update_button_states(sliderBox);
}
static void on_minus_button_clicked(lv_event_t* event) {
on_step_button_clicked(event, -1);
}
static void on_plus_button_clicked(lv_event_t* event) {
on_step_button_clicked(event, 1);
}
static lv_obj_t* create_step_button(lv_obj_t* parent, const char* symbol, lv_event_cb_t callback, void* userData, uint32_t size) {
auto* button = lv_button_create(parent);
lv_obj_remove_flag(button, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(button, size, size);
lv_obj_set_style_pad_all(button, 0, LV_STATE_DEFAULT);
lv_obj_add_event_cb(button, callback, LV_EVENT_SHORT_CLICKED, userData);
auto* label = lv_label_create(button);
lv_label_set_text(label, symbol);
lv_obj_center(label);
return button;
}
lv_obj_t* sliderbox_create(lv_obj_t* parent, int32_t min, int32_t max, int32_t step, int32_t value) {
if (max <= min) {
max = min + 1;
}
if (step <= 0) {
step = 1;
}
lv_obj_t* obj = lv_obj_class_create_obj(&sliderbox_class, parent);
lv_obj_class_init_obj(obj);
auto* sliderBox = reinterpret_cast<SliderBox*>(obj);
sliderBox->min = min;
sliderBox->max = max;
sliderBox->step = step;
auto button_size = lvgl_get_text_font_height(FONT_SIZE_DEFAULT) + 8;
sliderBox->minusButton = create_step_button(obj, LV_SYMBOL_MINUS, &on_minus_button_clicked, obj, button_size);
sliderBox->slider = lv_slider_create(obj);
lv_obj_remove_flag(sliderBox->slider, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_flex_grow(sliderBox->slider, 1);
lv_slider_set_range(sliderBox->slider, min, max);
lv_obj_add_event_cb(sliderBox->slider, &on_slider_value_changed, LV_EVENT_VALUE_CHANGED, obj);
sliderBox->valueLabel = lv_label_create(obj);
lv_obj_set_style_text_align(sliderBox->valueLabel, LV_TEXT_ALIGN_RIGHT, LV_STATE_DEFAULT);
lv_label_set_long_mode(sliderBox->valueLabel, LV_LABEL_LONG_MODE_CLIP);
// Reserve enough width for the largest value so the layout doesn't jump around.
// +4 padding wasn't enough margin for 3-digit values to never wrap; widened to
// a flat per-character estimate instead of trusting raw glyph width too tightly.
char buffer[16];
lv_snprintf(buffer, sizeof(buffer), "%" LV_PRId32, min);
auto width_min = lv_text_get_width(buffer, lv_strlen(buffer), lv_obj_get_style_text_font(sliderBox->valueLabel, LV_PART_MAIN), 0);
lv_snprintf(buffer, sizeof(buffer), "%" LV_PRId32, max);
auto width_max = lv_text_get_width(buffer, lv_strlen(buffer), lv_obj_get_style_text_font(sliderBox->valueLabel, LV_PART_MAIN), 0);
auto max_width = (width_min > width_max) ? width_min : width_max;
lv_obj_set_width(sliderBox->valueLabel, max_width + 8);
sliderBox->plusButton = create_step_button(obj, LV_SYMBOL_PLUS, &on_plus_button_clicked, obj, button_size);
sliderbox_set_value(obj, value, LV_ANIM_OFF);
return obj;
}
int32_t sliderbox_get_value(lv_obj_t* obj) {
auto* sliderBox = reinterpret_cast<SliderBox*>(obj);
return lv_slider_get_value(sliderBox->slider);
}
void sliderbox_set_value(lv_obj_t* obj, int32_t value, lv_anim_enable_t anim) {
auto* sliderBox = reinterpret_cast<SliderBox*>(obj);
if (value < sliderBox->min) {
value = sliderBox->min;
} else if (value > sliderBox->max) {
value = sliderBox->max;
}
lv_slider_set_value(sliderBox->slider, value, anim);
update_value_label(sliderBox);
update_button_states(sliderBox);
}
void sliderbox_add_value_changed_cb(lv_obj_t* obj, lv_event_cb_t callback, void* userData) {
lv_obj_add_event_cb(obj, callback, LV_EVENT_VALUE_CHANGED, userData);
}
} // namespace tt::lvgl
-58
View File
@@ -1,58 +0,0 @@
#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration
#include <Tactility/Assets.h>
#include <Tactility/CoreDefines.h>
#include <lvgl.h>
namespace tt::lvgl {
static void spinner_constructor(const lv_obj_class_t* object_class, lv_obj_t* object);
const lv_obj_class_t tt_spinner_class = {
.base_class = &lv_image_class,
.constructor_cb = spinner_constructor,
.destructor_cb = nullptr,
.event_cb = nullptr,
.user_data = nullptr,
.name = "tt_spinner",
.width_def = 0,
.height_def = 0,
.editable = 0,
.group_def = 0,
.instance_size = 0,
.theme_inheritable = 0
};
lv_obj_t* spinner_create(lv_obj_t* parent) {
lv_obj_t* obj = lv_obj_class_create_obj(&tt_spinner_class, parent);
lv_obj_class_init_obj(obj);
lv_image_set_src(obj, TT_ASSETS_UI_SPINNER);
return obj;
}
static void anim_rotation_callback(void* var, int32_t v) {
auto* object = (lv_obj_t*) var;
auto width = lv_obj_get_width(object);
auto height = lv_obj_get_width(object);
lv_obj_set_style_transform_pivot_x(object, width / 2, 0);
lv_obj_set_style_transform_pivot_y(object, height / 2, 0);
lv_obj_set_style_transform_rotation(object, v, 0);
}
static void spinner_constructor(const lv_obj_class_t* object_class, lv_obj_t* object) {
lv_obj_remove_flag(object, LV_OBJ_FLAG_CLICKABLE);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, object);
lv_anim_set_values(&a, 0, 3600);
lv_anim_set_duration(&a, 800);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_exec_cb(&a, anim_rotation_callback);
lv_anim_start(&a);
}
}
+2 -2
View File
@@ -10,10 +10,10 @@
#include <Tactility/lvgl/Style.h>
#include <Tactility/settings/Time.h>
#include <lvgl/fonts.h>
#include <lvgl/lvgl.h>
#include <tactility/check.h>
#include <tactility/log.h>
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl.h>
#include <lvgl.h>
#include <memory>
+2 -251
View File
@@ -1,259 +1,10 @@
#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration
#include <Tactility/Tactility.h>
#include <Tactility/lvgl/Toolbar.h>
#include "tactility/drivers/pointer.h"
#include <Tactility/lvgl/Spinner.h>
#include <Tactility/service/loader/Loader.h>
#include <tactility/check.h>
#include <lvgl/lvgl_fonts.h>
#include <lvgl/lvgl.h>
#include <Tactility/app/AppManifest.h>
namespace tt::lvgl {
static uint32_t getToolbarHeight(UiDensity uiDensity) {
if (uiDensity == LVGL_UI_DENSITY_COMPACT) {
return lvgl_get_text_font_height(FONT_SIZE_DEFAULT) * 1.4f;
} else {
return lvgl_get_text_font_height(FONT_SIZE_LARGE) * 2.2f;
}
}
static const _lv_font_t* getToolbarFont(UiDensity uiDensity) {
if (uiDensity == LVGL_UI_DENSITY_COMPACT) {
return lvgl_get_text_font(FONT_SIZE_DEFAULT);
} else {
return lvgl_get_text_font(FONT_SIZE_LARGE);
}
}
static uint32_t getActionIconPadding(UiDensity uiDensity) {
auto toolbar_height = getToolbarHeight(uiDensity);
// Minimal 8 pixels total padding for selection/animation (4+4 pixels)
return (uiDensity != LVGL_UI_DENSITY_COMPACT) ? (uint32_t)(toolbar_height * 0.2f) : 8;
}
/**
* Helps with button expansion and also with vertical alignment of content,
* as the parent flex doesn't allow for vertical alignment
*/
static lv_obj_t* create_action_wrapper(lv_obj_t* parent, UiDensity ui_density) {
auto* wrapper = lv_obj_create(parent);
auto toolbar_height = getToolbarHeight(ui_density);
lv_obj_set_size(wrapper, LV_SIZE_CONTENT, toolbar_height);
auto icon_padding = getActionIconPadding(ui_density);
auto icon_padding_half = icon_padding / 2;
lv_obj_set_style_pad_all(wrapper, icon_padding_half, LV_STATE_DEFAULT); // For selection and touch animation
lv_obj_set_style_bg_opa(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_opa(wrapper, 0, LV_STATE_DEFAULT);
return wrapper;
}
typedef struct {
lv_obj_t obj;
lv_obj_t* title_label;
lv_obj_t* close_button;
lv_obj_t* close_button_image;
lv_obj_t* action_container;
uint8_t action_count;
} Toolbar;
static void toolbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj);
static lv_obj_class_t toolbar_class = {
.base_class = &lv_obj_class,
.constructor_cb = &toolbar_constructor,
.destructor_cb = nullptr,
.event_cb = nullptr,
.user_data = nullptr,
.name = nullptr,
.width_def = LV_PCT(100),
.height_def = 0,
.editable = false,
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
.instance_size = sizeof(Toolbar),
.theme_inheritable = false
};
static void stop_app(lv_event_t* event) {
app::stop();
}
static void toolbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) {
LV_UNUSED(class_p);
lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
}
lv_obj_t* toolbar_create(lv_obj_t* parent, const std::string& title) {
auto ui_density = lvgl_get_ui_density();
auto toolbar_height = getToolbarHeight(ui_density);
toolbar_class.height_def = toolbar_height;
lv_obj_t* obj = lv_obj_class_create_obj(&toolbar_class, parent);
lv_obj_class_init_obj(obj);
lv_obj_set_height(obj, toolbar_height);
auto* toolbar = reinterpret_cast<Toolbar*>(obj);
lv_obj_set_width(obj, LV_PCT(100));
lv_obj_set_style_pad_all(obj, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_column(obj, 0, LV_STATE_DEFAULT);
lv_obj_center(obj);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
auto icon_padding = getActionIconPadding(ui_density);
auto* close_button_wrapper = create_action_wrapper(obj, ui_density);
toolbar->close_button = lv_button_create(close_button_wrapper);
if (ui_density == LVGL_UI_DENSITY_COMPACT) {
lv_obj_set_style_bg_opa(toolbar->close_button, LV_OPA_TRANSP, LV_STATE_DEFAULT);
}
lv_obj_set_size(toolbar->close_button, toolbar_height - icon_padding, toolbar_height - icon_padding);
lv_obj_set_style_pad_all(toolbar->close_button, 0, LV_STATE_DEFAULT);
lv_obj_align(toolbar->close_button, LV_ALIGN_CENTER, 0, 0);
toolbar->close_button_image = lv_image_create(toolbar->close_button);
lv_obj_align(toolbar->close_button_image, LV_ALIGN_CENTER, 0, 0);
auto* title_wrapper = lv_obj_create(obj);
uint32_t title_left_padding = (ui_density != LVGL_UI_DENSITY_COMPACT) ? icon_padding : 2;
uint32_t title_right_padding = (ui_density != LVGL_UI_DENSITY_COMPACT) ? (icon_padding / 2) : 2;
lv_obj_set_size(title_wrapper, LV_SIZE_CONTENT, LV_PCT(100));
lv_obj_set_style_bg_opa(title_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(title_wrapper, title_left_padding, LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(title_wrapper, title_right_padding, LV_STATE_DEFAULT);
lv_obj_set_style_pad_ver(title_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(title_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_flex_grow(title_wrapper, 1);
toolbar->title_label = lv_label_create(title_wrapper);
lv_obj_set_style_text_font(toolbar->title_label, getToolbarFont(ui_density), LV_STATE_DEFAULT);
lv_label_set_text(toolbar->title_label, title.c_str());
lv_label_set_long_mode(toolbar->title_label, LV_LABEL_LONG_MODE_SCROLL);
lv_obj_set_style_text_align(toolbar->title_label, LV_TEXT_ALIGN_LEFT, LV_STATE_DEFAULT);
lv_obj_align(toolbar->title_label, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_set_width(toolbar->title_label, LV_PCT(100));
toolbar->action_container = lv_obj_create(obj);
lv_obj_set_width(toolbar->action_container, LV_SIZE_CONTENT);
lv_obj_set_flex_flow(toolbar->action_container, LV_FLEX_FLOW_ROW);
lv_obj_set_style_pad_all(toolbar->action_container, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_column(toolbar->action_container, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(toolbar->action_container, 0, LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(toolbar->action_container, 0, LV_STATE_DEFAULT);
toolbar_set_nav_action(obj, LV_SYMBOL_CLOSE, &stop_app, nullptr);
// If we don't have a touch device, we assume there's some other kind of input like a keyboard, an encoder or button control
// In that scenario we want to automatically have the close button selected so the user doesn't have to press the widget selection
// an extra time for every screen.
if (!device_has_active_by_type(&POINTER_TYPE)) {
lv_group_focus_obj(toolbar->close_button);
}
return obj;
}
lv_obj_t* toolbar_create(lv_obj_t* parent, const app::AppContext& app) {
return toolbar_create(parent, app.getManifest().appName);
}
void toolbar_set_title(lv_obj_t* obj, const std::string& title) {
auto* toolbar = reinterpret_cast<Toolbar*>(obj);
lv_label_set_text(toolbar->title_label, title.c_str());
}
void toolbar_set_nav_action(lv_obj_t* obj, const char* icon, lv_event_cb_t callback, void* user_data) {
auto* toolbar = reinterpret_cast<Toolbar*>(obj);
lv_obj_add_event_cb(toolbar->close_button, callback, LV_EVENT_SHORT_CLICKED, user_data);
lv_image_set_src(toolbar->close_button_image, icon); // e.g. LV_SYMBOL_CLOSE
}
lv_obj_t* toolbar_add_button_action(lv_obj_t* obj, const char* imageOrButton, bool isImage, lv_event_cb_t callback, void* user_data) {
auto* toolbar = reinterpret_cast<Toolbar*>(obj);
check(toolbar->action_count < TOOLBAR_ACTION_LIMIT, "max actions reached");
toolbar->action_count++;
auto ui_density = lvgl_get_ui_density();
auto toolbar_height = getToolbarHeight(ui_density);
auto* wrapper = create_action_wrapper(toolbar->action_container, ui_density);
auto padding = getActionIconPadding(ui_density);
lv_obj_t* action_button = lv_button_create(wrapper);
lv_obj_set_size(action_button, toolbar_height - padding, toolbar_height - padding);
lv_obj_set_style_pad_all(action_button, 0, LV_STATE_DEFAULT);
lv_obj_align(action_button, LV_ALIGN_CENTER, 0, 0);
if (ui_density == LVGL_UI_DENSITY_COMPACT) {
lv_obj_set_style_bg_opa(action_button, LV_OPA_TRANSP, LV_STATE_DEFAULT);
}
lv_obj_add_event_cb(action_button, callback, LV_EVENT_SHORT_CLICKED, user_data);
lv_obj_t* button_content;
if (isImage) {
button_content = lv_image_create(action_button);
lv_image_set_src(button_content, imageOrButton);
} else {
button_content = lv_label_create(action_button);
lv_label_set_text(button_content, imageOrButton);
}
lv_obj_align(button_content, LV_ALIGN_CENTER, 0, 0);
return action_button;
}
lv_obj_t* toolbar_add_image_button_action(lv_obj_t* obj, const char* imagePath, lv_event_cb_t callback, void* user_data) {
return toolbar_add_button_action(obj, imagePath, true, callback, user_data);
}
lv_obj_t* toolbar_add_text_button_action(lv_obj_t* obj, const char* text, lv_event_cb_t callback, void* user_data) {
return toolbar_add_button_action(obj, text, false, callback, user_data);
}
lv_obj_t* toolbar_add_switch_action(lv_obj_t* obj) {
auto* toolbar = reinterpret_cast<Toolbar*>(obj);
auto ui_density = lvgl_get_ui_density();
auto* wrapper = create_action_wrapper(toolbar->action_container, ui_density);
lv_obj_set_style_pad_hor(wrapper, 4, LV_STATE_DEFAULT);
lv_obj_t* widget = lv_switch_create(wrapper);
lv_obj_set_align(widget, LV_ALIGN_CENTER);
return widget;
}
lv_obj_t* toolbar_add_spinner_action(lv_obj_t* obj) {
auto* toolbar = reinterpret_cast<Toolbar*>(obj);
auto ui_density = lvgl_get_ui_density();
auto* wrapper = create_action_wrapper(toolbar->action_container, ui_density);
auto* spinner = spinner_create(wrapper);
lv_obj_set_align(spinner, LV_ALIGN_CENTER);
if (lv_display_get_color_format(lv_obj_get_display(obj)) == LV_COLOR_FORMAT_L8) {
lv_obj_set_style_image_recolor(spinner, lv_theme_get_color_secondary(obj), LV_STATE_DEFAULT);
lv_obj_set_style_image_recolor_opa(spinner, LV_OPA_COVER, LV_STATE_DEFAULT);
}
return spinner;
}
void toolbar_clear_actions(lv_obj_t* obj) {
auto* toolbar = reinterpret_cast<Toolbar*>(obj);
lv_obj_clean(toolbar->action_container);
toolbar->action_count = 0;
return lvgl_toolbar_create(parent, app.getManifest().appName.c_str());
}
} // namespace
@@ -3,7 +3,7 @@
#include <Tactility/service/ServiceManifest.h>
#include <Tactility/service/memorychecker/MemoryCheckerService.h>
#include <lvgl/lvgl_icon_statusbar.h>
#include <lvgl/icons/statusbar.h>
#include <tactility/log.h>
namespace tt::service::memorychecker {
@@ -21,8 +21,8 @@
#include <tactility/log.h>
#include <lvgl/icons/statusbar.h>
#include <lvgl/lvgl.h>
#include <lvgl/lvgl_icon_statusbar.h>
#include <cstring>
@@ -30,7 +30,7 @@
#include <lv_screenshot.h>
#endif
#include <lvgl/lvgl_icon_statusbar.h>
#include <lvgl/icons/statusbar.h>
#include <atomic>
#include <cctype>