From: sjlongland Date: Thu, 24 Sep 2015 08:12:19 +0000 (+0000) Subject: menu: Heirachical callback-based menu system X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=330bd2dc871e8e0eb4e1a30de2c1b3cb9fd0eac0;p=freetel-svn-tracking.git menu: Heirachical callback-based menu system This is an event-driven menu handler that allows arbirary depth and event handling. git-svn-id: https://svn.code.sf.net/p/freetel/code@2368 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/stm32/inc/menu.h b/codec2-dev/stm32/inc/menu.h new file mode 100644 index 00000000..f93601bf --- /dev/null +++ b/codec2-dev/stm32/inc/menu.h @@ -0,0 +1,92 @@ +#ifndef _MENU_H +#define _MENU_H +/*! + * Callback driven menu handler. + * + * The following is an implementation of a callback-driven menu system. + * It supports arbitrary levels of menus (limited by size of return stack) + * and supports arbitrary user events. + * + * Author Stuart Longland + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * . + */ + +#include + +#define MENU_STACK_SZ 8 /*!< Size of the menu return stack */ + +#define MENU_EVT_ENTERED 0 /*!< Menu item has been entered */ +#define MENU_EVT_RETURNED 1 /*!< We have returned from a submenu */ + +/*! Menu state structure */ +struct menu_t { + /*! The last seen menu item */ + const struct menu_item_t* last; + /*! Currently selected item index */ + uint32_t current; + /*! Current menu item stack */ + struct menu_stack_item_t { + const struct menu_item_t* item; + uint32_t index; + } stack[MENU_STACK_SZ]; + /*! Present depth of the stack */ + uint8_t stack_depth; +}; + +/*! Menu item structure */ +struct menu_item_t { + /*! Morse-code label for the menu item */ + const char* label; + /*! Event callback pointer for menu item */ + void (*event_cb)( + struct menu_t* const menu, + uint32_t event); + /*! Children of this menu item */ + const struct menu_item_t** const children; + uint32_t num_children; + /*! Arbitrary data */ + union menu_item_data_t { + /*! Arbitrary pointer */ + const void* p; + /*! Arbitrary unsigned integer */ + uintptr_t ui; + /*! Arbitrary signed integer */ + intptr_t si; + } data; +}; + +/*! + * Return the Nth item on the stack. + */ +const struct menu_item_t* const menu_item( + const struct menu_t* const menu, uint8_t index); + +/*! + * Enter a (sub)-menu. + * @retval -1 Stack is full + * @retval 0 Success + */ +int menu_enter(struct menu_t* const menu, + const struct menu_item_t* const item); + +/*! Return from a (sub)-menu */ +void menu_leave(struct menu_t* const menu); + +/*! + * Execute the callback for the current item with a user-supplied event. + */ +void menu_exec(struct menu_t* const menu, uint32_t event); + +#endif diff --git a/codec2-dev/stm32/src/menu.c b/codec2-dev/stm32/src/menu.c new file mode 100644 index 00000000..cb8ba97b --- /dev/null +++ b/codec2-dev/stm32/src/menu.c @@ -0,0 +1,98 @@ +/*! + * Callback driven menu handler. + * + * The following is an implementation of a callback-driven menu system. + * It supports arbitrary levels of menus (limited by size of return stack) + * and supports arbitrary user events. + * + * Author Stuart Longland + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * . + */ + +#include "menu.h" +#include + +/*! + * Return the Nth item on the stack. + */ +static const struct menu_stack_item_t* const menu_stack( + const struct menu_t* const menu, + uint8_t index) +{ + if (menu->stack_depth <= index) + return NULL; + + return &(menu->stack[menu->stack_depth - index - 1]); +} + +/*! + * Return the Nth item on the stack. + */ +const struct menu_item_t* const menu_item( + const struct menu_t* const menu, uint8_t index) +{ + const struct menu_stack_item_t* const current + = menu_stack(menu, index); + + if (!current) + return NULL; + return current->item; +} + +/*! + * Enter a (sub)-menu. + */ +int menu_enter(struct menu_t* const menu, + const struct menu_item_t* const item) +{ + if (menu->stack_depth == MENU_STACK_SZ) + return -1; + + menu->stack[menu->stack_depth].item = item; + menu->stack[menu->stack_depth].index = menu->current; + menu->stack_depth++; + + (item->event_cb)(menu, MENU_EVT_ENTERED); + + return 0; +} + +/*! + * Return from a (sub)-menu. + */ +void menu_leave(struct menu_t* const menu) +{ + if (!menu->stack_depth) + return; /* Already out of the menu */ + + menu->last = menu_item(menu, 0); + menu->stack_depth--; + + const struct menu_stack_item_t* current = menu_stack(menu, 0); + if (current && current->item) { + menu->current = current->index; + (current->item->event_cb)(menu, MENU_EVT_RETURNED); + } +} + +/*! + * Execute the callback for the current item with a user-supplied event. + */ +void menu_exec(struct menu_t* const menu, uint32_t event) +{ + const struct menu_item_t* item = menu_item(menu, 0); + if (item && item->event_cb) + (item->event_cb)(menu, event); +}