fix #K4058 - tty: perm_invent fixes

I think this fixes all problems with the boundary boz drawn around
perm_invent.  Also, if you enabled perm_invent in inuse_only mode
while there are already more items in use than would fix in the
available number of lines, it wasn't switching to two columns until
the next update_inventory().  And the new color handling wasn't
incorporate into tty_refresh_inventory() so after a corner window
clobbered some of perm_invent, it got redrawn but without color,
again until the next update_inventory().

With any luck this fixes more bugs than it introduces....
This commit is contained in:
PatR
2023-12-07 03:22:44 -08:00
parent 7c20bf4afa
commit 634f492827

View File

@@ -180,7 +180,7 @@ static volatile int erasing_tty_screen; /* volatile: SIGWINCH */
static char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */
#endif
static char winpanicstr[] = "Bad window Id %d (%s)";
static const char winpanicstr[] = "Bad window Id %d (%s)";
#define ttywindowpanic() panic(winpanicstr, window, __func__)
char defmorestr[] = "--More--";
@@ -253,7 +253,9 @@ void g_pututf8(uint8 *utf8str);
#endif
#ifdef TTY_PERM_INVENT
static struct tty_perminvent_cell zerottycell = { 0, 0, 0, { 0 }, 0 };
static struct tty_perminvent_cell emptyttycell = {
0, 0, 0, { 0 }, NO_COLOR + 1
};
static glyph_info zerogi = { 0 };
static struct to_core zero_tocore = { 0 };
enum { border_left, border_middle, border_right, border_elements };
@@ -959,7 +961,10 @@ tty_create_nhwindow(int type)
RESTORE_WARNING_UNREACHABLE_CODE
static void
erase_menu_or_text(winid window, struct WinDesc *cw, boolean clear)
erase_menu_or_text(
winid window,
struct WinDesc *cw,
boolean clear)
{
if (cw->offx == 0) {
if (cw->offy) {
@@ -1023,8 +1028,6 @@ free_window_info(struct WinDesc *cw, boolean free_data)
}
}
DISABLE_WARNING_FORMAT_NONLITERAL
void
tty_clear_nhwindow(winid window)
{
@@ -1100,8 +1103,6 @@ tty_clear_nhwindow(winid window)
/* cw->blanked = TRUE; -- this isn't used */
}
RESTORE_WARNING_FORMAT_NONLITERAL
/* toggle a specific entry */
static boolean
toggle_menu_curr(
@@ -1815,8 +1816,6 @@ process_text_window(winid window, struct WinDesc *cw)
}
}
DISABLE_WARNING_FORMAT_NONLITERAL /* RESTORE after tty_select_menu */
/*ARGSUSED*/
void
tty_display_nhwindow(
@@ -2798,10 +2797,11 @@ tty_message_menu(char let, int how, const char *mesg)
return ((how == PICK_ONE && morc == let) || morc == '\033') ? morc : '\0';
}
RESTORE_WARNING_FORMAT_NONLITERAL
win_request_info *
tty_ctrl_nhwindow(winid window UNUSED, int request, win_request_info *wri)
tty_ctrl_nhwindow(
winid window UNUSED,
int request,
win_request_info *wri)
{
#if defined(TTY_PERM_INVENT)
boolean tty_ok /*, show_gold */, inuse_only;
@@ -2859,7 +2859,7 @@ tty_ctrl_nhwindow(winid window UNUSED, int request, win_request_info *wri)
static int
ttyinv_create_window(int newid, struct WinDesc *newwin)
{
int i, r, c;
int r, c;
long minrow; /* long to match maxrow declaration */
unsigned n;
@@ -2897,14 +2897,17 @@ ttyinv_create_window(int newid, struct WinDesc *newwin)
if (!assesstty(ttyinvmode, &newwin->offx, &newwin->offy, &newwin->rows,
&newwin->cols, &newwin->maxcol, &minrow,
&newwin->maxrow)) {
tty_destroy_nhwindow(newid); /* sets WIN_INVEN to WIN_ERR */
tty_destroy_nhwindow(newid);
WIN_INVEN = WIN_ERR;
pline("%s.", "tty perm_invent could not be enabled");
pline("tty perm_invent needs a terminal that is at least %dx%d, "
"yours is %dx%d.",
(int) (minrow + 1 + ROWNO + StatusRows()), tty_perminv_mincol,
ttyDisplay->rows, ttyDisplay->cols);
tty_wait_synch();
#ifndef RESIZABLE
set_option_mod_status("perm_invent", set_gameview);
#endif
iflags.perm_invent = FALSE;
return WIN_ERR;
}
@@ -2922,30 +2925,20 @@ ttyinv_create_window(int newid, struct WinDesc *newwin)
there are more items than the number of full lines */
if ((ttyinvmode & InvInUse) != 0)
bordercol[border_middle] = bordercol[border_right];
ttyinv_slots_used = 0;
n = (unsigned) (newwin->maxrow * sizeof (struct tty_perminvent_cell *));
newwin->cells = (struct tty_perminvent_cell **) alloc(n);
n = (unsigned) (newwin->maxcol * sizeof (struct tty_perminvent_cell));
for (i = 0; i < newwin->maxrow; i++)
newwin->cells[i] = (struct tty_perminvent_cell *) alloc(n);
n = (unsigned) sizeof (glyph_info);
for (r = 0; r < newwin->maxrow; r++)
for (c = 0; c < newwin->maxcol; c++) {
newwin->cells[r][c] = zerottycell;
if (r == 0 || r == newwin->maxrow - 1
|| c == bordercol[border_left]
|| c == bordercol[border_middle]
|| c == bordercol[border_right]) {
newwin->cells[r][c].content.gi = (glyph_info *) alloc(n);
*newwin->cells[r][c].content.gi = zerogi;
newwin->cells[r][c].glyph = 1;
}
}
for (r = 0; r < newwin->maxrow; r++) {
newwin->cells[r] = (struct tty_perminvent_cell *) alloc(n);
for (c = 0; c < newwin->maxcol; c++)
newwin->cells[r][c] = emptyttycell;
}
newwin->active = 1;
ttyinv_slots_used = 0;
tty_invent_box_glyph_init(newwin);
return newid;
}
@@ -2972,7 +2965,7 @@ ttyinv_remove_data(boolean destroy)
contains a glyph_info structure or just a char */
if (invcell->glyph)
free((genericptr_t) invcell->content.gi);
*invcell = zerottycell; /* sets glyph flag to 0 */
*invcell = emptyttycell; /* sets glyph flag to 0 */
if (!destroy) { /* erasing */
invcell->content.ttychar = ' ';
invcell->text = 1;
@@ -2995,6 +2988,7 @@ ttyinv_remove_data(boolean destroy)
/*WIN_INVEN = WIN_ERR;*/ /* caller's responsibility */
done_tty_perm_invent_init = FALSE;
}
ttyinv_slots_used = 0; /* reset: inuse_only isn't using any slots */
}
static void
@@ -3028,9 +3022,10 @@ ttyinv_add_menu(
slots 0 thru rows_per_side-1, so zero-based slot==rows_per_side
is the entry that will be shown on first row of the second side
(and one-base ttyinv_slots_used==rows_per_side means that on the
previous inventory_update(), full lines filled all the rows) */
previous inventory_update(), full lines filled all the rows;
ttyinv_slots_used==0 means that we've just enabled perm_invent) */
if (inuse_only && slot == rows_per_side
&& ttyinv_slots_used == rows_per_side)
&& ttyinv_slots_used % rows_per_side == 0)
ttyinv_inuse_twosides(cw, rows_per_side);
text = str; /* 'text' will switch to invbuf[] below */
@@ -3056,7 +3051,7 @@ ttyinv_add_menu(
*/
Snprintf(invbuf, sizeof invbuf, "%c - %s", ch, text);
text = invbuf;
startcolor_at = sizeof ("a - ") - 1;
startcolor_at = (int) (sizeof "a - " - sizeof ""); /* 4 */
row = (slot % rows_per_side) + 1; /* +1: top border */
/* side: left side panel or right side panel, not a window column */
side = slot / rows_per_side;
@@ -3209,7 +3204,7 @@ ttyinv_end_menu(int window, struct WinDesc *cw)
}
}
/* display persistent inventory */
/* display persistent inventory from data collected by add_menu() */
static void
ttyinv_render(winid window, struct WinDesc *cw)
{
@@ -3228,7 +3223,7 @@ ttyinv_render(winid window, struct WinDesc *cw)
slot_limit = SIZE(slot_tracker);
if (inuse_only) {
slot_limit = rows_per_side; /* assume one side */
if (ttyinv_slots_used >= rows_per_side)
if (ttyinv_slots_used == 0 || ttyinv_slots_used >= rows_per_side)
slot_limit *= 2; /* second side is populated */
} else if (!show_gold) {
slot_limit -= 2; /* there are two extra slots for gold and overflow;
@@ -3287,12 +3282,13 @@ ttyinv_render(winid window, struct WinDesc *cw)
for (col = 0; col < cw->maxcol; ++col) {
cell = &cw->cells[row][col];
if (cell->refresh || force_redraw) {
if (cell->color
&& (current_row_color != cell->color - 1)) {
if (cell->color && (current_row_color != cell->color - 1)) {
current_row_color = cell->color - 1;
#if 0
if (current_row_color == NO_COLOR)
term_end_color();
else
#endif
term_start_color(current_row_color);
}
if (cell->glyph) {
@@ -3350,7 +3346,7 @@ ttyinv_populate_slot(
each other in a union, so clear gi before assigning ttychar */
if (cell->glyph) {
free((genericptr_t) cell->content.gi);
*cell = zerottycell; /* clears cell->glyph and cell->content */
*cell = emptyttycell; /* clears cell->glyph and cell->content */
}
if ((c = *text) != '\0')
@@ -3374,8 +3370,6 @@ ttyinv_populate_slot(
}
}
DISABLE_WARNING_FORMAT_NONLITERAL
void
tty_refresh_inventory(int start, int stop, int y)
{
@@ -3383,8 +3377,10 @@ tty_refresh_inventory(int start, int stop, int y)
struct WinDesc *cw = 0;
winid window = WIN_INVEN;
struct tty_perminvent_cell *cell;
boolean printing_glyphs;
if (window == WIN_ERR || !iflags.perm_invent || y < 0)
if (window == WIN_ERR || !iflags.perm_invent
|| gp.perm_invent_toggling_direction == toggling_off)
return;
if ((cw = wins[window]) == (struct WinDesc *) 0)
@@ -3393,17 +3389,21 @@ tty_refresh_inventory(int start, int stop, int y)
if (col_limit > cw->maxcol)
col_limit = cw->maxcol;
if (row >= cw->maxrow)
return; /* out of our range. Huge menus can do this */
/* we've been asked to redisplay a portion of the screen, one row */
printing_glyphs = FALSE;
for (col = start - 1; col < col_limit; ++col) {
cell = &cw->cells[row][col];
if (cell->color != ttyDisplay->color + 1) {
term_start_color(cell->color - 1);
ttyDisplay->color = cell->color - 1;
}
if (cell->glyph) {
tty_print_glyph(window, col + 1, row, cell->content.gi,
&nul_glyphinfo);
end_glyphout();
printing_glyphs = TRUE;
} else {
if (printing_glyphs)
end_glyphout();
if (col != cw->curx || row != cw->cury)
tty_curs(window, col + 1, row);
(void) putchar(cell->content.ttychar);
@@ -3412,16 +3412,26 @@ tty_refresh_inventory(int start, int stop, int y)
}
cell->refresh = 0;
}
if (printing_glyphs)
end_glyphout();
if (ttyDisplay->color != NO_COLOR) {
term_end_color();
ttyDisplay->color = NO_COLOR;
}
}
RESTORE_WARNING_FORMAT_NONLITERAL
static void
tty_invent_box_glyph_init(struct WinDesc *cw)
{
int row, col, glyph, bordercolor = NO_COLOR;
uchar sym;
struct tty_perminvent_cell *cell;
boolean inuse_only = (ttyinvmode & InvInUse) != 0,
show_gold = (ttyinvmode & InvShowGold) != 0 && !inuse_only;
int rows_per_side = (inuse_only ? (cw->maxrow - 2)
: !show_gold ? 26
: 27),
bottomrow = rows_per_side + 1;
if (cw == 0 || !cw->active)
return;
@@ -3434,50 +3444,35 @@ tty_invent_box_glyph_init(struct WinDesc *cw)
[border_middle] because they could be the same column (for
InvInUse) and if so we want corner rather than tee there */
if (row == 0) {
if (col == bordercol[border_left])
sym = S_tlcorn;
else if (col == bordercol[border_right])
sym = S_trcorn;
else if (col == bordercol[border_middle])
sym = S_tdwall;
else /*if ((col > bordercol[border_left]
&& col < bordercol[border_middle])
|| (col > bordercol[border_middle]
&& col < bordercol[border_right]))*/
sym = S_hwall;
} else if (row == (cw->maxrow - 1)) {
if (col == bordercol[border_left])
sym = S_blcorn;
else if (col == bordercol[border_right])
sym = S_brcorn;
else if (col == bordercol[border_middle])
sym = S_tuwall;
else /*if ((col > bordercol[border_left]
&& col < bordercol[border_middle])
|| (col > bordercol[border_middle]
&& col < bordercol[border_right]))*/
sym = S_hwall;
} else {
sym = (col == bordercol[border_left]) ? S_tlcorn
: (col == bordercol[border_right]) ? S_trcorn
: (col == bordercol[border_middle]) ? S_tdwall
: S_hwall;
} else if (row < bottomrow) {
if (col == bordercol[border_left]
|| col == bordercol[border_middle]
|| col == bordercol[border_right])
sym = S_vwall;
/* else sym keeps placeholder value */
} else if (row == bottomrow) {
sym = (col == bordercol[border_left]) ? S_blcorn
: (col == bordercol[border_right]) ? S_brcorn
: (col == bordercol[border_middle]) ? S_tuwall
: S_hwall;
}
if (sym == S_crwall) { /* not a boundary (but might have been) */
if (cell->glyph) {
/* presumably is no longer wanted middle vertical line */
free((genericptr_t) cell->content.gi);
*cell = zerottycell; /* clears cell->glyph */
*cell = emptyttycell; /* clears cell->glyph */
cell->content.ttychar = ' ';
cell->text = 1;
cell->refresh = 1;
}
continue;
}
/* a boundary, but might not have been if this is the middle
and we were showing full lines and are now going to show two
sides; allocate glyph_info for middle vertical line */
/* a boundary; if it doesn't hold a glyph yet, allocate one */
if (!cell->glyph) {
cell->content.gi = (glyph_info *) alloc(sizeof (glyph_info));
*(cell->content.gi) = zerogi;
@@ -3489,7 +3484,7 @@ tty_invent_box_glyph_init(struct WinDesc *cw)
map_glyphinfo(0, 0, glyph, 0, cell->content.gi);
cell->glyph = 1; /* (redundant) */
cell->text = 0;
/* originaly this conditionally set refresh depending upon
/* originally this conditionally set refresh depending upon
whether the glyph was already shown, but that optimization
is for something that rarely happens (boundary lines aren't
redrawn very often, and most of the time when they are it's
@@ -3512,15 +3507,14 @@ assesstty(
{
boolean inuse_only = (invmode & InvInUse) != 0,
show_gold = (invmode & InvShowGold) != 0 && !inuse_only;
int perminv_minrow = tty_perminv_minrow + (show_gold ? 1 : 0);
*offx = 0;
/* topline + map rows + status lines */
*offy = 1 + ROWNO + StatusRows(); /* 1 + 21 + (2 or 3) */
*rows = (ttyDisplay->rows - *offy);
*cols = ttyDisplay->cols;
*minrow = tty_perminv_minrow;
if (show_gold)
*minrow += 1;
*minrow = perminv_minrow;
#define SMALL_INUSE_WINDOW
#ifdef SMALL_INUSE_WINDOW
#undef SMALL_INUSE_WINDOW
@@ -3535,7 +3529,7 @@ assesstty(
if (inuse_only)
*minrow = 1 + 15 + 1; /* top border + 15 lines + bottom border */
#endif
*maxrow = *rows;
*maxrow = min(*rows, perminv_minrow);
*maxcol = *cols;
return !(*rows < *minrow || *cols < tty_perminv_mincol);
}
@@ -3599,7 +3593,7 @@ docorner(
#ifdef TTY_PERM_INVENT
struct WinDesc *icw = 0;
if (WIN_INVEN != WIN_ERR)
if (WIN_INVEN != WIN_ERR && iflags.perm_invent)
icw = wins[WIN_INVEN];
#endif
@@ -3628,8 +3622,9 @@ docorner(
if (!ystart_between_menu_pages)
cl_end(); /* clear to end of line */
#ifdef TTY_PERM_INVENT
/* the whole thing is beyond the board */
if (icw)
/* the whole thing is beyond the board but not necessarily all the
way to the bottom of the screen */
if (icw && y >= (int) icw->offy && y < icw->offy + icw->maxrow)
tty_refresh_inventory(xmin - (int) icw->offx, icw->maxcol,
y - (int) icw->offy);
#endif