Merge branch 'NetHack-3.6.2'
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 winmisc.c $NHDT-Date: 1543830350 2018/12/03 09:45:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.42 $ */
|
||||
/* NetHack 3.6 winmisc.c $NHDT-Date: 1554135506 2019/04/01 16:18:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.44 $ */
|
||||
/* Copyright (c) Dean Luick, 1992 */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
static Widget extended_command_popup = 0;
|
||||
static Widget extended_command_form;
|
||||
static Widget *extended_commands = 0;
|
||||
static const char **command_list;
|
||||
static short *command_indx;
|
||||
static int extended_cmd_selected; /* index of the selected command; */
|
||||
static int ps_selected; /* index of selected role */
|
||||
#define PS_RANDOM (-50)
|
||||
@@ -50,6 +52,7 @@ static const char ps_randchars[] = "*@\n\rrR";
|
||||
static const char ps_quitchars[] = "\033qQ";
|
||||
|
||||
#define EC_NCHARS 32
|
||||
static boolean ec_full_list = FALSE;
|
||||
static boolean ec_active = FALSE;
|
||||
static int ec_nchars = 0;
|
||||
static char ec_chars[EC_NCHARS];
|
||||
@@ -111,13 +114,14 @@ XtPointer
|
||||
i2xtp(i)
|
||||
int i;
|
||||
{
|
||||
return (XtPointer)(long)i;
|
||||
return (XtPointer) (ptrdiff_t) i;
|
||||
}
|
||||
|
||||
int
|
||||
xtp2i(x)
|
||||
XtPointer x;
|
||||
{
|
||||
return (long)x;
|
||||
return (int) (ptrdiff_t) x;
|
||||
}
|
||||
|
||||
/* Player Selection ------------------------------------------------------- */
|
||||
@@ -1581,9 +1585,16 @@ X11_player_selection()
|
||||
}
|
||||
}
|
||||
|
||||
/* called by core to have the player pick an extended command */
|
||||
int
|
||||
X11_get_ext_cmd()
|
||||
{
|
||||
if (iflags.extmenu != ec_full_list) {
|
||||
/* player has toggled the 'extmenu' option, toss the old widgets */
|
||||
if (extended_commands)
|
||||
release_extended_cmds(); /* will set extended_commands to Null */
|
||||
ec_full_list = iflags.extmenu;
|
||||
}
|
||||
if (!extended_commands)
|
||||
init_extended_commands_popup();
|
||||
|
||||
@@ -1597,15 +1608,19 @@ X11_get_ext_cmd()
|
||||
/* The callbacks will enable the event loop exit. */
|
||||
(void) x_event(EXIT_ON_EXIT);
|
||||
|
||||
return extended_cmd_selected;
|
||||
if (extended_cmd_selected < 0)
|
||||
return -1;
|
||||
return command_indx[extended_cmd_selected];
|
||||
}
|
||||
|
||||
void
|
||||
release_extended_cmds()
|
||||
{
|
||||
if (extended_commands) {
|
||||
XtDestroyWidget(extended_command_popup);
|
||||
XtDestroyWidget(extended_command_popup), extended_command_popup = 0;
|
||||
free((genericptr_t) extended_commands), extended_commands = 0;
|
||||
free((genericptr_t) command_list), command_list = (const char **) 0;
|
||||
free((genericptr_t) command_indx), command_indx = (short *) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1816,6 +1831,22 @@ int ec_indx; /* might be greater than extended_cmd_selected */
|
||||
}
|
||||
}
|
||||
|
||||
/* decide whether extcmdlist[idx] should be part of extended commands menu */
|
||||
static boolean
|
||||
ignore_extcmd(idx)
|
||||
int idx;
|
||||
{
|
||||
/* #shell or #suspect might not be available;
|
||||
'extmenu' option controls whether we show full list
|
||||
or just the traditional extended commands */
|
||||
if ((extcmdlist[idx].flags & CMD_NOT_AVAILABLE) != 0
|
||||
|| ((extcmdlist[idx].flags & AUTOCOMPLETE) == 0 && !ec_full_list)
|
||||
|| strlen(extcmdlist[idx].ef_txt) < 2) /* ignore "#" and "?" */
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
ec_key(w, event, params, num_params)
|
||||
@@ -1825,11 +1856,12 @@ String *params;
|
||||
Cardinal *num_params;
|
||||
{
|
||||
char ch;
|
||||
int i;
|
||||
int pass;
|
||||
int i, pass;
|
||||
float shown, top;
|
||||
Arg arg[2];
|
||||
Widget hbar, vbar;
|
||||
XKeyEvent *xkey = (XKeyEvent *) event;
|
||||
|
||||
nhUse(w);
|
||||
nhUse(params);
|
||||
nhUse(num_params);
|
||||
|
||||
@@ -1857,6 +1889,25 @@ Cardinal *num_params;
|
||||
exit_x_event = TRUE; /* leave event loop */
|
||||
ec_active = FALSE;
|
||||
return;
|
||||
} else if (ch == MENU_FIRST_PAGE || ch == MENU_LAST_PAGE) {
|
||||
hbar = vbar = (Widget) 0;
|
||||
find_scrollbars(w, &hbar, &vbar);
|
||||
if (vbar) {
|
||||
top = (ch == MENU_FIRST_PAGE) ? 0.0 : 1.0;
|
||||
XtCallCallbacks(vbar, XtNjumpProc, &top);
|
||||
}
|
||||
return;
|
||||
} else if (ch == MENU_NEXT_PAGE || ch == MENU_PREVIOUS_PAGE) {
|
||||
hbar = vbar = (Widget) 0;
|
||||
find_scrollbars(w, &hbar, &vbar);
|
||||
if (vbar) {
|
||||
XtSetArg(arg[0], nhStr(XtNshown), &shown);
|
||||
XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top);
|
||||
XtGetValues(vbar, arg, TWO);
|
||||
top += ((ch == MENU_NEXT_PAGE) ? shown : -shown);
|
||||
XtCallCallbacks(vbar, XtNjumpProc, &top);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1886,19 +1937,14 @@ Cardinal *num_params;
|
||||
if (extended_cmd_selected >= 0)
|
||||
swap_fg_bg(extended_commands[extended_cmd_selected]);
|
||||
extended_cmd_selected = -1; /* dismiss */
|
||||
ec_chars[0] = ec_chars[ec_nchars-1];
|
||||
ec_chars[0] = ec_chars[ec_nchars - 1];
|
||||
ec_nchars = 1;
|
||||
}
|
||||
for (i = 0; extcmdlist[i].ef_txt; i++) {
|
||||
if (extcmdlist[i].flags & CMD_NOT_AVAILABLE)
|
||||
continue;
|
||||
if (extcmdlist[i].ef_txt[0] == '?')
|
||||
continue;
|
||||
|
||||
if (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars)) {
|
||||
for (i = 0; command_list[i]; ++i) {
|
||||
if (!strncmp(ec_chars, command_list[i], ec_nchars)) {
|
||||
if (extended_cmd_selected != i) {
|
||||
/* I should use set() and unset() actions, but how do */
|
||||
/* I send the an action to the widget? */
|
||||
/* I should use set() and unset() actions, but how do
|
||||
I send the an action to the widget? */
|
||||
if (extended_cmd_selected >= 0)
|
||||
swap_fg_bg(extended_commands[extended_cmd_selected]);
|
||||
extended_cmd_selected = i;
|
||||
@@ -1908,11 +1954,10 @@ Cardinal *num_params;
|
||||
ambiguous choices, plus one to show thare aren't any
|
||||
more such, will scroll into view */
|
||||
do {
|
||||
if (!extcmdlist[i + 1].ef_txt
|
||||
|| *extcmdlist[i + 1].ef_txt == '?')
|
||||
if (!command_list[i + 1])
|
||||
break; /* end of list */
|
||||
++i;
|
||||
} while (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars));
|
||||
} while (!strncmp(ec_chars, command_list[i], ec_nchars));
|
||||
|
||||
ec_scroll_to_view(i);
|
||||
return;
|
||||
@@ -1929,25 +1974,24 @@ static void
|
||||
init_extended_commands_popup()
|
||||
{
|
||||
int i, j, num_commands, ignore_cmds = 0;
|
||||
const char **command_list;
|
||||
|
||||
/* count commands */
|
||||
for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++)
|
||||
if (extcmdlist[num_commands].flags & CMD_NOT_AVAILABLE)
|
||||
if (ignore_extcmd(num_commands))
|
||||
++ignore_cmds;
|
||||
|
||||
/* If the last entry is "help", don't use it. */
|
||||
if (strcmp(extcmdlist[num_commands - 1].ef_txt, "?") == 0)
|
||||
--num_commands;
|
||||
|
||||
j = num_commands - ignore_cmds;
|
||||
command_list = (const char **) alloc((unsigned) j * sizeof (char *));
|
||||
command_list = (const char **) alloc((unsigned) (j * sizeof (char *) + 1));
|
||||
command_indx = (short *) alloc((unsigned) (j * sizeof (short) + 1));
|
||||
|
||||
for (i = j = 0; i < num_commands; i++) {
|
||||
if (extcmdlist[i].flags & CMD_NOT_AVAILABLE)
|
||||
if (ignore_extcmd(i))
|
||||
continue;
|
||||
command_indx[j] = (short) i;
|
||||
command_list[j++] = extcmdlist[i].ef_txt;
|
||||
}
|
||||
command_list[j] = (char *) 0;
|
||||
command_indx[j] = -1;
|
||||
num_commands = j;
|
||||
|
||||
extended_command_popup =
|
||||
@@ -1955,8 +1999,6 @@ init_extended_commands_popup()
|
||||
extended_command_translations, "dismiss", extend_dismiss,
|
||||
"help", extend_help, num_commands, command_list,
|
||||
&extended_commands, extend_select, &extended_command_form);
|
||||
|
||||
free((char *) command_list);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#define strncasecmp strncmpi
|
||||
#endif
|
||||
|
||||
extern long curs_mesg_suppress_turn; /* from cursmesg.c */
|
||||
|
||||
/*
|
||||
* Note:
|
||||
*
|
||||
@@ -79,6 +81,7 @@ typedef struct nhm {
|
||||
int height; /* Window height of menu */
|
||||
int width; /* Window width of menu */
|
||||
boolean reuse_accels; /* Non-unique accelerators per page */
|
||||
boolean bottom_heavy; /* display multi-page menu starting at end */
|
||||
struct nhm *prev_menu; /* Pointer to previous entry */
|
||||
struct nhm *next_menu; /* Pointer to next entry */
|
||||
} nhmenu;
|
||||
@@ -89,6 +92,8 @@ typedef enum menu_op_type {
|
||||
INVERT
|
||||
} menu_op;
|
||||
|
||||
static nhmenu_item *curs_new_menu_item(winid, const char *);
|
||||
static void curs_pad_menu(nhmenu *, boolean);
|
||||
static nhmenu *get_menu(winid wid);
|
||||
static char menu_get_accel(boolean first);
|
||||
static void menu_determine_pages(nhmenu *menu);
|
||||
@@ -120,6 +125,10 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer)
|
||||
int height = prompt_height;
|
||||
char input[BUFSZ];
|
||||
|
||||
/* if messages were being suppressed for the remainder of the turn,
|
||||
re-activate them now that input is being requested */
|
||||
curs_mesg_suppress_turn = -1;
|
||||
|
||||
if (buffer >= (int) sizeof input)
|
||||
buffer = (int) sizeof input - 1;
|
||||
maxwidth = term_cols - 2;
|
||||
@@ -201,6 +210,10 @@ curses_character_input_dialog(const char *prompt, const char *choices,
|
||||
boolean any_choice = FALSE;
|
||||
boolean accept_count = FALSE;
|
||||
|
||||
/* if messages were being suppressed for the remainder of the turn,
|
||||
re-activate them now that input is being requested */
|
||||
curs_mesg_suppress_turn = -1;
|
||||
|
||||
if (g.invent || (g.moves > 1)) {
|
||||
curses_get_window_size(MAP_WIN, &map_height, &map_width);
|
||||
} else {
|
||||
@@ -369,6 +382,7 @@ curses_ext_cmd()
|
||||
starty = 0;
|
||||
if (iflags.wc_popup_dialog) { /* Prompt in popup window */
|
||||
int x0, y0, w, h; /* bounding coords of popup */
|
||||
|
||||
extwin2 = curses_create_window(25, 1, UP);
|
||||
wrefresh(extwin2);
|
||||
/* create window inside window to prevent overwriting of border */
|
||||
@@ -513,6 +527,7 @@ curses_create_nhmenu(winid wid)
|
||||
new_menu->height = 0;
|
||||
new_menu->width = 0;
|
||||
new_menu->reuse_accels = FALSE;
|
||||
new_menu->bottom_heavy = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -524,6 +539,7 @@ curses_create_nhmenu(winid wid)
|
||||
new_menu->height = 0;
|
||||
new_menu->width = 0;
|
||||
new_menu->reuse_accels = FALSE;
|
||||
new_menu->bottom_heavy = FALSE;
|
||||
new_menu->next_menu = NULL;
|
||||
|
||||
if (nhmenus == NULL) { /* no menus in memory yet */
|
||||
@@ -538,15 +554,38 @@ curses_create_nhmenu(winid wid)
|
||||
}
|
||||
}
|
||||
|
||||
static nhmenu_item *
|
||||
curs_new_menu_item(winid wid, const char *str)
|
||||
{
|
||||
char *new_str;
|
||||
nhmenu_item *new_item;
|
||||
|
||||
new_str = curses_copy_of(str);
|
||||
curses_rtrim(new_str);
|
||||
new_item = (nhmenu_item *) alloc((unsigned) sizeof (nhmenu_item));
|
||||
new_item->wid = wid;
|
||||
new_item->glyph = NO_GLYPH;
|
||||
new_item->identifier = cg.zeroany;
|
||||
new_item->accelerator = '\0';;
|
||||
new_item->group_accel = '\0';
|
||||
new_item->attr = 0;
|
||||
new_item->str = new_str;
|
||||
new_item->presel = FALSE;
|
||||
new_item->selected = FALSE;
|
||||
new_item->page_num = 0;
|
||||
new_item->line_num = 0;
|
||||
new_item->num_lines = 0;
|
||||
new_item->count = -1;
|
||||
new_item->next_item = NULL;
|
||||
return new_item;
|
||||
}
|
||||
/* Add a menu item to the given menu window */
|
||||
|
||||
void
|
||||
curses_add_nhmenu_item(winid wid, int glyph, const ANY_P * identifier,
|
||||
curses_add_nhmenu_item(winid wid, int glyph, const ANY_P *identifier,
|
||||
CHAR_P accelerator, CHAR_P group_accel, int attr,
|
||||
const char *str, BOOLEAN_P presel)
|
||||
{
|
||||
char *new_str;
|
||||
nhmenu_item *new_item, *current_items, *menu_item_ptr;
|
||||
nhmenu *current_menu = get_menu(wid);
|
||||
|
||||
@@ -560,23 +599,13 @@ curses_add_nhmenu_item(winid wid, int glyph, const ANY_P * identifier,
|
||||
return;
|
||||
}
|
||||
|
||||
new_str = curses_copy_of(str);
|
||||
curses_rtrim((char *) new_str);
|
||||
new_item = (nhmenu_item *) alloc((unsigned) sizeof (nhmenu_item));
|
||||
new_item->wid = wid;
|
||||
new_item = curs_new_menu_item(wid, str);
|
||||
new_item->glyph = glyph;
|
||||
new_item->identifier = *identifier;
|
||||
new_item->accelerator = accelerator;
|
||||
new_item->group_accel = group_accel;
|
||||
new_item->attr = attr;
|
||||
new_item->str = new_str;
|
||||
new_item->presel = presel;
|
||||
new_item->selected = FALSE;
|
||||
new_item->page_num = 0;
|
||||
new_item->line_num = 0;
|
||||
new_item->num_lines = 0;
|
||||
new_item->count = -1;
|
||||
new_item->next_item = NULL;
|
||||
|
||||
current_items = current_menu->entries;
|
||||
menu_item_ptr = current_items;
|
||||
@@ -593,6 +622,67 @@ curses_add_nhmenu_item(winid wid, int glyph, const ANY_P * identifier,
|
||||
}
|
||||
}
|
||||
|
||||
/* for menu->bottom_heavy -- insert enough blank lines at top of
|
||||
first page to make the last page become a full one */
|
||||
static void
|
||||
curs_pad_menu(nhmenu *current_menu, boolean do_pad UNUSED)
|
||||
{
|
||||
nhmenu_item *menu_item_ptr;
|
||||
int numpages = current_menu->num_pages;
|
||||
|
||||
/* caller has already called menu_win_size() */
|
||||
menu_determine_pages(current_menu); /* sets 'menu->num_pages' */
|
||||
numpages = current_menu->num_pages;
|
||||
/* pad beginning of menu so that partial last page becomes full;
|
||||
might be slightly less than full if any entries take multiple
|
||||
lines and the padding would force those to span page boundary
|
||||
and that gets prevented; so we re-count the number of pages
|
||||
with every insertion instead of trying to calculate the number
|
||||
of them to add */
|
||||
do {
|
||||
menu_item_ptr = curs_new_menu_item(current_menu->wid, "");
|
||||
menu_item_ptr->next_item = current_menu->entries;
|
||||
current_menu->entries->prev_item = menu_item_ptr;
|
||||
current_menu->entries = menu_item_ptr;
|
||||
current_menu->num_entries += 1;
|
||||
|
||||
menu_determine_pages(current_menu);
|
||||
} while (current_menu->num_pages == numpages);
|
||||
|
||||
/* we inserted blank lines at beginning until final entry spilled
|
||||
over to another page; take the most recent blank one back out */
|
||||
current_menu->num_entries -= 1;
|
||||
current_menu->entries = menu_item_ptr->next_item;
|
||||
current_menu->entries->prev_item = (nhmenu_item *) 0;
|
||||
free((genericptr_t) menu_item_ptr->str);
|
||||
free((genericptr_t) menu_item_ptr);
|
||||
|
||||
/* reset page count; shouldn't need to re-count */
|
||||
current_menu->num_pages = numpages;
|
||||
return;
|
||||
}
|
||||
|
||||
/* mark ^P message recall menu, for msg_window:full (FIFO), where we'll
|
||||
start viewing on the last page so be able to see most recent immediately */
|
||||
void
|
||||
curs_menu_set_bottom_heavy(winid wid)
|
||||
{
|
||||
nhmenu *menu = get_menu(wid);
|
||||
|
||||
/*
|
||||
* Called after end_menu + finalize_nhmenu,
|
||||
* before select_menu + display_nhmenu.
|
||||
*/
|
||||
menu_win_size(menu); /* (normally not done until display_nhmenu) */
|
||||
if (menu_is_multipage(menu, menu->width, menu->height)) {
|
||||
menu->bottom_heavy = TRUE;
|
||||
|
||||
/* insert enough blank lines at top of first page to make the
|
||||
last page become a full one */
|
||||
curs_pad_menu(menu, TRUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* No more entries are to be added to menu, so details of the menu can be
|
||||
finalized in memory */
|
||||
@@ -689,8 +779,8 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected)
|
||||
}
|
||||
|
||||
if (count != num_chosen) {
|
||||
impossible("curses_display_nhmenu: Selected items less than "
|
||||
"expected number");
|
||||
impossible(
|
||||
"curses_display_nhmenu: Selected items less than expected number");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,7 +833,7 @@ curses_del_menu(winid wid, boolean del_wid_too)
|
||||
if ((tmpmenu = current_menu->prev_menu) != NULL) {
|
||||
tmpmenu->next_menu = current_menu->next_menu;
|
||||
} else {
|
||||
nhmenus = current_menu->next_menu; /* New head mode or NULL */
|
||||
nhmenus = current_menu->next_menu; /* New head node or NULL */
|
||||
}
|
||||
if ((tmpmenu = current_menu->next_menu) != NULL) {
|
||||
tmpmenu->prev_menu = current_menu->prev_menu;
|
||||
@@ -811,7 +901,7 @@ menu_is_multipage(nhmenu *menu, int width, int height)
|
||||
int curline = 0;
|
||||
nhmenu_item *menu_item_ptr = menu->entries;
|
||||
|
||||
if (strlen(menu->prompt) > 0) {
|
||||
if (*menu->prompt) {
|
||||
curline += curses_num_lines(menu->prompt, width) + 1;
|
||||
}
|
||||
|
||||
@@ -854,7 +944,7 @@ menu_determine_pages(nhmenu *menu)
|
||||
int page_end = height;
|
||||
|
||||
|
||||
if (strlen(menu->prompt) > 0) {
|
||||
if (*menu->prompt) {
|
||||
curline += curses_num_lines(menu->prompt, width) + 1;
|
||||
}
|
||||
|
||||
@@ -922,8 +1012,7 @@ menu_win_size(nhmenu *menu)
|
||||
/* Add space for accelerator */
|
||||
curentrywidth = strlen(menu_item_ptr->str) + 4;
|
||||
#if 0 /* FIXME: menu glyphs */
|
||||
if (menu_item_ptr->glyph != NO_GLYPH
|
||||
&& iflags.use_menu_glyphs)
|
||||
if (menu_item_ptr->glyph != NO_GLYPH && iflags.use_menu_glyphs)
|
||||
curentrywidth += 2;
|
||||
#endif
|
||||
}
|
||||
@@ -979,7 +1068,7 @@ static void
|
||||
menu_display_page(nhmenu *menu, WINDOW * win, int page_num)
|
||||
{
|
||||
nhmenu_item *menu_item_ptr;
|
||||
int count, curletter, entry_cols, start_col, num_lines, footer_x;
|
||||
int count, curletter, entry_cols, start_col, num_lines;
|
||||
char *tmpstr;
|
||||
boolean first_accel = TRUE;
|
||||
int color = NO_COLOR;
|
||||
@@ -1102,20 +1191,25 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num)
|
||||
}
|
||||
|
||||
if (menu->num_pages > 1) {
|
||||
footer_x = menu->width - strlen("<- (Page X of Y) ->");
|
||||
if (menu->num_pages > 9) { /* Unlikely */
|
||||
footer_x -= 2;
|
||||
int footer_x, footwidth, shoesize = menu->num_pages;
|
||||
|
||||
footwidth = (int) (sizeof "<- (Page X of Y) ->" - sizeof "");
|
||||
while (shoesize >= 10) { /* possible for pickup from big piles... */
|
||||
/* room for wider feet; extra digit for both X and Y */
|
||||
footwidth += 2;
|
||||
shoesize /= 10;
|
||||
}
|
||||
mvwprintw(win, menu->height, footer_x + 3, "(Page %d of %d)",
|
||||
page_num, menu->num_pages);
|
||||
footer_x = !menu->bottom_heavy ? (menu->width - footwidth) : 2;
|
||||
if (page_num != 1) {
|
||||
curses_toggle_color_attr(win, HIGHLIGHT_COLOR, NONE, ON);
|
||||
mvwaddstr(win, menu->height, footer_x, "<=");
|
||||
curses_toggle_color_attr(win, HIGHLIGHT_COLOR, NONE, OFF);
|
||||
}
|
||||
mvwprintw(win, menu->height, footer_x + 2, " (Page %d of %d) ",
|
||||
page_num, menu->num_pages);
|
||||
if (page_num != menu->num_pages) {
|
||||
curses_toggle_color_attr(win, HIGHLIGHT_COLOR, NONE, ON);
|
||||
mvwaddstr(win, menu->height, menu->width - 2, "=>");
|
||||
mvwaddstr(win, menu->height, footer_x + footwidth - 2, "=>");
|
||||
curses_toggle_color_attr(win, HIGHLIGHT_COLOR, NONE, OFF);
|
||||
}
|
||||
}
|
||||
@@ -1132,13 +1226,13 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how)
|
||||
int curletter;
|
||||
int count = -1;
|
||||
int count_letter = '\0';
|
||||
int curpage = 1;
|
||||
int curpage = !menu->bottom_heavy ? 1 : menu->num_pages;
|
||||
int num_selected = 0;
|
||||
boolean dismiss = FALSE;
|
||||
char search_key[BUFSZ];
|
||||
nhmenu_item *menu_item_ptr = menu->entries;
|
||||
|
||||
menu_display_page(menu, win, 1);
|
||||
menu_display_page(menu, win, curpage);
|
||||
|
||||
while (!dismiss) {
|
||||
curletter = getch();
|
||||
|
||||
@@ -16,6 +16,7 @@ void curses_create_nhmenu(winid wid);
|
||||
void curses_add_nhmenu_item(winid wid, int glyph, const ANY_P *identifier,
|
||||
CHAR_P accelerator, CHAR_P group_accel, int attr,
|
||||
const char *str, BOOLEAN_P presel);
|
||||
void curs_menu_set_bottom_heavy(winid);
|
||||
void curses_finalize_nhmenu(winid wid, const char *prompt);
|
||||
int curses_display_nhmenu(winid wid, int how, MENU_ITEM_P **_selected);
|
||||
boolean curses_menu_exists(winid wid);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "color.h"
|
||||
#include "wincurs.h"
|
||||
|
||||
extern long curs_mesg_suppress_turn; /* from cursmesg.c */
|
||||
|
||||
/* Public functions for curses NetHack interface */
|
||||
|
||||
/* Interface definition, for windows.c */
|
||||
@@ -72,8 +74,8 @@ struct window_procs curses_procs = {
|
||||
curses_end_screen,
|
||||
genl_outrip,
|
||||
curses_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory,
|
||||
curses_getmsghistory,
|
||||
curses_putmsghistory,
|
||||
curses_status_init,
|
||||
curses_status_finish,
|
||||
genl_status_enablefield,
|
||||
@@ -687,6 +689,9 @@ curses_nhgetch()
|
||||
{
|
||||
int ch;
|
||||
|
||||
/* if messages are being suppressed, reenable them */
|
||||
curs_mesg_suppress_turn = -1;
|
||||
|
||||
curses_prehousekeeping();
|
||||
ch = curses_read_char();
|
||||
curses_posthousekeeping();
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "cursmesg.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/* player can type ESC at More>> prompt to avoid seeing more messages
|
||||
for the current move; but hero might get more than one move per turn,
|
||||
so the input routines need to be able to cancel this */
|
||||
long curs_mesg_suppress_turn = -1; /* also used in cursdial.c && cursmain.c */
|
||||
|
||||
/* Message window routines for curses interface */
|
||||
|
||||
@@ -46,16 +50,13 @@ curses_message_win_puts(const char *message, boolean recursed)
|
||||
boolean border = curses_window_has_border(MESSAGE_WIN);
|
||||
int message_length = strlen(message);
|
||||
int border_space = 0;
|
||||
static long suppress_turn = -1;
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
/*
|
||||
* Handled by core's use of putstr(WIN_MESSAGE,ATR_NOHISTORY,message)
|
||||
* for intermediate counts, but get_count() also uses putmsghistory()
|
||||
* for the final count, to remember that without showing it. But
|
||||
* curses is using genl_putmsghistory() which just delivers the text
|
||||
* via a normal pline(). This hides that at cost of not having it
|
||||
* in ^P recall and being out of sync with DUMPLOG's message history.
|
||||
* This was useful when curses used genl_putmsghistory() but is not
|
||||
* needed now that it has its own curses_putmsghistory() that's
|
||||
* capable of putting something into the ^P recall history without
|
||||
* displaying it at the same time.
|
||||
*/
|
||||
if (strncmp("Count:", message, 6) == 0) {
|
||||
curses_count_window(message);
|
||||
@@ -63,8 +64,8 @@ curses_message_win_puts(const char *message, boolean recursed)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (suppress_turn == g.moves) {
|
||||
return;
|
||||
if (curs_mesg_suppress_turn == g.moves) {
|
||||
return; /* user has typed ESC to avoid seeing remaining messages. */
|
||||
}
|
||||
|
||||
curses_get_window_size(MESSAGE_WIN, &height, &width);
|
||||
@@ -105,7 +106,7 @@ curses_message_win_puts(const char *message, boolean recursed)
|
||||
/* Pause until key is hit - Esc suppresses any further
|
||||
messages that turn */
|
||||
if (curses_more() == '\033') {
|
||||
suppress_turn = g.moves;
|
||||
curs_mesg_suppress_turn = g.moves;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -156,6 +157,9 @@ curses_block(boolean noscroll) /* noscroll - blocking because of msgtype
|
||||
WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
|
||||
const char *resp = " \r\n\033"; /* space, enter, esc */
|
||||
|
||||
/* if messages are being suppressed, reenable them */
|
||||
curs_mesg_suppress_turn = -1;
|
||||
|
||||
curses_get_window_size(MESSAGE_WIN, &height, &width);
|
||||
curses_toggle_color_attr(win, MORECOLOR, NONE, ON);
|
||||
mvwprintw(win, my, mx, ">>");
|
||||
@@ -309,6 +313,8 @@ curses_prev_mesg()
|
||||
"[No past messages available.]", FALSE);
|
||||
|
||||
curses_end_menu(wid, "");
|
||||
if (!do_lifo)
|
||||
curs_menu_set_bottom_heavy(wid);
|
||||
curses_select_menu(wid, PICK_NONE, &selected);
|
||||
curses_del_wid(wid);
|
||||
}
|
||||
@@ -692,4 +698,99 @@ get_msg_line(boolean reverse, int mindex)
|
||||
return current_mesg;
|
||||
}
|
||||
|
||||
/* save/restore code retrieves one ^P message at a time during save and
|
||||
puts it into save file; if any new messages are added to the list while
|
||||
that is taking place, the results are likely to be scrambled */
|
||||
char *
|
||||
curses_getmsghistory(init)
|
||||
boolean init;
|
||||
{
|
||||
static int nxtidx;
|
||||
nhprev_mesg *mesg;
|
||||
|
||||
if (init)
|
||||
nxtidx = 0;
|
||||
else
|
||||
++nxtidx;
|
||||
|
||||
if (nxtidx < num_messages) {
|
||||
/* we could encode mesg->turn with the text of the message,
|
||||
but then that text might need to be truncated, and more
|
||||
significantly, restoring the save file with another
|
||||
interface wouldn't know how find and decode or remove it;
|
||||
likewise, restoring another interface's save file with
|
||||
curses wouldn't find the expected turn info;
|
||||
so, we live without that */
|
||||
mesg = get_msg_line(FALSE, nxtidx);
|
||||
} else
|
||||
mesg = (nhprev_mesg *) 0;
|
||||
|
||||
return mesg ? mesg->str : (char *) 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by the core savefile restore routines.
|
||||
* Each time we are called, we stuff the string into our message
|
||||
* history recall buffer. The core will send the oldest message
|
||||
* first (actually it sends them in the order they exist in the
|
||||
* save file, but that is supposed to be the oldest first).
|
||||
* These messages get pushed behind any which have been issued
|
||||
* during this session since they come from a previous session
|
||||
* and logically precede anything (like "Restoring save file...")
|
||||
* that's happened now.
|
||||
*
|
||||
* Called with a null pointer to finish up restoration.
|
||||
*
|
||||
* It's also called by the quest pager code when a block message
|
||||
* has a one-line summary specified. We put that line directly
|
||||
* into message history for ^P recall without having displayed it.
|
||||
*/
|
||||
void
|
||||
curses_putmsghistory(msg, restoring_msghist)
|
||||
const char *msg;
|
||||
boolean restoring_msghist;
|
||||
{
|
||||
static boolean initd = FALSE;
|
||||
static int stash_count;
|
||||
static nhprev_mesg *stash_head = 0;
|
||||
|
||||
if (restoring_msghist && !initd) {
|
||||
/* hide any messages we've gathered since starting current session
|
||||
so that the ^P data will start out empty as we add ones being
|
||||
restored from save file; we'll put these back after that's done */
|
||||
stash_count = num_messages, num_messages = 0;
|
||||
stash_head = first_mesg, first_mesg = (nhprev_mesg *) 0;
|
||||
last_mesg = (nhprev_mesg *) 0; /* no need to remember the tail */
|
||||
initd = TRUE;
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
mesg_add_line(msg);
|
||||
/* treat all saved and restored messages as turn #1 */
|
||||
last_mesg->turn = 1L;
|
||||
} else if (stash_count) {
|
||||
nhprev_mesg *mesg;
|
||||
long mesg_turn;
|
||||
|
||||
/* put any messages generated during the beginning of the current
|
||||
session back; they logically follow any from the previous
|
||||
session's save file */
|
||||
while (stash_count > 0) {
|
||||
/* we could manipulate the linked list directly but treating
|
||||
stashed messages as newly occurring ones is much simpler;
|
||||
we ignore the backlinks because the list is destroyed as it
|
||||
gets processed hence there can't be any other traversals */
|
||||
mesg = stash_head;
|
||||
stash_head = mesg->next_mesg;
|
||||
--stash_count;
|
||||
mesg_turn = mesg->turn;
|
||||
mesg_add_line(mesg->str);
|
||||
last_mesg->turn = mesg_turn;
|
||||
free((genericptr_t) mesg->str);
|
||||
free((genericptr_t) mesg);
|
||||
}
|
||||
initd = FALSE; /* reset */
|
||||
}
|
||||
}
|
||||
|
||||
/*cursmesg.c*/
|
||||
|
||||
@@ -18,5 +18,7 @@ void curses_last_messages(void);
|
||||
void curses_init_mesg_history(void);
|
||||
void curses_prev_mesg(void);
|
||||
void curses_count_window(const char *count_text);
|
||||
char *curses_getmsghistory(BOOLEAN_P);
|
||||
void curses_putmsghistory(const char *, BOOLEAN_P);
|
||||
|
||||
#endif /* CURSMESG_H */
|
||||
|
||||
@@ -25,6 +25,7 @@ extern boolean status_activefields[MAXBLSTATS];
|
||||
static char *status_vals_long[MAXBLSTATS];
|
||||
|
||||
#ifdef STATUS_HILITES
|
||||
static unsigned long *curses_colormasks;
|
||||
static long curses_condition_bits;
|
||||
static int curses_status_colors[MAXBLSTATS];
|
||||
static int hpbar_percent, hpbar_color;
|
||||
@@ -36,12 +37,11 @@ static int FDECL(condcolor, (long, unsigned long *));
|
||||
static int FDECL(condattr, (long, unsigned long *));
|
||||
static int FDECL(nhattr2curses, (int));
|
||||
#endif /* STATUS_HILITES */
|
||||
static void FDECL(draw_status, (unsigned long *));
|
||||
static void FDECL(draw_vertical, (BOOLEAN_P, unsigned long *));
|
||||
static void FDECL(draw_horizontal, (BOOLEAN_P, unsigned long *));
|
||||
static void NDECL(draw_status);
|
||||
static void FDECL(draw_vertical, (BOOLEAN_P));
|
||||
static void FDECL(draw_horizontal, (BOOLEAN_P));
|
||||
static void curs_HPbar(char *, int);
|
||||
static void curs_stat_conds(int, int *, int *, unsigned long *,
|
||||
char *, boolean *);
|
||||
static void curs_stat_conds(int, int *, int *, char *, boolean *);
|
||||
static void curs_vert_status_vals(int);
|
||||
|
||||
/* width of a single line in vertical status orientation (one field per line;
|
||||
@@ -162,6 +162,7 @@ unsigned long *colormasks;
|
||||
return;
|
||||
if (fldidx == BL_CONDITION) {
|
||||
curses_condition_bits = *condptr;
|
||||
curses_colormasks = colormasks;
|
||||
} else {
|
||||
#ifndef TEXTCOLOR
|
||||
color_and_attr = (color_and_attr & ~0x00FF) | NO_COLOR;
|
||||
@@ -204,19 +205,13 @@ unsigned long *colormasks;
|
||||
}
|
||||
}
|
||||
} else { /* BL_FLUSH */
|
||||
if (!changed_fields && !g.context.botlx) {
|
||||
; /* TODO: this isn't impossible but we want to track
|
||||
* down the circumstances where it happens in order to
|
||||
* minimize occurrences */
|
||||
}
|
||||
draw_status(colormasks);
|
||||
draw_status();
|
||||
changed_fields = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
draw_status(colormasks)
|
||||
unsigned long *colormasks;
|
||||
static void
|
||||
draw_status()
|
||||
{
|
||||
WINDOW *win = curses_get_nhwin(STATUS_WIN);
|
||||
int orient = curses_get_window_orientation(STATUS_WIN);
|
||||
@@ -242,9 +237,9 @@ unsigned long *colormasks;
|
||||
|
||||
werase(win);
|
||||
if (horiz)
|
||||
draw_horizontal(border, colormasks);
|
||||
draw_horizontal(border);
|
||||
else
|
||||
draw_vertical(border, colormasks);
|
||||
draw_vertical(border);
|
||||
|
||||
if (border)
|
||||
box(win, 0, 0);
|
||||
@@ -252,10 +247,9 @@ unsigned long *colormasks;
|
||||
}
|
||||
|
||||
/* horizontal layout on 2 or 3 lines */
|
||||
void
|
||||
draw_horizontal(border, colormasks)
|
||||
static void
|
||||
draw_horizontal(border)
|
||||
boolean border;
|
||||
unsigned long *colormasks;
|
||||
{
|
||||
#define blPAD BL_FLUSH
|
||||
/* almost all fields already come with a leading space;
|
||||
@@ -343,7 +337,7 @@ unsigned long *colormasks;
|
||||
/* collect active conditions in cbuf[], space separated, suitable
|
||||
for direct output if no highlighting is requested ('asis') but
|
||||
primarily used to measure the length */
|
||||
curs_stat_conds(0, &x, &y, colormasks, cbuf, &asis);
|
||||
curs_stat_conds(0, &x, &y, cbuf, &asis);
|
||||
clen = (int) strlen(cbuf);
|
||||
|
||||
cap_and_hunger = 0;
|
||||
@@ -640,8 +634,7 @@ unsigned long *colormasks;
|
||||
if (asis)
|
||||
waddstr(win, cbuf);
|
||||
else /* cond by cond if any cond specifies highlighting */
|
||||
curs_stat_conds(0, &x, &y, colormasks,
|
||||
(char *) 0, (boolean *) 0);
|
||||
curs_stat_conds(0, &x, &y, (char *) 0, (boolean *) 0);
|
||||
} /* curses_condition_bits */
|
||||
} /* hitpointbar vs regular field vs conditions */
|
||||
} /* i (fld) */
|
||||
@@ -651,10 +644,9 @@ unsigned long *colormasks;
|
||||
}
|
||||
|
||||
/* vertical layout, to left or right of map */
|
||||
void
|
||||
draw_vertical(border, colormasks)
|
||||
static void
|
||||
draw_vertical(border)
|
||||
boolean border;
|
||||
unsigned long *colormasks;
|
||||
{
|
||||
/* for blank lines, the digit prefix is the order in which they get
|
||||
removed if we need to shrink to fit within height limit (very rare) */
|
||||
@@ -893,8 +885,7 @@ unsigned long *colormasks;
|
||||
if (cond_count) {
|
||||
/* output active conditions, three per line;
|
||||
cursor is already positioned where they should start */
|
||||
curs_stat_conds(1, &x, &y, colormasks,
|
||||
(char *) 0, (boolean *) 0);
|
||||
curs_stat_conds(1, &x, &y, (char *) 0, (boolean *) 0);
|
||||
}
|
||||
} /* hitpointbar vs regular field vs conditions */
|
||||
} /* fld loop */
|
||||
@@ -971,7 +962,6 @@ extern const struct condmap valid_conditions[]; /* botl.c */
|
||||
static void
|
||||
curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */
|
||||
int *x, int *y, /* real for vertical, ignored otherwise */
|
||||
unsigned long *colormasks, /* input */
|
||||
char *condbuf, /* optional output; collect string of conds */
|
||||
boolean *nohilite) /* optional output; indicates whether -*/
|
||||
{ /*+ condbuf[] could be used as-is */
|
||||
@@ -994,8 +984,8 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */
|
||||
Strcpy(condnam, valid_conditions[i].id);
|
||||
Strcat(strcat(condbuf, " "), upstart(condnam));
|
||||
if (nohilite && *nohilite
|
||||
&& (condcolor(bitmsk, colormasks) != NO_COLOR
|
||||
|| condattr(bitmsk, colormasks) != 0))
|
||||
&& (condcolor(bitmsk, curses_colormasks) != NO_COLOR
|
||||
|| condattr(bitmsk, curses_colormasks) != 0))
|
||||
*nohilite = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -1034,12 +1024,14 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */
|
||||
if (!do_vert || (vert_cond % 3) != 1)
|
||||
waddch(win, ' ');
|
||||
if (iflags.hilite_delta) {
|
||||
if ((attrmask = condattr(bitmsk, colormasks)) != 0) {
|
||||
if ((attrmask = condattr(bitmsk, curses_colormasks))
|
||||
!= 0) {
|
||||
attrmask = nhattr2curses(attrmask);
|
||||
wattron(win, attrmask);
|
||||
}
|
||||
#ifdef TEXTCOLOR
|
||||
if ((color = condcolor(bitmsk, colormasks)) != NO_COLOR)
|
||||
if ((color = condcolor(bitmsk, curses_colormasks))
|
||||
!= NO_COLOR)
|
||||
curses_toggle_color_attr(win, color, NONE, ON);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 termcap.c $NHDT-Date: 1456907853 2016/03/02 08:37:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.24 $ */
|
||||
/* NetHack 3.6 termcap.c $NHDT-Date: 1553858473 2019/03/29 11:21:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.29 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Pasi Kallinen, 2018. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -1206,12 +1206,37 @@ int n;
|
||||
return nulstr;
|
||||
}
|
||||
|
||||
/* suppress nonfunctional highlights so render_status() might be able to
|
||||
optimize more; keep this in sync with s_atr2str() */
|
||||
int
|
||||
term_attr_fixup(msk)
|
||||
int msk;
|
||||
{
|
||||
/* underline is converted to bold if its start sequence isn't available */
|
||||
if ((msk & (1 << ATR_ULINE)) && !nh_US) {
|
||||
msk |= (1 << ATR_BOLD);
|
||||
msk &= ~(1 << ATR_ULINE);
|
||||
}
|
||||
/* blink is converted to bold unconditionally [why?] */
|
||||
if (msk & (1 << ATR_BLINK)) {
|
||||
msk |= (1 << ATR_BOLD);
|
||||
msk &= ~(1 << ATR_BLINK);
|
||||
}
|
||||
/* dim is ignored */
|
||||
if (msk & (1 << ATR_DIM))
|
||||
msk &= ~(1 << ATR_DIM);
|
||||
return msk;
|
||||
}
|
||||
|
||||
void
|
||||
term_start_attr(attr)
|
||||
int attr;
|
||||
{
|
||||
if (attr) {
|
||||
xputs(s_atr2str(attr));
|
||||
const char *astr = s_atr2str(attr);
|
||||
|
||||
if (*astr)
|
||||
xputs(s_atr2str(attr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,7 +1245,10 @@ term_end_attr(attr)
|
||||
int attr;
|
||||
{
|
||||
if (attr) {
|
||||
xputs(e_atr2str(attr));
|
||||
const char *astr = e_atr2str(attr);
|
||||
|
||||
if (*astr)
|
||||
xputs(e_atr2str(attr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1248,7 +1276,8 @@ void
|
||||
term_start_color(color)
|
||||
int color;
|
||||
{
|
||||
xputs(hilites[color]);
|
||||
if (color < CLR_MAX)
|
||||
xputs(hilites[color]);
|
||||
}
|
||||
|
||||
/* not to be confused with has_colors() in unixtty.c */
|
||||
|
||||
667
win/tty/wintty.c
667
win/tty/wintty.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user