Multilevel menus working with key repeat

This commit is contained in:
2025-05-16 17:11:59 -05:00
parent da0dd55b20
commit d4a402428b
9 changed files with 386 additions and 118 deletions

View File

@@ -33,6 +33,7 @@
#include "menu.h"
#include "ports.h"
#include "display.h"
#include "io.h"
/*******************************************************************************
* Definitions
@@ -40,38 +41,7 @@
#define MENU_TIMER_PERIOD_MS (100) //100mS for 10Hz update
#define MENU_STACK_SIZE 4
#define MENU_ITEM_SIZE 10
typedef struct Menu_s Menu_t;
typedef int (*MenuHandler_t)(Menu_t *menu);
struct Menu_s
{
MenuHandler_t handler;
bool init;
bool draw;
int selected;
MENU_ITEM_t items[MENU_ITEM_SIZE];
int itemCount;
int displayIndex;
};
typedef struct MenuData_s
{
int stackCount;
Menu_t menuStack[MENU_STACK_SIZE];
Menu_t *currentMenu;
} MenuData_t;
typedef struct {
bool exitToMainScreen;
} MENU_t;
@@ -90,9 +60,9 @@ static MenuData_t _menuData;
MENU_t menu;
MENU_ITEM_t mainMenu[MAIN_MENU_NUM_TX10];
MENU_ITEM_t linkMenu[LINK_MENU_NUM];
MENU_ITEM_t langMenu[LANG_MENU_NUM];
MenuItem_t mainMenu[MAIN_MENU_NUM_TX10];
MenuItem_t linkMenu[LINK_MENU_NUM];
MenuItem_t langMenu[LANG_MENU_NUM];
extern const char *languageNames[];
@@ -109,7 +79,7 @@ extern uint8_t Dds_Pot_Val[];
extern uint8_t Port_State[];
extern HARDWARE_FIX_t hwf;
extern uint32_t systemTime;
@@ -117,9 +87,10 @@ extern HARDWARE_FIX_t hwf;
* Static Function Declarations
******************************************************************************/
static Menu_t* getNewMenu(MenuHandler_t handler);
static int handleSystemInfoMenu(Menu_t *menu);
static void ClearMenuItems(MENU_ITEM_t items[], uint32_t num);
static void ClearMenuItems(MenuItem_t items[], uint32_t num);
static void DrawMenuScrollBar(uint32_t displayIndex, uint32_t numItems);
@@ -141,68 +112,121 @@ static void DisplayRegulatoryInfo(void);
/*******************************************************************************
* Static Functions
******************************************************************************/
static int handleMainMenu(Menu_t *menu)
static void createMenuItem(MenuItemId_t id, MenuItem_t *item)
{
if (menu->init)
item->id = id;
switch (id)
{
int itemCount = 0;
case MENU_ID_SYSINFO:
{
item->pMonoIcon = menuMore;
strcpy(item->text, "System Information");
item->handler = handleSystemInfoMenu;
break;
}
menu->items[itemCount].pMonoIcon = menuMore;
menu->items[itemCount].id = MENU_ID_SYSINFO;
strcpy(menu->items[itemCount].text, "System Information"); //System info screen
itemCount++;
case MENU_ID_FREQUENCIES:
{
item->pMonoIcon = menuMore;
strcpy(item->text, "Frequencies");
break;
}
menu->items[itemCount].pMonoIcon = menuMore;
menu->items[itemCount].id = MENU_ID_FREQUENCIES;
strcpy(menu->items[itemCount].text, "Frequencies"); //Frequency Selection Menu
itemCount++;
case MENU_ID_AUTOSHUTDOWN:
{
item->pMonoIcon = 0;
strcpy(item->text, "Auto Shutdown");
break;
}
menu->items[itemCount].pMonoIcon = 0;
menu->items[itemCount].id = MENU_ID_AUTOSHUTDOWN;
strcpy(menu->items[itemCount].text, "Auto Shutdown"); //Auto Shutdown selection
itemCount++;
case MENU_ID_LANGUAGE:
{
item->pMonoIcon = menuMore;
strcpy(item->text, "Language");
break;
}
}
}
menu->items[itemCount].pMonoIcon = menuMore;
menu->items[itemCount].id = MENU_ID_LANGUAGE;
strcpy(menu->items[itemCount].text, "Language"); //Language Selection Menu
itemCount++;
menu->itemCount = itemCount;
menu->init = false;
menu->draw = true;
static void handleUpDown(uint32_t pressed, Menu_t *menu)
{
switch (menu->longPress)
{
case (KEY_UP << KEY_LONG_PRESS):
{
if (!GPIO_READ(PIN_KEY_UP))
{
if (systemTime >= menu->nextRepeat)
{
pressed = KEY_UP;
menu->nextRepeat = systemTime + 100;
}
}
else
{
menu->longPress = 0;
}
break;
}
case (KEY_DOWN << KEY_LONG_PRESS):
{
if (!GPIO_READ(PIN_KEY_DOWN))
{
if (systemTime >= menu->nextRepeat)
{
pressed = KEY_DOWN;
menu->nextRepeat = systemTime + 100;
}
}
else
{
menu->longPress = 0;
}
break;
}
}
switch(KEY_GetPressed())
switch(pressed)
{
case KEY_UP:
{
if(--menu->selected < 0)
menu->selected--;
if(menu->selected < 0)
{
menu->selected = 0;
}
menu->draw = true;
break;
}
case KEY_DOWN:
{
if(++menu->selected >= menu->itemCount)
menu->selected++;
if(menu->selected >= menu->itemCount)
{
menu->selected = menu->itemCount - 1;
}
menu->draw = true;
break;
}
case (KEY_UP << KEY_LONG_PRESS):
case (KEY_DOWN << KEY_LONG_PRESS):
{
menu->longPress = pressed;
menu->nextRepeat = 0;
break;
}
}
if (menu->draw)
{
LCD_Clear();
if(menu->selected >= (menu->displayIndex + MENU_MAX_LINES_DISPLAYED))
{
menu->displayIndex++;
@@ -211,10 +235,181 @@ static int handleMainMenu(Menu_t *menu)
{
menu->displayIndex--;
}
}
}
static void drawScrollBar(Menu_t *menu)
{
DrawMenuScrollBar(menu->displayIndex, menu->itemCount);
}
static Menu_t* getNewMenu(MenuHandler_t handler)
{
Menu_t *menu = NULL;
if (_menuData.stackCount < MENU_STACK_SIZE)
{
menu = &_menuData.menuStack[_menuData.stackCount];
menu->handler = handler;
menu->init = true;
menu->selected = 0;
menu->displayIndex = 0;
menu->exitCode = MENU_OK;
_menuData.currentMenu = menu;
_menuData.stackCount++;
}
return menu;
}
static int handleSystemInfoMenu(Menu_t *menu)
{
if (menu == NULL)
{
menu = getNewMenu(handleSystemInfoMenu);
if (menu == NULL)
{
return MENU_EXIT;
}
}
if (menu->init)
{
int itemCount = 0;
createMenuItem(MENU_ID_SYSINFO , &menu->items[itemCount++]);
createMenuItem(MENU_ID_FREQUENCIES , &menu->items[itemCount++]);
menu->itemCount = itemCount;
menu->init = false;
menu->draw = true;
}
uint32_t pressed = KEY_GetPressed();
handleUpDown(pressed, menu);
if (pressed == KEY_BACK)
{
menu->exitCode = MENU_EXIT;
}
else
if (pressed == KEY_ENTER)
{
if (menu->items[menu->selected].handler != NULL)
{
menu->items[menu->selected].handler(NULL);
}
}
if (menu->draw)
{
LCD_Clear();
// Draw menu items
MENU_ITEM_t *item;
MenuItem_t *item;
for(uint32_t i = menu->displayIndex; i < menu->displayIndex + menu->itemCount; i++) //this can draw extra lines off the screen but we don't care
{
item = &menu->items[i];
//Menu strings
FL_DrawTranslatedString(item->text, MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START + (i-menu->displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
// Draw item status
if (item->pMonoIcon != NULL)
{
GL_DrawMonoBitmap(item->pMonoIcon, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i-menu->displayIndex)*MENU_LINE_HEIGHT + MENU_MAIN_STATUS_Y_OFF, LCD_DRAW_SET);
}
}
//Draw selection bar
uint32_t selRectY0 = MENU_MAIN_TEXT_Y_START + (menu->selected - menu->displayIndex)*MENU_LINE_HEIGHT;
GL_DrawFilledRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1, selRectY0 + MENU_LINE_HEIGHT, LCD_DRAW_XOR);
drawScrollBar(menu);
LCD_Update();
menu->draw = false;
}
return menu->exitCode;
//SystemInfoMenu();
}
static int handleMainMenu(Menu_t *menu)
{
if (menu == NULL)
{
// get new menu on stack and init
menu = getNewMenu(handleMainMenu);
//menu->handler = handleMainMenu;
}
if (menu->init)
{
int itemCount = 0;
createMenuItem(MENU_ID_SYSINFO , &menu->items[itemCount++]);
createMenuItem(MENU_ID_FREQUENCIES , &menu->items[itemCount++]);
createMenuItem(MENU_ID_AUTOSHUTDOWN , &menu->items[itemCount++]);
createMenuItem(MENU_ID_LANGUAGE , &menu->items[itemCount++]);
createMenuItem(MENU_ID_SYSINFO , &menu->items[itemCount++]);
createMenuItem(MENU_ID_FREQUENCIES , &menu->items[itemCount++]);
createMenuItem(MENU_ID_AUTOSHUTDOWN , &menu->items[itemCount++]);
createMenuItem(MENU_ID_LANGUAGE , &menu->items[itemCount++]);
menu->itemCount = itemCount;
menu->init = false;
menu->draw = true;
}
uint32_t pressed = KEY_GetPressed();
handleUpDown(pressed, menu);
if (pressed == KEY_BACK)
{
menu->exitCode = MENU_EXIT;
}
else
if (pressed == KEY_ENTER)
{
if (menu->items[menu->selected].handler != NULL)
{
menu->items[menu->selected].handler(NULL);
return MENU_OK;
}
}
if (menu->draw)
{
LCD_Clear();
// Draw menu items
MenuItem_t *item;
for(uint32_t i = menu->displayIndex; i < menu->displayIndex + menu->itemCount; i++) //this can draw extra lines off the screen but we don't care
{
@@ -242,10 +437,7 @@ static int handleMainMenu(Menu_t *menu)
uint32_t selRectY0 = MENU_MAIN_TEXT_Y_START + (menu->selected - menu->displayIndex)*MENU_LINE_HEIGHT;
GL_DrawFilledRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1, selRectY0 + MENU_LINE_HEIGHT, LCD_DRAW_XOR);
//Draw menu icons
//Use DrawMenuBitmap(mainMenu[i], x, y)
//DrawMenuScrollBar(displayIndex, menuNum);
drawScrollBar(menu);
LCD_Update();
@@ -254,19 +446,18 @@ static int handleMainMenu(Menu_t *menu)
return 0;
return menu->exitCode;
}
//Clear an array of MENU_ITEM_t
static void ClearMenuItems(MENU_ITEM_t items[], uint32_t num)
static void ClearMenuItems(MenuItem_t items[], uint32_t num)
{
for(uint32_t i = 0; i < num; i++)
{
items[i].pMonoIcon = 0; //Init mono icon pointer to null
items[i].text[0] = 0; //Init first char to null
items[i].pMonoIcon = NULL; //Init mono icon pointer to null
items[i].text[0] = NULL; //Init first char to null
}
}
@@ -1266,10 +1457,12 @@ void Menu_init(void)
for (int i=0; i<MENU_STACK_SIZE; ++i)
{
_menuData.menuStack[i].displayIndex = 0;
_menuData.menuStack[i].exitCode = MENU_OK;
for (int j=0; j<MENU_ITEM_SIZE; ++j)
{
_menuData.menuStack[i].items[j].id = MENU_ID_NONE;
_menuData.menuStack[i].items[j].handler = NULL;
}
}
}
@@ -1278,21 +1471,47 @@ void Menu_mainMenu(void)
{
sys.guiMode = GUI_MODE_MENU;
Menu_t *menu = &_menuData.menuStack[0];
// menu at top of stack is always "Main Menu"
_menuData.stackCount = 0;
getNewMenu(handleMainMenu);
menu->handler = handleMainMenu;
menu->selected = 0;
menu->init = true;
_menuData.currentMenu = menu;
}
void Menu_service(void)
{
int exitCode = MENU_OK;
// run the menu state machine and prevent blocking
if (_menuData.currentMenu != NULL)
{
_menuData.currentMenu->handler(_menuData.currentMenu);
exitCode = _menuData.currentMenu->handler(_menuData.currentMenu);
switch (exitCode)
{
case MENU_HOME:
{
_menuData.stackCount = 0;
break;
}
case MENU_EXIT:
{
// pop the menu off the stack
_menuData.stackCount--;
if (_menuData.stackCount > 0)
{
_menuData.currentMenu = &_menuData.menuStack[_menuData.stackCount-1];
_menuData.currentMenu->draw = true;
}
break;
}
}
if (_menuData.stackCount == 0)
{
sys.guiMode = GUI_MODE_NORMAL;
}
}
}