pull request #443 - X11 color status highlighting

for 'fancy status'.  This is from an emailed diff rather than
directly from git, and the git code has a bunch of commits,
so this may or may not match the latest.  It needs formatting
cleanup and triggers a couple of warnings on OSX.  Fix to follow.

Status highlight colors use the same names as menu coloring
but this uses different X11 colors for the two sets.  That
will have to be changed so that yellow either means yellow all
the time or goldenrod all the time instead of sometimes yellow
and sometimes goldenrod.

Adopts #443
This commit is contained in:
PatR
2021-01-26 13:39:50 -08:00
parent ea12c70e46
commit acbf423734
3 changed files with 197 additions and 81 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 winX.h $NHDT-Date: 1596498574 2020/08/03 23:49:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ */
/* NetHack 3.7 winX.h $NHDT-Date: 1611697182 2021/01/26 21:39:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.42 $ */
/* Copyright (c) Dean Luick, 1992 */
/* NetHack may be freely redistributed. See license for details. */
@@ -419,6 +419,7 @@ E Widget FDECL(create_value, (Widget, const char *));
E void FDECL(set_name, (Widget, const char *));
E void FDECL(set_name_width, (Widget, int));
E int FDECL(get_name_width, (Widget));
E Widget FDECL(get_value_widget, (Widget));
E void FDECL(set_value, (Widget, const char *));
E void FDECL(set_value_width, (Widget, int));
E int FDECL(get_value_width, (Widget));

View File

@@ -1,11 +1,11 @@
/* NetHack 3.7 winstat.c $NHDT-Date: 1596498375 2020/08/03 23:46:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.28 $ */
/* NetHack 3.7 winstat.c $NHDT-Date: 1611697183 2021/01/26 21:39:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */
/* Copyright (c) Dean Luick, 1992 */
/* NetHack may be freely redistributed. See license for details. */
/*
* Status window routines. This file supports both the "traditional"
* tty status display and a "fancy" status display. A tty status is
* made if a popup window is requested, otherewise a fancy status is
* made if a popup window is requested, otherwise a fancy status is
* made. This code assumes that only one fancy status will ever be made.
* Currently, only one status window (of any type) is _ever_ made.
*/
@@ -107,6 +107,7 @@ static void FDECL(tt_reset_color, (int, int, unsigned long *));
static void NDECL(tt_status_fixup);
static Widget FDECL(create_tty_status_field, (int, int, Widget, Widget));
static Widget FDECL(create_tty_status, (Widget, Widget));
static void FDECL(update_fancy_status_field_with_hilites, (int, int, int));
static void FDECL(update_fancy_status_field, (int));
static void FDECL(update_fancy_status, (BOOLEAN_P));
static Widget FDECL(create_fancy_status, (Widget, Widget));
@@ -178,6 +179,25 @@ static Widget X11_cond_labels[32]; /* Ugh */
static XFontStruct *X11_status_font;
static Pixel X11_status_fg, X11_status_bg;
static const char* fancy_status_hilite_colors[] = {
"grey15",
"red3",
"dark green",
"saddle brown",
"blue",
"magenta3",
"dark cyan",
"web gray",
"", /* NO_COLOR */
"orange",
"green3",
"goldenrod",
"royal blue",
"magenta",
"cyan",
"white"
};
struct xwindow *xw_status_win;
static int
@@ -812,9 +832,9 @@ unsigned long *colormasks; /* bitmask of highlights for conditions */
/*ARGSUSED*/
static void
X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks)
int fld, chg UNUSED, percent UNUSED, color UNUSED;
int fld, chg UNUSED, percent UNUSED, color;
genericptr_t ptr;
unsigned long *colormasks UNUSED;
unsigned long *colormasks;
{
static const struct bl_to_ff {
int bl, ff;
@@ -883,13 +903,16 @@ unsigned long *colormasks UNUSED;
if (changed_bits) {
for (i = 0; i < SIZE(mask_to_fancyfield); i++)
if ((changed_bits & mask_to_fancyfield[i].mask) != 0L)
update_fancy_status_field(mask_to_fancyfield[i].ff);
update_fancy_status_field_with_hilites(mask_to_fancyfield[i].ff,
condcolor(mask_to_fancyfield[i].mask, colormasks),
condattr(mask_to_fancyfield[i].mask, colormasks));
old_condition_bits = X11_condition_bits; /* remember 'On' bits */
}
} else {
for (i = 0; i < SIZE(bl_to_fancyfield); i++)
if (bl_to_fancyfield[i].bl == fld) {
update_fancy_status_field(bl_to_fancyfield[i].ff);
update_fancy_status_field_with_hilites(bl_to_fancyfield[i].ff,
color & 0xf, color >> 8 & 0xff);
break;
}
}
@@ -1228,8 +1251,6 @@ const char *str;
extern const char *hu_stat[]; /* from eat.c */
extern const char *enc_stat[]; /* from botl.c */
static int hilight_time = 1; /* number of turns to hilight a changed value */
struct X_status_value {
/* we have to cast away 'const' when assigning new names */
const char *name; /* text name */
@@ -1239,6 +1260,8 @@ struct X_status_value {
int turn_count; /* last time the value changed */
boolean set; /* if highlighted */
boolean after_init; /* don't highlight on first change (init) */
boolean inverted_hilite; /* if highlighted due to hilite_status inverse rule */
Pixel default_fg; /* what FG color it initialized with */
};
/* valid type values */
@@ -1280,53 +1303,53 @@ static Widget FDECL(init_info_form, (Widget, Widget, Widget));
* - These must be in the same order as the F_foo numbers.
*/
static struct X_status_value shown_stats[NUM_STATS] = {
{ "", SV_NAME, (Widget) 0, -1L, 0, FALSE, FALSE }, /* 0 */
{ "", SV_NAME, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /* 0 */
{ "Strength", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE }, /* 1*/
{ "Dexterity", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Constitution", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Intelligence", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Wisdom", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE }, /* 5*/
{ "Charisma", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Strength", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /* 1*/
{ "Dexterity", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Constitution", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Intelligence", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Wisdom", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /* 5*/
{ "Charisma", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "", SV_LABEL, (Widget) 0, -1L, 0, FALSE, FALSE }, /*NAME*/
{ "", SV_LABEL, (Widget) 0, -1L, 0, FALSE, FALSE }, /*DLEVEL*/
{ "Gold", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Hit Points", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE }, /*10*/
{ "Max HP", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Power", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Max Power", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Armor Class", SV_VALUE, (Widget) 0, 256L, 0, FALSE, FALSE },
{ "Xp Level", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE }, /*15*/
/*{ "Hit Dice", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE }, ==15*/
{ "Exp Points", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Alignment", SV_VALUE, (Widget) 0, -2L, 0, FALSE, FALSE },
{ "Time", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE },
{ "Score", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE }, /*19*/
{ "", SV_LABEL, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /*NAME*/
{ "", SV_LABEL, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /*DLEVEL*/
{ "Gold", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Hit Points", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /*10*/
{ "Max HP", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Power", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Max Power", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Armor Class", SV_VALUE, (Widget) 0, 256L, 0, FALSE, FALSE, FALSE, 0 },
{ "Xp Level", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /*15*/
/*{ "Hit Dice", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, ==15*/
{ "Exp Points", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Alignment", SV_VALUE, (Widget) 0, -2L, 0, FALSE, FALSE, FALSE, 0 },
{ "Time", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 },
{ "Score", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0 }, /*19*/
{ "", SV_NAME, (Widget) 0, -1L, 0, FALSE, TRUE }, /*20 */
{ "", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*ENCMBR*/
{ "Trapped", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Tethered", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Levitating", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Flying", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*25*/
{ "Riding", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "", SV_NAME, (Widget) 0, -1L, 0, FALSE, TRUE, FALSE, 0 }, /*20 */
{ "", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*ENCMBR*/
{ "Trapped", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Tethered", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Levitating", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Flying", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*25*/
{ "Riding", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Grabbed!", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*27*/
{ "Petrifying", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*STONE*/
{ "Slimed", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Strangled", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*30*/
{ "Food Pois", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Term Ill", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Sinking", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*LAVA*/
{ "Grabbed!", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*27*/
{ "Petrifying", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*STONE*/
{ "Slimed", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Strangled", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*30*/
{ "Food Pois", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Term Ill", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Sinking", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*LAVA*/
{ "Held", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*34*/
{ "Holding", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*35*/
{ "Blind", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Deaf", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Stunned", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Confused", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE },
{ "Hallucinat", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE }, /*40*/
{ "Held", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*34*/
{ "Holding", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*35*/
{ "Blind", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Deaf", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Stunned", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Confused", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 },
{ "Hallucinat", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0 }, /*40*/
};
/*
* The following are supported by the core but not yet handled here:
@@ -1625,23 +1648,26 @@ long new_value;
* or changing to not-hungry or not-encumbered, there's nothing to
* highlight because the field becomes blank.
*/
if (attr_rec != &shown_stats[F_TIME]) {
if (attr_rec->after_init) {
/* toggle if not highlighted and just set to nonblank or if
already highlighted and just set to blank */
if (!attr_rec->set ^ !*buf) {
if (attr_rec->type == SV_LABEL || attr_rec->type == SV_NAME)
hilight_label(attr_rec->w);
else
hilight_value(attr_rec->w);
attr_rec->set = !attr_rec->set;
}
attr_rec->turn_count = 0;
} else {
attr_rec->after_init = TRUE;
}
}
if (attr_rec->after_init) {
/* toggle if not highlighted and just set to nonblank or if
already highlighted and just set to blank */
if (attr_rec != &shown_stats[F_TIME] && !attr_rec->set ^ !*buf) {
/* But don't hilite if inverted from status_hilite since
it will already be hilited by apply_hilite_attributes(). */
if (!attr_rec->inverted_hilite) {
if (attr_rec->type == SV_VALUE)
hilight_value(attr_rec->w);
else
hilight_label(attr_rec->w);
}
attr_rec->set = !attr_rec->set;
}
attr_rec->turn_count = 0;
} else {
XtSetArg(args[0], XtNforeground, &attr_rec->default_fg);
XtGetValues(attr_rec->w, args, ONE);
attr_rec->after_init = TRUE;
}
}
/* overloaded condition is being cleared without going through update_val()
@@ -1661,6 +1687,74 @@ struct X_status_value *sv;
}
}
static void
update_color(sv, color)
struct X_status_value *sv;
int color;
{
Pixel pixel;
Arg args[1];
XrmValue source;
XrmValue dest;
Widget w = (sv->type == SV_LABEL || sv->type == SV_NAME ? sv->w : get_value_widget(sv->w));
if (color == NO_COLOR) {
if (sv->after_init)
pixel = sv->default_fg;
}
else {
source.size = strlen(fancy_status_hilite_colors[color]) + 1;
source.addr = (char *)fancy_status_hilite_colors[color];
dest.size = sizeof(Pixel);
dest.addr = (XPointer)&pixel;
if (!XtConvertAndStore(w, XtRString, &source, XtRPixel, &dest))
pixel = 0;
}
if (pixel != 0) {
char *arg_name = (sv->set || sv->inverted_hilite ? XtNbackground : XtNforeground);
XtSetArg(args[0], arg_name, pixel);
XtSetValues(w, args, ONE);
}
}
boolean
name_widget_has_label(sv)
struct X_status_value *sv;
{
Arg args[1];
const char *label;
XtSetArg(args[0], XtNlabel, &label);
XtGetValues(sv->w, args, ONE);
return strlen(label) > 0;
}
static void
apply_hilite_attributes(sv, attributes)
struct X_status_value *sv;
int attributes;
{
boolean attr_inversion
= HL_INVERSE & attributes
&& (sv->type != SV_NAME || name_widget_has_label(sv))
? TRUE
: FALSE;
if (sv->inverted_hilite != attr_inversion) {
sv->inverted_hilite = attr_inversion;
if (!sv->set) {
if (sv->type == SV_VALUE)
hilight_value(sv->w);
else
hilight_label(sv->w);
}
}
/* Could possibly add more attributes here: HL_ATTCLR_DIM,
HL_ATTCLR_BLINK, HL_ATTCLR_ULINE, and HL_ATTCLR_BOLD. If so,
extract the above into its own function apply_hilite_inverse()
and each other attribute into its own to keep the code clean. */
}
/*
* Update the displayed status. The current code in botl.c updates
* two lines of information. Both lines are always updated one after
@@ -1679,8 +1773,8 @@ struct X_status_value *sv;
* [**] HD is shown instead of level and exp if Upolyd.
*/
static void
update_fancy_status_field(i)
int i;
update_fancy_status_field_with_hilites(i, color, attributes)
int i, color, attributes;
{
struct X_status_value *sv = &shown_stats[i];
unsigned long condmask = 0L;
@@ -1860,6 +1954,17 @@ int i;
}
}
update_val(sv, val);
if (color >= 0 )
update_color(sv, color);
if (attributes >=0 )
apply_hilite_attributes(sv, attributes);
}
static void
update_fancy_status_field(i)
int i;
{
update_fancy_status_field_with_hilites(i, -1, -1);
}
/* fully update status after bl_flush or window resize */
@@ -1906,12 +2011,15 @@ check_turn_events()
if (!sv->set)
continue;
if (sv->turn_count++ >= hilight_time) {
/* unhighlights by toggling a highlighted item back off again */
if (sv->type == SV_LABEL || sv->type == SV_NAME)
hilight_label(sv->w);
else
hilight_value(sv->w);
if (sv->turn_count++ >= iflags.hilite_delta) {
/* unhighlights by toggling a highlighted item back off again,
unless forced inverted by a status_hilite rule */
if (!sv->inverted_hilite) {
if (sv->type == SV_VALUE)
hilight_value(sv->w);
else
hilight_label(sv->w);
}
sv->set = FALSE;
}
}

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 winval.c $NHDT-Date: 1596498377 2020/08/03 23:46:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */
/* NetHack 3.7 winval.c $NHDT-Date: 1611697183 2021/01/26 21:39:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */
/* Copyright (c) Dean Luick, 1992 */
/* NetHack may be freely redistributed. See license for details. */
@@ -114,6 +114,13 @@ Widget w;
return (int) width;
}
Widget
get_value_widget(w)
Widget w;
{
return XtNameToWidget(w, WVALUE);
}
void
set_value(w, new_value)
Widget w;
@@ -122,7 +129,7 @@ const char *new_value;
Arg args[1];
Widget val;
val = XtNameToWidget(w, WVALUE);
val = get_value_widget(w);
XtSetArg(args[0], XtNlabel, new_value);
XtSetValues(val, args, ONE);
}
@@ -135,7 +142,7 @@ int new_width;
Arg args[1];
Widget val;
val = XtNameToWidget(w, WVALUE);
val = get_value_widget(w);
XtSetArg(args[0], XtNwidth, new_width);
XtSetValues(val, args, ONE);
}
@@ -148,7 +155,7 @@ Widget w;
Widget val;
Dimension width;
val = XtNameToWidget(w, WVALUE);
val = get_value_widget(w);
XtSetArg(args[0], XtNwidth, &width);
XtGetValues(val, args, ONE);
return (int) width;
@@ -160,7 +167,7 @@ void
hilight_value(w)
Widget w;
{
swap_fg_bg(XtNameToWidget(w, WVALUE));
swap_fg_bg(get_value_widget(w));
}
/* Swap the foreground and background colors of the given widget */