gintrace/src/gui/menu.c

235 lines
5.4 KiB
C

//---
// gintrace:menu - Menu helper
//---
#include "gintrace/gui/menu.h"
#include "gintrace/gui/fkey.h"
#include "gintrace/gui/input.h"
#include "gintrace/gui/display.h"
#include "gintrace/lexer.h"
#include <gint/std/string.h>
#include <gint/std/stdlib.h>
#include <gint/keyboard.h>
/* menu_create(): Create a group of menus */
int menu_create(struct menu_group **gmenu, volatile void *arg)
{
*gmenu = calloc(sizeof(struct menu_group), 1);
if (*gmenu == NULL)
return (menu_retval_enomem);
(*gmenu)->arg = arg;
return (menu_retval_success);
}
/* menu_register(): Register a new menu to the internal menu table */
int menu_register(struct menu_group *gmenu,
struct menu *menu, const char *name)
{
struct menu_list **node;
if (gmenu == NULL || name == NULL)
return (menu_retval_efault);
node = &gmenu->list;
while (*node != NULL) {
if (strcmp((*node)->name, name) == 0)
return (menu_retval_already_registered);
node = &(*node)->next;
}
*node = calloc(sizeof(struct menu_list), 1);
if (*node == NULL)
return (menu_retval_enomem);
if (menu != NULL && menu->ctor != NULL)
menu->ctor((void*)gmenu->arg);
if (gmenu->selected == NULL)
gmenu->selected = menu;
(*node)->menu = menu;
(*node)->name = name;
gmenu->menu_counter += 1;
return (menu_retval_success);
}
/* menu_unregister(): Unregister menu */
int menu_unregister(struct menu_group *gmenu, const char *name)
{
struct menu_list **node;
void *tmp;
if (gmenu == NULL || name == NULL)
return (menu_retval_efault);
node = &gmenu->list;
while (*node != NULL) {
if (strcmp((*node)->name, name) != 0) {
node = &(*node)->next;
continue;
}
tmp = *node;
*node = (*node)->next;
free(tmp);
return (menu_retval_success);
}
gmenu->menu_counter -= 1;
return (menu_retval_unregistered);
}
/* menu_special_ctor(): Involve special contructor */
int menu_special_ctor(struct menu_group *gmenu)
{
struct menu_list *node;
int a;
if (gmenu == NULL)
return (menu_retval_efault);
a = 0;
node = gmenu->list;
while (node != NULL) {
if (node->menu != NULL && node->menu->special.ctor != NULL)
a += node->menu->special.ctor((void*)gmenu->arg);
node = node->next;
}
return (a);
}
/* menu_special_ctor(): Involve special contructor */
int menu_special_dtor(struct menu_group *gmenu)
{
struct menu_list *node;
int a;
if (gmenu == NULL)
return (menu_retval_efault);
a = 0;
node = gmenu->list;
while (node != NULL) {
if (node->menu != NULL && node->menu->special.dtor != NULL)
a += node->menu->special.dtor((void*)gmenu->arg);
node = node->next;
}
return (a);
}
/* menu_init(): Initialize all menu */
int menu_init(struct menu_group *gmenu)
{
struct menu_list *node;
if (gmenu == NULL)
return (menu_retval_efault);
node = gmenu->list;
while (node != NULL) {
if (node->menu != NULL && node->menu->init != NULL)
node->menu->init((void*)gmenu->arg);
node = node->next;
}
gmenu->is_open = 0;
return (menu_retval_success);
}
/* menu_is_open(): Return the menu status */
int menu_is_open(struct menu_group *gmenu)
{
if (gmenu == NULL)
return (menu_retval_efault);
return (gmenu->is_open != 0);
}
/* menu_draw(): Draw menu specific information and menu abstraction overlay */
int menu_draw(struct menu_group *gmenu)
{
struct menu_list *node;
int offset;
int counter;
if (gmenu == NULL)
return (menu_retval_efault);
gclear();
if (gmenu->selected != NULL && gmenu->selected->display != NULL)
gmenu->selected->display((void*)gmenu->arg);
counter = 0;
node = gmenu->list;
offset = gmenu->menu_page * 5;
while (node != NULL) {
if (gmenu->menu_counter <= 6) {
fkey_menu(1 + counter, node->name);
counter += 1;
node = node->next;
continue;
}
if (counter - offset >= 5)
break;
if (counter - offset >= 0)
fkey_menu(1 + (counter - offset), node->name);
node = node->next;
counter += 1;
}
if (gmenu->menu_counter >= 7)
fkey_action(6, ">");
gupdate();
return (menu_retval_success);
}
/* menu_keyboard(): handle keyboard event */
int menu_keyboard(struct menu_group *gmenu)
{
const int keylist[] = {KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6};
struct menu_list *node;
int counter;
int target;
int key;
if (gmenu == NULL)
return (menu_retval_efault);
clearevents();
key = getkey().key;
if (key == KEY_0) {
gcolor_scheme_change();
return (menu_retval_success);
}
if (key == KEY_EXE) {
gmenu->is_open = 1;
return (menu_retval_success);
}
if (key == KEY_SQUARE) {
if (gmenu->selected == NULL
|| gmenu->selected->command == NULL) {
goto check_fkeys;
}
char buf[256];
if (input_read(buf, 256, NULL) <= 0)
goto check_fkeys;
int ac;
char **av;
if (lexer_strtotab(&ac, &av, buf) == 0) {
gmenu->selected->command((void*)gmenu->arg, ac, av);
lexer_strtotab_quit(&ac, &av);
}
}
check_fkeys:
for (int i = 0; i < 6; ++i) {
if (keylist[i] != key)
continue;
if (key == KEY_F6 && gmenu->menu_counter >= 7) {
gmenu->menu_page += 1;
if (gmenu->menu_page * 5 >= gmenu->menu_counter)
gmenu->menu_page = 0;
return (0);
}
counter = 0;
target = (gmenu->menu_page * 5) + i;
node = gmenu->list;
while (node != NULL) {
if (counter == target) {
gmenu->selected = node->menu;
return (menu_retval_success);
}
counter += 1;
node = node->next;
}
return (menu_retval_success);
}
if (gmenu->selected == NULL || gmenu->selected->keyboard == NULL)
return (menu_retval_success);
if (gmenu->selected->keyboard((void*)gmenu->arg, key) != 0)
gmenu->is_open = 1;
return (menu_retval_success);
}