2 * Curses UI for slide puzzle game
3 * Copyright © 2022 Nick Bowler
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
33 static const struct menuitem {
34 uint_least8_t label, position, action;
35 } menu[] = { FUNC_INITIALIZER };
37 static void do_function(struct app_state *state, unsigned action)
39 if (action < sizeof menu / sizeof menu[0]) {
40 state->toolbar_state = action;
41 curs_draw_toolbar(state);
55 void curs_execute_function(struct app_state *state, int func)
59 for (i = state->toolbar_state; menu[i].position; i++) {
60 if (func == menu[i].position) {
61 do_function(state, menu[i].action);
68 * Return the width of the toolbar and the target width of toolbar labels.
70 static int toolbar_width(WINDOW *toolbar, int *item_width)
74 getmaxyx(toolbar, h, w);
75 *item_width = MAX(6, w/10);
80 * Given the toolbar function number (between 1 and 10, inclusive), and the
81 * total width of the screen, return the character position for the start of
84 * The intention is to divide the width of the screen into 10 roughly
85 * equally-sized areas, spreading out the remainder so that the width of
86 * each label is a monotone increasing function of the total width.
88 * The minimum size of a label is 6 characters (2 of which are used for the
91 static int toolbar_xpos(int i, int total_width, int item_width)
93 int rem = total_width - 10*item_width;
94 int pos = (i-1)*item_width;
100 case 6: pos += i > 3;
101 case 5: pos += i > 8;
102 case 4: pos += i > 4;
103 case 3: pos += i > 9;
104 case 2: pos += i > 5;
111 * Redraw the current set of toolbar labels.
113 void curs_draw_toolbar(struct app_state *state)
115 WINDOW *toolbar = state->toolbar;
120 w = toolbar_width(toolbar, &lw);
121 for (i = state->toolbar_state; menu[i].position; i++) {
122 int pos = toolbar_xpos(menu[i].position, w, lw);
123 mvwprintw(toolbar, 0, pos+2, "%.*s", lw, strtab+menu[i].label);
126 mvwchgat(toolbar, 0, 0, -1, A_REVERSE, RR_COLOUR_TOOLBAR, 0);
127 for (i = 1; i <= 10; i++) {
128 mvwprintw(toolbar, 0, toolbar_xpos(i, w, lw), "%2d", i);
131 wnoutrefresh(state->toolbar);
134 #if HAVE_CURSES_MOUSE_SUPPORT
136 * Returns the toolbar function (1 through 10) under the given x, y screen
137 * coordinates, or 0 if the coordinates are outside of the toolbar.
139 int curs_toolbar_mouse_func(struct app_state *state, int x, int y)
141 int toolbar_x, toolbar_y, i, w, lw;
143 getbegyx(state->toolbar, toolbar_y, toolbar_x);
144 if ((void)toolbar_x, y != toolbar_y)
147 /* OK, selected a button, determine which one */
148 w = toolbar_width(state->toolbar, &lw);
149 for (i = 10; i > 1; i--) {
150 if (x >= toolbar_xpos(i, w, lw))