diff --git a/include/winX.h b/include/winX.h index 4d7689c04..03244d04d 100644 --- a/include/winX.h +++ b/include/winX.h @@ -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)); diff --git a/win/X11/winstat.c b/win/X11/winstat.c index cbc0ce078..bb82c91f4 100644 --- a/win/X11/winstat.c +++ b/win/X11/winstat.c @@ -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; } } diff --git a/win/X11/winval.c b/win/X11/winval.c index dd041012b..6bb620539 100644 --- a/win/X11/winval.c +++ b/win/X11/winval.c @@ -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 */