X-Git-Url: https://git.draconx.ca/gitweb/rrace.git/blobdiff_plain/320851f215662265a2ab323c2bc7424e1b6acd33..2fe01fae44c88046139ddc51c8521d5962ed9ac7:/src/cursmenu.c diff --git a/src/cursmenu.c b/src/cursmenu.c new file mode 100644 index 0000000..e665a32 --- /dev/null +++ b/src/cursmenu.c @@ -0,0 +1,156 @@ +/* + * Curses UI for slide puzzle game + * Copyright © 2022 Nick Bowler + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "cursesui.h" +#include "cursmenu.h" + +enum { + ACTION_EXIT = 0x80, + ACTION_ABOUT, + ACTION_NEWGAME, + ACTION_MAX +}; + +static const struct menuitem { + uint_least8_t label, position, action; +} menu[] = { FUNC_INITIALIZER }; + +static void do_function(struct app_state *state, unsigned action) +{ + if (action < sizeof menu / sizeof menu[0]) { + state->toolbar_state = action; + curs_draw_toolbar(state); + doupdate(); + } + + switch (action) { + case ACTION_NEWGAME: + curs_new_game(state); + break; + case ACTION_EXIT: + endwin(); + exit(0); + }; +} + +void curs_execute_function(struct app_state *state, int func) +{ + int i; + + for (i = state->toolbar_state; menu[i].position; i++) { + if (func == menu[i].position) { + do_function(state, menu[i].action); + return; + } + } +} + +/* + * Return the width of the toolbar and the target width of toolbar labels. + */ +static int toolbar_width(WINDOW *toolbar, int *label_width) +{ + int w, h; + + getmaxyx(toolbar, h, w); + *label_width = MAX(6, w/10); + return (void)h, w; +} + +/* + * Given the toolbar function number (between 1 and 10, inclusive), and the + * total width of the screen, return the character position for the start of + * its label display. + * + * The intention is to divide the width of the screen into 10 roughly + * equally-sized areas, spreading out the remainder so that the width of + * each label is a monotone increasing function of the total width. + * + * The minimum size of a label is 6 characters (2 of which are used for the + * number indicator) + */ +static int toolbar_xpos(int i, int total_width, int label_width) +{ + int rem = total_width - 10*label_width; + int pos = (i-1)*label_width; + + switch (rem) { + case 9: pos += i > 6; + case 8: pos += i > 2; + case 7: pos += i > 7; + case 6: pos += i > 3; + case 5: pos += i > 8; + case 4: pos += i > 4; + case 3: pos += i > 9; + case 2: pos += i > 5; + } + + return pos; +} + +/* + * Redraw the current set of toolbar labels. + */ +void curs_draw_toolbar(struct app_state *state) +{ + WINDOW *toolbar = state->toolbar; + int i, w, lw; + + werase(toolbar); + + w = toolbar_width(toolbar, &lw); + for (i = state->toolbar_state; menu[i].position; i++) { + int pos = toolbar_xpos(menu[i].position, w, lw); + mvwprintw(toolbar, 0, pos+2, "%.*s", lw, strtab+menu[i].label); + } + + mvwchgat(toolbar, 0, 0, -1, A_REVERSE, RR_COLOUR_TOOLBAR, 0); + for (i = 1; i <= 10; i++) { + mvwprintw(toolbar, 0, toolbar_xpos(i, w, lw), "%2d", i); + } + + wnoutrefresh(state->toolbar); +} + +#if HAVE_CURSES_MOUSE_SUPPORT +/* + * Returns the toolbar function (1 through 10) under the given x, y screen + * coordinates, or 0 if the coordinates are outside of the toolbar. + */ +int curs_toolbar_mouse_func(struct app_state *state, int x, int y) +{ + int toolbar_x, toolbar_y, i, w, lw; + + getbegyx(state->toolbar, toolbar_y, toolbar_x); + if ((void)toolbar_x, y != toolbar_y) + return 0; + + /* OK, selected a button, determine which one */ + w = toolbar_width(state->toolbar, &lw); + for (i = 10; i > 1; i--) { + if (x >= toolbar_xpos(i, w, lw)) + break; + } + + return i; +} +#endif