implement left/right with callback

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2025-06-15 00:49:30 +02:00
parent 52a49363eb
commit 2191174681
29 changed files with 1783 additions and 641 deletions

View File

@@ -1,10 +1,11 @@
if (DEFINED ENV{IDF_PATH})
idf_component_register(SRCS
src/common/PSMenu.cpp
src/common/Menu.cpp
src/common/ScrollBar.cpp
src/common/Widget.cpp
src/data/MenuItem.cpp
src/ui/LightMenu.cpp
src/ui/LightSettingsMenu.cpp
src/ui/MainMenu.cpp
src/ui/SettingsMenu.cpp
src/ui/SplashScreen.cpp
@@ -17,11 +18,12 @@ cmake_minimum_required(VERSION 3.30)
project(insa)
add_library(${PROJECT_NAME} STATIC
src/common/PSMenu.cpp
src/common/Menu.cpp
src/common/ScrollBar.cpp
src/common/Widget.cpp
src/data/MenuItem.cpp
src/ui/LightMenu.cpp
src/ui/LightSettingsMenu.cpp
src/ui/MainMenu.cpp
src/ui/SettingsMenu.cpp
src/ui/SplashScreen.cpp

View File

@@ -1,4 +1,14 @@
// Prevents multiple inclusions of this header file
/**
* @file MenuOptions.h
* @brief Menu configuration structure and callback definitions
* @details This header defines the menu_options_t structure which contains all
* necessary configuration options and callback functions for menu widgets.
* It provides the interface between menu widgets and the application's
* screen management system, display context, and input handling.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
// Standard libraries for function objects and smart pointers
@@ -6,28 +16,114 @@
#include <memory>
// Project-specific headers
#include "persistence.h"
#include "common/Widget.h"
#include "u8g2.h"
// Structure for menu options and callback functions
class MenuItem;
/**
* @struct menu_options_t
* @brief Configuration structure for menu widgets containing display context and callbacks
* @details This structure serves as a configuration container that provides menu widgets
* with access to the display system, screen management functions, and input
* handling callbacks. It acts as the bridge between individual menu widgets
* and the broader application framework.
*
* The structure contains:
* - Display context for rendering operations
* - Screen management callbacks for navigation
* - Input handling callback for button events
*
* All callback functions use std::function for type safety and flexibility,
* allowing both function pointers and lambda expressions to be used.
*
* @note This structure should be initialized by the application framework
* and passed to menu widgets during construction.
*
* @see Widget
* @see ButtonType
*/
typedef struct
{
// Pointer to u8g2 display object for graphics output
/**
* @brief Pointer to u8g2 display context for graphics output operations
* @details This pointer provides access to the u8g2 graphics library functions
* for rendering text, shapes, and other visual elements. It must be
* initialized and ready for drawing operations before being passed
* to menu widgets.
*
* @note The menu widgets do not take ownership of this pointer and assume
* it remains valid throughout their lifetime. Ensure the u8g2 context
* is properly managed by the application framework.
*
* @warning Must not be nullptr when passed to menu widgets
*/
u8g2_t *u8g2;
// Callback function to set the current screen
// Parameter: Smart pointer to a Widget object
/**
* @brief Callback function to set the current active screen
* @param screen Smart pointer to the Widget that should become the active screen
*
* @details This callback replaces the currently active screen with the provided
* widget. It is typically used for direct screen transitions where the
* previous screen should be completely replaced rather than stacked.
*
* @note The callback takes ownership of the provided Widget through the shared_ptr.
* The previous screen will be destroyed unless other references exist.
*
* @see pushScreen for adding screens to a navigation stack
*/
std::function<void(std::shared_ptr<Widget>)> setScreen;
// Callback function to add a new screen to the stack
// Parameter: Smart pointer to a Widget object
/**
* @brief Callback function to add a new screen to the navigation stack
* @param screen Smart pointer to the Widget that should be pushed onto the screen stack
*
* @details This callback adds a new screen on top of the current screen stack,
* allowing for hierarchical navigation where users can return to
* previous screens. Commonly used for sub-menus, settings screens,
* or modal dialogs.
*
* @note The callback takes ownership of the provided Widget through the shared_ptr.
* The current screen remains in memory and can be returned to via popScreen().
*
* @see popScreen for removing screens from the navigation stack
* @see setScreen for direct screen replacement
*/
std::function<void(std::shared_ptr<Widget>)> pushScreen;
// Callback function to remove the top screen from the stack
// No parameters required
/**
* @brief Callback function to remove the top screen from the navigation stack
* @details This callback removes the currently active screen and returns to the
* previous screen in the navigation stack. It is typically used for
* "back" or "cancel" operations in hierarchical menu systems.
*
* @note If the navigation stack is empty or contains only one screen, the
* behavior is implementation-dependent and should be handled gracefully
* by the application framework.
*
* @see pushScreen for adding screens to the navigation stack
*/
std::function<void()> popScreen;
// Callback function to handle button presses
// Parameter: 8-bit button ID/status
std::function<void(uint8_t button)> onButtonClicked;
/**
* @brief Callback function to handle button press events
* @param button The type of button that was pressed
*
* @details This callback is invoked when a button press event occurs that is
* not handled directly by the menu widget. It allows the application
* framework to implement global button handling logic, such as
* system-wide shortcuts or fallback behavior.
*
* @note This callback is typically used for buttons that have application-wide
* meaning (e.g., home button, menu button) rather than widget-specific
* navigation which is handled internally by the widgets.
*
* @see ButtonType for available button types
* @see Widget::onButtonClicked for widget-specific button handling
*/
std::function<void(ButtonType button)> onButtonClicked;
persistence_t *persistence;
} menu_options_t;

View File

@@ -1,21 +1,63 @@
/**
* @file Common.h
* @brief Common definitions and types for the INSA component
* @details This header file contains shared enumerations, type definitions, and
* callback function types used throughout the INSA component system.
* It provides the foundation for button handling and event management.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include <functional>
// Enumeration defining the different types of buttons available in the system
// NONE represents no button pressed or an invalid button state
enum class ButtonType {
NONE, // No button or invalid state
UP, // Up directional button
DOWN, // Down directional button
LEFT, // Left directional button
RIGHT, // Right directional button
SELECT, // Select/confirm button
BACK // Back/cancel button
/**
* @enum ButtonType
* @brief Enumeration defining the different types of buttons available in the system
* @details This enumeration represents all possible button types that can be handled
* by the system's input management. NONE represents no button pressed or
* an invalid button state, while the other values correspond to specific
* directional and action buttons.
*/
enum class ButtonType
{
NONE, ///< No button pressed or invalid button state
UP, ///< Up directional button for navigation
DOWN, ///< Down directional button for navigation
LEFT, ///< Left directional button for navigation
RIGHT, ///< Right directional button for navigation
SELECT, ///< Select/confirm button for accepting choices
BACK ///< Back/cancel button for returning to previous state
};
// Type alias for button event callback function
// Parameters:
// - uint8_t: Button identifier or additional data
// - ButtonType: The type of button that was pressed
typedef std::function<void(uint8_t, ButtonType)> ButtonCallback;
// Forward declaration of MenuItem to avoid circular dependency
class MenuItem;
/**
* @typedef ButtonCallback
* @brief Type alias for button event callback function
* @details This function type is used to define callback functions that handle
* button press events. The callback receives information about which
* button was pressed and any additional context data.
*
* @param MenuItem menu item for the specific action
* @param ButtonType The type of button that was pressed
*
* @note The first parameter can be used to distinguish between multiple instances
* of the same button type or to pass additional event-specific data.
*
* @example
* @code
* ButtonCallback myCallback = [](const MenuItem& item, ButtonType type) {
* if (type == ButtonType::SELECT) {
* // Handle select button press
* processSelection(item);
* }
* };
* @endcode
*/
typedef std::function<void(MenuItem, ButtonType)> ButtonCallback;
// Include MenuItem.h after the typedef to avoid circular dependency
#include "data/MenuItem.h"

View File

@@ -0,0 +1,232 @@
/**
* @file Menu.h
* @brief Menu widget class for creating interactive menu systems
* @details This header defines the Menu class which extends the Widget base class
* to provide a comprehensive, customizable menu system supporting various
* types of interactive menu items including text buttons, selections,
* number inputs, and toggles. The menu supports navigation with directional
* input and provides visual feedback through selection highlighting and scrollbars.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include "Common.h"
#include "MenuOptions.h"
#include "Widget.h"
#include "data/MenuItem.h"
/**
* @class Menu
* @brief A comprehensive menu widget class for interactive user interfaces
* @details This class extends the Widget base class to provide a customizable menu system
* with support for various types of interactive menu items. It handles user input
* through directional navigation and action buttons, provides visual feedback
* through selection highlighting, and supports scrolling for long menu lists.
*
* The menu system supports four types of menu items:
* - Text buttons: Simple selectable text items
* - Selection items: Dropdown/list selection with multiple options
* - Number inputs: Numeric value adjustment controls
* - Toggle items: Boolean on/off switches
*
* @note Menu items are identified by unique IDs and can be dynamically added
* after menu creation.
*
* @see Widget
* @see MenuItem
* @see menu_options_t
*/
class Menu : public Widget
{
public:
/**
* @brief Constructs a new Menu instance with the specified configuration
* @param options Pointer to menu configuration options structure
*
* @pre options must not be nullptr and must remain valid for the menu's lifetime
* @post Menu is initialized with the provided configuration and ready for item addition
*
* @note The menu does not take ownership of the options structure and assumes
* it remains valid throughout the menu's lifetime.
*/
explicit Menu(menu_options_t *options);
/**
* @brief Destructor - Cleans up resources when menu is destroyed
* @details Properly releases any allocated resources and ensures clean shutdown
* of the menu system.
*/
~Menu() override;
/**
* @brief Adds a text-based menu item (button) to the menu
* @param id Unique identifier for this menu item (must be unique within the menu)
* @param text Display text shown on the menu item
*
* @pre id must be unique within this menu instance
* @post A new text menu item is added to the menu's item collection
*
* @note Text items act as buttons and generate selection events when activated
*/
void addText(uint8_t id, const std::string &text);
/**
* @brief Adds a selection menu item (dropdown/list selection) to the menu
* @param id Unique identifier for this menu item (must be unique within the menu)
* @param text Display text/label for the selection item
* @param values Vector of all available options to choose from
* @param index Reference to current selected value (will be modified by user interaction)
*
* @pre id must be unique within this menu instance
* @pre values vector must not be empty
* @pre value must be one of the strings in the values vector
* @post A new selection menu item is added with the specified options
*
* @note The value parameter is modified directly when the user changes the selection
*/
void addSelection(uint8_t id, const std::string &text, const std::vector<std::string> &values, int index);
/**
* @brief Adds a toggle/checkbox menu item to the menu
* @param id Unique identifier for this menu item (must be unique within the menu)
* @param text Display text/label for the toggle item
* @param selected Current state of the toggle (true = on/enabled, false = off/disabled)
*
* @pre id must be unique within this menu instance
* @post A new toggle menu item is added with the specified initial state
*
* @note Toggle state can be changed through user interaction with select button
*/
void addToggle(uint8_t id, const std::string &text, bool selected);
protected:
/**
* @brief Virtual callback method for handling button press events on specific menu items
* @param item The menu item that received the button press
* @param button The type of button that was pressed
*
* @details This method can be overridden by derived classes to implement custom
* button handling logic for specific menu items. The base implementation
* is empty, allowing derived classes to selectively handle events.
*
* @note Override this method in derived classes to implement custom menu item
* interaction behavior beyond the standard navigation and value modification.
*/
virtual void onButtonPressed(const MenuItem &item, const ButtonType button)
{
// Base implementation intentionally empty - override in derived classes as needed
}
MenuItem getItem(int index);
[[nodiscard]] size_t getItemCount() const;
void setItemSize(size_t size);
void replaceItem(int index, const MenuItem &item);
private:
/**
* @brief Renders the entire menu on screen
* @details Override from Widget base class. Handles the complete rendering process
* including menu items, selection highlighting, and scroll indicators.
*
* @note This method is called during each frame's render cycle
*/
void render() override;
/**
* @brief Handles button press events from the input system
* @param button The button that was pressed
* @details Override from Widget base class. Processes user input and delegates
* to appropriate handler methods based on button type.
*
* @see ButtonType for available button types
*/
void onButtonClicked(ButtonType button) override;
// Navigation event handlers
/**
* @brief Handles down arrow/stick input - moves selection down in the menu
* @details Moves the current selection to the next menu item, wrapping to the
* beginning if at the end of the list.
*/
void onPressedDown();
/**
* @brief Handles up arrow/stick input - moves selection up in the menu
* @details Moves the current selection to the previous menu item, wrapping to the
* end if at the beginning of the list.
*/
void onPressedUp();
/**
* @brief Handles left arrow/stick input - decreases value for current item
* @details For selection items: moves to previous option in the list
* For number items: decreases the numeric value
* For other items: no action
*/
void onPressedLeft() const;
/**
* @brief Handles right arrow/stick input - increases value for current item
* @details For selection items: moves to next option in the list
* For number items: increases the numeric value
* For other items: no action
*/
void onPressedRight() const;
/**
* @brief Handles select/confirm button press
* @details Activates the currently selected menu item:
* - Text items: triggers selection event
* - Toggle items: toggles the boolean state
* - Other items: context-dependent behavior
*/
void onPressedSelect() const;
/**
* @brief Handles back/cancel button press
* @details Typically used to exit the menu or return to a previous screen.
* The specific behavior depends on the menu configuration.
*/
void onPressedBack() const;
// Rendering helper methods
/**
* @brief Draws the scroll bar indicating position in long menus
* @details Renders a visual scroll indicator when the menu contains more items
* than can be displayed on screen simultaneously.
*/
void drawScrollBar() const;
/**
* @brief Draws the selection highlight box around current menu item
* @details Renders visual feedback showing which menu item is currently selected
* and will respond to user input.
*/
void drawSelectionBox() const;
/**
* @brief Renders an individual menu item widget
* @param item Pointer to the menu item to render (must not be nullptr)
* @param font Font to use for rendering text
* @param x X coordinate for rendering position
* @param y Y coordinate for rendering position
*
* @pre item must not be nullptr
* @pre font must be a valid u8g2 font
* @pre x and y must be valid screen coordinates
*
* @details Handles the rendering of a single menu item based on its type,
* including text, current values, and any type-specific visual elements.
*/
void renderWidget(const MenuItem *item, const uint8_t *font, int x, int y) const;
// Member variables
size_t m_selected_item = 0; ///< Index of currently selected menu item (0-based)
std::vector<MenuItem> m_items; ///< Collection of all menu items in display order
menu_options_t *m_options; ///< Pointer to menu configuration options (not owned)
};

View File

@@ -1,137 +0,0 @@
#pragma once
#include <functional>
#include "Common.h"
#include "MenuOptions.h"
#include "Widget.h"
#include "data/MenuItem.h"
/**
* PSMenu - A menu widget class
*
* This class extends the Widget base class to provide a customizable menu system
* with various types of interactive menu items including text buttons, selections,
* number inputs, and toggles.
*/
class PSMenu : public Widget
{
public:
/**
* Constructor - Creates a new PSMenu instance
* @param options Pointer to menu configuration options
*/
explicit PSMenu(menu_options_t *options);
/**
* Destructor - Cleans up resources when menu is destroyed
*/
~PSMenu() override;
/**
* Adds a text-based menu item (button) to the menu
* @param id Unique identifier for this menu item
* @param text Display text shown on the menu
* @param callback Function to call when this item is selected
*/
void addText(uint8_t id, const std::string &text, const ButtonCallback &callback);
/**
* Adds a selection menu item (dropdown/list selection)
* @param id Unique identifier for this menu item
* @param text Display text/label for the selection
* @param value Reference to current selected value (will be modified)
* @param values Vector of all available options to choose from
* @param callback Function to call when selection changes
*/
void addSelection(uint8_t id, const std::string &text, std::string &value, const std::vector<std::string>& values,
const ButtonCallback &callback);
/**
* Adds a numeric input menu item
* @param id Unique identifier for this menu item
* @param text Display text/label for the number input
* @param value Reference to current numeric value as string (will be modified)
* @param callback Function to call when value changes
*/
void addNumber(uint8_t id, const std::string &text, std::string &value, const ButtonCallback &callback);
/**
* Adds a toggle/checkbox menu item
* @param id Unique identifier for this menu item
* @param text Display text/label for the toggle
* @param selected Current state of the toggle (true = on, false = off)
* @param callback Function to call when toggle state changes
*/
void addToggle(uint8_t id, const std::string &text, bool selected, const ButtonCallback &callback);
private:
/**
* Renders the entire menu on screen
* Override from Widget base class
*/
void render() override;
/**
* Handles button press events from the controller/input system
* @param button The button that was pressed
* Override from Widget base class
*/
void onButtonClicked(uint8_t button) override;
// Navigation event handlers
/**
* Handles down arrow/stick input - moves selection down
*/
void onPressedDown();
/**
* Handles up arrow/stick input - moves selection up
*/
void onPressedUp();
/**
* Handles left arrow/stick input - decreases value for current item
*/
void onPressedLeft() const;
/**
* Handles right arrow/stick input - increases value for current item
*/
void onPressedRight() const;
/**
* Handles select/confirm button (X on PlayStation controller)
*/
void onPressedSelect() const;
/**
* Handles back/cancel button (Circle on PlayStation controller)
*/
void onPressedBack() const;
// Rendering helper methods
/**
* Draws the scroll bar indicating position in long menus
*/
void drawScrollBar() const;
/**
* Draws the selection highlight box around current menu item
*/
void drawSelectionBox() const;
/**
* Renders an individual menu item widget
* @param item Pointer to the menu item to render
* @param font Font to use for rendering text
* @param x X coordinate for rendering position
* @param y Y coordinate for rendering position
*/
void renderWidget(const MenuItem *item, const uint8_t *font, int x, int y) const;
// Member variables
size_t m_selected_item = 0; ///< Index of currently selected menu item
std::vector<MenuItem> m_items; ///< Collection of all menu items
menu_options_t *m_options; ///< Pointer to menu configuration options
};

View File

@@ -1,52 +1,106 @@
/**
* @file ScrollBar.h
* @brief Vertical scrollbar widget for indicating scroll position in long content
* @details This header defines the ScrollBar class which provides a visual scrollbar
* widget for indicating the current position within scrollable content.
* The scrollbar displays a thumb that moves proportionally to represent
* the current scroll position and visible area relative to the total content.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include "MenuOptions.h"
#include "Widget.h"
/**
* ScrollBar class that represents a vertical scrollbar widget
* Inherits from Widget base class and provides scrolling functionality
* @class ScrollBar
* @brief A vertical scrollbar widget that represents scroll position and range
* @details This final class inherits from Widget and provides visual feedback for
* scrollable content. It displays a vertical track with a movable thumb
* that indicates the current position within a scrollable range. The thumb
* size is proportional to the visible area relative to the total content,
* and its position reflects the current scroll offset.
*
* The scrollbar automatically calculates thumb dimensions and position based on
* the provided scroll values (current, minimum, maximum). It is designed to be
* used alongside scrollable content like menus or lists to provide visual
* feedback about scroll state.
*
* @note This class is marked as final and cannot be inherited from.
*
* @see Widget
* @see menu_options_t
*/
class ScrollBar final : public Widget
{
public:
/**
* Constructor for ScrollBar
* @param options Pointer to menu options configuration
* @param x X coordinate position of the scrollbar
* @param y Y coordinate position of the scrollbar
* @param width Width of the scrollbar
* @param height Height of the scrollbar
* @brief Constructs a ScrollBar with specified position and dimensions
* @param options Pointer to menu options configuration structure
* @param x X coordinate position of the scrollbar on screen
* @param y Y coordinate position of the scrollbar on screen
* @param width Width of the scrollbar in pixels
* @param height Height of the scrollbar in pixels
*
* @pre options must not be nullptr and must remain valid for the scrollbar's lifetime
* @pre width and height must be greater than 0
* @pre x and y must be valid screen coordinates
* @post ScrollBar is initialized with the specified geometry and ready for use
*
* @note The scrollbar does not take ownership of the options structure and
* assumes it remains valid throughout the scrollbar's lifetime.
*/
ScrollBar(const menu_options_t *options, size_t x, size_t y, size_t width, size_t height);
/**
* Renders the scrollbar to the screen
* Overrides the base Widget render method
* @brief Renders the scrollbar to the screen
* @details Overrides the base Widget render method to draw the scrollbar track
* and thumb. The appearance is determined by the current scroll state
* and the menu options configuration.
*
* @pre u8g2 display context must be initialized and ready for drawing
* @post Scrollbar's visual representation is drawn to the display buffer
*
* @note This method is called during each frame's render cycle. The scrollbar
* track and thumb are drawn based on the current scroll values set by refresh().
*/
void render() override;
/**
* Updates the scrollbar state with new values
* @param value Current scroll position value
* @param max Maximum scroll value
* @param min Minimum scroll value (default: 0)
* @brief Updates the scrollbar state with new scroll values
* @param value Current scroll position value (must be between min and max)
* @param max Maximum scroll value (total content size)
* @param min Minimum scroll value (default: 0, typically the start of content)
*
* @pre value must be between min and max (inclusive)
* @pre max must be greater than or equal to min
* @post Scrollbar thumb position and size are recalculated based on new values
*
* @details This method recalculates the thumb's height and vertical position
* based on the provided scroll range and current position. The thumb
* height represents the proportion of visible content to total content,
* while its position represents the current scroll offset within the range.
*
* @note Call this method whenever the scroll state changes to keep the
* scrollbar visualization synchronized with the actual content position.
*/
void refresh(size_t value, size_t max, size_t min = 0);
private:
// Position and dimensions
size_t m_x; // X coordinate of the scrollbar
size_t m_y; // Y coordinate of the scrollbar
size_t m_width; // Width of the scrollbar
size_t m_height; // Height of the scrollbar
size_t m_x; ///< X coordinate of the scrollbar's left edge
size_t m_y; ///< Y coordinate of the scrollbar's top edge
size_t m_width; ///< Width of the scrollbar track in pixels
size_t m_height; ///< Height of the scrollbar track in pixels
// Scroll state values
size_t m_value; // Current scroll position
size_t m_max; // Maximum scroll value
size_t m_min; // Minimum scroll value
size_t m_value; ///< Current scroll position within the range [m_min, m_max]
size_t m_max; ///< Maximum scroll value representing the end of content
size_t m_min; ///< Minimum scroll value representing the start of content
// Calculated thumb properties
size_t m_thumbHeight; // Height of the scroll thumb
size_t m_thumbY; // Y position of the scroll thumb
// Calculated thumb properties (updated by refresh())
size_t m_thumbHeight; ///< Calculated height of the scroll thumb in pixels
size_t m_thumbY; ///< Calculated Y position of the scroll thumb relative to track
};

View File

@@ -1,52 +1,114 @@
/**
* @file Widget.h
* @brief Base widget class for UI components in the INSA system
* @details This header defines the Widget base class that serves as the foundation
* for all UI components in the system. It provides a standardized interface
* for rendering, updating, and handling user input using the u8g2 graphics library.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include "u8g2.h"
#include "common/Common.h"
/**
* Base class for UI widgets that can be rendered and interact with user input.
* This class provides a common interface for all widgets in the system.
* @class Widget
* @brief Base class for UI widgets that can be rendered and interact with user input
* @details This abstract base class provides a common interface for all widgets in the system.
* It manages the u8g2 display context and defines the core methods that all widgets
* must implement or can override. The class follows the template method pattern,
* allowing derived classes to customize behavior while maintaining a consistent
* interface for the UI system.
*
* @note All widgets should inherit from this class to ensure compatibility with
* the UI management system.
*
* @see u8g2_t
* @see ButtonType
*/
class Widget
{
public:
/**
* Constructs a widget with the given u8g2 display context.
* @param u8g2 Pointer to the u8g2 display context used for rendering
* @brief Constructs a widget with the given u8g2 display context
* @param u8g2 Pointer to the u8g2 display context used for rendering operations
*
* @pre u8g2 must not be nullptr
* @post Widget is initialized with the provided display context
*
* @note The widget does not take ownership of the u8g2 context and assumes
* it remains valid for the lifetime of the widget.
*/
explicit Widget(u8g2_t *u8g2);
/**
* Virtual destructor to ensure proper cleanup of derived classes.
* @brief Virtual destructor to ensure proper cleanup of derived classes
* @details Ensures that derived class destructors are called correctly when
* a widget is destroyed through a base class pointer.
*/
virtual ~Widget() = default;
/**
* Updates the widget's internal state based on elapsed time.
* This method is called once per frame to handle animations,
* timers, or other time-dependent behavior.
* @param dt Delta time in milliseconds since last update
* @brief Updates the widget's internal state based on elapsed time
* @param dt Delta time in milliseconds since the last update call
*
* @details This method is called once per frame by the UI system to handle
* animations, timers, state transitions, or other time-dependent behavior.
* The base implementation is empty, allowing derived classes to override
* only if time-based updates are needed.
*
* @note Override this method in derived classes to implement time-based behavior
* such as animations, blinking effects, or timeout handling.
*/
virtual void update(uint64_t dt);
/**
* Renders the widget to the display.
* This method should be overridden by derived classes to implement
* their specific rendering logic using the u8g2 display context.
* @brief Renders the widget to the display
* @details This method should be overridden by derived classes to implement
* their specific rendering logic using the u8g2 display context.
* The base implementation is empty, requiring derived classes to
* provide their own rendering code.
*
* @pre u8g2 context must be initialized and ready for drawing operations
* @post Widget's visual representation is drawn to the display buffer
*
* @note This method is called during the rendering phase of each frame.
* Derived classes should use the u8g2 member variable to perform
* drawing operations.
*/
virtual void render();
/**
* Handles button click events.
* This method is called when a button is pressed and allows
* the widget to respond to user input.
* @param button The identifier of the button that was clicked
* @brief Handles button press events
* @param button The type of button that was pressed
*
* @details This method is called when a button press event occurs and allows
* the widget to respond to user input. The base implementation is empty,
* allowing derived classes to override only if input handling is needed.
*
* @note Override this method in derived classes to implement button-specific
* behavior such as navigation, selection, or state changes.
*
* @see ButtonType for available button types
*/
virtual void onButtonClicked(uint8_t button);
virtual void onButtonClicked(ButtonType button);
protected:
/**
* Pointer to the u8g2 display context used for rendering operations.
* This provides access to drawing functions for text, graphics, and other UI elements.
* @brief Pointer to the u8g2 display context used for rendering operations
* @details This member provides access to the u8g2 graphics library functions
* for drawing text, shapes, bitmaps, and other UI elements. It is
* initialized during construction and remains valid for the widget's lifetime.
*
* @note This member is protected to allow derived classes direct access while
* preventing external modification. Derived classes should use this
* context for all rendering operations.
*
* @warning Do not modify or delete this pointer. The widget does not own
* the u8g2 context and assumes it is managed externally.
*/
u8g2_t *u8g2;
};

View File

@@ -1,107 +1,337 @@
/**
* @file MenuItem.h
* @brief Menu item data structure for user interface menu systems
* @details This header defines the MenuItem class which represents individual menu
* items that can be displayed and interacted with in user interface menus.
* It supports various types of menu items including simple buttons, toggles,
* value selectors, and multi-option selections with flexible callback handling.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include <functional>
#include <string>
#include <vector>
#include "common/Common.h"
/**
* Represents a menu item that can be displayed in a user interface.
* Supports different types of menu items with various interaction capabilities.
* @class MenuItem
* @brief Flexible menu item class supporting various interaction types and behaviors
* @details This class represents individual menu items that can be displayed in user
* interface menus. It provides a flexible foundation for different types of
* menu interactions including simple navigation buttons, toggle switches,
* value adjustments, and multi-option selections.
*
* The MenuItem class supports multiple interaction patterns:
* - **Simple Actions**: Basic menu items that execute a function when activated
* - **Value Display**: Items that show a current value (read-only or editable)
* - **Selection Lists**: Items that cycle through multiple predefined values
* - **Toggle States**: Boolean items that can be switched on/off
* - **Custom Behaviors**: Flexible callback system for specialized interactions
*
* Each menu item is identified by a unique ID and has a type that defines its
* visual appearance and interaction behavior. The callback system allows for
* flexible event handling while maintaining type safety through std::function.
*
* Key features include:
* - Multiple constructor overloads for different menu item types
* - Type-safe callback system with ButtonCallback function objects
* - Support for both single values and value lists
* - Flexible text and value management
* - Efficient state management and validation
*
* @note This class is designed to be lightweight and efficient for embedded
* systems while providing rich functionality for complex user interfaces.
*
* @see ButtonCallback for callback function signature
* @see ButtonType for available button types
* @see Menu for menu container functionality
*/
class MenuItem
{
public:
/**
* Constructor for a simple menu item with text and callback.
* @param id Unique identifier for this menu item
* @param type Type of the menu item (defines behavior and appearance)
* @param text Display text for the menu item
* @brief Constructs a simple action menu item with text and callback
* @param id Unique identifier for this menu item within its parent menu
* @param type Type identifier defining the item's behavior and visual appearance
* @param text Display text shown to the user for this menu item
* @param callback Function to call when the item is activated
*
* @pre id must be unique within the parent menu context
* @pre text should not be empty for proper user interface display
* @pre callback should be a valid callable object
* @post MenuItem is initialized as a simple action item ready for display
*
* @details Creates a basic menu item that displays text and executes a callback
* when activated. This is the most common type of menu item used for
* navigation, simple actions, and command execution.
*
* Typical use cases include:
* - Navigation items (e.g., "Settings", "Back", "Exit")
* - Action items (e.g., "Save", "Reset", "Start")
* - Sub-menu entries (e.g., "Light Control", "System Info")
*
* @note The callback is stored as a std::function and can be a lambda,
* function pointer, or any callable object matching the ButtonCallback signature.
*/
MenuItem(uint8_t id, uint8_t type, std::string text, ButtonCallback callback);
/**
* Constructor for a menu item with a value field.
* @param id Unique identifier for this menu item
* @param type Type of the menu item
* @param text Display text for the menu item
* @param value Current value associated with this item
* @brief Constructs a value-displaying menu item with text, value, and callback
* @param id Unique identifier for this menu item within its parent menu
* @param type Type identifier defining the item's behavior and visual appearance
* @param text Display text shown to the user for this menu item
* @param value Current value associated with this item (displayed to user)
* @param callback Function to call when the item is activated
*
* @pre id must be unique within the parent menu context
* @pre text should not be empty for proper user interface display
* @pre callback should be a valid callable object
* @post MenuItem is initialized with text and value display capabilities
*
* @details Creates a menu item that displays both text and a current value.
* This type is commonly used for settings display, status information,
* or items where the current state needs to be visible to the user.
*
* Typical use cases include:
* - Setting displays (e.g., "Brightness: 75%")
* - Status information (e.g., "Connection: WiFi")
* - Editable values (e.g., "Timeout: 30s")
* - Current selections (e.g., "Mode: Auto")
*
* @note The value can be updated later using setValue() to reflect changes
* in the underlying system state.
*/
MenuItem(uint8_t id, uint8_t type, std::string text, std::string value, ButtonCallback callback);
/**
* Constructor for a menu item with multiple selectable values.
* @param id Unique identifier for this menu item
* @param type Type of the menu item
* @param text Display text for the menu item
* @param value Currently selected value
* @param values List of all available values for selection
* @brief Constructs a multi-selection menu item with selectable values
* @param id Unique identifier for this menu item within its parent menu
* @param type Type identifier defining the item's behavior and visual appearance
* @param text Display text shown to the user for this menu item
* @param values List of all available values that can be selected
* @param index Currently selected value from the available options
* @param callback Function to call when the item is activated
*
* @pre id must be unique within the parent menu context
* @pre text should not be empty for proper user interface display
* @pre value should be present in the values vector
* @pre values should not be empty and should contain valid options
* @pre callback should be a valid callable object
* @post MenuItem is initialized with multiple selectable values
*
* @details Creates a menu item that allows selection from multiple predefined
* values. This type enables cycling through options or displaying
* selection dialogs, making it ideal for configuration settings
* with discrete choices.
*
* Typical use cases include:
* - Mode selection (e.g., "Display Mode: [Day, Night, Auto]")
* - Configuration options (e.g., "Language: [English, Deutsch, Français]")
* - Preset selection (e.g., "Profile: [Home, Office, Travel]")
* - Format selection (e.g., "Time Format: [12H, 24H]")
*
* @note The callback can implement cycling logic to move through the values
* or open a selection dialog for user choice.
* @note The values vector is stored by copy, so modifications to the original
* vector after construction do not affect the menu item.
*/
MenuItem(uint8_t id, uint8_t type, std::string text, std::string value, std::vector<std::string> values,
MenuItem(uint8_t id, uint8_t type, std::string text, std::vector<std::string> values, int index,
ButtonCallback callback);
/**
* Constructor for a boolean/toggle menu item.
* @param id Unique identifier for this menu item
* @param type Type of the menu item
* @param text Display text for the menu item
* @param selected Whether this item is currently selected/checked
* @brief Constructs a boolean/toggle menu item with on/off state
* @param id Unique identifier for this menu item within its parent menu
* @param type Type identifier defining the item's behavior and visual appearance
* @param text Display text shown to the user for this menu item
* @param selected Whether this item is currently selected/enabled/checked
* @param callback Function to call when the item is activated
*
* @pre id must be unique within the parent menu context
* @pre text should not be empty for proper user interface display
* @pre callback should be a valid callable object
* @post MenuItem is initialized as a boolean toggle item
*
* @details Creates a menu item that represents a boolean state (on/off, enabled/disabled,
* checked/unchecked). This type is ideal for settings that have binary states
* and need to show their current status visually.
*
* Typical use cases include:
* - Feature toggles (e.g., "Auto-save: ON")
* - Enable/disable settings (e.g., "Sound: ENABLED")
* - Checkbox-style options (e.g., "Show notifications: ✓")
* - Boolean configurations (e.g., "Dark mode: OFF")
*
* @note The selected state is converted to a string value internally for
* consistent value handling across all menu item types.
* @note The callback typically implements toggle logic to switch between states.
*/
MenuItem(uint8_t id, uint8_t type, std::string text, bool selected, ButtonCallback callback);
/**
* Gets the unique identifier of this menu item.
* @return The menu item's ID
* @brief Gets the unique identifier of this menu item
* @return The menu item's unique ID as assigned during construction
*
* @details Returns the unique identifier that distinguishes this menu item
* from others within the same menu context. This ID is used by
* menu systems for item identification, event routing, and state management.
*
* @note The ID is immutable after construction and guaranteed to be unique
* within the menu context where this item is used.
*/
[[nodiscard]] uint8_t getId() const;
/**
* Gets the type of this menu item.
* @return The menu item's type
* @brief Gets the type identifier of this menu item
* @return The menu item's type identifier defining its behavior
*
* @details Returns the type identifier that defines how this menu item
* behaves and appears in the user interface. The type determines
* rendering style, interaction patterns, and event handling behavior.
*
* @note The type is immutable after construction and should correspond
* to predefined menu item type constants defined in the system.
*/
[[nodiscard]] uint8_t getType() const;
/**
* Gets the display text of this menu item.
* @return Reference to the menu item's text
* @brief Gets the display text of this menu item
* @return Const reference to the menu item's display text
*
* @details Returns the text that is displayed to the user for this menu item.
* This text serves as the primary label and should be descriptive
* enough for users to understand the item's purpose.
*
* @note Returns a const reference for efficiency while preventing
* accidental modification of the text content.
*/
[[nodiscard]] const std::string &getText() const;
/**
* Gets the current value of this menu item.
* @return Reference to the menu item's current value
* @brief Gets the current value of this menu item
* @return Const reference to the menu item's current value
*
* @details Returns the current value associated with this menu item.
* For simple action items, this may be empty. For value-based
* items, this represents the current state, selection, or setting.
*
* @note Returns a const reference for efficiency while preventing
* accidental modification through the getter.
* @note For boolean items, the value is typically "true"/"false" or similar.
*/
[[nodiscard]] const std::string &getValue() const;
/**
* Sets a new value for this menu item.
* @param value The new value to set
* @brief Sets a new value for this menu item
* @param value The new value to assign to this menu item
*
* @details Updates the current value of this menu item. This is commonly
* used to reflect changes in system state, user selections, or
* configuration updates. The new value should be appropriate
* for the menu item's type and purpose.
*
* @note For multi-selection items, the value should be one of the
* predefined values in the values vector.
* @note For boolean items, typical values are "true"/"false", "ON"/"OFF",
* or other boolean representations.
* @note The value update does not automatically trigger the callback;
* this is purely for state management.
*/
void setValue(const std::string &value);
/**
* Handles button press events for this menu item.
* Calls the associated callback function if one exists.
* @param id The ID of the item that was pressed
* @brief Handles button press events for this menu item
* @param button The type of button that was pressed
*
* @details Processes button press events by invoking the associated callback
* function if one exists. This method serves as the event handler
* that connects user interactions to the menu item's functionality.
*
* The method performs the following actions:
* - Validates that the ID matches this menu item
* - Checks if a callback function is available
* - Invokes the callback with the provided button type
* - Handles any callback-related error conditions gracefully
*
* @note This method is typically called by the parent menu system when
* user interaction occurs on this menu item.
* @note If no callback is set, the method returns without error.
* @note The callback is responsible for implementing the specific behavior
* for the button press (navigation, value changes, actions, etc.).
*/
void onButtonPressed(uint8_t id, ButtonType button) const;
void onButtonPressed(ButtonType button) const;
/**
* Checks if this menu item has an associated callback function.
* @return true if a callback is set, false otherwise
* @brief Checks if this menu item has an associated callback function
* @return true if a callback function is set, false otherwise
*
* @details Determines whether this menu item has a valid callback function
* that can be invoked when the item is activated. This is useful
* for menu systems that need to distinguish between interactive
* and non-interactive items.
*
* @note Menu items without callbacks are typically used for display-only
* purposes such as headers, separators, or status information.
* @note Interactive menu items should always have callbacks to provide
* meaningful user interaction.
*/
[[nodiscard]] bool hasCallback() const;
[[nodiscard]] int getIndex() const;
std::vector<std::string> getValues() const;
[[nodiscard]] size_t getItemCount() const;
[[nodiscard]] MenuItem copyWith(size_t index) const;
private:
uint8_t m_id; // Unique identifier for this menu item
uint8_t m_type; // Type defining the item's behavior
std::string m_text; // Display text shown to the user
std::string m_value; // Current value (for value-based items)
std::vector<std::string> m_values; // Available values (for selection items)
ButtonCallback m_callback; // Function to call when activated
/**
* @brief Unique identifier for this menu item
* @details Stores the unique ID that distinguishes this menu item from others
* within the same menu context. Used for event routing and item identification.
*/
uint8_t m_id;
/**
* @brief Type identifier defining the item's behavior and appearance
* @details Stores the type that determines how this menu item behaves,
* how it's rendered, and what interaction patterns it supports.
*/
uint8_t m_type;
/**
* @brief Display text shown to the user
* @details Stores the primary text label that is displayed to users,
* serving as the main identifier and description of the menu item's purpose.
*/
std::string m_text;
/**
* @brief Current value associated with this menu item
* @details Stores the current value for value-based menu items, representing
* the current state, selection, or setting that should be displayed to the user.
*/
std::string m_value;
/**
* @brief Available values for selection-based menu items
* @details Stores the list of all possible values that can be selected for
* multi-option menu items. Used for cycling through options or
* displaying selection dialogs.
*/
std::vector<std::string> m_values;
int m_index = -1;
/**
* @brief Callback function invoked when the menu item is activated
* @details Stores the function object that implements the menu item's behavior
* when activated by user interaction. Uses std::function for flexibility
* and type safety.
*/
ButtonCallback m_callback;
};

View File

@@ -1,14 +1,141 @@
/**
* @file LightMenu.h
* @brief Light control menu implementation for lighting system management
* @details This header defines the LightMenu class which provides a specialized
* user interface for controlling lighting systems and illumination features.
* It extends the Menu base class to offer comprehensive light control
* functionality including brightness adjustment, color selection, and
* lighting mode configuration.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include "common/PSMenu.h"
#include "common/Menu.h"
class LightMenu final : public PSMenu
/**
* @class LightMenu
* @brief Light control menu interface class for illumination system management
* @details This final class inherits from Menu and provides a comprehensive interface
* for controlling various aspects of the lighting system. It allows users to
* adjust brightness levels, select colors, configure lighting modes, and
* manage automated lighting behaviors.
*
* The LightMenu class extends the base Menu functionality by:
* - Providing light-specific control options (brightness, color, modes)
* - Implementing real-time lighting preview and feedback
* - Managing lighting presets and custom configurations
* - Handling immediate lighting adjustments and scheduled operations
*
* Typical lighting control features include:
* - Brightness adjustment (0-100% or similar range)
* - Color selection (RGB, HSV, or predefined colors)
* - Lighting modes (solid, fade, strobe, custom patterns)
* - Timer-based automation (on/off schedules)
* - Preset management (save/load favorite configurations)
* - Zone-based control (if multiple light zones are supported)
*
* The menu provides immediate visual feedback by applying changes to the
* connected lighting hardware in real-time as users navigate through options.
*
* @note This class is marked as final and cannot be inherited from.
* @note Lighting changes are typically applied immediately for instant feedback,
* with the option to save configurations as presets.
*
* @see Menu for base menu functionality
* @see menu_options_t for configuration structure
* @see MainMenu for navigation back to main interface
*/
class LightMenu final : public Menu
{
public:
public:
/**
* @brief Constructs the light control menu with the specified configuration
* @param options Pointer to menu options configuration structure
*
* @pre options must not be nullptr and must remain valid for the menu's lifetime
* @pre options->u8g2 must be initialized and ready for graphics operations
* @pre All callback functions in options must be properly configured
* @pre Lighting hardware must be initialized and responsive
* @post LightMenu is initialized with current lighting state and ready for user interaction
*
* @details The constructor initializes the light control menu by:
* - Reading current lighting system state and parameters
* - Creating appropriate menu items for available lighting features
* - Setting up real-time preview capabilities
* - Loading saved lighting presets and configurations
* - Configuring value ranges and validation for lighting parameters
*
* The menu automatically detects available lighting capabilities and presents
* only the controls that are supported by the connected hardware. This ensures
* a consistent user experience across different lighting system configurations.
*
* @note The menu does not take ownership of the options structure and assumes
* it remains valid throughout the menu's lifetime.
* @note Current lighting state is preserved and can be restored if the user
* exits without saving changes.
*
* @see Menu::Menu for base class construction details
*/
explicit LightMenu(menu_options_t *options);
private:
void onButtonPressed(uint8_t id, ButtonType button) const;
/**
* @brief Handles button press events specific to light control menu items
* @param menuItem
* @param button Type of button that was pressed
*
* @details Overrides the base Menu class method to provide light control-specific
* button handling logic. This method processes user interactions with
* lighting control items and performs appropriate actions such as:
* - Adjusting brightness levels (increment/decrement)
* - Changing color values or selecting predefined colors
* - Switching between lighting modes and patterns
* - Saving/loading lighting presets
* - Toggling lighting zones on/off
* - Applying lighting changes immediately to hardware
*
* The method provides real-time feedback by immediately applying lighting
* changes to the connected hardware, allowing users to see the effects of
* their adjustments instantly. It also handles validation to ensure that
* lighting parameters remain within safe and supported ranges.
*
* Special handling includes:
* - Smooth transitions for brightness adjustments
* - Color wheel navigation for color selection
* - Mode cycling for lighting patterns
* - Confirmation prompts for preset operations
*
* @note This method is called by the base Menu class when a button press
* occurs on a menu item, after the base class has handled standard
* navigation operations.
* @note Changes are applied immediately to provide instant visual feedback,
* but can be reverted if the user cancels or exits without saving.
*
* @see Menu::onButtonPressed for the base implementation
* @see ButtonType for available button types
*/
void onButtonPressed(const MenuItem& menuItem, ButtonType button) override;
/**
* @brief Pointer to menu options configuration structure
* @details Stores a reference to the menu configuration passed during construction.
* This pointer provides access to the display context and callback functions
* needed for menu operations, screen transitions, and lighting control
* communication with the hardware subsystem.
*
* The configuration enables:
* - Display context for rendering lighting control interface
* - Screen management callbacks for navigation to other menus
* - Hardware communication for real-time lighting control
* - System callbacks for lighting state persistence
*
* @note This pointer is not owned by the LightMenu and must remain valid
* throughout the menu's lifetime. It is managed by the application framework.
*
* @warning Must not be modified after construction as it may be shared
* with other components and contains critical system callbacks.
*/
menu_options_t *m_options;
};
};

View File

@@ -0,0 +1,14 @@
#pragma once
#include "common/Menu.h"
class LightSettingsMenu final : public Menu
{
public:
explicit LightSettingsMenu(menu_options_t *options);
private:
void onButtonPressed(const MenuItem& menuItem, ButtonType button) override;
menu_options_t *m_options;
};

View File

@@ -1,31 +1,104 @@
/**
* @file MainMenu.h
* @brief Main menu implementation for the application's primary interface
* @details This header defines the MainMenu class which serves as the primary
* user interface entry point for the application. It extends the Menu
* base class to provide a customized main menu experience with
* application-specific menu items and navigation behavior.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include "common/PSMenu.h"
#include "common/Menu.h"
/**
* MainMenu class - represents the main menu interface of the application
* Inherits from PSMenu to provide menu functionality
* @class MainMenu
* @brief Main menu interface class providing the primary application navigation
* @details This final class inherits from Menu and represents the main menu interface
* of the application. It serves as the primary entry point for user interaction
* and provides navigation to all major application features and sub-menus.
*
* The MainMenu class customizes the base Menu functionality by:
* - Defining application-specific menu items during construction
* - Implementing custom button handling for main menu navigation
* - Managing transitions to sub-menus and application features
*
* This class is typically the first screen presented to users after the splash
* screen and serves as the central hub for all application functionality.
*
* @note This class is marked as final and cannot be inherited from.
*
* @see Menu for base menu functionality
* @see menu_options_t for configuration structure
*/
class MainMenu final : public PSMenu
class MainMenu final : public Menu
{
public:
/**
* Constructor - initializes the main menu with given options
* @param options Pointer to menu options configuration
* @brief Constructs the main menu with the specified configuration
* @param options Pointer to menu options configuration structure
*
* @pre options must not be nullptr and must remain valid for the menu's lifetime
* @pre options->u8g2 must be initialized and ready for graphics operations
* @pre All callback functions in options must be properly configured
* @post MainMenu is initialized with application-specific menu items and ready for use
*
* @details The constructor initializes the main menu by setting up all the
* primary application menu items such as:
* - Settings access
* - Feature-specific menus
* - System controls
* - Application exit options
*
* @note The menu does not take ownership of the options structure and assumes
* it remains valid throughout the menu's lifetime.
*/
explicit MainMenu(menu_options_t *options);
private:
/**
* Handles button press events from the menu interface
* @param id Button identifier that was pressed
* @brief Handles button press events specific to main menu items
* @param menuItem
* @param button Type of button that was pressed
*
* @details Overrides the base Menu class method to provide main menu-specific
* button handling logic. This method processes user interactions with
* main menu items and initiates appropriate actions such as:
* - Navigation to sub-menus (Settings, Light Control, etc.)
* - Direct feature activation
* - System operations
*
* The method uses the menu item ID to determine which action to take and
* utilizes the callback functions provided in m_options to perform screen
* transitions or other application-level operations.
*
* @note This method is called by the base Menu class when a button press
* occurs on a menu item, after the base class has handled standard
* navigation operations.
*
* @see Menu::onButtonPressed for the base implementation
* @see ButtonType for available button types
*/
void onButtonPressed(uint8_t id, ButtonType button) const;
void onButtonPressed(const MenuItem& menuItem, ButtonType button) override;
/**
* Pointer to menu options configuration
* Stores the menu configuration passed during construction
* @brief Pointer to menu options configuration structure
* @details Stores a reference to the menu configuration passed during construction.
* This pointer provides access to the display context and callback functions
* needed for menu operations, screen transitions, and user interaction handling.
*
* The configuration includes:
* - Display context for rendering operations
* - Screen management callbacks for navigation
* - Input handling callbacks for button events
*
* @note This pointer is not owned by the MainMenu and must remain valid
* throughout the menu's lifetime. It is managed by the application framework.
*
* @warning Must not be modified after construction as it may be shared
* with other components.
*/
menu_options_t *m_options;
};

View File

@@ -1,9 +1,77 @@
/**
* @file SettingsMenu.h
* @brief Settings menu implementation for application configuration
* @details This header defines the SettingsMenu class which provides a user interface
* for configuring application settings and preferences. It extends the Menu
* base class to offer a specialized settings management interface with
* various configuration options and system parameters.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include "common/PSMenu.h"
#include "common/Menu.h"
class SettingsMenu final : public PSMenu
/**
* @class SettingsMenu
* @brief Settings menu interface class for application configuration management
* @details This final class inherits from Menu and provides a comprehensive settings
* interface for the application. It allows users to configure various aspects
* of the system including display preferences, system behavior, network
* settings, and other configurable parameters.
*
* The SettingsMenu class extends the base Menu functionality by:
* - Providing settings-specific menu items (toggles, selections, number inputs)
* - Managing configuration persistence and validation
* - Organizing settings into logical categories and sections
* - Implementing real-time preview of setting changes where applicable
*
* Typical settings categories include:
* - Display settings (brightness, contrast, theme)
* - System preferences (timeouts, auto-save, etc.)
* - Network configuration (if applicable)
* - User interface preferences
* - Hardware-specific parameters
*
* @note This class is marked as final and cannot be inherited from.
* @note Settings changes are typically applied immediately or after confirmation,
* depending on the specific setting type and system requirements.
*
* @see Menu for base menu functionality
* @see menu_options_t for configuration structure
* @see MainMenu for navigation back to main interface
*/
class SettingsMenu final : public Menu
{
public:
public:
/**
* @brief Constructs the settings menu with the specified configuration
* @param options Pointer to menu options configuration structure
*
* @pre options must not be nullptr and must remain valid for the menu's lifetime
* @pre options->u8g2 must be initialized and ready for graphics operations
* @pre All callback functions in options must be properly configured
* @post SettingsMenu is initialized with all available configuration options and ready for use
*
* @details The constructor initializes the settings menu by creating all the
* configuration menu items based on the current system state and
* available options. This includes:
* - Loading current setting values from persistent storage
* - Creating appropriate menu items (toggles, selections, number inputs)
* - Setting up validation ranges and allowed values
* - Organizing items in a logical, user-friendly order
*
* The menu automatically detects which settings are available based on
* hardware capabilities and system configuration, ensuring only relevant
* options are presented to the user.
*
* @note The menu does not take ownership of the options structure and assumes
* it remains valid throughout the menu's lifetime.
* @note Setting values are loaded from persistent storage during construction
* and changes are typically saved automatically or on confirmation.
*
* @see Menu::Menu for base class construction details
*/
explicit SettingsMenu(menu_options_t *options);
};
};

View File

@@ -1,50 +1,177 @@
/**
* @file SplashScreen.h
* @brief Application splash screen implementation for startup presentation
* @details This header defines the SplashScreen class which provides the initial
* visual presentation when the application starts. It serves as a loading
* screen that displays branding information, initialization progress, and
* provides visual feedback during the application startup sequence.
* @author System Control Team
* @date 2025-06-14
*/
#pragma once
#include "MenuOptions.h"
#include "common/Widget.h"
/**
* @brief SplashScreen class represents the initial screen shown when the application starts
* @class SplashScreen
* @brief Application startup screen widget with branding and initialization feedback
* @details This final class inherits from Widget and represents the initial screen
* displayed when the application starts. It serves multiple purposes including
* brand presentation, system initialization feedback, and smooth transition
* preparation to the main application interface.
*
* This class inherits from Widget and is responsible for displaying the splash screen
* that typically shows application branding, loading status, or initialization messages.
* It's marked as final to prevent further inheritance.
* The SplashScreen class provides:
* - Brand identity display (logos, company information, product name)
* - System initialization progress indication
* - Smooth animations and visual effects for professional appearance
* - Automatic transition timing to main menu after initialization
* - Error indication if initialization fails
*
* Key features include:
* - Time-based automatic progression to main menu
* - Animated elements (fade-in effects, progress indicators)
* - Version information display
* - Loading status messages
* - Graceful handling of initialization delays
*
* The splash screen typically displays for a minimum duration to ensure users
* can read branding information, even if system initialization completes quickly.
* It automatically transitions to the main menu once both the minimum display
* time and system initialization are complete.
*
* @note This class is marked as final and cannot be inherited from.
* @note The splash screen does not handle user input - it operates on timing
* and system state rather than user interaction.
*
* @see Widget for base widget functionality
* @see menu_options_t for configuration structure
* @see MainMenu for the target transition screen
*/
class SplashScreen final : public Widget
{
public:
public:
/**
* @brief Constructs a new SplashScreen object
* @brief Constructs the splash screen with specified configuration
* @param options Pointer to menu options configuration structure
*
* @param options Pointer to menu options configuration that controls
* the behavior and appearance of the splash screen
* @pre options must not be nullptr and must remain valid for the splash screen's lifetime
* @pre options->u8g2 must be initialized and ready for graphics operations
* @pre Screen transition callbacks in options must be properly configured
* @post SplashScreen is initialized and ready to display startup sequence
*
* @details The constructor initializes the splash screen by:
* - Setting up the initial display state and animations
* - Preparing branding elements (logos, text, version info)
* - Initializing timing controls for minimum display duration
* - Configuring transition parameters for smooth progression
* - Loading any required graphics resources or assets
*
* The splash screen prepares all visual elements during construction to
* ensure smooth rendering performance during the critical startup phase.
* It also establishes the timing framework for controlling display duration
* and transition timing.
*
* @note The splash screen does not take ownership of the options structure
* and assumes it remains valid throughout the screen's lifetime.
* @note Graphics resources are loaded during construction, so any required
* assets must be available at initialization time.
*
* @see Widget::Widget for base class construction details
*/
explicit SplashScreen(menu_options_t *options);
/**
* @brief Updates the splash screen state and animations
* @brief Updates the splash screen state, animations, and timing logic
* @param dt Delta time in milliseconds since the last update call
*
* This method is called every frame to update the splash screen's
* internal state, handle timing, animations, or transitions.
* @details Overrides the base Widget update method to handle splash screen-specific
* logic including:
* - Animation progression (fade effects, transitions, progress indicators)
* - Timing control for minimum display duration
* - System initialization status monitoring
* - Automatic transition preparation to main menu
* - Loading progress updates and status message changes
*
* @param dt Delta time in milliseconds since the last update
* The update method manages the splash screen's lifecycle by tracking
* elapsed time and system readiness state. It ensures the splash screen
* remains visible for a minimum duration while also monitoring system
* initialization completion. Once both conditions are met, it initiates
* the transition to the main application interface.
*
* Animation updates include:
* - Fade-in effects for branding elements
* - Progress bar or spinner animations
* - Text transitions for status messages
* - Smooth preparation for screen transition
*
* @note This method is called every frame during the splash screen display
* and must be efficient to maintain smooth visual presentation.
* @note The method automatically handles transition to the main menu when
* appropriate, using the callback functions provided in m_options.
*
* @see Widget::update for the base update interface
*/
void update(uint64_t dt) override;
/**
* @brief Renders the splash screen to the display
* @brief Renders the splash screen visual elements to the display
*
* This method handles all the drawing operations for the splash screen,
* including background, logos, text, and any visual effects.
* @details Overrides the base Widget render method to draw all splash screen
* elements including branding, status information, and visual effects.
* The rendering includes:
* - Company/product logos and branding elements
* - Application name and version information
* - Loading progress indicators (progress bars, spinners, etc.)
* - Status messages indicating initialization progress
* - Background graphics and visual effects
*
* The render method creates a professional, polished appearance that
* reinforces brand identity while providing useful feedback about the
* application startup process. All elements are positioned and styled
* to create a cohesive, attractive presentation.
*
* Rendering features include:
* - Centered layout with balanced visual hierarchy
* - Smooth animations and transitions
* - Consistent typography and color scheme
* - Progress feedback elements
* - Error indication if initialization problems occur
*
* @pre u8g2 display context must be initialized and ready for drawing
* @post All splash screen visual elements are drawn to the display buffer
*
* @note This method is called every frame and must be efficient to maintain
* smooth visual presentation during the startup sequence.
* @note The visual design should be consistent with the overall application
* theme and branding guidelines.
*
* @see Widget::render for the base render interface
*/
void render() override;
private:
private:
/**
* @brief Pointer to menu options configuration
* @brief Pointer to menu options configuration structure
* @details Stores a reference to the menu configuration passed during construction.
* This provides access to the display context for rendering operations
* and screen transition callbacks for automatic progression to the main menu.
*
* Stores the configuration options that control various aspects
* of the splash screen's behavior and appearance.
* The configuration enables:
* - Display context (u8g2) for graphics rendering operations
* - Screen transition callbacks for automatic progression to main menu
* - System integration for initialization status monitoring
*
* The splash screen uses the setScreen callback to automatically transition
* to the main menu once the startup sequence is complete. This ensures a
* seamless user experience from application launch to main interface.
*
* @note This pointer is not owned by the SplashScreen and must remain valid
* throughout the screen's lifetime. It is managed by the application framework.
*
* @warning Must not be modified after construction as it contains critical
* system callbacks required for proper application flow.
*/
menu_options_t *m_options;
};

View File

@@ -0,0 +1,308 @@
#include "common/Menu.h"
#include "common/ScrollBar.h"
#include "u8g2.h"
// Menu item type constants for better readability
namespace MenuItemTypes
{
constexpr uint8_t TEXT = 0;
constexpr uint8_t SELECTION = 1;
constexpr uint8_t TOGGLE = 2;
}
// UI layout constants
namespace UIConstants
{
constexpr int LEFT_MARGIN = 8;
constexpr int RIGHT_PADDING = 8;
constexpr int SCROLLBAR_WIDTH = 3;
constexpr int FRAME_BOX_SIZE = 14;
constexpr int FRAME_OFFSET = 11;
constexpr int SELECTION_MARGIN = 10;
constexpr int CORNER_RADIUS = 3;
constexpr int LINE_SPACING = 14;
constexpr int BOTTOM_OFFSET = 10;
}
Menu::Menu(menu_options_t *options) : Widget(options->u8g2), m_options(options)
{
// Set up button callback using lambda to forward to member function
m_options->onButtonClicked = [this](const ButtonType button) {
onButtonClicked(button);
};
}
Menu::~Menu()
{
// Clean up callback to prevent dangling pointer
if (m_options)
{
m_options->onButtonClicked = nullptr;
}
}
MenuItem Menu::getItem(const int index)
{
return m_items.at(index);
}
size_t Menu::getItemCount() const
{
return m_items.size();
}
void Menu::setItemSize(const size_t size)
{
if ((m_items.size() - 1) < size)
{
for (size_t i = m_items.size() - 1; i < size; i++)
{
auto caption = std::string("Section ") + std::to_string(i + 1);
addSelection(i + 1, caption, m_items.at(0).getValues(), 0);
}
}
else
{
m_items.erase(m_items.begin() + static_cast<int>(size + 1), m_items.end());
}
}
void Menu::replaceItem(const int index, const MenuItem &item)
{
m_items.at(index) = item;
}
void Menu::render()
{
// Initialize selection if not set
if (m_selected_item >= m_items.size() && !m_items.empty())
{
m_selected_item = 0;
}
// Early return if no items to render
if (m_items.empty())
{
return;
}
// Clear screen with black background
u8g2_SetDrawColor(u8g2, 0);
u8g2_DrawBox(u8g2, 0, 0, u8g2->width, u8g2->height);
// Set white foreground color for drawing
u8g2_SetDrawColor(u8g2, 1);
// Draw UI components
drawScrollBar();
drawSelectionBox();
// Calculate center position for main item
const int centerY = u8g2->height / 2 + 3;
// Render the currently selected item (main/center item)
const auto &selectedItem = m_items[m_selected_item];
renderWidget(&selectedItem, u8g2_font_helvB08_tr, UIConstants::LEFT_MARGIN, centerY);
// Render previous item (above) if available
if (m_selected_item > 0)
{
const auto &prevItem = m_items[m_selected_item - 1];
renderWidget(&prevItem, u8g2_font_haxrcorp4089_tr, UIConstants::LEFT_MARGIN, UIConstants::LINE_SPACING);
}
// Render next item (below) if available
if (m_selected_item < m_items.size() - 1)
{
const auto &nextItem = m_items[m_selected_item + 1];
renderWidget(&nextItem, u8g2_font_haxrcorp4089_tr, UIConstants::LEFT_MARGIN,
u8g2->height - UIConstants::BOTTOM_OFFSET);
}
}
void Menu::renderWidget(const MenuItem *item, const uint8_t *font, const int x, const int y) const
{
// Set font and draw main text
u8g2_SetFont(u8g2, font);
u8g2_DrawStr(u8g2, x, y, item->getText().c_str());
// Render type-specific elements
switch (item->getType())
{
case MenuItemTypes::SELECTION: {
// Format selection value with angle brackets
const std::string formattedValue = "< " + item->getValue() + " >";
const u8g2_uint_t textWidth = u8g2_GetStrWidth(u8g2, formattedValue.c_str());
u8g2_DrawStr(u8g2, u8g2->width - textWidth - UIConstants::SELECTION_MARGIN, y, formattedValue.c_str());
break;
}
case MenuItemTypes::TOGGLE: {
// Draw checkbox frame
const int frameX = u8g2->width - UIConstants::FRAME_BOX_SIZE - UIConstants::SELECTION_MARGIN;
const int frameY = y - UIConstants::FRAME_OFFSET;
u8g2_DrawFrame(u8g2, frameX, frameY, UIConstants::FRAME_BOX_SIZE, UIConstants::FRAME_BOX_SIZE);
// Draw checkmark (X) if toggle is true
if (item->getValue() == "true")
{
const int checkX1 = frameX + 2;
const int checkY1 = frameY + 2;
const int checkX2 = frameX + UIConstants::FRAME_BOX_SIZE - 3;
const int checkY2 = frameY + UIConstants::FRAME_BOX_SIZE - 3;
// Draw X pattern for checked state
u8g2_DrawLine(u8g2, checkX1, checkY1, checkX2, checkY2);
u8g2_DrawLine(u8g2, checkX1, checkY2, checkX2, checkY1);
}
break;
}
case MenuItemTypes::TEXT:
default:
// No additional rendering needed for text and number types
break;
}
}
void Menu::onButtonClicked(const ButtonType button)
{
// Map button input to navigation functions
switch (button)
{
case ButtonType::UP:
onPressedUp();
break;
case ButtonType::DOWN:
onPressedDown();
break;
case ButtonType::LEFT:
onPressedLeft();
break;
case ButtonType::RIGHT:
onPressedRight();
break;
case ButtonType::SELECT:
onPressedSelect();
break;
case ButtonType::BACK:
onPressedBack();
break;
default:
// Ignore unknown button inputs
break;
}
}
void Menu::onPressedDown()
{
if (m_items.empty())
return;
// Wrap around to first item when at the end
m_selected_item = (m_selected_item + 1) % m_items.size();
}
void Menu::onPressedUp()
{
if (m_items.empty())
return;
// Wrap around to last item when at the beginning
m_selected_item = (m_selected_item == 0) ? m_items.size() - 1 : m_selected_item - 1;
}
void Menu::onPressedLeft() const
{
if (m_selected_item < m_items.size())
{
const auto &item = m_items.at(m_selected_item);
item.onButtonPressed(ButtonType::LEFT);
}
}
void Menu::onPressedRight() const
{
if (m_selected_item < m_items.size())
{
const auto &item = m_items.at(m_selected_item);
item.onButtonPressed(ButtonType::RIGHT);
}
}
void Menu::onPressedSelect() const
{
if (m_selected_item < m_items.size())
{
const auto &item = m_items.at(m_selected_item);
item.onButtonPressed(ButtonType::SELECT);
}
}
void Menu::onPressedBack() const
{
// Navigate back to previous screen if callback is available
if (m_options && m_options->popScreen)
{
m_options->popScreen();
}
}
void Menu::addText(uint8_t id, const std::string &text)
{
auto callback = [this](const MenuItem &menuItem, const ButtonType button) -> void {
onButtonPressed(menuItem, button);
};
m_items.emplace_back(id, MenuItemTypes::TEXT, text, callback);
}
void Menu::addSelection(uint8_t id, const std::string &text, const std::vector<std::string> &values, const int index)
{
auto callback = [this](const MenuItem &menuItem, const ButtonType button) -> void {
onButtonPressed(menuItem, button);
};
m_items.emplace_back(id, MenuItemTypes::SELECTION, text, values, index, callback);
}
void Menu::addToggle(uint8_t id, const std::string &text, bool selected)
{
auto callback = [this](const MenuItem &menuItem, const ButtonType button) -> void {
onButtonPressed(menuItem, button);
};
m_items.emplace_back(id, MenuItemTypes::TOGGLE, text, selected, callback);
}
void Menu::drawScrollBar() const
{
// Create scrollbar instance
ScrollBar scrollBar(m_options, u8g2->width - UIConstants::SCROLLBAR_WIDTH, 3, 1, u8g2->height - 6);
scrollBar.refresh(m_selected_item, m_items.size());
scrollBar.render();
}
void Menu::drawSelectionBox() const
{
// Calculate dimensions for the selection box
const auto displayHeight = u8g2->height;
const auto displayWidth = u8g2->width;
const auto boxHeight = displayHeight / 3;
const auto y = boxHeight * 2 - 2;
const auto x = displayWidth - UIConstants::RIGHT_PADDING;
// Draw the rounded frame for the selection box
u8g2_DrawRFrame(u8g2, 2, boxHeight, displayWidth - UIConstants::RIGHT_PADDING, boxHeight,
UIConstants::CORNER_RADIUS);
// Draw horizontal line separator
u8g2_DrawLine(u8g2, 4, y, displayWidth - UIConstants::RIGHT_PADDING, y);
// Draw vertical line on the right side
u8g2_DrawLine(u8g2, x, y - boxHeight + 3, x, y - 1);
}

View File

@@ -1,260 +0,0 @@
#include "common/PSMenu.h"
#include "PushButton.h"
#include "common/ScrollBar.h"
#include "u8g2.h"
// Menu item type constants for better readability
namespace MenuItemTypes {
constexpr uint8_t TEXT = 0;
constexpr uint8_t SELECTION = 1;
constexpr uint8_t NUMBER = 2;
constexpr uint8_t TOGGLE = 3;
}
// UI layout constants
namespace UIConstants {
constexpr int LEFT_MARGIN = 8;
constexpr int RIGHT_PADDING = 8;
constexpr int SCROLLBAR_WIDTH = 3;
constexpr int FRAME_BOX_SIZE = 14;
constexpr int FRAME_OFFSET = 11;
constexpr int SELECTION_MARGIN = 10;
constexpr int CORNER_RADIUS = 3;
constexpr int LINE_SPACING = 14;
constexpr int BOTTOM_OFFSET = 10;
}
PSMenu::PSMenu(menu_options_t *options) : Widget(options->u8g2), m_options(options)
{
// Set up button callback using lambda to forward to member function
m_options->onButtonClicked = [this](const uint8_t button) {
onButtonClicked(button);
};
}
PSMenu::~PSMenu()
{
// Clean up callback to prevent dangling pointer
if (m_options) {
m_options->onButtonClicked = nullptr;
}
}
void PSMenu::render()
{
// Initialize selection if not set
if (m_selected_item >= m_items.size() && !m_items.empty()) {
m_selected_item = 0;
}
// Early return if no items to render
if (m_items.empty()) {
return;
}
// Clear screen with black background
u8g2_SetDrawColor(u8g2, 0);
u8g2_DrawBox(u8g2, 0, 0, u8g2->width, u8g2->height);
// Set white foreground color for drawing
u8g2_SetDrawColor(u8g2, 1);
// Draw UI components
drawScrollBar();
drawSelectionBox();
// Calculate center position for main item
const int centerY = u8g2->height / 2 + 3;
// Render the currently selected item (main/center item)
const auto& selectedItem = m_items[m_selected_item];
renderWidget(&selectedItem, u8g2_font_helvB08_tr, UIConstants::LEFT_MARGIN, centerY);
// Render previous item (above) if available
if (m_selected_item > 0) {
const auto& prevItem = m_items[m_selected_item - 1];
renderWidget(&prevItem, u8g2_font_haxrcorp4089_tr, UIConstants::LEFT_MARGIN, UIConstants::LINE_SPACING);
}
// Render next item (below) if available
if (m_selected_item < m_items.size() - 1) {
const auto& nextItem = m_items[m_selected_item + 1];
renderWidget(&nextItem, u8g2_font_haxrcorp4089_tr, UIConstants::LEFT_MARGIN, u8g2->height - UIConstants::BOTTOM_OFFSET);
}
}
void PSMenu::renderWidget(const MenuItem *item, const uint8_t *font, const int x, const int y) const
{
// Set font and draw main text
u8g2_SetFont(u8g2, font);
u8g2_DrawStr(u8g2, x, y, item->getText().c_str());
// Render type-specific elements
switch (item->getType()) {
case MenuItemTypes::SELECTION: {
// Format selection value with angle brackets
const std::string formattedValue = "< " + item->getValue() + " >";
const u8g2_uint_t textWidth = u8g2_GetStrWidth(u8g2, formattedValue.c_str());
u8g2_DrawStr(u8g2, u8g2->width - textWidth - UIConstants::SELECTION_MARGIN, y, formattedValue.c_str());
break;
}
case MenuItemTypes::TOGGLE: {
// Draw checkbox frame
const int frameX = u8g2->width - UIConstants::FRAME_BOX_SIZE - UIConstants::SELECTION_MARGIN;
const int frameY = y - UIConstants::FRAME_OFFSET;
u8g2_DrawFrame(u8g2, frameX, frameY, UIConstants::FRAME_BOX_SIZE, UIConstants::FRAME_BOX_SIZE);
// Draw checkmark (X) if toggle is true
if (item->getValue() == "true") {
const int checkX1 = frameX + 2;
const int checkY1 = frameY + 2;
const int checkX2 = frameX + UIConstants::FRAME_BOX_SIZE - 3;
const int checkY2 = frameY + UIConstants::FRAME_BOX_SIZE - 3;
// Draw X pattern for checked state
u8g2_DrawLine(u8g2, checkX1, checkY1, checkX2, checkY2);
u8g2_DrawLine(u8g2, checkX1, checkY2, checkX2, checkY1);
}
break;
}
case MenuItemTypes::TEXT:
case MenuItemTypes::NUMBER:
default:
// No additional rendering needed for text and number types
break;
}
}
void PSMenu::onButtonClicked(const uint8_t button)
{
// Map button input to navigation functions
switch (button) {
case BUTTON_UP:
onPressedUp();
break;
case BUTTON_DOWN:
onPressedDown();
break;
case BUTTON_LEFT:
onPressedLeft();
break;
case BUTTON_RIGHT:
onPressedRight();
break;
case BUTTON_SELECT:
onPressedSelect();
break;
case BUTTON_BACK:
onPressedBack();
break;
default:
// Ignore unknown button inputs
break;
}
}
void PSMenu::onPressedDown()
{
if (m_items.empty()) return;
// Wrap around to first item when at the end
m_selected_item = (m_selected_item + 1) % m_items.size();
}
void PSMenu::onPressedUp()
{
if (m_items.empty()) return;
// Wrap around to last item when at the beginning
m_selected_item = (m_selected_item == 0) ? m_items.size() - 1 : m_selected_item - 1;
}
void PSMenu::onPressedLeft() const
{
if (m_selected_item < m_items.size()) {
const auto& item = m_items[m_selected_item];
item.onButtonPressed(item.getId(), ButtonType::LEFT);
}
}
void PSMenu::onPressedRight() const
{
if (m_selected_item < m_items.size()) {
const auto& item = m_items[m_selected_item];
item.onButtonPressed(item.getId(), ButtonType::RIGHT);
}
}
void PSMenu::onPressedSelect() const
{
if (m_selected_item < m_items.size()) {
const auto& item = m_items[m_selected_item];
item.onButtonPressed(item.getId(), ButtonType::SELECT);
}
}
void PSMenu::onPressedBack() const
{
// Navigate back to previous screen if callback is available
if (m_options && m_options->popScreen) {
m_options->popScreen();
}
}
void PSMenu::addText(uint8_t id, const std::string &text, const ButtonCallback &callback)
{
m_items.emplace_back(id, MenuItemTypes::TEXT, text, callback);
}
void PSMenu::addSelection(uint8_t id, const std::string &text, std::string &value,
const std::vector<std::string> &values,
const ButtonCallback &callback)
{
m_items.emplace_back(id, MenuItemTypes::SELECTION, text, value, values, callback);
}
void PSMenu::addNumber(uint8_t id, const std::string &text, std::string &value, const ButtonCallback &callback)
{
m_items.emplace_back(id, MenuItemTypes::NUMBER, text, value, callback);
}
void PSMenu::addToggle(uint8_t id, const std::string &text, bool selected, const ButtonCallback &callback)
{
m_items.emplace_back(id, MenuItemTypes::TOGGLE, text, selected, callback);
}
void PSMenu::drawScrollBar() const
{
// Create scrollbar instance
ScrollBar scrollBar(m_options, u8g2->width - UIConstants::SCROLLBAR_WIDTH, 3, 1, u8g2->height - 6);
scrollBar.refresh(m_selected_item, m_items.size());
scrollBar.render();
}
void PSMenu::drawSelectionBox() const
{
// Calculate dimensions for the selection box
const auto displayHeight = u8g2->height;
const auto displayWidth = u8g2->width;
const auto boxHeight = displayHeight / 3;
const auto y = boxHeight * 2 - 2;
const auto x = displayWidth - UIConstants::RIGHT_PADDING;
// Draw the rounded frame for the selection box
u8g2_DrawRFrame(u8g2, 2, boxHeight, displayWidth - UIConstants::RIGHT_PADDING, boxHeight, UIConstants::CORNER_RADIUS);
// Draw horizontal line separator
u8g2_DrawLine(u8g2, 4, y, displayWidth - UIConstants::RIGHT_PADDING, y);
// Draw vertical line on the right side
u8g2_DrawLine(u8g2, x, y - boxHeight + 3, x, y - 1);
}

View File

@@ -12,6 +12,6 @@ void Widget::render()
{
}
void Widget::onButtonClicked(uint8_t button)
void Widget::onButtonClicked(ButtonType button)
{
}

View File

@@ -11,10 +11,9 @@ MenuItem::MenuItem(const uint8_t id, const uint8_t type, std::string text, std::
{
}
MenuItem::MenuItem(const uint8_t id, const uint8_t type, std::string text, std::string value,
std::vector<std::string> values,
MenuItem::MenuItem(const uint8_t id, const uint8_t type, std::string text, std::vector<std::string> values, int index,
ButtonCallback callback)
: m_id(id), m_type(type), m_text(std::move(text)), m_value(std::move(value)), m_values(std::move(values)),
: m_id(id), m_type(type), m_text(std::move(text)), m_values(std::move(values)), m_index(index),
m_callback(std::move(callback))
{
}
@@ -43,6 +42,10 @@ const std::string &MenuItem::getText() const
const std::string &MenuItem::getValue() const
{
if (!m_values.empty() && m_index >= 0 && m_index < m_values.size())
{
return m_values.at(m_index);
}
return m_value;
}
@@ -51,15 +54,41 @@ void MenuItem::setValue(const std::string &value)
m_value = value;
}
void MenuItem::onButtonPressed(const uint8_t id, const ButtonType button) const
void MenuItem::onButtonPressed(const ButtonType button) const
{
if (m_callback)
{
m_callback(id, button);
m_callback(*this, button);
}
}
bool MenuItem::hasCallback() const
{
return (m_callback != nullptr);
}
int MenuItem::getIndex() const
{
return m_index;
}
std::vector<std::string> MenuItem::getValues() const
{
return m_values;
}
size_t MenuItem::getItemCount() const
{
return m_values.size();
}
MenuItem MenuItem::copyWith(const size_t index) const
{
MenuItem copy = *this;
if (index > std::numeric_limits<int>::max())
{
throw std::overflow_error("index is too large");
}
copy.m_index = static_cast<int>(index);
return copy;
}

View File

@@ -1,28 +1,31 @@
#include "ui/LightMenu.h"
LightMenu::LightMenu(menu_options_t *options) : PSMenu(options), m_options(options)
#include "ui/LightSettingsMenu.h"
namespace LightMenuItem
{
constexpr uint8_t MODE = 1;
constexpr uint8_t TOGGLE = 2;
constexpr uint8_t LED_SETTINGS = 3;
}
LightMenu::LightMenu(menu_options_t *options) : Menu(options), m_options(options)
{
std::vector<std::string> values;
values.emplace_back("Tag");
values.emplace_back("Nacht");
addSelection(1, "Modus", values.front(), values, [this](const uint8_t id, const ButtonType button) {
onButtonPressed(id, button);
});
addSelection(LightMenuItem::MODE, "Modus", values, 0);
addText(2, "LED Einstellungen", [this](const uint8_t id, const ButtonType button) {
onButtonPressed(id, button);
});
addToggle(3, "Toggle", false, nullptr);
addText(LightMenuItem::LED_SETTINGS, "LED Einstellungen");
}
void LightMenu::onButtonPressed(const uint8_t id, const ButtonType button) const
void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button)
{
std::shared_ptr<Widget> widget;
switch (id)
switch (menuItem.getId())
{
case 2:
widget = std::make_shared<LightMenu>(m_options);
case LightMenuItem::LED_SETTINGS:
widget = std::make_shared<LightSettingsMenu>(m_options);
break;
default:

View File

@@ -0,0 +1,65 @@
#include "ui/LightSettingsMenu.h"
namespace LightSettingsMenuItem
{
constexpr uint8_t SECTION_COUNTER = 0;
}
LightSettingsMenu::LightSettingsMenu(menu_options_t *options) : Menu(options), m_options(options)
{
std::vector<std::string> values;
for (size_t i = 1; i <= 99; i++)
{
values.emplace_back(std::to_string(i));
}
addSelection(LightSettingsMenuItem::SECTION_COUNTER, "Sektionen", values, 0);
addSelection(1, "Sektion 1", values, 0);
}
void LightSettingsMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button)
{
/// change visible counter
switch (button)
{
case ButtonType::LEFT:
if (menuItem.getIndex() > 0)
{
const auto item = menuItem.copyWith(menuItem.getIndex() - 1);
replaceItem(menuItem.getId(), item);
}
else
{
const auto item = menuItem.copyWith(menuItem.getItemCount() - 1);
replaceItem(menuItem.getId(), item);
}
break;
case ButtonType::RIGHT:
if (menuItem.getIndex() < menuItem.getItemCount() - 1)
{
const auto item = menuItem.copyWith(menuItem.getIndex() + 1);
replaceItem(menuItem.getId(), item);
}
else
{
const auto item = menuItem.copyWith(0);
replaceItem(menuItem.getId(), item);
}
break;
default:
break;
}
/// change section list
setItemSize(std::stoull(getItem(0).getValue()));
/// persist section values
if (m_options && m_options->persistence && m_options->persistence->save)
{
const auto key = "section_" + std::to_string(menuItem.getId());
const auto &value = getItem(menuItem.getId()).getValue();
m_options->persistence->save(key.c_str(), value.c_str());
}
}

View File

@@ -4,23 +4,17 @@
#include "ui/LightMenu.h"
#include "ui/SettingsMenu.h"
MainMenu::MainMenu(menu_options_t *options) : PSMenu(options), m_options(options)
MainMenu::MainMenu(menu_options_t *options) : Menu(options), m_options(options)
{
addText(1, "Lichtsteuerung", [this](const uint8_t id, const ButtonType button) {
onButtonPressed(id, button);
});
addText(2, "externe Geraete", [this](const uint8_t id, const ButtonType button) {
onButtonPressed(id, button);
});
addText(3, "Einstellungen", [this](const uint8_t id, const ButtonType button) {
onButtonPressed(id, button);
});
addText(1, "Lichtsteuerung");
addText(2, "externe Geraete");
addText(3, "Einstellungen");
}
void MainMenu::onButtonPressed(const uint8_t id, const ButtonType button) const
void MainMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button)
{
std::shared_ptr<Widget> widget;
switch (id)
switch (menuItem.getId())
{
case 1:
widget = std::make_shared<LightMenu>(m_options);

View File

@@ -1,11 +1,6 @@
#include "ui/SettingsMenu.h"
void demo(uint8_t id, ButtonType button)
SettingsMenu::SettingsMenu(menu_options_t *options) : Menu(options)
{
///
}
SettingsMenu::SettingsMenu(menu_options_t *options) : PSMenu(options)
{
addText(1, "OTA Einspielen", demo);
addText(1, "OTA Einspielen");
}

View File

@@ -1,6 +1,6 @@
if (DEFINED ENV{IDF_PATH})
idf_component_register(SRCS
PushButton.cpp
persistence.c
INCLUDE_DIRS "include"
)
return()
@@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.30)
project(ruth)
add_library(${PROJECT_NAME} STATIC
PushButton.cpp
persistence.c
)
include_directories(include)

View File

@@ -1 +0,0 @@
#include "include/PushButton.h"

View File

@@ -1,9 +0,0 @@
#pragma once
#define BUTTON_UP 0
#define BUTTON_DOWN 1
#define BUTTON_LEFT 2
#define BUTTON_RIGHT 3
#define BUTTON_SELECT 4
#define BUTTON_BACK 5

View File

@@ -0,0 +1,8 @@
#pragma once
typedef struct
{
char *name;
void (*save)(const char *key, const char *value);
} persistence_t;

View File

@@ -0,0 +1,3 @@
//
// Created by Siegmund, Peter on 14.06.25.
//