A co třeba nějak takhle …
Definice typů a proměnných
[code]typedef struct // Položka menu
{
char *ItemText; // Text položky, pokud není definovaná programově generovaná položka.
void (*UserPaintLine)(void); // Programově generovaný text položky (třeba položka obsahující v textu nastavovanou hodnotu)
void *OnEnterKey; // Které menu se má zobrazit při krátkém stisku Enter.
void *OnLongEnterKey; // Které menu se má zobrazit při dlouhém stisku Enter.
void (*OnEnterCall)(void); // Funkce, která se zavolá při stisku Enter.
} MenuItemStruct;
typedef struct // Struktura menu
{
unsigned char ItemCount; // Počet položek
unsigned char ItemIndex; // Index vybrané položka
char *MenuLabel; // Záhlaví menu
void *OnEscapeKey; // Nadřazené menu (NULL = žádné)
void *OnLongEscapeKey; // Dlouhý stisk Escape (NULL = žádné)
MenuItemStruct MenuItem[4]; // Položky menu (počet položek odpovídá nejdelšímu menu
unsigned char TopIndex; // Index (0…x) první zobrazené položky (pro scrolování menu)
} MenuStruct;
MenuStruct *ActiveMenu; // Pointer na proměnnou aktuálně zobrazeného menu (NULL = žádné menu nezobrazeno)
[/code]
Zobrazovací rutina
[code]void UserMenu( void )
{
if (ActiveMenu!=NULL)
{
char Line = 0;
if ( ActiveMenu->MenuLabel != NULL )
{
LCD_GotoXY(Line++, 0);
LCD_Write_PM_String(ActiveMenu->MenuLabel);
}
volatile char PrintedMenuLine=ActiveMenu->TopIndex ;
while((Line < 4)&&(PrintedMenuLine < ActiveMenu->ItemCount ))
{
if ( ActiveMenu->MenuItem[PrintedMenuLine].UserPaintLine != NULL )
{
LCD_GotoXY(Line++, 1);
ActiveMenu->MenuItem[PrintedMenuLine].UserPaintLine();
}
else
{
if ( ActiveMenu->MenuItem[PrintedMenuLine].ItemText != NULL )
{
LCD_GotoXY(Line++, 1);
LCD_Write_PM_String(ActiveMenu->MenuItem[PrintedMenuLine].ItemText);
}
}
if ( PrintedMenuLine == ActiveMenu->ItemIndex )
{
LCD_GotoXY(Line-1, 0);
LCD_Data = 0;
LCD_Write_Data();
}
PrintedMenuLine++;
}
}
}
[/code]
Hlavní program
// Deklarace textů položek menu.
const PROGMEM char MenuItemText][17] = {\
" Hlavni menu ", "Polozka hl. 1 ", "Polozka hl. 2 ", "Polozka hl. 3 ", \
" Podmenu 1 ", "Polozka pm. 1-1", "Polozka pm. 1-2", "Polozka pm. 1-3", \
" Podmenu 2 ", "Polozka pm. 2-1", "Polozka pm. 2-2", "Polozka pm. 2-3", \
"Polozka pm. 2-4", "Polozka pm. 3-1", "Polozka pm. 3-2", "Polozka pm. 3-3" \
};
MenuStruct HlavniMenu, Podmenu1, Podmenu2; // Deklarace tří menu
int main(void)
{
// Nastavit hlavní menu
HlavniMenu.ItemIndex = 0;
HlavniMenu.ItemCount = 2;
HlavniMenu.MenuLabel = MenuItemText[0];
HlavniMenu.MenuItem[0].ItemText = MenuItemText[1];
HlavniMenu.MenuItem[1].ItemText = MenuItemText[2];
HlavniMenu.MenuItem[2].ItemText = MenuItemText[3];
HlavniMenu.MenuItem[0].OnEnterKey = &Podmenu1;
HlavniMenu.MenuItem[1].OnEnterKey = &Podmenu2;
// Nastavit podmenu 1
Podmenu1.ItemIndex = 0;
Podmenu1.ItemCount = 2;
Podmenu1.MenuLabel = MenuItemText[4];
Podmenu1.MenuItem[0].ItemText = MenuItemText[5];
Podmenu1.MenuItem[0].UserPaintLine = NapisTestovaciRadekMenu;
Podmenu1.MenuItem[1].ItemText = MenuItemText[6];
Podmenu1.MenuItem[2].ItemText = MenuItemText[7];
Podmenu1.OnEscapeKey = &HlavniMenu;
// Nastavit podmenu 2
Podmenu2.ItemIndex = 0;
Podmenu2.ItemCount = 4;
Podmenu2.MenuLabel = MenuItemText[8];
Podmenu2.MenuItem[0].ItemText = MenuItemText[9];
Podmenu2.MenuItem[1].ItemText = MenuItemText[10];
Podmenu2.MenuItem[2].ItemText = MenuItemText[11];
Podmenu2.MenuItem[3].ItemText = MenuItemText[12];
Podmenu2.OnEscapeKey = &HlavniMenu;
// Zvolit hlavní menu
ActiveMenu = &HlavniMenu;
// Zobrazit zvolené menu
UserMenu();
.
.
.
.
.
Zobrazovací rutina i obsluha vstupů (tlačítka, rotační koder, dotykový panel atd.) je společná pro všechna menu. Přepínání jednotlvých menu se děje jenom přepnutím jednoho pointeru.
Psané je to v Atmel Studiu 7.