/*
* 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 *item_width)
{
int w, h;
getmaxyx(toolbar, h, w);
*item_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 item_width)
{
int rem = total_width - 10*item_width;
int pos = (i-1)*item_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