/* * menu.c * * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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. * * See . */ #include #include "config.h" #include "buttons.h" #include "text.h" #include "textbox.h" #include "lcd.h" #include "menu.h" static char prev_buff[MENU_MAX_LEN] = {0}; static struct menu_state menu = { .off = 0, .selection = -1, .length = 0, .buff = {0} }; static void (*enter_callback)(int) = NULL; static void (*up_callback)(int) = NULL; static void (*down_callback)(int) = NULL; static void (*exit_callback)(void) = NULL; bool menu_got_input = false; static void menu_buttons(enum buttons btn, bool state) { menu_got_input = true; if (state && ((btn == BTN_ENTER) || (btn == BTN_A))) { if (enter_callback) { enter_callback(menu.selection); } return; } else if (state && (btn == BTN_B)) { if (up_callback) { up_callback(menu.selection); } return; } else if (state && (btn == BTN_X)) { if (down_callback) { down_callback(menu.selection); } return; } else if (state && (btn == BTN_Y)) { if (exit_callback) { exit_callback(); } } else if ((!state) || ((btn != BTN_UP) && (btn != BTN_DOWN))) { return; } if (state && (btn == BTN_UP)) { if (menu.selection < 0) { menu.selection = menu.length - 1; } else { menu.selection -= 1; } } else if (state && (btn == BTN_DOWN)) { if (menu.selection < 0) { menu.selection = 0; } else { menu.selection += 1; } } if (menu.selection < 0) { menu.selection += menu.length; } if (menu.selection >= menu.length) { menu.selection -= menu.length; } if (menu.selection >= 0) { while (menu.selection < menu.off) { menu.off -= 1; } while (menu.selection >= (menu.off + menu.lines)) { menu.off += 1; } } } void menu_init(void (*enter)(int), void (*up)(int), void (*down)(int), void (*exit)(void)) { menu.off = 0; menu.selection = -1; menu.length = 0; menu.lines = MENU_MAX_LINES; menu.y_off = 0; enter_callback = enter; up_callback = up; down_callback = down; exit_callback = exit; buttons_callback(menu_buttons); } void menu_deinit(void) { buttons_callback(NULL); } void menu_run(void (*draw)(struct menu_state *), bool centered) { if (draw) { draw(&menu); } if (strncmp(menu.buff, prev_buff, MENU_MAX_LEN) != 0) { strncpy(prev_buff, menu.buff, MENU_MAX_LEN); text_box(menu.buff, centered, "fixed_10x20", 0, LCD_WIDTH, 50 + menu.y_off, MENU_BOX_HEIGHT(menu.lines, 20, 2), 0); } }