diff --git a/Boards/M5stackCardputer/Source/M5stackCardputer.cpp b/Boards/M5stackCardputer/Source/M5stackCardputer.cpp index e22fe4bb..9b8137a0 100644 --- a/Boards/M5stackCardputer/Source/M5stackCardputer.cpp +++ b/Boards/M5stackCardputer/Source/M5stackCardputer.cpp @@ -25,7 +25,27 @@ static DeviceVector createDevices() { extern const Configuration m5stack_cardputer = { .initBoot = initBoot, + .uiScale = UiScale::Smallest, .createDevices = createDevices, + .i2c { + i2c::Configuration { + .name = "Port A", // Grove + .port = I2C_NUM_1, + .initMode = i2c::InitMode::Disabled, + .isMutable = true, + .config = (i2c_config_t) { + .mode = I2C_MODE_MASTER, + .sda_io_num = GPIO_NUM_2, + .scl_io_num = GPIO_NUM_1, + .sda_pullup_en = true, + .scl_pullup_en = true, + .master = { + .clk_speed = 400000 + }, + .clk_flags = 0 + } + }, + }, .spi { // Display spi::Configuration { @@ -79,10 +99,10 @@ extern const Configuration m5stack_cardputer = { }, .uart { uart::Configuration { - .name = "Grove", + .name = "Port A", .port = UART_NUM_1, - .rxPin = GPIO_NUM_32, - .txPin = GPIO_NUM_33, + .rxPin = GPIO_NUM_2, + .txPin = GPIO_NUM_1, .rtsPin = GPIO_NUM_NC, .ctsPin = GPIO_NUM_NC, .rxBufferSize = 1024, @@ -100,6 +120,6 @@ extern const Configuration m5stack_cardputer = { .backup_before_sleep = 0, } } - }, + } } }; diff --git a/Boards/Simulator/Source/Simulator.cpp b/Boards/Simulator/Source/Simulator.cpp index 4d942381..51d92241 100644 --- a/Boards/Simulator/Source/Simulator.cpp +++ b/Boards/Simulator/Source/Simulator.cpp @@ -28,12 +28,18 @@ TT_UNUSED static void deinitPower() { #endif } +static std::vector> createDevices() { + return { + std::make_shared(), + std::make_shared(), + std::make_shared(), + std::make_shared() + }; +} + extern const Configuration hardware = { .initBoot = initBoot, - .createDisplay = createDisplay, - .createKeyboard = createKeyboard, - .sdcard = std::make_shared(), - .power = simulatorPower, + .createDevices = createDevices, .i2c = { i2c::Configuration { .name = "Internal", diff --git a/Boards/Simulator/Source/hal/SdlDisplay.h b/Boards/Simulator/Source/hal/SdlDisplay.h index bde1c947..3ccc7f59 100644 --- a/Boards/Simulator/Source/hal/SdlDisplay.h +++ b/Boards/Simulator/Source/hal/SdlDisplay.h @@ -26,8 +26,3 @@ public: bool supportsDisplayDriver() const override { return false; } std::shared_ptr _Nullable getDisplayDriver() override { return nullptr; } }; - -std::shared_ptr createDisplay() { - return std::make_shared(); -} - diff --git a/Boards/Simulator/Source/hal/SdlKeyboard.h b/Boards/Simulator/Source/hal/SdlKeyboard.h index 9bf3dc50..10e6978e 100644 --- a/Boards/Simulator/Source/hal/SdlKeyboard.h +++ b/Boards/Simulator/Source/hal/SdlKeyboard.h @@ -23,7 +23,3 @@ public: lv_indev_t* _Nullable getLvglIndev() override { return handle; } }; - -std::shared_ptr createKeyboard() { - return std::make_shared(); -} diff --git a/Boards/Simulator/Source/hal/SimulatorPower.cpp b/Boards/Simulator/Source/hal/SimulatorPower.cpp index 593cbe61..84450bc0 100644 --- a/Boards/Simulator/Source/hal/SimulatorPower.cpp +++ b/Boards/Simulator/Source/hal/SimulatorPower.cpp @@ -1,6 +1,6 @@ #include "SimulatorPower.h" -#define TAG "simulator_power" +constexpr auto* TAG = "SimulatorPower"; bool SimulatorPower::supportsMetric(MetricType type) const { switch (type) { @@ -34,13 +34,3 @@ bool SimulatorPower::getMetric(MetricType type, MetricData& data) { return false; // Safety guard for when new enum values are introduced } - -static std::shared_ptr power; - -std::shared_ptr simulatorPower() { - if (power == nullptr) { - power = std::make_shared(); - } - return power; -} - diff --git a/Boards/Simulator/Source/hal/SimulatorPower.h b/Boards/Simulator/Source/hal/SimulatorPower.h index b4949502..f2b6bc91 100644 --- a/Boards/Simulator/Source/hal/SimulatorPower.h +++ b/Boards/Simulator/Source/hal/SimulatorPower.h @@ -1,6 +1,6 @@ #pragma once -#include "Tactility/hal/power/PowerDevice.h" +#include #include using tt::hal::power::PowerDevice; @@ -14,8 +14,8 @@ public: SimulatorPower() = default; ~SimulatorPower() override = default; - std::string getName() const final { return "Power Mock"; } - std::string getDescription() const final { return ""; } + std::string getName() const override { return "Power Mock"; } + std::string getDescription() const override { return ""; } bool supportsMetric(MetricType type) const override; bool getMetric(MetricType type, MetricData& data) override; @@ -24,5 +24,3 @@ public: bool isAllowedToCharge() const override { return allowedToCharge; } void setAllowedToCharge(bool canCharge) override { allowedToCharge = canCharge; } }; - -std::shared_ptr simulatorPower(); diff --git a/Boards/WaveshareS3Lcd13/Source/WaveshareS3Lcd13.cpp b/Boards/WaveshareS3Lcd13/Source/WaveshareS3Lcd13.cpp index 0f78d97e..0663244e 100644 --- a/Boards/WaveshareS3Lcd13/Source/WaveshareS3Lcd13.cpp +++ b/Boards/WaveshareS3Lcd13/Source/WaveshareS3Lcd13.cpp @@ -20,6 +20,7 @@ static bool initBoot() { extern const Configuration waveshare_s3_lcd_13 = { .initBoot = initBoot, + .uiScale = UiScale::Smallest, .createDevices = createDevices, .i2c = { //IMU diff --git a/Boards/WaveshareS3Touch43/Source/WaveshareS3Touch43.cpp b/Boards/WaveshareS3Touch43/Source/WaveshareS3Touch43.cpp index a0ba71ef..ffc953a0 100644 --- a/Boards/WaveshareS3Touch43/Source/WaveshareS3Touch43.cpp +++ b/Boards/WaveshareS3Touch43/Source/WaveshareS3Touch43.cpp @@ -13,6 +13,7 @@ static DeviceVector createDevices() { } extern const Configuration waveshare_s3_touch_43 = { + .uiScale = UiScale::Smallest, .createDevices = createDevices, .i2c = { // There is only 1 (internal for touch, and also serves as "I2C-OUT" port) diff --git a/Boards/WaveshareS3TouchLcd128/Source/WaveshareS3TouchLcd128.cpp b/Boards/WaveshareS3TouchLcd128/Source/WaveshareS3TouchLcd128.cpp index 691d0065..1e22c495 100644 --- a/Boards/WaveshareS3TouchLcd128/Source/WaveshareS3TouchLcd128.cpp +++ b/Boards/WaveshareS3TouchLcd128/Source/WaveshareS3TouchLcd128.cpp @@ -22,6 +22,7 @@ static bool initBoot() { extern const Configuration waveshare_s3_touch_lcd_128 = { .initBoot = initBoot, + .uiScale = UiScale::Smallest, .createDevices = createDevices, .i2c = { i2c::Configuration { diff --git a/Boards/WaveshareS3TouchLcd147/Source/WaveshareS3TouchLcd147.cpp b/Boards/WaveshareS3TouchLcd147/Source/WaveshareS3TouchLcd147.cpp index 09933b9c..11c4b96d 100644 --- a/Boards/WaveshareS3TouchLcd147/Source/WaveshareS3TouchLcd147.cpp +++ b/Boards/WaveshareS3TouchLcd147/Source/WaveshareS3TouchLcd147.cpp @@ -19,6 +19,7 @@ static std::vector> createDevices() { extern const Configuration waveshare_s3_touch_lcd_147 = { .initBoot = initBoot, + .uiScale = UiScale::Smallest, .createDevices = createDevices, .i2c = { i2c::Configuration { diff --git a/CMakeLists.txt b/CMakeLists.txt index c22d6d45..91f27fc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,15 @@ if (DEFINED ENV{ESP_IDF_VERSION}) add_compile_definitions(LV_CONF_PATH="${LVGL_CONFIG_FULL_PATH}/lv_conf_kconfig.h") idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_panic_handler" APPEND) idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_log_write" APPEND) + idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_button_create" APPEND) + idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_dropdown_create" APPEND) + idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_list_create" APPEND) + idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_list_add_button" APPEND) + idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_obj_create" APPEND) + idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_obj_set_flex_flow" APPEND) + idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_switch_create" APPEND) idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_textarea_create" APPEND) + else () message("Building for sim target") add_compile_definitions(CONFIG_TT_BOARD_ID="simulator") diff --git a/Data/system/app/Launcher/icon_apps.png b/Data/system/app/Launcher/assets/icon_apps.png similarity index 100% rename from Data/system/app/Launcher/icon_apps.png rename to Data/system/app/Launcher/assets/icon_apps.png diff --git a/Data/system/app/Launcher/icon_files.png b/Data/system/app/Launcher/assets/icon_files.png similarity index 100% rename from Data/system/app/Launcher/icon_files.png rename to Data/system/app/Launcher/assets/icon_files.png diff --git a/Data/system/app/Launcher/icon_settings.png b/Data/system/app/Launcher/assets/icon_settings.png similarity index 100% rename from Data/system/app/Launcher/icon_settings.png rename to Data/system/app/Launcher/assets/icon_settings.png diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 8af0de7b..856bc531 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -32,9 +32,11 @@ - Toolbar: when the title doesn't fit, scroll the text instead of splitting it onto a new line (try on Waveshare 1.47") - UI: create UI size classification (e.g. "compact" for tiny screens without touch) - Bug: Crash handling app cannot be exited with an EncoderDevice. (current work-around is to manually reset the device) +- I2C app should show error when I2C port is disabled when the scan button was manually pressed ## Lower Priority +- Implement system suspend that turns off the screen - The boot button on some devices can be used as GPIO_NUM_0 at runtime - Localize all apps - Support hot-plugging SD card (note: this is not possible if they require the CS pin hack) @@ -53,6 +55,10 @@ - Show a warning screen if firmware encryption or secure boot are off when saving WiFi credentials. - Remove flex_flow from app_container in Gui.cpp - Files app: copy/cut/paste actions +- ElfAppManifest: change name (remove "manifest" as it's confusing), remove icon and title, publish snapshot SDK on CDN +- `UiScale` implementation for devices like the CYD 2432S032C +- Bug: CYD 2432S032C screen rotation fails due to touch driver issue +- Calculator app should show regular text input field on non-touch devices that have a keyboard (Cardputer, T-Lora Pager) # Nice-to-haves diff --git a/Drivers/EstimatedPower/Source/EstimatedPower.h b/Drivers/EstimatedPower/Source/EstimatedPower.h index ec2a6a00..dd80e57f 100644 --- a/Drivers/EstimatedPower/Source/EstimatedPower.h +++ b/Drivers/EstimatedPower/Source/EstimatedPower.h @@ -16,7 +16,7 @@ class EstimatedPower final : public PowerDevice { public: - EstimatedPower(ChargeFromAdcVoltage::Configuration configuration) : + explicit EstimatedPower(ChargeFromAdcVoltage::Configuration configuration) : chargeFromAdcVoltage(std::make_unique(std::move(configuration))) {} std::string getName() const override { return "ADC Power Measurement"; } diff --git a/Tactility/Include/Tactility/Tactility.h b/Tactility/Include/Tactility/Tactility.h index 01ac0d41..067a017e 100644 --- a/Tactility/Include/Tactility/Tactility.h +++ b/Tactility/Include/Tactility/Tactility.h @@ -33,7 +33,17 @@ void run(const Configuration& config); */ const Configuration* _Nullable getConfiguration(); - +/** Provides access to the dispatcher that runs on the main task. + * @warning This dispatcher is used for WiFi and might block for some time during WiFi connection. + * @return the dispatcher + */ Dispatcher& getMainDispatcher(); -} // namespace +namespace hal { + +/** While technically this configuration is nullable, it's never null after initHeadless() is called. */ +const Configuration* _Nullable getConfiguration(); + +} // namespace hal + +} // namespace tt diff --git a/Tactility/Include/Tactility/TactilityConfig.h b/Tactility/Include/Tactility/TactilityConfig.h index 33d00898..a1848524 100644 --- a/Tactility/Include/Tactility/TactilityConfig.h +++ b/Tactility/Include/Tactility/TactilityConfig.h @@ -11,3 +11,9 @@ #else // Sim #define TT_FEATURE_SCREENSHOT_ENABLED true #endif + +namespace tt::config { + +constexpr auto SHOW_SYSTEM_PARTITION = false; + +} diff --git a/Tactility/Include/Tactility/TactilityHeadless.h b/Tactility/Include/Tactility/TactilityHeadless.h deleted file mode 100644 index 3094dbd5..00000000 --- a/Tactility/Include/Tactility/TactilityHeadless.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "Tactility/hal/Configuration.h" - -#include -#include - -namespace tt { - -/** Initialize the hardware and started the internal services. */ -void initHeadless(const hal::Configuration& config); - -/** Provides access to the dispatcher that runs on the main task. - * @warning This dispatcher is used for WiFi and might block for some time during WiFi connection. - * @return the dispatcher - */ -Dispatcher& getMainDispatcher(); - -} // namespace - -namespace tt::hal { - -/** While technically this configuration is nullable, it's never null after initHeadless() is called. */ -const Configuration* _Nullable getConfiguration(); - -} // namespace diff --git a/Tactility/Include/Tactility/hal/Configuration.h b/Tactility/Include/Tactility/hal/Configuration.h index e3eded79..ee2353a9 100644 --- a/Tactility/Include/Tactility/hal/Configuration.h +++ b/Tactility/Include/Tactility/hal/Configuration.h @@ -9,14 +9,6 @@ namespace tt::hal { typedef bool (*InitBoot)(); -namespace display { class DisplayDevice; } -namespace keyboard { class KeyboardDevice; } -namespace power { class PowerDevice; } - -typedef std::shared_ptr (*CreateDisplay)(); -typedef std::shared_ptr (*CreateKeyboard)(); -typedef std::shared_ptr (*CreatePower)(); - typedef std::vector> DeviceVector; typedef std::shared_ptr (*CreateDevice)(); @@ -26,6 +18,14 @@ enum class LvglInit { None }; +/** Affects LVGL widget style */ +enum class UiScale { + /** Ideal for very small non-touch screen devices (e.g. Waveshare S3 LCD 1.3") */ + Smallest, + /** Nothing was changed in the LVGL UI/UX */ + Default +}; + struct Configuration { /** * Called before I2C/SPI/etc is initialized. @@ -36,21 +36,8 @@ struct Configuration { /** Init behaviour: default (esp_lvgl_port for ESP32, nothing for PC) or None (nothing on any platform). Only used in Tactility, not in TactilityHeadless. */ const LvglInit lvglInit = LvglInit::Default; - /** Display HAL functionality. */ - [[deprecated("use createDevices")]] - const CreateDisplay _Nullable createDisplay = nullptr; - - /** Keyboard HAL functionality. */ - [[deprecated("use createDevices")]] - const CreateKeyboard _Nullable createKeyboard = nullptr; - - /** An optional SD card interface. */ - [[deprecated("use createDevices")]] - const std::shared_ptr _Nullable sdcard = nullptr; - - /** An optional power interface for battery or other power delivery. */ - [[deprecated("use createDevices")]] - const CreatePower _Nullable power = nullptr; + /** Modify LVGL widget size */ + const UiScale uiScale = UiScale::Default; std::function createDevices = [] { return std::vector>(); }; diff --git a/Tactility/Include/Tactility/hal/Device.h b/Tactility/Include/Tactility/hal/Device.h index 71247213..e323c965 100644 --- a/Tactility/Include/Tactility/hal/Device.h +++ b/Tactility/Include/Tactility/hal/Device.h @@ -8,7 +8,6 @@ #include namespace tt::hal { - /** Base class for HAL-related devices. */ class Device { @@ -119,4 +118,7 @@ std::shared_ptr findFirstDevice(Device::Type type) { } } +/** @return true if there are 1 or more devices of the specified type */ +bool hasDevice(Device::Type type); + } diff --git a/Tactility/Include/Tactility/lvgl/Toolbar.h b/Tactility/Include/Tactility/lvgl/Toolbar.h index 733f1474..65ea2d23 100644 --- a/Tactility/Include/Tactility/lvgl/Toolbar.h +++ b/Tactility/Include/Tactility/lvgl/Toolbar.h @@ -1,12 +1,12 @@ #pragma once #include "../app/AppContext.h" +#include "Tactility/Tactility.h" + #include namespace tt::lvgl { -#define TOOLBAR_HEIGHT 40 -#define TOOLBAR_TITLE_FONT_HEIGHT 18 #define TOOLBAR_ACTION_LIMIT 4 /** Create a toolbar widget that shows the app name as title */ diff --git a/Tactility/Source/MountPoints.cpp b/Tactility/Source/MountPoints.cpp index 1f5db3d4..c354df78 100644 --- a/Tactility/Source/MountPoints.cpp +++ b/Tactility/Source/MountPoints.cpp @@ -1,4 +1,6 @@ #include "Tactility/MountPoints.h" + +#include "Tactility/TactilityConfig.h" #include "Tactility/hal/Device.h" #include "Tactility/hal/sdcard/SdCardDevice.h" @@ -14,15 +16,6 @@ std::vector getMountPoints() { std::vector dir_entries; dir_entries.clear(); - // System partition - auto system_dirent = dirent{ - .d_ino = 0, - .d_type = TT_DT_DIR, - .d_name = { 0 } - }; - strcpy(system_dirent.d_name, SYSTEM_PARTITION_NAME); - dir_entries.push_back(system_dirent); - // Data partition auto data_dirent = dirent{ .d_ino = 1, @@ -49,6 +42,17 @@ std::vector getMountPoints() { } } + if (config::SHOW_SYSTEM_PARTITION) { + // System partition + auto system_dirent = dirent{ + .d_ino = 0, + .d_type = TT_DT_DIR, + .d_name = { 0 } + }; + strcpy(system_dirent.d_name, SYSTEM_PARTITION_NAME); + dir_entries.push_back(system_dirent); + } + return dir_entries; } diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index 50fd3b70..3e16832c 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -98,7 +98,6 @@ namespace app { // List of all apps excluding Boot app (as Boot app calls this function indirectly) static void registerSystemApps() { - addApp(app::addgps::manifest); addApp(app::alertdialog::manifest); addApp(app::applist::manifest); addApp(app::calculator::manifest); @@ -106,26 +105,25 @@ static void registerSystemApps() { addApp(app::filebrowser::manifest); addApp(app::fileselection::manifest); addApp(app::gpio::manifest); - addApp(app::gpssettings::manifest); - addApp(app::i2cscanner::manifest); - addApp(app::i2csettings::manifest); addApp(app::imageviewer::manifest); addApp(app::inputdialog::manifest); addApp(app::launcher::manifest); addApp(app::localesettings::manifest); addApp(app::log::manifest); addApp(app::notes::manifest); - addApp(app::serialconsole::manifest); addApp(app::settings::manifest); addApp(app::selectiondialog::manifest); addApp(app::systeminfo::manifest); addApp(app::timedatesettings::manifest); addApp(app::timezone::manifest); - addApp(app::usbsettings::manifest); addApp(app::wifiapsettings::manifest); addApp(app::wificonnect::manifest); addApp(app::wifimanage::manifest); +#if defined(CONFIG_TINYUSB_MSC_ENABLED) && CONFIG_TINYUSB_MSC_ENABLED + addApp(app::usbsettings::manifest); +#endif + #if TT_FEATURE_SCREENSHOT_ENABLED addApp(app::screenshot::manifest); #endif @@ -136,7 +134,18 @@ static void registerSystemApps() { addApp(app::development::manifest); #endif - if (hal::findDevices(hal::Device::Type::Power).size() > 0) { + if (!hal::getConfiguration()->i2c.empty()) { + addApp(app::i2cscanner::manifest); + addApp(app::i2csettings::manifest); + } + + if (!hal::getConfiguration()->uart.empty()) { + addApp(app::addgps::manifest); + addApp(app::gpssettings::manifest); + addApp(app::serialconsole::manifest); + } + + if (hal::hasDevice(hal::Device::Type::Power)) { addApp(app::power::manifest); } } diff --git a/Tactility/Source/app/applist/AppList.cpp b/Tactility/Source/app/applist/AppList.cpp index 05c71c1a..37a8f2c6 100644 --- a/Tactility/Source/app/applist/AppList.cpp +++ b/Tactility/Source/app/applist/AppList.cpp @@ -3,18 +3,14 @@ #include "Tactility/lvgl/Toolbar.h" #include -#include #include #include namespace tt::app::applist { - class AppListApp : public App { -private: - static void onAppPressed(lv_event_t* e) { const auto* manifest = static_cast(lv_event_get_user_data(e)); service::loader::startApp(manifest->id); @@ -23,7 +19,7 @@ private: static void createAppWidget(const std::shared_ptr& manifest, lv_obj_t* list) { 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, &onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)manifest.get()); + lv_obj_add_event_cb(btn, &onAppPressed, LV_EVENT_SHORT_CLICKED, manifest.get()); } public: @@ -41,7 +37,7 @@ public: lv_obj_set_height(list, parent_content_height - toolbar_height); auto manifests = getApps(); - std::sort(manifests.begin(), manifests.end(), SortAppManifestByName); + std::ranges::sort(manifests, SortAppManifestByName); for (const auto& manifest: manifests) { if (manifest->type == Type::User || manifest->type == Type::System) { @@ -51,7 +47,6 @@ public: } }; - extern const AppManifest manifest = { .id = "AppList", .name = "Apps", diff --git a/Tactility/Source/app/gpio/Gpio.cpp b/Tactility/Source/app/gpio/Gpio.cpp index 96df2861..f72cb270 100644 --- a/Tactility/Source/app/gpio/Gpio.cpp +++ b/Tactility/Source/app/gpio/Gpio.cpp @@ -101,10 +101,20 @@ void GpioApp::stopTask() { // endregion Task +static int getSquareSpacing(hal::UiScale uiScale) { + if (uiScale == hal::UiScale::Smallest) { + return 0; + } else { + return 4; + } +} void GpioApp::onShow(AppContext& app, lv_obj_t* parent) { + auto ui_scale = hal::getConfiguration()->uiScale; + 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, app); lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0); @@ -113,13 +123,16 @@ void GpioApp::onShow(AppContext& app, lv_obj_t* parent) { lv_obj_set_width(wrapper, LV_PCT(100)); lv_obj_set_flex_grow(wrapper, 1); lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT); + lv_obj_set_style_pad_all(wrapper, 0, LV_STATE_DEFAULT); auto* display = lv_obj_get_display(parent); auto horizontal_px = lv_display_get_horizontal_resolution(display); auto vertical_px = lv_display_get_vertical_resolution(display); bool is_landscape_display = horizontal_px > vertical_px; - int32_t x_spacing = 20; + constexpr auto block_width = 16; + const auto square_spacing = getSquareSpacing(ui_scale); + int32_t x_spacing = block_width + square_spacing; uint8_t column = 0; const uint8_t offset_from_left_label = 4; const uint8_t column_limit = is_landscape_display ? 10 : 5; @@ -138,7 +151,7 @@ void GpioApp::onShow(AppContext& app, lv_obj_t* parent) { // Add a new GPIO status indicator auto* status_label = lv_label_create(row_wrapper); - lv_obj_set_pos(status_label, (int32_t)((column+1) * x_spacing + offset_from_left_label), 0); + lv_obj_set_pos(status_label, (column+1) * x_spacing + offset_from_left_label, 0); lv_label_set_text_fmt(status_label, "%s", LV_SYMBOL_STOP); lv_obj_set_style_text_color(status_label, lv_color_background_darkest(), LV_STATE_DEFAULT); lvPins[i] = status_label; @@ -153,7 +166,7 @@ void GpioApp::onShow(AppContext& app, lv_obj_t* parent) { // Add a new row wrapper underneath the last one auto* new_row_wrapper = createGpioRowWrapper(wrapper); - lv_obj_align_to(new_row_wrapper, row_wrapper, LV_ALIGN_BOTTOM_LEFT, 0, 4); + lv_obj_align_to(new_row_wrapper, row_wrapper, LV_ALIGN_BOTTOM_LEFT, 0, square_spacing); row_wrapper = new_row_wrapper; column = 0; diff --git a/Tactility/Source/app/imageviewer/ImageViewer.cpp b/Tactility/Source/app/imageviewer/ImageViewer.cpp index bfac67cc..dae0fa12 100644 --- a/Tactility/Source/app/imageviewer/ImageViewer.cpp +++ b/Tactility/Source/app/imageviewer/ImageViewer.cpp @@ -30,7 +30,8 @@ class ImageViewerApp : public App { lv_obj_align_to(image_wrapper, toolbar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); lv_obj_set_width(image_wrapper, LV_PCT(100)); auto parent_height = lv_obj_get_height(wrapper); - lv_obj_set_height(image_wrapper, parent_height - TOOLBAR_HEIGHT); + auto toolbar_height = lv_obj_get_height(toolbar); + lv_obj_set_height(image_wrapper, parent_height - toolbar_height); lv_obj_set_flex_flow(image_wrapper, LV_FLEX_FLOW_COLUMN); lv_obj_set_flex_align(image_wrapper, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); lv_obj_set_style_pad_all(image_wrapper, 0, 0); diff --git a/Tactility/Source/app/launcher/Launcher.cpp b/Tactility/Source/app/launcher/Launcher.cpp index 7a460f1a..3189899a 100644 --- a/Tactility/Source/app/launcher/Launcher.cpp +++ b/Tactility/Source/app/launcher/Launcher.cpp @@ -11,11 +11,20 @@ namespace tt::app::launcher { constexpr auto* TAG = "Launcher"; -constexpr auto BUTTON_SIZE = 64; + +static int getButtonSize(hal::UiScale scale) { + if (scale == hal::UiScale::Smallest) { + return 40; + } else { + return 64; + } +} class LauncherApp final : public App { - static lv_obj_t* createAppButton(lv_obj_t* parent, const char* imageFile, const char* appId, int32_t horizontalMargin) { + static lv_obj_t* createAppButton(lv_obj_t* parent, hal::UiScale uiScale, const char* imageFile, const char* appId, int32_t horizontalMargin) { + auto button_size = getButtonSize(uiScale); + auto* apps_button = lv_button_create(parent); lv_obj_set_style_pad_all(apps_button, 0, LV_STATE_DEFAULT); lv_obj_set_style_margin_hor(apps_button, horizontalMargin, LV_STATE_DEFAULT); @@ -28,7 +37,7 @@ class LauncherApp final : public App { lv_obj_set_style_image_recolor_opa(button_image, LV_OPA_COVER, LV_STATE_DEFAULT); // Ensure buttons are still tappable when the asset fails to load // Icon images are 40x40, so we get some extra padding too - lv_obj_set_size(button_image, BUTTON_SIZE, BUTTON_SIZE); + lv_obj_set_size(button_image, button_size, button_size); lv_obj_add_event_cb(apps_button, onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)appId); @@ -73,6 +82,9 @@ public: void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) override { auto* buttons_wrapper = lv_obj_create(parent); + auto ui_scale = hal::getConfiguration()->uiScale; + auto button_size = getButtonSize(ui_scale); + lv_obj_align(buttons_wrapper, LV_ALIGN_CENTER, 0, 0); // lv_obj_set_style_pad_all(buttons_wrapper, 0, LV_STATE_DEFAULT); lv_obj_set_size(buttons_wrapper, LV_SIZE_CONTENT, LV_SIZE_CONTENT); @@ -89,17 +101,17 @@ public: lv_obj_set_flex_flow(buttons_wrapper, LV_FLEX_FLOW_COLUMN); } - const int32_t available_width = lv_display_get_horizontal_resolution(display) - (3 * BUTTON_SIZE); - const int32_t margin = is_landscape_display ? std::min(available_width / 16, BUTTON_SIZE) : 0; + const int32_t available_width = lv_display_get_horizontal_resolution(display) - (3 * button_size); + const int32_t margin = is_landscape_display ? std::min(available_width / 16, button_size) : 0; const auto paths = app.getPaths(); - const auto apps_icon_path = paths->getSystemPathLvgl("icon_apps.png"); - const auto files_icon_path = paths->getSystemPathLvgl("icon_files.png"); - const auto settings_icon_path = paths->getSystemPathLvgl("icon_settings.png"); + const auto apps_icon_path = paths->getSystemPathLvgl("assets/icon_apps.png"); + const auto files_icon_path = paths->getSystemPathLvgl("assets/icon_files.png"); + const auto settings_icon_path = paths->getSystemPathLvgl("assets/icon_settings.png"); - createAppButton(buttons_wrapper, apps_icon_path.c_str(), "AppList", margin); - createAppButton(buttons_wrapper, files_icon_path.c_str(), "Files", margin); - createAppButton(buttons_wrapper, settings_icon_path.c_str(), "Settings", margin); + createAppButton(buttons_wrapper, ui_scale, apps_icon_path.c_str(), "AppList", margin); + createAppButton(buttons_wrapper, ui_scale, files_icon_path.c_str(), "Files", margin); + createAppButton(buttons_wrapper, ui_scale, settings_icon_path.c_str(), "Settings", margin); if (shouldShowPowerButton()) { auto* power_button = lv_btn_create(parent); diff --git a/Tactility/Source/app/systeminfo/SystemInfo.cpp b/Tactility/Source/app/systeminfo/SystemInfo.cpp index a4d8f4dd..37da31ac 100644 --- a/Tactility/Source/app/systeminfo/SystemInfo.cpp +++ b/Tactility/Source/app/systeminfo/SystemInfo.cpp @@ -1,3 +1,4 @@ +#include "Tactility/TactilityConfig.h" #include "Tactility/lvgl/Toolbar.h" #include @@ -141,7 +142,12 @@ static void addMemoryBar(lv_obj_t* parent, const char* label, uint64_t free, uin lv_label_set_text_fmt(bottom_label, "%s / %s %s used", used_converted.c_str(), total_converted.c_str(), unit_label.c_str()); lv_obj_set_width(bottom_label, LV_PCT(100)); lv_obj_set_style_text_align(bottom_label, LV_TEXT_ALIGN_RIGHT, 0); - lv_obj_set_style_pad_bottom(bottom_label, 12, LV_STATE_DEFAULT); + + if (hal::getConfiguration()->uiScale == hal::UiScale::Smallest) { + lv_obj_set_style_pad_bottom(bottom_label, 2, LV_STATE_DEFAULT); + } else { + lv_obj_set_style_pad_bottom(bottom_label, 12, LV_STATE_DEFAULT); + } } #if configUSE_TRACE_FACILITY @@ -245,9 +251,6 @@ class SystemInfoApp : public App { uint64_t storage_total = 0; uint64_t storage_free = 0; - if (esp_vfs_fat_info(file::MOUNT_POINT_SYSTEM, &storage_total, &storage_free) == ESP_OK) { - addMemoryBar(storage_tab, file::MOUNT_POINT_SYSTEM, storage_free, storage_total); - } if (esp_vfs_fat_info(file::MOUNT_POINT_DATA, &storage_total, &storage_free) == ESP_OK) { addMemoryBar(storage_tab, file::MOUNT_POINT_DATA, storage_free, storage_total); @@ -264,6 +267,13 @@ class SystemInfoApp : public App { ); } } + + if (config::SHOW_SYSTEM_PARTITION) { + if (esp_vfs_fat_info(file::MOUNT_POINT_SYSTEM, &storage_total, &storage_free) == ESP_OK) { + addMemoryBar(storage_tab, file::MOUNT_POINT_SYSTEM, storage_free, storage_total); + } + } + #endif #if configUSE_TRACE_FACILITY diff --git a/Tactility/Source/hal/Device.cpp b/Tactility/Source/hal/Device.cpp index 21d8a548..2b18203d 100644 --- a/Tactility/Source/hal/Device.cpp +++ b/Tactility/Source/hal/Device.cpp @@ -92,4 +92,13 @@ std::vector> getDevices() { return devices; } +bool hasDevice(Device::Type type) { + auto scoped_mutex = mutex.asScopedLock(); + scoped_mutex.lock(); + auto result_set = devices | std::views::filter([&type](auto& device) { + return device->getType() == type; + }); + return !result_set.empty(); +} + } diff --git a/Tactility/Source/hal/Hal.cpp b/Tactility/Source/hal/Hal.cpp index 4ee6a6ea..4cb315f9 100644 --- a/Tactility/Source/hal/Hal.cpp +++ b/Tactility/Source/hal/Hal.cpp @@ -19,29 +19,6 @@ constexpr auto* TAG = "Hal"; void registerDevices(const Configuration& configuration) { TT_LOG_I(TAG, "Registering devices"); - if (configuration.sdcard != nullptr) { - registerDevice(configuration.sdcard); - } - - if (configuration.power != nullptr) { - std::shared_ptr power = configuration.power(); - registerDevice(power); - } - - if (configuration.createKeyboard) { - auto keyboard = configuration.createKeyboard(); - if (keyboard != nullptr) { - registerDevice(std::reinterpret_pointer_cast(keyboard)); - } - } - - if (configuration.createDisplay != nullptr) { - auto display = configuration.createDisplay(); - if (display != nullptr) { - registerDevice(display); - } - } - auto devices = configuration.createDevices(); for (auto& device : devices) { registerDevice(device); diff --git a/Tactility/Source/hal/uart/Uart.cpp b/Tactility/Source/hal/uart/Uart.cpp index 6f1df0f8..4bac75f6 100644 --- a/Tactility/Source/hal/uart/Uart.cpp +++ b/Tactility/Source/hal/uart/Uart.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #ifdef ESP_PLATFORM #include @@ -142,7 +142,7 @@ void close(uint32_t uartId) { std::vector getNames() { std::vector names; #ifdef ESP_PLATFORM - for (auto& config : hal::getConfiguration()->uart) { + for (auto& config : getConfiguration()->uart) { names.push_back(config.name); } #else diff --git a/Tactility/Source/lvgl/Toolbar.cpp b/Tactility/Source/lvgl/Toolbar.cpp index 75873f00..2bfcedd9 100644 --- a/Tactility/Source/lvgl/Toolbar.cpp +++ b/Tactility/Source/lvgl/Toolbar.cpp @@ -8,6 +8,30 @@ namespace tt::lvgl { +static int getToolbarHeight(hal::UiScale uiScale) { + if (uiScale == hal::UiScale::Smallest) { + return 20; + } else { + return 40; + } +} + +static int getToolbarFontHeight(hal::UiScale uiScale) { + if (uiScale == hal::UiScale::Smallest) { + return 14; + } else { + return 18; + } +} + +static const _lv_font_t* getToolbarFont(hal::UiScale uiScale) { + if (uiScale == hal::UiScale::Smallest) { + return &lv_font_montserrat_14; + } else { + return &lv_font_montserrat_18; + } +} + typedef struct { lv_obj_t obj; lv_obj_t* title_label; @@ -19,7 +43,7 @@ typedef struct { static void toolbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj); -static const lv_obj_class_t toolbar_class = { +static lv_obj_class_t toolbar_class = { .base_class = &lv_obj_class, .constructor_cb = &toolbar_constructor, .destructor_cb = nullptr, @@ -27,7 +51,7 @@ static const lv_obj_class_t toolbar_class = { .user_data = nullptr, .name = nullptr, .width_def = LV_PCT(100), - .height_def = TOOLBAR_HEIGHT, + .height_def = 40, .editable = false, .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE, .instance_size = sizeof(Toolbar), @@ -48,41 +72,46 @@ static void toolbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) { lv_obj_t* toolbar_create(lv_obj_t* parent, const std::string& title) { LV_LOG_INFO("begin"); + auto ui_scale = hal::getConfiguration()->uiScale; + auto toolbar_height = getToolbarHeight(ui_scale); + toolbar_class.height_def = toolbar_height; lv_obj_t* obj = lv_obj_class_create_obj(&toolbar_class, parent); lv_obj_class_init_obj(obj); auto* toolbar = (Toolbar*)obj; - lv_obj_set_style_pad_all(obj, 0, 0); - lv_obj_set_style_pad_gap(obj, 0, 0); + lv_obj_set_style_pad_all(obj, 0, LV_STATE_DEFAULT); + lv_obj_set_style_pad_gap(obj, 0, LV_STATE_DEFAULT); lv_obj_center(obj); lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); toolbar->close_button = lv_button_create(obj); - lv_obj_set_size(toolbar->close_button, TOOLBAR_HEIGHT - 4, TOOLBAR_HEIGHT - 4); - lv_obj_set_style_pad_all(toolbar->close_button, 0, 0); - lv_obj_set_style_pad_gap(toolbar->close_button, 0, 0); + + lv_obj_set_size(toolbar->close_button, toolbar_height - 4, toolbar_height - 4); + lv_obj_set_style_pad_all(toolbar->close_button, 0, LV_STATE_DEFAULT); + lv_obj_set_style_pad_gap(toolbar->close_button, 0, LV_STATE_DEFAULT); toolbar->close_button_image = lv_image_create(toolbar->close_button); lv_obj_align(toolbar->close_button_image, LV_ALIGN_CENTER, 0, 0); toolbar->title_label = lv_label_create(obj); - lv_obj_set_style_text_font(toolbar->title_label, &lv_font_montserrat_18, 0); // TODO replace with size 18 + lv_obj_set_style_text_font(toolbar->title_label, getToolbarFont(ui_scale), LV_STATE_DEFAULT); lv_label_set_text(toolbar->title_label, title.c_str()); - lv_obj_set_style_text_align(toolbar->title_label, LV_TEXT_ALIGN_LEFT, 0); + 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_set_flex_grow(toolbar->title_label, 1); - int32_t title_offset_x = (TOOLBAR_HEIGHT - TOOLBAR_TITLE_FONT_HEIGHT - 8) / 4 * 3; + int32_t title_offset_x = (toolbar_height - getToolbarFontHeight(ui_scale) - 8) / 4 * 3; // Margin top doesn't work - lv_obj_set_style_pad_top(toolbar->title_label, title_offset_x, 0); - lv_obj_set_style_margin_left(toolbar->title_label, 8, 0); + lv_obj_set_style_pad_top(toolbar->title_label, title_offset_x, LV_STATE_DEFAULT); + lv_obj_set_style_margin_left(toolbar->title_label, 8, LV_STATE_DEFAULT); // Hack for margin bug where buttons in flex get rendered more narrowly - lv_obj_set_style_margin_right(toolbar->title_label, -8, 0); + lv_obj_set_style_margin_right(toolbar->title_label, -8, LV_STATE_DEFAULT); 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, 0); - lv_obj_set_style_border_width(toolbar->action_container, 0, 0); + lv_obj_set_style_pad_all(toolbar->action_container, 0, LV_STATE_DEFAULT); + lv_obj_set_style_border_width(toolbar->action_container, 0, LV_STATE_DEFAULT); lv_obj_set_flex_align(toolbar->action_container, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START); toolbar_set_nav_action(obj, LV_SYMBOL_CLOSE, &stop_app, nullptr); @@ -110,10 +139,13 @@ lv_obj_t* toolbar_add_button_action(lv_obj_t* obj, const char* icon, lv_event_cb tt_check(toolbar->action_count < TOOLBAR_ACTION_LIMIT, "max actions reached"); toolbar->action_count++; + auto ui_scale = hal::getConfiguration()->uiScale; + auto toolbar_height = getToolbarHeight(ui_scale); + lv_obj_t* action_button = lv_button_create(toolbar->action_container); - lv_obj_set_size(action_button, TOOLBAR_HEIGHT - 4, TOOLBAR_HEIGHT - 4); - lv_obj_set_style_pad_all(action_button, 0, 0); - lv_obj_set_style_pad_gap(action_button, 0, 0); + lv_obj_set_size(action_button, toolbar_height - 4, toolbar_height - 4); + lv_obj_set_style_pad_all(action_button, 0, LV_STATE_DEFAULT); + lv_obj_set_style_pad_gap(action_button, 0, LV_STATE_DEFAULT); lv_obj_add_event_cb(action_button, callback, LV_EVENT_SHORT_CLICKED, user_data); lv_obj_t* action_button_image = lv_image_create(action_button); lv_image_set_src(action_button_image, icon); @@ -125,14 +157,14 @@ lv_obj_t* toolbar_add_button_action(lv_obj_t* obj, const char* icon, lv_event_cb lv_obj_t* toolbar_add_switch_action(lv_obj_t* obj) { auto* toolbar = (Toolbar*)obj; lv_obj_t* widget = lv_switch_create(toolbar->action_container); - lv_obj_set_style_margin_top(widget, 4, 0); // Because aligning doesn't work - lv_obj_set_style_margin_right(widget, 4, 0); + lv_obj_set_style_margin_top(widget, 4, LV_STATE_DEFAULT); // Because aligning doesn't work + lv_obj_set_style_margin_right(widget, 4, LV_STATE_DEFAULT); return widget; } lv_obj_t* toolbar_add_spinner_action(lv_obj_t* obj) { auto* toolbar = (Toolbar*)obj; - return tt::lvgl::spinner_create(toolbar->action_container); + return spinner_create(toolbar->action_container); } } // namespace diff --git a/Tactility/Source/lvgl/Wrappers.cpp b/Tactility/Source/lvgl/Wrappers.cpp deleted file mode 100644 index 1e3f162c..00000000 --- a/Tactility/Source/lvgl/Wrappers.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifdef ESP_PLATFORM - -#include "Tactility/app/App.h" -#include "Tactility/service/gui/GuiService.h" - -#include -#include - -extern "C" { - -extern lv_obj_t * __real_lv_textarea_create(lv_obj_t * parent); - -lv_obj_t * __wrap_lv_textarea_create(lv_obj_t * parent) { - auto textarea = __real_lv_textarea_create(parent); - - auto gui_service = tt::service::gui::findService(); - if (gui_service != nullptr) { - gui_service->keyboardAddTextArea(textarea); - } - - return textarea; -} - -} - -#endif // ESP_PLATFORM \ No newline at end of file diff --git a/Tactility/Source/lvgl/wrappers/button.cpp b/Tactility/Source/lvgl/wrappers/button.cpp new file mode 100644 index 00000000..e35cd846 --- /dev/null +++ b/Tactility/Source/lvgl/wrappers/button.cpp @@ -0,0 +1,23 @@ +#ifdef ESP_PLATFORM + +#include + +#include + +extern "C" { + +extern lv_obj_t* __real_lv_button_create(lv_obj_t* parent); + +lv_obj_t* __wrap_lv_button_create(lv_obj_t* parent) { + auto button = __real_lv_button_create(parent); + + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_pad_all(button, 2, LV_STATE_DEFAULT); + } + + return button; +} + +} + +#endif // ESP_PLATFORM \ No newline at end of file diff --git a/Tactility/Source/lvgl/wrappers/dropdown.cpp b/Tactility/Source/lvgl/wrappers/dropdown.cpp new file mode 100644 index 00000000..24e0930d --- /dev/null +++ b/Tactility/Source/lvgl/wrappers/dropdown.cpp @@ -0,0 +1,23 @@ +#ifdef ESP_PLATFORM + +#include + +#include + +extern "C" { + +extern lv_obj_t* __real_lv_dropdown_create(lv_obj_t* parent); + +lv_obj_t* __wrap_lv_dropdown_create(lv_obj_t* parent) { + auto dropdown = __real_lv_dropdown_create(parent); + + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_pad_all(dropdown, 2, LV_STATE_DEFAULT); + } + + return dropdown; +} + +} + +#endif // ESP_PLATFORM \ No newline at end of file diff --git a/Tactility/Source/lvgl/wrappers/list.cpp b/Tactility/Source/lvgl/wrappers/list.cpp new file mode 100644 index 00000000..348fc107 --- /dev/null +++ b/Tactility/Source/lvgl/wrappers/list.cpp @@ -0,0 +1,35 @@ +#ifdef ESP_PLATFORM + +#include + +#include + +extern "C" { + +extern lv_obj_t* __real_lv_list_create(lv_obj_t* parent); +extern lv_obj_t* __real_lv_list_add_button(lv_obj_t* list, const void* icon, const char* txt); + +lv_obj_t* __wrap_lv_list_create(lv_obj_t* parent) { + auto list = __real_lv_list_create(parent); + + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_pad_row(list, 2, LV_STATE_DEFAULT); + lv_obj_set_style_pad_column(list, 2, LV_STATE_DEFAULT); + } + + return list; +} + +lv_obj_t* __wrap_lv_list_add_button(lv_obj_t* list, const void* icon, const char* txt) { + auto button = __real_lv_list_add_button(list, icon, txt); + + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_pad_ver(button, 2, LV_STATE_DEFAULT); + } + + return button; +} + +} + +#endif // ESP_PLATFORM \ No newline at end of file diff --git a/Tactility/Source/lvgl/wrappers/obj.cpp b/Tactility/Source/lvgl/wrappers/obj.cpp new file mode 100644 index 00000000..c3a9f4a1 --- /dev/null +++ b/Tactility/Source/lvgl/wrappers/obj.cpp @@ -0,0 +1,35 @@ +#ifdef ESP_PLATFORM + +#include + +#include + +extern "C" { + +extern void __real_lv_obj_set_flex_flow(lv_obj_t* obj, lv_flex_flow_t flow); +extern lv_obj_t* __real_lv_obj_create(lv_obj_t* parent); + +void __wrap_lv_obj_set_flex_flow(lv_obj_t* obj, lv_flex_flow_t flow) { + __real_lv_obj_set_flex_flow(obj, flow); + + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_pad_row(obj, 2, LV_STATE_DEFAULT); + lv_obj_set_style_pad_column(obj, 2, LV_STATE_DEFAULT); + } +} + +lv_obj_t* __wrap_lv_obj_create(lv_obj_t* parent) { + auto obj = __real_lv_obj_create(parent); + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_pad_row(obj, 2, LV_STATE_DEFAULT); + lv_obj_set_style_pad_column(obj, 2, LV_STATE_DEFAULT); + lv_obj_set_style_pad_all(obj, 2, LV_STATE_DEFAULT); + lv_obj_set_style_radius(obj, 3, LV_STATE_DEFAULT); + lv_obj_set_style_border_width(obj, 1, LV_STATE_DEFAULT); + } + return obj; +} + +} + +#endif // ESP_PLATFORM \ No newline at end of file diff --git a/Tactility/Source/lvgl/wrappers/switch.cpp b/Tactility/Source/lvgl/wrappers/switch.cpp new file mode 100644 index 00000000..45ef57dc --- /dev/null +++ b/Tactility/Source/lvgl/wrappers/switch.cpp @@ -0,0 +1,23 @@ +#ifdef ESP_PLATFORM + +#include + +#include + +extern "C" { + +extern lv_obj_t* __real_lv_switch_create(lv_obj_t* parent); + +lv_obj_t* __wrap_lv_switch_create(lv_obj_t* parent) { + auto widget = __real_lv_switch_create(parent); + + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_size(widget, 25, 15, LV_STATE_DEFAULT); + } + + return widget; +} + +} + +#endif // ESP_PLATFORM diff --git a/Tactility/Source/lvgl/wrappers/textarea.cpp b/Tactility/Source/lvgl/wrappers/textarea.cpp new file mode 100644 index 00000000..38028eb0 --- /dev/null +++ b/Tactility/Source/lvgl/wrappers/textarea.cpp @@ -0,0 +1,28 @@ +#ifdef ESP_PLATFORM + +#include +#include +#include + +extern "C" { + +extern lv_obj_t* __real_lv_textarea_create(lv_obj_t* parent); + +lv_obj_t* __wrap_lv_textarea_create(lv_obj_t* parent) { + auto textarea = __real_lv_textarea_create(parent); + + if (tt::hal::getConfiguration()->uiScale == tt::hal::UiScale::Smallest) { + lv_obj_set_style_pad_all(textarea, 2, LV_STATE_DEFAULT); + } + + auto gui_service = tt::service::gui::findService(); + if (gui_service != nullptr) { + gui_service->keyboardAddTextArea(textarea); + } + + return textarea; +} + +} + +#endif // ESP_PLATFORM \ No newline at end of file diff --git a/Tactility/Source/service/gui/GuiService.cpp b/Tactility/Source/service/gui/GuiService.cpp index 8ab73918..8ce0be78 100644 --- a/Tactility/Source/service/gui/GuiService.cpp +++ b/Tactility/Source/service/gui/GuiService.cpp @@ -27,7 +27,7 @@ void GuiService::onLoaderEvent(loader::LoaderEvent event) { int32_t GuiService::guiMain() { while (true) { - uint32_t flags = Thread::awaitFlags(GUI_THREAD_FLAG_ALL, EventFlag::WaitAny, (uint32_t)portMAX_DELAY); + uint32_t flags = Thread::awaitFlags(GUI_THREAD_FLAG_ALL, EventFlag::WaitAny, portMAX_DELAY); // When service not started or starting -> exit State service_state = getState(manifest.id); diff --git a/Tactility/Source/service/gui/Keyboard.cpp b/Tactility/Source/service/gui/Keyboard.cpp index ae754848..727049d3 100644 --- a/Tactility/Source/service/gui/Keyboard.cpp +++ b/Tactility/Source/service/gui/Keyboard.cpp @@ -59,13 +59,13 @@ void GuiService::keyboardAddTextArea(lv_obj_t* textarea) { lv_obj_add_event_cb(textarea, show_keyboard, LV_EVENT_FOCUSED, nullptr); lv_obj_add_event_cb(textarea, hide_keyboard, LV_EVENT_DEFOCUSED, nullptr); lv_obj_add_event_cb(textarea, hide_keyboard, LV_EVENT_READY, nullptr); + + // lv_obj_t auto-remove themselves from the group when they are destroyed (last checked in LVGL 8.3) + lv_group_add_obj(keyboardGroup, textarea); + + lvgl::software_keyboard_activate(keyboardGroup); } - // lv_obj_t auto-remove themselves from the group when they are destroyed (last checked in LVGL 8.3) - lv_group_add_obj(keyboardGroup, textarea); - - lvgl::software_keyboard_activate(keyboardGroup); - lvgl::unlock(); } diff --git a/sdkconfig.board.cyd-2432s032c b/sdkconfig.board.cyd-2432s032c index 5b17edbf..feb9b267 100644 --- a/sdkconfig.board.cyd-2432s032c +++ b/sdkconfig.board.cyd-2432s032c @@ -43,7 +43,7 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_FLASHMODE_QIO=y # LVGL CONFIG_LV_DISP_DEF_REFR_PERIOD=10 -CONFIG_LV_DPI_DEF=160 +CONFIG_LV_DPI_DEF=139 CONFIG_LV_THEME_DEFAULT_DARK=y # Fix for IRAM CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y