/* SCCS Id: @(#)winstat.c 3.3 96/04/05 */ /* 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 #include #include #include #include #include #include #include #include #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], XtNdisplayCaret, False); num_args++; XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollWhenNeeded); num_args++; XtSetArg(args[num_args], 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], XtNtopMargin, &top_margin); num_args++; XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++; XtSetArg(args[num_args], XtNleftMargin, &left_margin); num_args++; XtSetArg(args[num_args], XtNrightMargin, &right_margin); num_args++; XtGetValues(wp->w, args, num_args); /* font height is ascent + descent */ wp->pixel_height = 2 * (fs->ascent + fs->descent) + 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 { 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, (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. */ Strcpy(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; #ifdef EXP_ON_BOTL 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; #else if (flagexp) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagexp = FALSE; } return; /* don't show it at all */ #endif } /* 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 = (long) u.ugold; 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; #ifdef EXP_ON_BOTL case F_EXP: val = flags.showexp ? u.uexp : 0L; break; #else case F_EXP: val = 0L; break; #endif 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); sv->name[0] = '\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) 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], XtNfromVert, top); num_args++; } if (left != (Widget) 0) { XtSetArg(args[num_args], XtNfromHoriz, left); num_args++; } XtSetArg(args[num_args], 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], 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], XtNfromVert, top); num_args++; } if (left != (Widget) 0) { XtSetArg(args[num_args], XtNfromHoriz, left); num_args++; } XtSetArg(args[num_args], 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], 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], XtNfromVert, top); num_args++; } XtSetArg(args[num_args], 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*/