feat: initial

This commit is contained in:
aZholtikov committed 2026-09-20 22:38:05 +03:00
1 parent 53b3a102d0
commit 3522c5b950
9 files changed
+622 -3

No files matched your search

View File
Whitespace-only changes.
+174
View File
@@ -0,0 +1,174 @@
/**
* @file zh_menu.h
*
* @brief Hierarchical menu component for ESP-IDF.
*
* This header provides types and functions for building a multi-level
* menu with navigation, selection handling and user callback support.
* The component is independent of any particular input method (buttons,
* encoder, interface commands) and operates with abstract navigation
* commands.
*
* This component is a derivative work based on the original project
* "menu_manager" by Marcio Bulla, available at:
* https://github.com/MarcioBulla/menu_manager
* The original project is distributed under the Apache License,
* Version 2.0. The original code was adapted, modified and extended
* for use with ESP-IDF as the zh_menu component.
*
* Key features:
* - Support for nested submenus with a depth limit
* - Configurable callbacks for position change, enter and exit
* - Cyclic navigation mode over menu items
* - Flexible handling of selectable and non-selectable items
* - Low memory footprint due to dynamic allocation of the handle
*
* @note The component functions are thread-safe only to the extent
* provided by the caller. External synchronization is required
* when accessed from multiple tasks.
*/
#pragma once
#include "esp_err.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Opaque menu handle.
*
* The internal structure is hidden from the user and is defined
* in the implementation file. All operations are performed through
* a pointer to this type.
*/
typedef struct _zh_menu_handle_t zh_menu_handle_t;
/**
* @brief Menu navigation commands.
*/
typedef enum
{
ZH_MENU_ENTER, /*!< Activate the menu and go to the root level */
ZH_MENU_SHOW, /*!< Force refresh of the current state via callback */
ZH_MENU_UP, /*!< Move selection to the previous item */
ZH_MENU_DOWN, /*!< Move selection to the next item */
ZH_MENU_SELECT, /*!< Select the current item or enter a submenu */
ZH_MENU_BACK, /*!< Return to the previous level or exit the menu */
ZH_MENU_MAX /*!< Upper bound of valid commands, not a command itself */
} zh_menu_navigate_t;
/**
* @brief Menu tree node.
*
* Describes a single menu item: its displayed label, nested submenu,
* number of items in the submenu, user callback and selectable flag.
*
* @warning The submenu array must exist during the entire lifetime
* of the menu. The component does not copy nodes.
*/
typedef struct zh_menu_node_t
{
const char *label; /*!< Displayed label of the menu item */
struct zh_menu_node_t *submenu; /*!< Pointer to an array of nested items or NULL */
uint8_t item_numbers; /*!< Number of items in the nested submenu array */
void (*item_cb)(void *args); /*!< Callback invoked when the item is selected */
bool selectable; /*!< Flag indicating that the item can be selected */
} zh_menu_node_t;
/**
* @brief Current menu state.
*
* Used to pass activity and selection status to external code
* through the zh_menu_get() function.
*/
typedef struct
{
bool is_active; /*!< Flag indicating that the menu is activated */
bool is_selected; /*!< Flag indicating that the current item is in the selection state */
} zh_menu_status_t;
/**
* @brief Menu initialization configuration.
*
* Contains the root node, a set of user callbacks and the cyclic navigation flag.
*
* @note The change_cb, enter_cb and exit_cb callbacks may be NULL
* if the corresponding handling is not required.
*/
typedef struct
{
zh_menu_node_t *root; /*!< Root node of the menu tree */
void (*change_cb)(zh_menu_node_t *current_path, uint8_t current_index); /*!< Callback for the current position change */
void (*enter_cb)(void *args); /*!< Callback for entering the menu */
void (*exit_cb)(void *args); /*!< Callback for exiting the menu */
bool loop; /*!< Cyclic navigation flag over items */
} zh_menu_init_config_t;
/**
* @brief Initialize the menu.
*
* Creates the menu handle, stores the configuration and prepares
* the internal state. After a successful call, the menu is in
* an inactive state until the ZH_MENU_ENTER command.
*
* @param[in] config Initialization configuration (must not be NULL)
* @param[out] handle Pointer to the handle pointer (must be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if config, config->root or handle is NULL
* @return ESP_ERR_INVALID_STATE if *handle is already initialized
* @return ESP_ERR_NO_MEM if memory allocation for the handle failed
*/
esp_err_t zh_menu_init(const zh_menu_init_config_t *config, zh_menu_handle_t **handle);
/**
* @brief Deinitialize the menu.
*
* Frees the dynamic memory occupied by the handle and resets the pointer to it.
*
* @param[in,out] handle Pointer to the handle pointer (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle or *handle is NULL
*/
esp_err_t zh_menu_deinit(zh_menu_handle_t **handle);
/**
* @brief Execute a menu navigation command.
*
* Processes one of the zh_menu_navigate_t commands, changing
* the internal menu state and invoking the corresponding callbacks.
* The exact behavior depends on the current activity and selection state.
*
* @param[in,out] handle Pointer to the handle pointer (must not be NULL)
* @param[in] command Navigation command. Must be less than ZH_MENU_MAX
* @param[in] arg Arbitrary argument passed to the user callbacks (enter_cb, exit_cb, item_cb) (may be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle, *handle is NULL or command >= ZH_MENU_MAX
*
* @note Commands that are invalid in the current state are ignored and do not cause an error.
*/
esp_err_t zh_menu_set(zh_menu_handle_t **handle, zh_menu_navigate_t command, void *arg);
/**
* @brief Get the current menu state.
*
* Fills the status structure with the activity and selection flags.
*
* @param[in] handle Pointer to the handle pointer (must not be NULL)
* @param[out] status Pointer to the status structure to be filled (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle, *handle or status is NULL
*/
esp_err_t zh_menu_get(zh_menu_handle_t **handle, zh_menu_status_t *status);
#ifdef __cplusplus
}
#endif