loader: increase buf size for file reads
[rofl0r-gnuboy.git] / ezmenu.h
blob1cc6186e8d2d612588bc4017db8be26d0995ff08
1 /*
2 MIT License
3 Copyright (C) 2022 rofl0r
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the “Software”), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
24 /* a single-file library to implement a simple menu system in emulators.
25 it mainly deals with scrolling/selection in a list of string items.
26 the interfacing code supplies a list of strings, optional header and
27 footer text, and sends up/down key movement user input. ezmenu then
28 takes care of scrolling up and down, so the interface code simply
29 has to print the vislines onto the screen using the fontsize
30 specified in ezmenu_init(). if a user presses e.g. enter to activate
31 a menu item, the interface code has to deal with the input itself
32 and read vislines[vissel] to find out which entry was activated. */
34 #include <string.h>
35 #include <stdlib.h>
37 struct ezmenu {
38 /* internal list of lines, passed via ezmenu_setlines.
39 if you use malloc()'d strings here you need to free them before
40 repopulating the list with new lines. */
41 char **lines;
42 /* these are the visible lines you need to render. */
43 char **vislines;
44 char *header, *footer;
45 /* internal bookkeeping for the amount of lines in "lines". */
46 unsigned linecount;
47 int sel; /* internal bookkeeping of which line of lines is selected */
48 int vissel; /* which line out of vislines is selected, for extern use */
49 int w, h; /* width and height of visible character grid, in cells */
50 int wraparound; /* whether to wrap around if user presses up on first item, or down on last */
53 /* ezmenu only cares about down and up events, to scroll and select.
54 any other event is handled by the caller, e.g. if button "a" was
55 pressed, you gotta extract the text of vislines[vissel] and act
56 upon it. */
57 enum ezmenu_input {
58 EZM_DOWN,
59 EZM_UP,
62 static void ezmenu_init(struct ezmenu *m, int hres, int vres,
63 int fontw, int fonth) {
64 memset(m, 0, sizeof *m);
65 m->w = hres/fontw;
66 m->h = vres/fonth;
67 m->vislines = calloc(sizeof(char*), m->h);
70 static void ezmenu_setlines(struct ezmenu *m, char**lines, unsigned linecount) {
71 m->lines = lines;
72 m->linecount = linecount;
73 m->sel = 0;
76 static void ezmenu_setheader(struct ezmenu *m, char* hdr) {
77 m->header = hdr;
78 m->vislines[0] = hdr;
79 m->vislines[1] = "";
82 static void ezmenu_setfooter(struct ezmenu *m, char* ftr) {
83 m->footer = ftr;
84 m->vislines[m->h-2] = "";
85 m->vislines[m->h-1] = ftr;
87 #ifndef MAX
88 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
89 #endif
90 static void ezmenu_update(struct ezmenu *m) {
91 int start = (!!m->header)*2, end = m->h - (!!m->footer)*2;
92 int vis = end - start;
93 int y, ly = MAX(0, m->sel - vis/2);
94 m->vissel = (m->sel-ly)+(!!m->header)*2;
95 for(y = start; y < end; ++y) {
96 m->vislines[y] = ly>=m->linecount?"":m->lines[ly++];
100 static void ezmenu_userinput(struct ezmenu *m, enum ezmenu_input inp) {
101 static const int dir[] = {[EZM_DOWN] = 1, [EZM_UP] = -1};
102 m->sel += dir[inp];
103 if(m->sel < 0) {
104 if(m->wraparound)
105 m->sel = m->linecount-1;
106 else
107 m->sel = 0;
109 else if(m->sel >= m->linecount) {
110 if(m->wraparound)
111 m->sel = 0;
112 else
113 m->sel = m->linecount-1;
115 ezmenu_update(m);