From 84bbb1297b80dd5afef3a8cfd6120eb23d55fc9e Mon Sep 17 00:00:00 2001 From: Alexander Klein Date: Fri, 10 Feb 2023 09:32:39 +0100 Subject: [PATCH] Initial commit --- README.md | 0 include/displayWrapper.h | 22 ++++ include/menu.h | 55 +++++++++ include/menuAction.h | 103 ++++++++++++++++ include/menuControl.h | 77 ++++++++++++ include/menuInformationSites.h | 92 ++++++++++++++ include/menuIntInput.h | 103 ++++++++++++++++ library.json | 23 ++++ src/menu.cpp | 128 +++++++++++++++++++ src/menuAction.cpp | 67 ++++++++++ src/menuControl.cpp | 22 ++++ src/menuInformationSites.cpp | 98 +++++++++++++++ src/menuIntInput.cpp | 218 +++++++++++++++++++++++++++++++++ 13 files changed, 1008 insertions(+) create mode 100644 README.md create mode 100644 include/displayWrapper.h create mode 100644 include/menu.h create mode 100644 include/menuAction.h create mode 100644 include/menuControl.h create mode 100644 include/menuInformationSites.h create mode 100644 include/menuIntInput.h create mode 100644 library.json create mode 100644 src/menu.cpp create mode 100644 src/menuAction.cpp create mode 100644 src/menuControl.cpp create mode 100644 src/menuInformationSites.cpp create mode 100644 src/menuIntInput.cpp diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/include/displayWrapper.h b/include/displayWrapper.h new file mode 100644 index 0000000..866bc3e --- /dev/null +++ b/include/displayWrapper.h @@ -0,0 +1,22 @@ +/** + * @file displayWrapper.h + * @author Alexander Klein (alex@kleiax.de) + * @brief + * @version 0.1 + * @date 2023-01-08 + * + * @copyright Copyright (c) 2023 + * + */ + +#ifndef DISPLAY_WRAPPER_H +#define DISPLAY_WRAPPER_H + +class DisplayWrapper { + public: + virtual void clear() = 0; + virtual void setCursor(uint8_t row, uint8_t line) = 0; + virtual void print(const char *str) = 0; +}; + +#endif // DISPLAY_WRAPPER_H diff --git a/include/menu.h b/include/menu.h new file mode 100644 index 0000000..832b055 --- /dev/null +++ b/include/menu.h @@ -0,0 +1,55 @@ +/** + * @file menu.h + * @author Alexander Klein (alex@kleiax.de) + * @brief Contains the Menu class + * @version 0.1 + * @date 2022-01-12 + * + * @copyright Copyright (c) 2022 + * + */ +#ifndef MENU_H +#define MENU_H + +#include + +#include "menuAction.h" +#include "menuControl.h" + +class MenuAction; + +/** + * @brief A class to build menu structers + */ +class Menu : public MenuControl { + public: + Menu(); + ~Menu() override; + + /** + * @brief Add a menu action to the menu + * + * @param entry + */ + void addEntry(MenuAction* entry); + bool isInSubmenu(); + + void printMenu() override; + void update() override; + + void down() override; + void up() override; + void right() override; + void left() override; + void yes() override; + void no() override; + + private: + bool inSubmenu = false; + + std::list entrys; + std::list::iterator selectedEntry; + +}; + +#endif // MENU_H diff --git a/include/menuAction.h b/include/menuAction.h new file mode 100644 index 0000000..f4bf046 --- /dev/null +++ b/include/menuAction.h @@ -0,0 +1,103 @@ +/** + * @file menuAction.h + * @author Alexander Klein (alex@kleiax.de) + * @brief Contains the MenuAction class + * @version 0.1 + * @date 2022-01-12 + * + * @copyright Copyright (c) 2022 + * + */ +#ifndef MENU_ENTRY_H +#define MENU_ENTRY_H + +#include "menu.h" + +class MenuControl; + +class MenuActionWrapper { + public: + virtual ~MenuActionWrapper() {} + virtual void action() = 0; +}; + +/** + * @brief This class forms the transition between menus. + * + * In the Menu these are the entries. + * This class can be call an submenu or a function. + */ +class MenuAction { + public: + + /** + * @brief Construct a new Menu Action object + * + * @param name shown in the Menu + * @param function to call when activate the entry + * @param callback to call when leave the entry + */ + MenuAction(const char* name, void (*function) (), void (*callback) () = nullptr); + + /** + * @brief Construct a new Menu Action object + * + * @param name shown in the Menu + * @param action to call when activate the entry + */ + MenuAction(const char* name, MenuActionWrapper* action); + + /** + * @brief Construct a new Menu Action object + * + * This constructer is used for submenus. + * + * @param name shown in the Menu + * @param menu to call when activate the entry + */ + MenuAction(const char* name, MenuControl* menu); + + ~MenuAction(); + + /** + * @brief activates the entry + */ + void runAction(); + + /** + * @brief Get the Name string + * + * @return const char* + */ + const char* getName(); + + /** + * @brief Get the Is Menu object + * + * @return true runAction calls a submenu + * @return false runAction call a function + */ + bool getIsMenu(); + + /** + * @brief Get the Menu object + * + * Before call this function it may be useful + * to check if is it a submenu with getIsMenu. + * + * @return MenuControl* + */ + MenuControl* getMenu(); + + private: + const char* name; + + void (*function) () = nullptr; + void (*callback) () = nullptr; + + bool isMenu = false; + MenuControl* menu = nullptr; + MenuActionWrapper* action = nullptr; +}; + +#endif // MENU_ENTRY_H diff --git a/include/menuControl.h b/include/menuControl.h new file mode 100644 index 0000000..3cbd2f2 --- /dev/null +++ b/include/menuControl.h @@ -0,0 +1,77 @@ +/** + * @file menuControl.h + * @author Alexander Klein (alex@kleiax.de) + * @brief Contains a abstract class for Menu + * @version 0.1 + * @date 2022-01-19 + * + * @copyright Copyright (c) 2022 + * + */ + +#ifndef MENU_CONTROLL_H +#define MENU_CONTROLL_H + +#include +#include "displayWrapper.h" + +/** + * @brief Baseclass to build Menus + * + * This class have to be inherited by other classes which want to be + * act as a menu, because the menu structure uses polymorphism. + * + */ +class MenuControl { + public: + virtual ~MenuControl() {}; + + /** @name UserInputs + * @brief This functions should be called be user actions. + * + * This functions have to be implement in every other menu + * class. + */ + ///@{ + virtual void down() {}; + virtual void up() {}; + virtual void right() {}; + virtual void left() {}; + virtual void yes() {}; + virtual void no() {}; + ///@} + + /** + * @brief can be called to update shown data + */ + virtual void update() {} + + virtual void printMenu() = 0; + + /** + * @brief Set the Parent Menu + * + * If the parentMenu is set it will be called automaticaly + * when the user left the child menu. + * + * @param menu + */ + void setParentMenu(MenuControl* menu) { this->parentMenu = menu; } + // MenuControl* getParentMenu() { return this->parentMenu; } + + /** + * @brief Set the Lcd object + * + * If this is set the menu will be print on the display too. + * + * @param lcd + */ + void setLcd(DisplayWrapper* lcd) { this->lcd = lcd; } + + protected: + void print(String lineOne, String lineTwo) const; + + MenuControl* parentMenu = nullptr; + DisplayWrapper* lcd = nullptr; +}; +#endif // MENU_CONTROLL_H diff --git a/include/menuInformationSites.h b/include/menuInformationSites.h new file mode 100644 index 0000000..5ea1462 --- /dev/null +++ b/include/menuInformationSites.h @@ -0,0 +1,92 @@ +/** + * @file menuInformationSites.h + * @author Alexander Klein (alex@kleiax.de) + * @brief Contains a class to print informations over more pages + * @version 0.1 + * @date 2022-12-27 + * + * @copyright Copyright (c) 2022 + * + */ +#ifndef MENU_INFORMATION_SITES_H +#define MENU_INFORMATION_SITES_H + +#include "menuControl.h" + +class MenuInformationSites : public MenuControl { + public: + /** + * @brief Construct a new Menu Information Sites object + * + * @param amount of pages + */ + MenuInformationSites(uint8_t pages = 1); + + /** + * @brief Next page + */ + void down() override; + + /** + * @brief Previous page + */ + void up() override; + + /** + * @brief Update information + */ + void right() override; + + /** + * @brief Go to the parent menu + */ + void left() override; + + /** + * @brief Go to the parent menu + */ + void no() override; + + /** + * @brief Update information + */ + void yes() override; + + /** + * @brief Prints the Information to display and console + * + * Prints the selected page. + * The informations are only printed to the display if it + * set. + */ + void printMenu() override; + + /** + * @brief can be called to update shown data + */ + void update() override; + + protected: + bool setCountPages(uint8_t pages); + uint8_t getCountPages() const; + uint8_t getCurrentPage() const; + + virtual void printPage() const = 0; + virtual void runCommand() const {} + virtual void init() {} + + void printDefault() const; + + uint8_t lastPageNumber = 0; + bool leaved = true; + + private: + uint8_t countPages; + uint8_t currentPage; + + + const uint16_t delay = 5000; + uint32_t lastMillis = 0; +}; + +#endif // MENU_INFORMATION_SITES_H diff --git a/include/menuIntInput.h b/include/menuIntInput.h new file mode 100644 index 0000000..75934ad --- /dev/null +++ b/include/menuIntInput.h @@ -0,0 +1,103 @@ +/** + * @file menuIntInput.h + * @author Alexander Klein (alex@kleiax.de) + * @brief + * @version 0.1 + * @date 2022-09-12 + * + * @copyright Copyright (c) 2022 + * + */ +#ifndef MENU_INT_INPUT_H +#define MENU_INT_INPUT_H + +#include "menuControl.h" +#include + +#define MAX_NAME_LENGTH 12 + +class MenuIntInputWrapper { + public: + virtual ~MenuIntInputWrapper() {} + virtual void action(int16_t* values, uint8_t length) = 0; +}; + +class MenuIntInput : public MenuControl { + public: + MenuIntInput(int16_t values[], char *names, uint8_t length, MenuIntInputWrapper* wrapper); + MenuIntInput(uint8_t length, MenuIntInputWrapper *wrapper); + ~MenuIntInput(); + + void setEntry(uint8_t valueNumber, const char* name, int16_t startValue = 0); + + void setMin(uint8_t valueNumber, int16_t min); + void setMin(int16_t min); + void setMax(uint8_t valueNumber, int16_t max); + void setMax(int16_t max); + void setMinMax(uint8_t valueNumber, int16_t min, int16_t max); + void setMinMax(int16_t min, int16_t max); + void setMinMaxSteps(uint8_t valueNumber, int16_t min, int16_t max, uint8_t steps); + void setMinMaxSteps(int16_t min, int16_t max, uint8_t steps); + void setPrintParentMenu(bool b) { this->printParentMenu = b; } + + void setStepsPerInput(uint8_t valueNumber, uint8_t steps); + void setStepsPerInput(uint8_t steps); + + /** + * @brief Decrement selected value + */ + void down() override; + + /** + * @brief Increment selected value + */ + void up() override; + + /** + * @brief Select next value + */ + void right() override; + + /** + * @brief Select previous value + */ + void left() override; + + /** + * @brief Leave menu without saving + */ + void no() override; + + /** + * @brief Leave menu with saving + */ + void yes() override; + + /** + * @brief Prints the Information to display and console + * + * The informations are only printed to the display if it + * set. + */ + void printMenu() override; + + void update() override {}; + + private: + MenuIntInputWrapper* wrapper; + + bool printParentMenu = true; + + uint8_t currentPosition = 0; + uint8_t length; + uint8_t *stepsPerInput; + uint8_t countSameActions = 0; + int16_t *values; + int16_t *originalValues; + int16_t *min; + int16_t *max; + char *names; + +}; + +#endif // MENU_INT_INPUT_H diff --git a/library.json b/library.json new file mode 100644 index 0000000..95997a3 --- /dev/null +++ b/library.json @@ -0,0 +1,23 @@ +{ + "name": "Menu", + "version": "1.0.0", + "description": "Build page based menus on uCs", + "keywords": "menu, page, input", + "repository": + { + "type": "git", + "url": "https://git.kleiax.de/PlatformIO-Libs/Menu.git" + }, + "authors": + [ + { + "name": "Alexander Klein", + "email": "alex@kleiax.de", + "url": "https://www.kleiax.de/contact" + } + ], + "license": "MIT", + "homepage": "https://www.kleiax.de/", + "frameworks": "*", + "platforms": "*" + } \ No newline at end of file diff --git a/src/menu.cpp b/src/menu.cpp new file mode 100644 index 0000000..33c30e0 --- /dev/null +++ b/src/menu.cpp @@ -0,0 +1,128 @@ +/** + * @file menu.cpp + * @author Alexander Klein (alex@kleiax.de) + * @brief Implementation of the class Menu + * @version 0.1 + * @date 2022-01-12 + * + * @copyright Copyright (c) 2022 + * + */ +#include "menu.h" + +Menu::Menu() { + this->selectedEntry = this->entrys.begin(); +} + +Menu::~Menu() { + for (std::list::iterator iter = this->entrys.begin(); iter != this->entrys.end(); iter++) + delete *iter; +} + +void Menu::addEntry(MenuAction* entry) { + this->entrys.push_back(entry); + + if (this->entrys.size() == 2) + this->selectedEntry = this->entrys.begin(); +} + +bool Menu::isInSubmenu() { + return this->inSubmenu; +} + +void Menu::printMenu() { + std::list::iterator iter = this->selectedEntry; + + String lineOne = "-> "; + String lineTwo = ""; + + lineOne.concat((**iter).getName()); + iter++; + if (iter != this->entrys.end()) { + lineTwo.concat((**iter).getName()); + } else + lineTwo.concat((*this->entrys.begin())->getName()); + + this->inSubmenu = false; + this->print(lineOne, lineTwo); +} + +void Menu::update() { + if (this->inSubmenu) { + (**this->selectedEntry).getMenu()->update(); + return; + } +} + +void Menu::down() { + if (this->inSubmenu) { + (**this->selectedEntry).getMenu()->down(); + return; + } + + // TODO: Why I need the fucking next two lines? here and in the next function + std::list::iterator iter = this->selectedEntry; + iter++; + if (iter != this->entrys.end()) + this->selectedEntry++; + else + this->selectedEntry = this->entrys.begin(); + this->printMenu(); +} + +void Menu::up() { + if (this->inSubmenu) { + (**this->selectedEntry).getMenu()->up(); + return; + } + std::list::iterator iter = this->entrys.end(); + iter--; + if (this->selectedEntry != this->entrys.begin()) { + this->selectedEntry--; + } + else { + this->selectedEntry = iter; + } + this->printMenu(); +} + +void Menu::right() { + if (this->inSubmenu) { + (**this->selectedEntry).getMenu()->right(); + return; + } + + if ((**this->selectedEntry).getIsMenu()) { + this->inSubmenu = true; + (**this->selectedEntry).getMenu()->setParentMenu(this); + } + (**this->selectedEntry).runAction(); +} + +void Menu::left() { + if (this->inSubmenu) { + (**this->selectedEntry).getMenu()->left(); + return; + } + + if (parentMenu) + this->parentMenu->printMenu(); +} + +void Menu::yes() { + if (this->inSubmenu) { + (**this->selectedEntry).getMenu()->yes(); + return; + } + + this->right(); +} + +void Menu::no() { + if (this->inSubmenu) { + (**this->selectedEntry).getMenu()->no(); + return; + } + + this->left(); +} diff --git a/src/menuAction.cpp b/src/menuAction.cpp new file mode 100644 index 0000000..f4bda6a --- /dev/null +++ b/src/menuAction.cpp @@ -0,0 +1,67 @@ +/** + * @file menuAction.cpp + * @author Alexander Klein (alex@kleiax.de) + * @brief Implentation of the class MenuAction + * @version 0.1 + * @date 2022-01-12 + * + * @copyright Copyright (c) 2022 + * + */ +#include "menuAction.h" + +MenuAction::MenuAction(const char* name, void (*function) (), void (*callback) ()) { + this->name = name; + this->function = function; + this->callback = callback; +} + +MenuAction::MenuAction(const char* name, MenuControl* menu) { + this->name = name; + this->menu = menu; + this->isMenu = true; +} + +MenuAction::MenuAction(const char* name, MenuActionWrapper* action) { + this->name = name; + this->action = action; +} + +MenuAction::~MenuAction() { + if (this->menu) + delete this->menu; + + if (this->action) + delete this->action; +} + +void MenuAction::runAction() { + if (isMenu) + this->menu->printMenu(); + else { + if (this->function) + this->function(); + else if (this->action) + this->action->action(); + else + std::cout << "Error in MenuAction::runAction" << std::endl; + } + + if (this->callback) + this->callback(); +} + +const char* MenuAction::getName() { + return this->name; +} + +bool MenuAction::getIsMenu() { + return this->isMenu; +} + +MenuControl* MenuAction::getMenu() { + if (isMenu) + return this->menu; + else + return nullptr; +} diff --git a/src/menuControl.cpp b/src/menuControl.cpp new file mode 100644 index 0000000..36facc1 --- /dev/null +++ b/src/menuControl.cpp @@ -0,0 +1,22 @@ +/** + * @file menuControl.cpp + * @author Alexander Klein (alex@kleiax.de) + * @brief + * @version 0.1 + * @date 2022-12-28 + * + * @copyright Copyright (c) 2022 + * + */ + +#include "menuControl.h" + +void MenuControl::print(String lineOne, String lineTwo) const { + if (this->lcd) { + lcd->clear(); + lcd->setCursor(0, 0); + lcd->print(lineOne.c_str()); + lcd->setCursor(0, 1); + lcd->print(lineTwo.c_str()); + } +} diff --git a/src/menuInformationSites.cpp b/src/menuInformationSites.cpp new file mode 100644 index 0000000..fbafc0f --- /dev/null +++ b/src/menuInformationSites.cpp @@ -0,0 +1,98 @@ +/** + * @file menuInformationSites.cpp + * @author Alexander Klein (alex@kleiax.de) + * @brief Contains an implementation of the class MenuInformationSites + * @version 0.1 + * @date 2022-12-27 + * + * @copyright Copyright (c) 2022 + * + */ + +#include "menuInformationSites.h" + +MenuInformationSites::MenuInformationSites(uint8_t pages) { + this->countPages = pages; + this->currentPage = 0; + this->lastMillis = millis(); +} + +void MenuInformationSites::up() { + if (this->currentPage == 0) + this->currentPage = this->countPages - 1; + else + this->currentPage--; + this->printMenu(); +} + +void MenuInformationSites::down() { + if (this->currentPage == this->countPages - 1) + this->currentPage = 0; + else + this->currentPage++; + this->printMenu(); +} + +void MenuInformationSites::right() { + this->yes(); +} + +void MenuInformationSites::left() { + if (this->parentMenu) { + this->parentMenu->printMenu(); + this->leaved = true; + } +} + +void MenuInformationSites::no() { + this->left(); +} + +void MenuInformationSites::yes() { + this->runCommand(); + this->printMenu(); +} + +void MenuInformationSites::printMenu() { + if (this->leaved) { + this->leaved = false; + this->lastPageNumber++; + this->init(); + } + + this->printPage(); + this->lastPageNumber = this->currentPage; +} + +void MenuInformationSites::update() { + if (millis() - this->lastMillis < this->delay) { + return; + } + this->printMenu(); + this->lastMillis = millis(); +} + +bool MenuInformationSites::setCountPages(uint8_t pages) { + this->countPages = pages; + this->currentPage = 0; + if (this->countPages == 0) { + this->countPages = 1; + return false; + } + return true; +} + +uint8_t MenuInformationSites::getCountPages() const { + return this->countPages; +} + +uint8_t MenuInformationSites::getCurrentPage() const { + return this->currentPage; +} + +void MenuInformationSites::printDefault() const { + String lineOne = String("Page: ") + (this->currentPage + 1); + String lineTwo = String("of ") + this->countPages; + + this->print(lineOne, lineTwo); +} diff --git a/src/menuIntInput.cpp b/src/menuIntInput.cpp new file mode 100644 index 0000000..3f8675b --- /dev/null +++ b/src/menuIntInput.cpp @@ -0,0 +1,218 @@ +/** + * @file menuIntInput.cpp + * @author Alexander Klein (alex@kleiax.de) + * @brief + * @version 0.1 + * @date 2022-09-12 + * + * @copyright Copyright (c) 2022 + * + */ + +#include "menuIntInput.h" + +MenuIntInput::MenuIntInput(int16_t values[], char *names, uint8_t length, MenuIntInputWrapper* wrapper) { + this->values = values; + this->names = names; + this->length = length; + this->wrapper = wrapper; + + this->min = new int16_t[this->length]; + this->max = new int16_t[this->length]; + this->originalValues = new int16_t[this->length]; + this->stepsPerInput = new uint8_t[this->length]; + + for (uint8_t i = 0; i < this->length; i++) { + this->min[i] = INT16_MIN; + this->max[i] = INT16_MAX; + this->originalValues[i] = this->values[i]; + this->stepsPerInput[i] = 1; + } +} + +MenuIntInput::MenuIntInput(uint8_t length, MenuIntInputWrapper *wrapper) { + this->length = length; + this->wrapper = wrapper; + + this->values = new int16_t[this->length]; + this->names = (char*) new char[this->length][MAX_NAME_LENGTH]; + this->min = new int16_t[this->length]; + this->max = new int16_t[this->length]; + this->originalValues = new int16_t[this->length]; + this->stepsPerInput = new uint8_t[this->length]; + + for (uint8_t i = 0; i < this->length; i++) { + this->min[i] = INT16_MIN; + this->max[i] = INT16_MAX; + this->values[i] = 0; + this->originalValues[i] = 0; + this->stepsPerInput[i] = 1; + strcpy(this->names + MAX_NAME_LENGTH * i, "Default"); + } +} + +MenuIntInput::~MenuIntInput() { + delete this->min; + delete this->max; + delete this->originalValues; + delete this->stepsPerInput; + delete this->values; + delete this->names; + delete this->wrapper; +} + +void MenuIntInput::setEntry(uint8_t valueNumber, const char* name, int16_t startValue) { + if (this->length < valueNumber) + return; + + if (strlen(name) > MAX_NAME_LENGTH) + return; + + + strcpy(this->names + MAX_NAME_LENGTH * valueNumber, name); + this->values[valueNumber] = startValue; + this->originalValues[valueNumber] = startValue; +} + +void MenuIntInput::setMin(uint8_t valueNumber, int16_t min) { + if (this->length < valueNumber) + return; + + this->min[valueNumber] = min; +} + +void MenuIntInput::setMax(uint8_t valueNumber, int16_t max) { + if (this->length < valueNumber) + return; + + this->max[valueNumber] = max; +} + +void MenuIntInput::setMinMax(uint8_t valueNumber, int16_t min, int16_t max) { + this->setMin(valueNumber, min); + this->setMax(valueNumber, max); +} + +void MenuIntInput::setMin(int16_t min) { + for (uint8_t i = 0; i < this->length; i++) + this->min[i] = min; +} + +void MenuIntInput::setMax(int16_t max) { + for (uint8_t i = 0; i < this->length; i++) + this->max[i] = max; +} + +void MenuIntInput::setMinMax(int16_t min, int16_t max) { + this->setMin(min); + this->setMax(max); +} + +void MenuIntInput::setMinMaxSteps(uint8_t valueNumber, int16_t min, int16_t max, uint8_t steps) { + this->setMin(valueNumber, min); + this->setMax(valueNumber, max); + this->setStepsPerInput(valueNumber, steps); +} + +void MenuIntInput::setMinMaxSteps(int16_t min, int16_t max, uint8_t steps) { + this->setMin(min); + this->setMax(max); + this->setStepsPerInput(steps); +} + +void MenuIntInput::setStepsPerInput(uint8_t valueNumber, uint8_t steps) { + if (this->length < valueNumber) + return; + + this->stepsPerInput[valueNumber] = steps; +} + +void MenuIntInput::setStepsPerInput(uint8_t steps) { + for (uint8_t i = 0; i < this->length; i++) + this->stepsPerInput[i] = steps; +} + +void MenuIntInput::down() { + if (this->values[this->currentPosition] + - this->stepsPerInput[this->currentPosition] + >= this->min[currentPosition]) + { + this->values[this->currentPosition] -= this->stepsPerInput[this->currentPosition]; + } else { + this->values[this->currentPosition] = this->max[this->currentPosition]; + } + + this->printMenu(); +} + +void MenuIntInput::up() { + if (this->values[this->currentPosition] + + this->stepsPerInput[this->currentPosition] + <= this->max[this->currentPosition]) + { + this->values[this->currentPosition] += this->stepsPerInput[this->currentPosition]; + } else { + this->values[this->currentPosition] = this->min[this->currentPosition]; + } + + this->printMenu(); +} + +void MenuIntInput::right() { + if (currentPosition < this->length - 1) + currentPosition++; + else + currentPosition = 0; + + this->printMenu(); +} + +void MenuIntInput::left() { + if (currentPosition > 0) + currentPosition--; + else + currentPosition = this->length - 1; + + this->printMenu(); +} + +void MenuIntInput::no() { + for (uint8_t i = 0; i < this->length; i++) + this->values[i] = this->originalValues[i]; + this->currentPosition = 0; + + if (this->parentMenu) + this->parentMenu->printMenu(); +} + +void MenuIntInput::yes() { + this->wrapper->action(this->values, this->length); + if (this->parentMenu && printParentMenu) + this->parentMenu->printMenu(); +} + +void MenuIntInput::printMenu() { + char bufferName[17]; + + if (this->currentPosition == 0 && this->length == 1) { + // No arrow + sprintf(bufferName, " %s ", this->names + MAX_NAME_LENGTH * this->currentPosition); + } else if (this->currentPosition > 0 && this->length - 1 == this->currentPosition) { + // Left arrow only + sprintf(bufferName, "< %s ", this->names + MAX_NAME_LENGTH * this->currentPosition); + } else if (this->currentPosition == 0 && this->length > 1) { + // Right arrow only + sprintf(bufferName, " %s >", this->names + MAX_NAME_LENGTH * this->currentPosition); + } else { + // Both arrow + sprintf(bufferName, "< %s >", this->names + MAX_NAME_LENGTH * this->currentPosition); + } + + char bufferValue[17]; + if (this->values[this->currentPosition]) + sprintf(bufferValue, " -> %5.d", this->values[this->currentPosition]); + else + sprintf(bufferValue, " -> 0"); + + this->print(bufferName, bufferValue); +}