From 29b5ff30ec119477fc9dc218e6dcfa2e028a2e21 Mon Sep 17 00:00:00 2001 From: forntoh Date: Wed, 18 Sep 2024 00:14:43 +0200 Subject: [PATCH] Replace `RotaryNavConfig` with `RotaryInputAdapter` Replaced the RotaryNavConfig struct with a new RotaryInputAdapter class to handle rotary input for LCD menus efficiently. The adapter manages user input through a rotary encoder, recognizing short, long, and double presses for menu navigation and selection. --- examples/InputRotary/InputRotary.ino | 18 ++----- examples/SimpleRotary/SimpleRotary.ino | 18 ++----- src/input/RotaryInputAdapter.h | 72 ++++++++++++++++++++++++++ src/utils/RotaryNavConfig.h | 65 ----------------------- 4 files changed, 82 insertions(+), 91 deletions(-) create mode 100644 src/input/RotaryInputAdapter.h delete mode 100644 src/utils/RotaryNavConfig.h diff --git a/examples/InputRotary/InputRotary.ino b/examples/InputRotary/InputRotary.ino index 01450098..15244e7d 100644 --- a/examples/InputRotary/InputRotary.ino +++ b/examples/InputRotary/InputRotary.ino @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #define LCD_ROWS 2 #define LCD_COLS 16 @@ -31,26 +31,18 @@ SUB_MENU( ITEM_INPUT_CHARSET("User", charset, inputCallback), ITEM_COMMAND("Clear", clearInput)); -LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS); -LcdMenu menu(lcdAdapter); - SimpleRotary encoder(2, 3, 4); -RotaryNavConfig menuConfig = { - .encoder = &encoder, - .menu = &menu, - .longPressDuration = 1000, -}; +LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS); +LcdMenu menu(lcdAdapter); +RotaryInputAdapter rotaryInput(&menu, &encoder); void setup() { Serial.begin(9600); menu.initialize(mainMenu); } -void loop() { - // Call the handleRotaryMenu function, passing the menuConfig instance - processWithRotaryEncoder(&menuConfig); -} +void loop() { rotaryInput.observe(); } // Define the callbacks void inputCallback(char* value) { diff --git a/examples/SimpleRotary/SimpleRotary.ino b/examples/SimpleRotary/SimpleRotary.ino index 806d82cf..34e5812f 100644 --- a/examples/SimpleRotary/SimpleRotary.ino +++ b/examples/SimpleRotary/SimpleRotary.ino @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -32,27 +33,18 @@ MAIN_MENU( ITEM_TOGGLE("Backlight", toggleBacklight), ITEM_BASIC("Blink random")); -LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS); -LcdMenu menu(lcdAdapter); - SimpleRotary encoder(2, 3, 4); -RotaryNavConfig menuConfig = { - .encoder = &encoder, - .menu = &menu, - .longPressDuration = 1000, - .doublePressThreshold = 500, -}; +LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS); +LcdMenu menu(lcdAdapter); +RotaryInputAdapter rotaryInput(&menu, &encoder); void setup() { Serial.begin(9600); menu.initialize(mainMenu); } -void loop() { - // Call the handleRotaryMenu function, passing the menuConfig instance - processWithRotaryEncoder(&menuConfig); -} +void loop() { rotaryInput.observe(); } // Define the callbacks void toggleBacklight(uint16_t isOn) { diff --git a/src/input/RotaryInputAdapter.h b/src/input/RotaryInputAdapter.h new file mode 100644 index 00000000..7f8a2d98 --- /dev/null +++ b/src/input/RotaryInputAdapter.h @@ -0,0 +1,72 @@ +#pragma once + +#include "InputInterface.h" +#include + +class RotaryInputAdapter : public InputInterface { + private: + uint16_t longPressDuration; // Duration to consider a long press + uint16_t doublePressThreshold; // Duration to consider a double press + unsigned long lastPressTime = 0; // Last time the button was pressed + bool pendingEnter = false; // Flag to indicate if an enter action is pending + + public: + SimpleRotary* encoder; + + /** + * @brief Adapter for handling rotary input for an LCD menu. + * + * This class interfaces with a rotary encoder to manage user input + * for navigating and selecting options in an LCD menu. + * + * @param menu Pointer to the LcdMenu instance that this adapter will control. + * @param encoder Pointer to the SimpleRotary instance representing the rotary encoder. + * @param longPressDuration Duration in milliseconds to recognize a long press (default is 1000 ms). + * @param doublePressThreshold Duration in milliseconds to recognize a double press (default is 300 ms). + */ + RotaryInputAdapter( + LcdMenu* menu, + SimpleRotary* encoder, + uint16_t longPressDuration = 1000, + uint16_t doublePressThreshold = 300) : InputInterface(menu), + encoder(encoder), + longPressDuration(longPressDuration), + doublePressThreshold(doublePressThreshold) {}; + + void observe() override { + // Handle rotary encoder rotation + uint8_t rotation = encoder->rotate(); + if (rotation == 1) { + menu->process(DOWN); // Call DOWN action + } else if (rotation == 2) { + menu->process(UP); // Call UP action + } + + // Handle button press (short, long, and double press) + uint8_t pressType = encoder->pushType(longPressDuration); + unsigned long currentTime = millis(); + + if (pressType == 1) { + if (pendingEnter) { + if (doublePressThreshold > 0 && + currentTime - lastPressTime < doublePressThreshold) { + menu->process(BACKSPACE); // Call BACKSPACE action (double press) + pendingEnter = false; + } + } else { + pendingEnter = true; + lastPressTime = currentTime; + } + } else if (pressType == 2) { + menu->process(BACK); // Call BACK action (long press) + pendingEnter = false; + } + + // Check if the doublePressThreshold has elapsed for pending enter action + if ((!menu->lcd.getEditModeEnabled() && pendingEnter) || + (pendingEnter && (currentTime - lastPressTime >= doublePressThreshold))) { + menu->process(ENTER); // Call ENTER action (short press) + pendingEnter = false; + } + } +}; \ No newline at end of file diff --git a/src/utils/RotaryNavConfig.h b/src/utils/RotaryNavConfig.h deleted file mode 100644 index 4d01aa9b..00000000 --- a/src/utils/RotaryNavConfig.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include - -/** - * @brief Configuration for rotary encoder navigation in the LCD menu. - * - * @param encoder Pointer to the rotary encoder instance - * @param menu Pointer to the LCD menu instance - * @param doublePressThreshold Duration (ms) to consider a double press - * @param longPressDuration Duration (ms) to consider a long press - * @param lastPressTime The last time the button was pressed - * @param pendingEnter Flag to indicate if an enter action is pending - */ -struct RotaryNavConfig { - SimpleRotary* encoder; - LcdMenu* menu; - uint16_t longPressDuration; - uint16_t doublePressThreshold; - unsigned long lastPressTime; - bool pendingEnter; -}; - -/** - * @brief Handles rotary encoder navigation in the LCD menu. - * - * @param config Pointer to the RotaryNavConfig struct - */ -void processWithRotaryEncoder(RotaryNavConfig* config) { - // Handle rotary encoder rotation - uint8_t rotation = config->encoder->rotate(); - if (rotation == 1) { - config->menu->process(DOWN); // Call DOWN action - } else if (rotation == 2) { - config->menu->process(UP); // Call UP action - } - - // Handle button press (short, long, and double press) - uint8_t pressType = config->encoder->pushType(config->longPressDuration); - unsigned long currentTime = millis(); - - if (pressType == 1) { - if (config->pendingEnter) { - if (config->doublePressThreshold > 0 && - currentTime - config->lastPressTime < config->doublePressThreshold) { - config->menu->process(BACKSPACE); // Call BACKSPACE action (double press) - config->pendingEnter = false; - } - } else { - config->pendingEnter = true; - config->lastPressTime = currentTime; - } - } else if (pressType == 2) { - config->menu->process(BACK); // Call BACK action (long press) - config->pendingEnter = false; - } - - // Check if the doublePressThreshold has elapsed for pending enter action - if ((!config->menu->lcd.getEditModeEnabled() && config->pendingEnter) || - (config->pendingEnter && (currentTime - config->lastPressTime >= config->doublePressThreshold))) { - config->menu->process(ENTER); // Call ENTER action (short press) - config->pendingEnter = false; - } -} \ No newline at end of file