Files
nethack/win/X11/winstat.c
2015-05-25 09:21:31 +09:00

1069 lines
31 KiB
C

/* NetHack 3.6 winstat.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */
/* 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. This code assumes that only one fancy status will ever be made.
* Currently, only one status window (of any type) is _ever_ made.
*/
#ifndef SYSV
#define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>
#include <X11/Xatom.h>
#ifdef PRESERVE_NO_SYSV
#ifdef SYSV
#undef SYSV
#endif
#undef PRESERVE_NO_SYSV
#endif
#include "hack.h"
#include "winX.h"
extern const char *hu_stat[]; /* from eat.c */
extern const char *enc_stat[]; /* from botl.c */
static void FDECL(update_fancy_status, (struct xwindow *));
static Widget FDECL(create_fancy_status, (Widget, Widget));
static void FDECL(destroy_fancy_status, (struct xwindow *));
void
create_status_window(wp, create_popup, parent)
struct xwindow *wp; /* window pointer */
boolean create_popup;
Widget parent;
{
XFontStruct *fs;
Arg args[8];
Cardinal num_args;
Position top_margin, bottom_margin, left_margin, right_margin;
wp->type = NHW_STATUS;
if (!create_popup) {
/*
* If we are not creating a popup, then we must be the "main" status
* window.
*/
if (!parent)
panic("create_status_window: no parent for fancy status");
wp->status_information = 0;
wp->w = create_fancy_status(parent, (Widget) 0);
return;
}
wp->status_information =
(struct status_info_t *) alloc(sizeof(struct status_info_t));
init_text_buffer(&wp->status_information->text);
num_args = 0;
XtSetArg(args[num_args], XtNallowShellResize, False);
num_args++;
XtSetArg(args[num_args], XtNinput, False);
num_args++;
wp->popup = parent = XtCreatePopupShell(
"status_popup", topLevelShellWidgetClass, toplevel, args, num_args);
/*
* If we're here, then this is an auxiliary status window. If we're
* cancelled via a delete window message, we should just pop down.
*/
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False);
num_args++;
XtSetArg(args[num_args], nhStr(XtNscrollHorizontal),
XawtextScrollWhenNeeded);
num_args++;
XtSetArg(args[num_args], nhStr(XtNscrollVertical),
XawtextScrollWhenNeeded);
num_args++;
wp->w = XtCreateManagedWidget("status", /* name */
asciiTextWidgetClass,
parent, /* parent widget */
args, /* set some values */
num_args); /* number of values to set */
/*
* Adjust the height and width of the message window so that it
* is two lines high and COLNO of the widest characters wide.
*/
/* Get the font and margin information. */
num_args = 0;
XtSetArg(args[num_args], XtNfont, &fs);
num_args++;
XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin);
num_args++;
XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin);
num_args++;
XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin);
num_args++;
XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin);
num_args++;
XtGetValues(wp->w, args, num_args);
wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin;
wp->pixel_width =
COLNO * fs->max_bounds.width + left_margin + right_margin;
/* Set the new width and height. */
num_args = 0;
XtSetArg(args[num_args], XtNwidth, wp->pixel_width);
num_args++;
XtSetArg(args[num_args], XtNheight, wp->pixel_height);
num_args++;
XtSetValues(wp->w, args, num_args);
}
void
destroy_status_window(wp)
struct xwindow *wp;
{
/* If status_information is defined, then it a "text" status window. */
if (wp->status_information) {
if (wp->popup) {
nh_XtPopdown(wp->popup);
if (!wp->keep_window)
XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
}
free((genericptr_t) wp->status_information);
wp->status_information = 0;
} else {
destroy_fancy_status(wp);
}
if (!wp->keep_window)
wp->type = NHW_NONE;
}
/*
* This assumes several things:
* + Status has only 2 lines
* + That both lines are updated in succession in line order.
* + We didn't set stringInPlace on the widget.
*/
void
adjust_status(wp, str)
struct xwindow *wp;
const char *str;
{
Arg args[2];
Cardinal num_args;
if (!wp->status_information) {
update_fancy_status(wp);
return;
}
if (wp->cursy == 0) {
clear_text_buffer(&wp->status_information->text);
append_text_buffer(&wp->status_information->text, str, FALSE);
return;
}
append_text_buffer(&wp->status_information->text, str, FALSE);
/* Set new buffer as text. */
num_args = 0;
XtSetArg(args[num_args], XtNstring, wp->status_information->text.text);
num_args++;
XtSetValues(wp->w, args, num_args);
}
/* Fancy Status
* -------------------------------------------------------------*/
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 */
int type; /* status type */
Widget w; /* widget of name/value pair */
long last_value; /* value displayed */
int turn_count; /* last time the value changed */
boolean set; /* if hilighed */
boolean after_init; /* don't hilight on first change (init) */
};
/* valid type values */
#define SV_VALUE 0 /* displays a label:value pair */
#define SV_LABEL 1 /* displays a changable label */
#define SV_NAME 2 /* displays an unchangeable name */
static void FDECL(hilight_label, (Widget));
static void FDECL(update_val, (struct X_status_value *, long));
static const char *FDECL(width_string, (int));
static void FDECL(create_widget, (Widget, struct X_status_value *, int));
static void FDECL(get_widths, (struct X_status_value *, int *, int *));
static void FDECL(set_widths, (struct X_status_value *, int, int));
static Widget FDECL(init_column,
(const char *, Widget, Widget, Widget, int *));
static Widget FDECL(init_info_form, (Widget, Widget, Widget));
/*
* Form entry storage indices.
*/
#define F_STR 0
#define F_DEX 1
#define F_CON 2
#define F_INT 3
#define F_WIS 4
#define F_CHA 5
#define F_NAME 6
#define F_DLEVEL 7
#define F_GOLD 8
#define F_HP 9
#define F_MAXHP 10
#define F_POWER 11
#define F_MAXPOWER 12
#define F_AC 13
#define F_LEVEL 14
#define F_EXP 15
#define F_ALIGN 16
#define F_TIME 17
#define F_SCORE 18
#define F_HUNGER 19
#define F_CONFUSED 20
#define F_SICK 21
#define F_BLIND 22
#define F_STUNNED 23
#define F_HALLU 24
#define F_ENCUMBER 25
#define NUM_STATS 26
/*
* Notes:
* + Alignment needs a different init value, because -1 is an alignment.
* + Armor Class is an schar, so 256 is out of range.
* + Blank value is 0 and should never change.
*/
static struct X_status_value shown_stats[NUM_STATS] = {
{ "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0*/
{ "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/
{ "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */
{ "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */
{ "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/
{ "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Armor Class", SV_VALUE, (Widget) 0, 256, 0, FALSE, FALSE },
{ "Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Experience", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/
{ "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
{ "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /* hunger*/
{ "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/
{ "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* sick */
{ "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*encumbr*/
};
/*
* Set all widget values to a null string. This is used after all spacings
* have been calculated so that when the window is popped up we don't get all
* kinds of funny values being displayed.
*/
void
null_out_status()
{
int i;
struct X_status_value *sv;
Arg args[1];
for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
switch (sv->type) {
case SV_VALUE:
set_value(sv->w, "");
break;
case SV_LABEL:
case SV_NAME:
XtSetArg(args[0], XtNlabel, "");
XtSetValues(sv->w, args, ONE);
break;
default:
impossible("null_out_status: unknown type %d\n", sv->type);
break;
}
}
}
/* This is almost an exact duplicate of hilight_value() */
static void
hilight_label(w)
Widget w; /* label widget */
{
Arg args[2];
Pixel fg, bg;
XtSetArg(args[0], XtNforeground, &fg);
XtSetArg(args[1], XtNbackground, &bg);
XtGetValues(w, args, TWO);
XtSetArg(args[0], XtNforeground, bg);
XtSetArg(args[1], XtNbackground, fg);
XtSetValues(w, args, TWO);
}
static void
update_val(attr_rec, new_value)
struct X_status_value *attr_rec;
long new_value;
{
char buf[BUFSZ];
Arg args[4];
if (attr_rec->type == SV_LABEL) {
if (attr_rec == &shown_stats[F_NAME]) {
Strcpy(buf, plname);
if ('a' <= buf[0] && buf[0] <= 'z')
buf[0] += 'A' - 'a';
Strcat(buf, " the ");
if (u.mtimedone) {
char mname[BUFSZ];
int k = 0;
Strcpy(mname, mons[u.umonnum].mname);
while (mname[k] != 0) {
if ((k == 0 || (k > 0 && mname[k - 1] == ' '))
&& 'a' <= mname[k] && mname[k] <= 'z')
mname[k] += 'A' - 'a';
k++;
}
Strcat(buf, mname);
} else
Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
} else if (attr_rec == &shown_stats[F_DLEVEL]) {
if (!describe_level(buf)) {
Strcpy(buf, dungeons[u.uz.dnum].dname);
Sprintf(eos(buf), ", level %d", depth(&u.uz));
}
} else {
impossible("update_val: unknown label type \"%s\"",
attr_rec->name);
return;
}
if (strcmp(buf, attr_rec->name) == 0)
return; /* same */
/* Set the label. 'name' field is const for most entries;
we need to cast away that const for this assignment */
Strcpy((char *) attr_rec->name, buf);
XtSetArg(args[0], XtNlabel, buf);
XtSetValues(attr_rec->w, args, ONE);
} else if (attr_rec->type == SV_NAME) {
if (attr_rec->last_value == new_value)
return; /* no change */
attr_rec->last_value = new_value;
/* special cases: hunger, encumbrance, sickness */
if (attr_rec == &shown_stats[F_HUNGER]) {
XtSetArg(args[0], XtNlabel, hu_stat[new_value]);
} else if (attr_rec == &shown_stats[F_ENCUMBER]) {
XtSetArg(args[0], XtNlabel, enc_stat[new_value]);
} else if (attr_rec == &shown_stats[F_SICK]) {
buf[0] = 0;
if (Sick) {
if (u.usick_type & SICK_VOMITABLE)
Strcat(buf, "FoodPois");
if (u.usick_type & SICK_NONVOMITABLE) {
if (u.usick_type & SICK_VOMITABLE)
Strcat(buf, " ");
Strcat(buf, "Ill");
}
}
XtSetArg(args[0], XtNlabel, buf);
} else if (new_value) {
XtSetArg(args[0], XtNlabel, attr_rec->name);
} else {
XtSetArg(args[0], XtNlabel, "");
}
XtSetValues(attr_rec->w, args, ONE);
} else { /* a value pair */
boolean force_update = FALSE;
/* special case: time can be enabled & disabled */
if (attr_rec == &shown_stats[F_TIME]) {
static boolean flagtime = TRUE;
if (flags.time && !flagtime) {
set_name(attr_rec->w, shown_stats[F_TIME].name);
force_update = TRUE;
flagtime = flags.time;
} else if (!flags.time && flagtime) {
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
flagtime = flags.time;
}
if (!flagtime)
return;
}
/* special case: exp can be enabled & disabled */
else if (attr_rec == &shown_stats[F_EXP]) {
static boolean flagexp = TRUE;
if (flags.showexp && !flagexp) {
set_name(attr_rec->w, shown_stats[F_EXP].name);
force_update = TRUE;
flagexp = flags.showexp;
} else if (!flags.showexp && flagexp) {
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
flagexp = flags.showexp;
}
if (!flagexp)
return;
}
/* special case: score can be enabled & disabled */
else if (attr_rec == &shown_stats[F_SCORE]) {
static boolean flagscore = TRUE;
#ifdef SCORE_ON_BOTL
if (flags.showscore && !flagscore) {
set_name(attr_rec->w, shown_stats[F_SCORE].name);
force_update = TRUE;
flagscore = flags.showscore;
} else if (!flags.showscore && flagscore) {
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
flagscore = flags.showscore;
}
if (!flagscore)
return;
#else
if (flagscore) {
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
flagscore = FALSE;
}
return;
#endif
}
/* special case: when polymorphed, show "HD", disable exp */
else if (attr_rec == &shown_stats[F_LEVEL]) {
static boolean lev_was_poly = FALSE;
if (u.mtimedone && !lev_was_poly) {
force_update = TRUE;
set_name(attr_rec->w, "HD");
lev_was_poly = TRUE;
} else if (!u.mtimedone && lev_was_poly) {
force_update = TRUE;
set_name(attr_rec->w, shown_stats[F_LEVEL].name);
lev_was_poly = FALSE;
}
} else if (attr_rec == &shown_stats[F_EXP]) {
static boolean exp_was_poly = FALSE;
if (u.mtimedone && !exp_was_poly) {
force_update = TRUE;
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
exp_was_poly = TRUE;
} else if (!u.mtimedone && exp_was_poly) {
force_update = TRUE;
set_name(attr_rec->w, shown_stats[F_EXP].name);
exp_was_poly = FALSE;
}
if (u.mtimedone)
return; /* no display for exp when poly */
}
if (attr_rec->last_value == new_value && !force_update) /* same */
return;
attr_rec->last_value = new_value;
/* Special cases: strength, alignment and "clear". */
if (attr_rec == &shown_stats[F_STR]) {
if (new_value > 18) {
if (new_value > 118)
Sprintf(buf, "%ld", new_value - 100);
else if (new_value < 118)
Sprintf(buf, "18/%02ld", new_value - 18);
else
Strcpy(buf, "18/**");
} else {
Sprintf(buf, "%ld", new_value);
}
} else if (attr_rec == &shown_stats[F_ALIGN]) {
Strcpy(buf,
(new_value == A_CHAOTIC)
? "Chaotic"
: (new_value == A_NEUTRAL) ? "Neutral" : "Lawful");
} else {
Sprintf(buf, "%ld", new_value);
}
set_value(attr_rec->w, buf);
}
/*
* Now hilight the changed information. Names, time and score don't
* hilight. If first time, don't hilight. If already lit, don't do
* it again.
*/
if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) {
if (attr_rec->after_init) {
if (!attr_rec->set) {
if (attr_rec->type == SV_LABEL)
hilight_label(attr_rec->w);
else
hilight_value(attr_rec->w);
attr_rec->set = TRUE;
}
attr_rec->turn_count = 0;
} else {
attr_rec->after_init = TRUE;
}
}
}
/*
* Update the displayed status. The current code in botl.c updates
* two lines of information. Both lines are always updated one after
* the other. So only do our update when we update the second line.
*
* Information on the first line:
* name, attributes, alignment, score
*
* Information on the second line:
* dlvl, gold, hp, power, ac, {level & exp or HD **}
* status (hunger, conf, halu, stun, sick, blind), time, encumbrance
*
* [**] HD is shown instead of level and exp if mtimedone is non-zero.
*/
static void
update_fancy_status(wp)
struct xwindow *wp;
{
struct X_status_value *sv;
long val;
int i;
if (wp->cursy != 0)
return; /* do a complete update when line 0 is done */
for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
switch (i) {
case F_STR:
val = (long) ACURR(A_STR);
break;
case F_DEX:
val = (long) ACURR(A_DEX);
break;
case F_CON:
val = (long) ACURR(A_CON);
break;
case F_INT:
val = (long) ACURR(A_INT);
break;
case F_WIS:
val = (long) ACURR(A_WIS);
break;
case F_CHA:
val = (long) ACURR(A_CHA);
break;
/*
* Label stats. With the exceptions of hunger, encumbrance, sick
* these are either on or off. Pleae leave the ternary operators
* the way they are. I want to specify 0 or 1, not a boolean.
*/
case F_HUNGER:
val = (long) u.uhs;
break;
case F_CONFUSED:
val = (long) Confusion ? 1L : 0L;
break;
case F_SICK:
val = (long) Sick ? (long) u.usick_type : 0L;
break;
case F_BLIND:
val = (long) Blind ? 1L : 0L;
break;
case F_STUNNED:
val = (long) Stunned ? 1L : 0L;
break;
case F_HALLU:
val = (long) Hallucination ? 1L : 0L;
break;
case F_ENCUMBER:
val = (long) near_capacity();
break;
case F_NAME:
val = (long) 0L;
break; /* special */
case F_DLEVEL:
val = (long) 0L;
break; /* special */
case F_GOLD:
val = money_cnt(invent);
break;
case F_HP:
val = (long) (u.mtimedone ? (u.mh > 0 ? u.mh : 0)
: (u.uhp > 0 ? u.uhp : 0));
break;
case F_MAXHP:
val = (long) (u.mtimedone ? u.mhmax : u.uhpmax);
break;
case F_POWER:
val = (long) u.uen;
break;
case F_MAXPOWER:
val = (long) u.uenmax;
break;
case F_AC:
val = (long) u.uac;
break;
case F_LEVEL:
val = (long) (u.mtimedone ? mons[u.umonnum].mlevel : u.ulevel);
break;
case F_EXP:
val = flags.showexp ? u.uexp : 0L;
break;
case F_ALIGN:
val = (long) u.ualign.type;
break;
case F_TIME:
val = flags.time ? (long) moves : 0L;
break;
#ifdef SCORE_ON_BOTL
case F_SCORE:
val = flags.showscore ? botl_score() : 0L;
break;
#else
case F_SCORE:
val = 0L;
break;
#endif
default: {
/*
* There is a possible infinite loop that occurs with:
*
* impossible->pline->flush_screen->bot->bot{1,2}->
* putstr->adjust_status->update_other->impossible
*
* Break out with this.
*/
static boolean active = FALSE;
if (!active) {
active = TRUE;
impossible("update_other: unknown shown value");
active = FALSE;
}
val = 0;
break;
}
}
update_val(sv, val);
}
}
/*
* Turn off hilighted status values after a certain amount of turns.
*/
void
check_turn_events()
{
int i;
struct X_status_value *sv;
for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
if (!sv->set)
continue;
if (sv->turn_count++ >= hilight_time) {
if (sv->type == SV_LABEL)
hilight_label(sv->w);
else
hilight_value(sv->w);
sv->set = FALSE;
}
}
}
/* Initialize alternate status =============================================
*/
/* Return a string for the initial width. */
static const char *
width_string(sv_index)
int sv_index;
{
switch (sv_index) {
case F_STR:
return "018/**";
case F_DEX:
case F_CON:
case F_INT:
case F_WIS:
case F_CHA:
return "088"; /* all but str never get bigger */
case F_HUNGER:
return shown_stats[F_HUNGER].name;
case F_CONFUSED:
return shown_stats[F_CONFUSED].name;
case F_SICK:
return shown_stats[F_SICK].name;
case F_BLIND:
return shown_stats[F_BLIND].name;
case F_STUNNED:
return shown_stats[F_STUNNED].name;
case F_HALLU:
return shown_stats[F_HALLU].name;
case F_ENCUMBER:
return shown_stats[F_ENCUMBER].name;
case F_NAME:
case F_DLEVEL:
return "";
case F_HP:
case F_MAXHP:
return "9999";
case F_POWER:
case F_MAXPOWER:
return "999";
case F_AC:
return "-99";
case F_LEVEL:
return "99";
case F_GOLD:
case F_EXP:
return "4294967295"; /* max ulong */
case F_ALIGN:
return "Neutral";
case F_TIME:
return "4294967295"; /* max ulong */
case F_SCORE:
return "4294967295"; /* max ulong */
}
impossible("width_string: unknown index %d\n", sv_index);
return "";
}
static void
create_widget(parent, sv, sv_index)
Widget parent;
struct X_status_value *sv;
int sv_index;
{
Arg args[4];
Cardinal num_args;
switch (sv->type) {
case SV_VALUE:
sv->w = create_value(parent, sv->name);
set_value(sv->w, width_string(sv_index));
break;
case SV_LABEL:
/* Labels get their own buffer. */
sv->name = (char *) alloc(BUFSZ);
/* we need to cast away 'const' when assigning a value */
*(char *) (sv->name) = '\0';
num_args = 0;
XtSetArg(args[num_args], XtNborderWidth, 0);
num_args++;
XtSetArg(args[num_args], XtNinternalHeight, 0);
num_args++;
sv->w =
XtCreateManagedWidget(sv_index == F_NAME ? "name" : "dlevel",
labelWidgetClass, parent, args, num_args);
break;
case SV_NAME:
num_args = 0;
XtSetArg(args[num_args], XtNborderWidth, 0);
num_args++;
XtSetArg(args[num_args], XtNinternalHeight, 0);
num_args++;
sv->w = XtCreateManagedWidget(sv->name, labelWidgetClass, parent,
args, num_args);
break;
default:
panic("create_widget: unknown type %d", sv->type);
}
}
/*
* Get current width of value. width2p is only valid for SV_LABEL types.
*/
static void
get_widths(sv, width1p, width2p)
struct X_status_value *sv;
int *width1p, *width2p;
{
Arg args[1];
Dimension width;
switch (sv->type) {
case SV_VALUE:
*width1p = get_name_width(sv->w);
*width2p = get_value_width(sv->w);
break;
case SV_LABEL:
case SV_NAME:
XtSetArg(args[0], XtNwidth, &width);
XtGetValues(sv->w, args, ONE);
*width1p = width;
*width2p = 0;
break;
default:
panic("get_widths: unknown type %d", sv->type);
}
}
static void
set_widths(sv, width1, width2)
struct X_status_value *sv;
int width1, width2;
{
Arg args[1];
switch (sv->type) {
case SV_VALUE:
set_name_width(sv->w, width1);
set_value_width(sv->w, width2);
break;
case SV_LABEL:
case SV_NAME:
XtSetArg(args[0], XtNwidth, (width1 + width2));
XtSetValues(sv->w, args, ONE);
break;
default:
panic("set_widths: unknown type %d", sv->type);
}
}
static Widget
init_column(name, parent, top, left, col_indices)
const char *name;
Widget parent, top, left;
int *col_indices;
{
Widget form;
Arg args[4];
Cardinal num_args;
int max_width1, width1, max_width2, width2;
int *ip;
struct X_status_value *sv;
num_args = 0;
if (top != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromVert), top);
num_args++;
}
if (left != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromHoriz), left);
num_args++;
}
XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0);
num_args++;
form =
XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args);
max_width1 = max_width2 = 0;
for (ip = col_indices; *ip >= 0; ip++) {
sv = &shown_stats[*ip];
create_widget(form, sv, *ip); /* will set init width */
if (ip != col_indices) { /* not first */
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNfromVert),
shown_stats[*(ip - 1)].w);
num_args++;
XtSetValues(sv->w, args, num_args);
}
get_widths(sv, &width1, &width2);
if (width1 > max_width1)
max_width1 = width1;
if (width2 > max_width2)
max_width2 = width2;
}
for (ip = col_indices; *ip >= 0; ip++) {
set_widths(&shown_stats[*ip], max_width1, max_width2);
}
/* There is room behind the end marker for the two widths. */
*++ip = max_width1;
*++ip = max_width2;
return form;
}
/*
* These are the orders of the displayed columns. Change to suit. The -1
* indicates the end of the column. The two numbers after that are used
* to store widths that are calculated at run-time.
*/
static int attrib_indices[] = { F_STR, F_DEX, F_CON, F_INT, F_WIS,
F_CHA, -1, 0, 0 };
static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND,
F_STUNNED, F_HALLU, F_ENCUMBER, -1,
0, 0 };
static int col2_indices[] = { F_MAXHP, F_ALIGN, F_TIME, F_EXP,
F_MAXPOWER, -1, 0, 0 };
static int col1_indices[] = { F_HP, F_AC, F_GOLD, F_LEVEL, F_POWER,
F_SCORE, -1, 0, 0 };
/*
* Produce a form that looks like the following:
*
* name
* dlevel
* col1_indices[0] col2_indices[0]
* col1_indices[1] col2_indices[1]
* . .
* . .
* col1_indices[n] col2_indices[n]
*/
static Widget
init_info_form(parent, top, left)
Widget parent, top, left;
{
Widget form, col1;
struct X_status_value *sv_name, *sv_dlevel;
Arg args[6];
Cardinal num_args;
int total_width, *ip;
num_args = 0;
if (top != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromVert), top);
num_args++;
}
if (left != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromHoriz), left);
num_args++;
}
XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0);
num_args++;
form = XtCreateManagedWidget("status_info", formWidgetClass, parent, args,
num_args);
/* top of form */
sv_name = &shown_stats[F_NAME];
create_widget(form, sv_name, F_NAME);
/* second */
sv_dlevel = &shown_stats[F_DLEVEL];
create_widget(form, sv_dlevel, F_DLEVEL);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w);
num_args++;
XtSetValues(sv_dlevel->w, args, num_args);
/* two columns beneath */
col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0,
col1_indices);
(void) init_column("name_col2", form, sv_dlevel->w, col1, col2_indices);
/* Add calculated widths. */
for (ip = col1_indices; *ip >= 0; ip++)
; /* skip to end */
total_width = *++ip;
total_width += *++ip;
for (ip = col2_indices; *ip >= 0; ip++)
; /* skip to end */
total_width += *++ip;
total_width += *++ip;
XtSetArg(args[0], XtNwidth, total_width);
XtSetValues(sv_name->w, args, ONE);
XtSetArg(args[0], XtNwidth, total_width);
XtSetValues(sv_dlevel->w, args, ONE);
return form;
}
/*
* Create the layout for the fancy status. Return a form widget that
* contains everything.
*/
static Widget
create_fancy_status(parent, top)
Widget parent, top;
{
Widget form; /* The form that surrounds everything. */
Widget w;
Arg args[8];
Cardinal num_args;
num_args = 0;
if (top != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromVert), top);
num_args++;
}
XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0);
num_args++;
XtSetArg(args[num_args], XtNborderWidth, 0);
num_args++;
XtSetArg(args[num_args], XtNorientation, XtorientHorizontal);
num_args++;
form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent,
args, num_args);
w = init_info_form(form, (Widget) 0, (Widget) 0);
w = init_column("status_attributes", form, (Widget) 0, w, attrib_indices);
(void) init_column("status_condition", form, (Widget) 0, w,
status_indices);
return form;
}
static void
destroy_fancy_status(wp)
struct xwindow *wp;
{
int i;
struct X_status_value *sv;
if (!wp->keep_window)
XtDestroyWidget(wp->w), wp->w = (Widget) 0;
for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++)
if (sv->type == SV_LABEL) {
free((genericptr_t) sv->name);
sv->name = 0;
}
}
/*winstat.c*/