TTY_PERM_INVENT perminv_mode=inuse

Revise the tty permanent inventory window's in-use mode to be able to
switch back and forth between one full width panel and two side-by-side
half width panels on the fly as needs dictate.

A lot of trial and error involved but I think it has reached a state
where it is reliable, and the smaller number of lines required at
present can probably be viable for actual usage.  At the moment it
requires at least 10 extra lines below the standard tty mesg+map+stat
display, 34 lines total for statuslines:2 or 35 for statuslines:3.
The top and bottom of the 10 or more extra lines get drawn as boundary
lines using wall characters, leaving 8 lines for full width or 16 half
lines when 8 isn't enough.  If more that 16 items are in use (maybe
lots of lit candles forced into separate inventory slots or a
menagerie on leashes), the excess get skipped.  However, it will use
more lines if they are available.  Prior to a few days ago it was
requiring 17 extra lines and able to show 15 items as full lines only,
unable to take advantage of more lines when available.
This commit is contained in:
PatR
2023-12-06 02:19:41 -08:00
parent 5dc94f3d83
commit 1b1c45d3ce

View File

@@ -263,6 +263,7 @@ static int inuse_only_start = 0; /* next slot to use for in-use-only mode */
static boolean done_tty_perm_invent_init = FALSE;
enum { tty_slots = invlet_basic + invlet_gold + invlet_overflow }; /* 54 */
static boolean slot_tracker[tty_slots];
static int ttyinv_slots_used = 0; /* 1-based, slot_trackter[0..slots-1] */
static long last_glyph_reset_when;
#ifndef NOINVSYM /* invent.c */
#define NOINVSYM '#'
@@ -274,13 +275,16 @@ static void ttyinv_add_menu(winid, struct WinDesc *, char ch, int attr,
int clr, const char *str);
static int selector_to_slot(char ch, const int invflags, boolean *ignore);
static char slot_to_invlet(int, boolean);
static void ttyinv_inuse_fulllines(struct WinDesc *, int);
static void ttyinv_inuse_twosides(struct WinDesc *, int);
static void ttyinv_end_menu(int, struct WinDesc *);
static void ttyinv_render(winid window, struct WinDesc *cw);
static void tty_invent_box_glyph_init(struct WinDesc *cw);
static boolean assesstty(enum inv_modes, short *, short *,
long *, long *, long *, long *, long *);
static void ttyinv_populate_slot(struct WinDesc *, int, int,
const char *, int32_t);
#endif
#endif /* TTY_PERM_INVENT */
/*
* A string containing all the default commands -- to add to a list
@@ -2615,12 +2619,9 @@ tty_end_menu(
ttywindowpanic();
}
#ifdef TTY_PERM_INVENT
if (cw->mbehavior == MENU_BEHAVE_PERMINV
&& (iflags.perm_invent
|| gp.perm_invent_toggling_direction == toggling_on)
&& window == WIN_INVEN) {
if (gp.program_state.in_moveloop)
ttyinv_render(window, cw);
/* (probably don't need to check both of these conditions) */
if (cw->mbehavior == MENU_BEHAVE_PERMINV && window == WIN_INVEN) {
ttyinv_end_menu(window, cw);
return;
}
#endif
@@ -2917,18 +2918,19 @@ ttyinv_create_window(int newid, struct WinDesc *newwin)
bordercol[border_left] = 0;
bordercol[border_middle] = (newwin->maxcol + 1) / 2;
bordercol[border_right] = newwin->maxcol - 1;
/* for in-use mode, use full lines */
/* for in-use mode, use full lines; it will switch to two panels if
there are more items than the number of full lines */
if ((ttyinvmode & InvInUse) != 0)
bordercol[border_middle] = bordercol[border_right];
n = (unsigned) (newwin->maxrow * sizeof(struct tty_perminvent_cell *));
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));
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);
n = (unsigned) sizeof (glyph_info);
for (r = 0; r < newwin->maxrow; r++)
for (c = 0; c < newwin->maxcol; c++) {
newwin->cells[r][c] = zerottycell;
@@ -2942,6 +2944,7 @@ ttyinv_create_window(int newid, struct WinDesc *newwin)
}
}
newwin->active = 1;
ttyinv_slots_used = 0;
tty_invent_box_glyph_init(newwin);
return newid;
}
@@ -3015,9 +3018,20 @@ ttyinv_add_menu(
if (!gp.program_state.in_moveloop)
return;
slot = selector_to_slot(ch, ttyinvmode, &ignore);
if (inuse_only && slot > 2 * rows_per_side)
ignore = TRUE; /* left & right sides full; no 3rd 'side' available */
if (!ignore) {
slot_tracker[slot] = TRUE;
/* maxslot = ((int) cw->maxrow - 2) * (!inuse_only ? 2 : 1); */
/* if we need to expand inuse_only from one side to two, do so now;
entries are shown in row 1 thru rows_per_side (with rows 0 and
rows_per_side+1 containing boundary lines) but stored in
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) */
if (inuse_only && slot == rows_per_side
&& ttyinv_slots_used == rows_per_side)
ttyinv_inuse_twosides(cw, rows_per_side);
/* TODO: check for MENUCOLORS match */
text = str; /* 'text' will switch to invbuf[] below */
@@ -3138,6 +3152,64 @@ slot_to_invlet(int slot, boolean incl_gold)
return res;
}
/* called if inuse_only contracts from two sides to one; there won't be
full lines shown until the next inventory update because the data past
the middle boundary was clipped rather than saved; caller or caller's
caller or somewhere up the call chain will call update_inventory() to
redraw it all and rectify that */
static void
ttyinv_inuse_fulllines(
struct WinDesc *cw,
int rows_per_side UNUSED)
{
bordercol[border_middle] = bordercol[border_right];
tty_invent_box_glyph_init(cw);
}
/* called when inuse_only expands from full lines (one side) to two sides */
static void
ttyinv_inuse_twosides(
struct WinDesc *cw,
int rows_per_side)
{
int row, col;
bordercol[border_middle] = (cw->maxcol + 1) / 2;
tty_invent_box_glyph_init(cw);
/* draw the middle boundary */
col = bordercol[border_middle];
for (row = 0; row <= rows_per_side; ++row)
tty_refresh_inventory(col, col, row);
}
/* split out of tty_end_menu(); persistent inventory is ready to display */
static void
ttyinv_end_menu(int window, struct WinDesc *cw)
{
if (iflags.perm_invent
|| gp.perm_invent_toggling_direction == toggling_on) {
if (gp.program_state.in_moveloop) {
boolean inuse_only = ((ttyinvmode & InvInUse) != 0);
int rows_per_side = inuse_only ? cw->maxrow - 2 : 0;
int old_slots_used = ttyinv_slots_used; /* value before render */
ttyinv_render(window, cw);
/* if inuse_only was using two sides and has just shrunk to one,
it will switch to full rows instead of side-by-side panels
but current data only holds the left-hand panel's portion;
rerun the whole thing to regenerate previously clipped data;
fortunately this should be a fairly rare occurrence */
if (inuse_only && old_slots_used > rows_per_side
/* 'ttyinv_slots_used' was just updated by ttyinv_render()
to the number of entries currently shown */
&& ttyinv_slots_used <= rows_per_side)
tty_update_inventory(0); /* will call back to core for data */
}
}
}
/* display persistent inventory */
static void
ttyinv_render(winid window, struct WinDesc *cw)
{
@@ -3145,15 +3217,18 @@ ttyinv_render(winid window, struct WinDesc *cw)
struct tty_perminvent_cell *cell;
char invbuf[BUFSZ];
boolean force_redraw = gp.program_state.in_docrt ? TRUE : FALSE,
show_gold = (ttyinvmode & InvShowGold) != 0,
inuse_only = (ttyinvmode & InvInUse) != 0,
show_gold = (ttyinvmode & InvShowGold) != 0 && !inuse_only,
sparse = (ttyinvmode & InvSparse) != 0 && !inuse_only;
int rows_per_side = (!show_gold ? 26 : 27);
int rows_per_side = (inuse_only ? (cw->maxrow - 2)
: !show_gold ? 26
: 27);
slot_limit = SIZE(slot_tracker);
if (inuse_only) {
rows_per_side = cw->maxrow - 2; /* -2 top and bottom borders */
slot_limit = rows_per_side;
slot_limit = rows_per_side; /* assume one side */
if (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;
* blanking them for !show_gold would wrap back to
@@ -3163,6 +3238,7 @@ ttyinv_render(winid window, struct WinDesc *cw)
for (slot = 0; slot < slot_limit; ++slot)
if (slot_tracker[slot])
filled_count++;
/* clear unused slots */
for (slot = 0; slot < slot_limit; ++slot) {
if (slot_tracker[slot])
continue;
@@ -3181,6 +3257,23 @@ ttyinv_render(winid window, struct WinDesc *cw)
side = slot / rows_per_side;
ttyinv_populate_slot(cw, row, side, invbuf, 0);
}
/* inuse_only might switch from one panel to two or vice versa */
if (inuse_only && filled_count != ttyinv_slots_used) {
if (filled_count > rows_per_side
&& ttyinv_slots_used <= rows_per_side) {
/* need second side; set up the middle border */
/* done earlier, in add_menu():
ttyinv_inuse_twosides(cw, rows_per_side);
*/
} else if (filled_count <= rows_per_side
&& ttyinv_slots_used > rows_per_side) {
/* have second side but don't need/want it anymore */
ttyinv_inuse_fulllines(cw, rows_per_side);
}
ttyinv_slots_used = filled_count;
}
/* has there been a glyph reset since we last got here? */
if (gg.glyph_reset_timestamp > last_glyph_reset_when) {
/* // tty_invent_box_glyph_init(wins[WIN_INVEN]); */
@@ -3265,12 +3358,13 @@ ttyinv_populate_slot(
struct tty_perminvent_cell *cell;
char c;
int ccnt, col, endcol;
boolean inuse_only = (ttyinvmode & InvInUse) != 0;
boolean oops, inuse_only = (ttyinvmode & InvInUse) != 0;
if (inuse_only && side == 1) /* there might be more in use than fits */
return;
if (row < 0 || (long) row >= cw->maxrow || side < 0 || side > 1)
panic("ttyinv_populate_slot row=%d, size=%d", row, side);
oops = (row < 0 || (long) row >= cw->maxrow || side < 0);
if (inuse_only && side > 1 && !oops)
return; /* there might be more in-use than fits; ignore excess */
if (oops || side > 1)
panic("ttyinv_populate_slot row=%d, side=%d", row, side);
col = bordercol[side] + 1;
endcol = bordercol[side + 1] - 1;
@@ -3283,8 +3377,8 @@ ttyinv_populate_slot(
memory allocated for it; gi pointer and ttychar character overlay
each other in a union, so clear gi before assigning ttychar */
if (cell->glyph) {
free((genericptr_t) cell->content.gi), cell->content.gi = 0;
cell->glyph = 0; /* cell->content.gi is gone */
free((genericptr_t) cell->content.gi);
*cell = zerottycell; /* clears cell->glyph and cell->content */
}
if ((c = *text) != '\0')
@@ -3343,8 +3437,8 @@ RESTORE_WARNING_FORMAT_NONLITERAL
static void
tty_invent_box_glyph_init(struct WinDesc *cw)
{
int row, col;
{
int row, col, glyph;
uchar sym;
struct tty_perminvent_cell *cell;
@@ -3354,13 +3448,7 @@ tty_invent_box_glyph_init(struct WinDesc *cw)
for (row = 0; row < cw->maxrow; ++row)
for (col = 0; col < cw->maxcol; ++col) {
cell = &cw->cells[row][col];
/* cell->glyph is a flag for whether the content union contains
a glyph_info structure rather than just a char */
if (!cell->glyph)
continue;
/* sym will always get another value; if for some reason it
doesn't, this default is valid for cmap_walls_to_glyph() */
sym = S_crwall;
sym = S_crwall; /* placeholder */
/* note: for top and bottom, check [border_right] before
[border_middle] because they could be the same column (for
InvInUse) and if so we want corner rather than tee there */
@@ -3395,25 +3483,38 @@ tty_invent_box_glyph_init(struct WinDesc *cw)
sym = S_vwall;
}
/* to get here, cell->glyph is 1 and cell->content union has gi */
{
int oldsymidx = cell->content.gi->gm.sym.symidx;
#ifdef ENHANCED_SYMBOLS
struct unicode_representation *
oldgmu = cell->content.gi->gm.u;
#endif
int glyph = cmap_D0walls_to_glyph(sym);
map_glyphinfo(0, 0, glyph, 0, cell->content.gi);
if (
#ifdef ENHANCED_SYMBOLS
cell->content.gi->gm.u != oldgmu ||
#endif
cell->content.gi->gm.sym.symidx != oldsymidx)
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->content.ttychar = ' ';
cell->text = 1;
cell->refresh = 1;
cell->glyph = 1; /* (redundant) */
cell->text = 0;
}
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 */
if (!cell->glyph) {
cell->content.gi = (glyph_info *) alloc(sizeof (glyph_info));
*(cell->content.gi) = zerogi;
cell->glyph = 1, cell->text = 0;
}
/* to get here, cell->glyph is 1 and cell->content union has gi */
glyph = cmap_D0walls_to_glyph(sym);
map_glyphinfo(0, 0, glyph, 0, cell->content.gi);
cell->glyph = 1; /* (redundant) */
cell->text = 0;
/* originaly 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
because they were erased or overwritten by something so
won't match the prior value anymore) so skip it */
cell->refresh = 1;
}
done_tty_perm_invent_init = TRUE;
}