1 /* NetHack 3.6 winstat.c $NHDT-Date: 1452920162 2016/01/16 04:56:02 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
6 * Status window routines. This file supports both the "traditional"
7 * tty status display and a "fancy" status display. A tty status is
8 * made if a popup window is requested, otherewise a fancy status is
9 * made. This code assumes that only one fancy status will ever be made.
10 * Currently, only one status window (of any type) is _ever_ made.
14 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
17 #include <X11/Intrinsic.h>
18 #include <X11/StringDefs.h>
19 #include <X11/Shell.h>
20 #include <X11/Xaw/AsciiText.h>
21 #include <X11/Xaw/Cardinals.h>
22 #include <X11/Xaw/Form.h>
23 #include <X11/Xaw/Paned.h>
24 #include <X11/Xaw/Label.h>
25 #include <X11/Xatom.h>
27 #ifdef PRESERVE_NO_SYSV
31 #undef PRESERVE_NO_SYSV
37 extern const char *hu_stat
[]; /* from eat.c */
38 extern const char *enc_stat
[]; /* from botl.c */
40 static void FDECL(update_fancy_status
, (struct xwindow
*));
41 static Widget
FDECL(create_fancy_status
, (Widget
, Widget
));
42 static void FDECL(destroy_fancy_status
, (struct xwindow
*));
45 create_status_window(wp
, create_popup
, parent
)
46 struct xwindow
*wp
; /* window pointer */
53 Position top_margin
, bottom_margin
, left_margin
, right_margin
;
55 wp
->type
= NHW_STATUS
;
59 * If we are not creating a popup, then we must be the "main" status
63 panic("create_status_window: no parent for fancy status");
64 wp
->status_information
= 0;
65 wp
->w
= create_fancy_status(parent
, (Widget
) 0);
69 wp
->status_information
=
70 (struct status_info_t
*) alloc(sizeof(struct status_info_t
));
72 init_text_buffer(&wp
->status_information
->text
);
75 XtSetArg(args
[num_args
], XtNallowShellResize
, False
);
77 XtSetArg(args
[num_args
], XtNinput
, False
);
80 wp
->popup
= parent
= XtCreatePopupShell(
81 "status_popup", topLevelShellWidgetClass
, toplevel
, args
, num_args
);
83 * If we're here, then this is an auxiliary status window. If we're
84 * cancelled via a delete window message, we should just pop down.
88 XtSetArg(args
[num_args
], nhStr(XtNdisplayCaret
), False
);
90 XtSetArg(args
[num_args
], nhStr(XtNscrollHorizontal
),
91 XawtextScrollWhenNeeded
);
93 XtSetArg(args
[num_args
], nhStr(XtNscrollVertical
),
94 XawtextScrollWhenNeeded
);
97 wp
->w
= XtCreateManagedWidget("status", /* name */
99 parent
, /* parent widget */
100 args
, /* set some values */
101 num_args
); /* number of values to set */
104 * Adjust the height and width of the message window so that it
105 * is two lines high and COLNO of the widest characters wide.
108 /* Get the font and margin information. */
110 XtSetArg(args
[num_args
], XtNfont
, &fs
);
112 XtSetArg(args
[num_args
], nhStr(XtNtopMargin
), &top_margin
);
114 XtSetArg(args
[num_args
], nhStr(XtNbottomMargin
), &bottom_margin
);
116 XtSetArg(args
[num_args
], nhStr(XtNleftMargin
), &left_margin
);
118 XtSetArg(args
[num_args
], nhStr(XtNrightMargin
), &right_margin
);
120 XtGetValues(wp
->w
, args
, num_args
);
122 wp
->pixel_height
= 2 * nhFontHeight(wp
->w
) + top_margin
+ bottom_margin
;
124 COLNO
* fs
->max_bounds
.width
+ left_margin
+ right_margin
;
126 /* Set the new width and height. */
128 XtSetArg(args
[num_args
], XtNwidth
, wp
->pixel_width
);
130 XtSetArg(args
[num_args
], XtNheight
, wp
->pixel_height
);
132 XtSetValues(wp
->w
, args
, num_args
);
136 destroy_status_window(wp
)
139 /* If status_information is defined, then it a "text" status window. */
140 if (wp
->status_information
) {
142 nh_XtPopdown(wp
->popup
);
143 if (!wp
->keep_window
)
144 XtDestroyWidget(wp
->popup
), wp
->popup
= (Widget
) 0;
146 free((genericptr_t
) wp
->status_information
);
147 wp
->status_information
= 0;
149 destroy_fancy_status(wp
);
151 if (!wp
->keep_window
)
156 * This assumes several things:
157 * + Status has only 2 lines
158 * + That both lines are updated in succession in line order.
159 * + We didn't set stringInPlace on the widget.
162 adjust_status(wp
, str
)
169 if (!wp
->status_information
) {
170 update_fancy_status(wp
);
174 if (wp
->cursy
== 0) {
175 clear_text_buffer(&wp
->status_information
->text
);
176 append_text_buffer(&wp
->status_information
->text
, str
, FALSE
);
179 append_text_buffer(&wp
->status_information
->text
, str
, FALSE
);
181 /* Set new buffer as text. */
183 XtSetArg(args
[num_args
], XtNstring
, wp
->status_information
->text
.text
);
185 XtSetValues(wp
->w
, args
, num_args
);
189 * -------------------------------------------------------------*/
190 static int hilight_time
= 1; /* number of turns to hilight a changed value */
192 struct X_status_value
{
193 /* we have to cast away 'const' when assigning new names */
194 const char *name
; /* text name */
195 int type
; /* status type */
196 Widget w
; /* widget of name/value pair */
197 long last_value
; /* value displayed */
198 int turn_count
; /* last time the value changed */
199 boolean set
; /* if highlighted */
200 boolean after_init
; /* don't highlight on first change (init) */
203 /* valid type values */
204 #define SV_VALUE 0 /* displays a label:value pair */
205 #define SV_LABEL 1 /* displays a changable label */
206 #define SV_NAME 2 /* displays an unchangeable name */
208 static void FDECL(hilight_label
, (Widget
));
209 static void FDECL(update_val
, (struct X_status_value
*, long));
210 static const char *FDECL(width_string
, (int));
211 static void FDECL(create_widget
, (Widget
, struct X_status_value
*, int));
212 static void FDECL(get_widths
, (struct X_status_value
*, int *, int *));
213 static void FDECL(set_widths
, (struct X_status_value
*, int, int));
214 static Widget
FDECL(init_column
, (const char *, Widget
, Widget
, Widget
,
216 static void NDECL(fixup_cond_widths
);
217 static Widget
FDECL(init_info_form
, (Widget
, Widget
, Widget
));
220 * Form entry storage indices.
236 #define F_MAXPOWER 13
244 /* status conditions grouped by columns; tty orders these differently */
248 #define F_FOODPOIS 23
252 #define F_ENCUMBER 26
267 * + Alignment needs a different init value, because -1 is an alignment.
268 * + Armor Class is an schar, so 256 is out of range.
269 * + Blank value is 0 and should never change.
271 static struct X_status_value shown_stats
[NUM_STATS
] = {
272 { "", SV_NAME
, (Widget
) 0, -1, 0, FALSE
, FALSE
}, /* 0*/
274 { "Strength", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
275 { "Dexterity", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
276 { "Constitution", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
277 { "Intelligence", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
278 { "Wisdom", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
}, /* 5*/
279 { "Charisma", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
281 { "", SV_LABEL
, (Widget
) 0, -1, 0, FALSE
, FALSE
}, /* name */
282 { "", SV_LABEL
, (Widget
) 0, -1, 0, FALSE
, FALSE
}, /* dlvl */
283 { "Gold", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
284 { "Hit Points", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
}, /*10*/
285 { "Max HP", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
286 { "Power", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
287 { "Max Power", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
288 { "Armor Class", SV_VALUE
, (Widget
) 0, 256, 0, FALSE
, FALSE
},
289 { "Level", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
}, /*15*/
290 { "Experience", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
291 { "Alignment", SV_VALUE
, (Widget
) 0, -2, 0, FALSE
, FALSE
},
292 { "Time", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
293 { "Score", SV_VALUE
, (Widget
) 0, -1, 0, FALSE
, FALSE
},
295 { "Petrifying", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
}, /*20*/
296 { "Slimed", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
297 { "Strangled", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
298 { "Food Pois", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
299 { "Term Ill", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
301 { "", SV_NAME
, (Widget
) 0, -1, 0, FALSE
, TRUE
}, /*25*/ /* hunger */
302 { "", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
}, /*encumbr */
303 { "Levitating", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
304 { "Flying", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
305 { "Riding", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
307 { "Blind", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
}, /*30*/
308 { "Deaf", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
309 { "Stunned", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
310 { "Confused", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
311 { "Hallucinating", SV_NAME
, (Widget
) 0, 0, 0, FALSE
, TRUE
},
315 * Set all widget values to a null string. This is used after all spacings
316 * have been calculated so that when the window is popped up we don't get all
317 * kinds of funny values being displayed.
323 struct X_status_value
*sv
;
326 for (i
= 0, sv
= shown_stats
; i
< NUM_STATS
; i
++, sv
++) {
329 set_value(sv
->w
, "");
334 XtSetArg(args
[0], XtNlabel
, "");
335 XtSetValues(sv
->w
, args
, ONE
);
339 impossible("null_out_status: unknown type %d\n", sv
->type
);
345 /* This is almost an exact duplicate of hilight_value() */
348 Widget w
; /* label widget */
353 XtSetArg(args
[0], XtNforeground
, &fg
);
354 XtSetArg(args
[1], XtNbackground
, &bg
);
355 XtGetValues(w
, args
, TWO
);
357 XtSetArg(args
[0], XtNforeground
, bg
);
358 XtSetArg(args
[1], XtNbackground
, fg
);
359 XtSetValues(w
, args
, TWO
);
363 update_val(attr_rec
, new_value
)
364 struct X_status_value
*attr_rec
;
370 if (attr_rec
->type
== SV_LABEL
) {
371 if (attr_rec
== &shown_stats
[F_NAME
]) {
373 buf
[0] = highc(buf
[0]);
374 Strcat(buf
, " the ");
379 Strcpy(mname
, mons
[u
.umonnum
].mname
);
380 for (k
= 0; mname
[k
] != '\0'; k
++) {
381 if (k
== 0 || mname
[k
- 1] == ' ')
382 mname
[k
] = highc(mname
[k
]);
386 Strcat(buf
, rank_of(u
.ulevel
, pl_character
[0], flags
.female
));
388 } else if (attr_rec
== &shown_stats
[F_DLEVEL
]) {
389 if (!describe_level(buf
)) {
390 Strcpy(buf
, dungeons
[u
.uz
.dnum
].dname
);
391 Sprintf(eos(buf
), ", level %d", depth(&u
.uz
));
394 impossible("update_val: unknown label type \"%s\"",
399 if (strcmp(buf
, attr_rec
->name
) == 0)
402 /* Set the label. 'name' field is const for most entries;
403 we need to cast away that const for this assignment */
404 Strcpy((char *) attr_rec
->name
, buf
);
405 XtSetArg(args
[0], XtNlabel
, buf
);
406 XtSetValues(attr_rec
->w
, args
, ONE
);
408 } else if (attr_rec
->type
== SV_NAME
) {
409 if (attr_rec
->last_value
== new_value
)
410 return; /* no change */
412 attr_rec
->last_value
= new_value
;
414 /* special cases: hunger, encumbrance, sickness */
415 if (attr_rec
== &shown_stats
[F_HUNGER
]) {
416 XtSetArg(args
[0], XtNlabel
, hu_stat
[new_value
]);
417 } else if (attr_rec
== &shown_stats
[F_ENCUMBER
]) {
418 XtSetArg(args
[0], XtNlabel
, enc_stat
[new_value
]);
419 } else if (new_value
) {
420 XtSetArg(args
[0], XtNlabel
, attr_rec
->name
);
422 XtSetArg(args
[0], XtNlabel
, "");
424 XtSetValues(attr_rec
->w
, args
, ONE
);
426 } else { /* a value pair */
427 boolean force_update
= FALSE
;
429 /* special case: time can be enabled & disabled */
430 if (attr_rec
== &shown_stats
[F_TIME
]) {
431 static boolean flagtime
= TRUE
;
433 if (flags
.time
&& !flagtime
) {
434 set_name(attr_rec
->w
, shown_stats
[F_TIME
].name
);
436 flagtime
= flags
.time
;
437 } else if (!flags
.time
&& flagtime
) {
438 set_name(attr_rec
->w
, "");
439 set_value(attr_rec
->w
, "");
440 flagtime
= flags
.time
;
446 /* special case: exp can be enabled & disabled */
447 else if (attr_rec
== &shown_stats
[F_EXP
]) {
448 static boolean flagexp
= TRUE
;
450 if (flags
.showexp
&& !flagexp
) {
451 set_name(attr_rec
->w
, shown_stats
[F_EXP
].name
);
453 flagexp
= flags
.showexp
;
454 } else if (!flags
.showexp
&& flagexp
) {
455 set_name(attr_rec
->w
, "");
456 set_value(attr_rec
->w
, "");
457 flagexp
= flags
.showexp
;
463 /* special case: score can be enabled & disabled */
464 else if (attr_rec
== &shown_stats
[F_SCORE
]) {
465 static boolean flagscore
= TRUE
;
468 if (flags
.showscore
&& !flagscore
) {
469 set_name(attr_rec
->w
, shown_stats
[F_SCORE
].name
);
471 flagscore
= flags
.showscore
;
472 } else if (!flags
.showscore
&& flagscore
) {
473 set_name(attr_rec
->w
, "");
474 set_value(attr_rec
->w
, "");
475 flagscore
= flags
.showscore
;
481 set_name(attr_rec
->w
, "");
482 set_value(attr_rec
->w
, "");
489 /* special case: when polymorphed, show "HD", disable exp */
490 else if (attr_rec
== &shown_stats
[F_LEVEL
]) {
491 static boolean lev_was_poly
= FALSE
;
493 if (Upolyd
&& !lev_was_poly
) {
495 set_name(attr_rec
->w
, "HD");
497 } else if (Upolyd
&& lev_was_poly
) {
499 set_name(attr_rec
->w
, shown_stats
[F_LEVEL
].name
);
500 lev_was_poly
= FALSE
;
502 } else if (attr_rec
== &shown_stats
[F_EXP
]) {
503 static boolean exp_was_poly
= FALSE
;
505 if (Upolyd
&& !exp_was_poly
) {
507 set_name(attr_rec
->w
, "");
508 set_value(attr_rec
->w
, "");
510 } else if (Upolyd
&& exp_was_poly
) {
512 set_name(attr_rec
->w
, shown_stats
[F_EXP
].name
);
513 exp_was_poly
= FALSE
;
516 return; /* no display for exp when poly */
519 if (attr_rec
->last_value
== new_value
&& !force_update
) /* same */
522 attr_rec
->last_value
= new_value
;
524 /* Special cases: strength, alignment and "clear". */
525 if (attr_rec
== &shown_stats
[F_STR
]) {
526 if (new_value
> 18) {
528 Sprintf(buf
, "%ld", new_value
- 100);
529 else if (new_value
< 118)
530 Sprintf(buf
, "18/%02ld", new_value
- 18);
532 Strcpy(buf
, "18/**");
534 Sprintf(buf
, "%ld", new_value
);
536 } else if (attr_rec
== &shown_stats
[F_ALIGN
]) {
538 (new_value
== A_CHAOTIC
)
540 : (new_value
== A_NEUTRAL
) ? "Neutral" : "Lawful");
542 Sprintf(buf
, "%ld", new_value
);
544 set_value(attr_rec
->w
, buf
);
548 * Now hilight the changed information. Names, time and score don't
549 * hilight. If first time, don't hilight. If already lit, don't do
552 if (attr_rec
->type
!= SV_NAME
&& attr_rec
!= &shown_stats
[F_TIME
]) {
553 if (attr_rec
->after_init
) {
554 if (!attr_rec
->set
) {
555 if (attr_rec
->type
== SV_LABEL
)
556 hilight_label(attr_rec
->w
);
558 hilight_value(attr_rec
->w
);
559 attr_rec
->set
= TRUE
;
561 attr_rec
->turn_count
= 0;
563 attr_rec
->after_init
= TRUE
;
569 * Update the displayed status. The current code in botl.c updates
570 * two lines of information. Both lines are always updated one after
571 * the other. So only do our update when we update the second line.
573 * Information on the first line:
574 * name, attributes, alignment, score
576 * Information on the second line:
577 * dlvl, gold, hp, power, ac, {level & exp or HD **}, time,
578 * status * (stone, slime, strngl, foodpois, termill,
579 * hunger, encumbrance, lev, fly, ride,
580 * blind, deaf, stun, conf, hallu)
582 * [*] order of status fields is different on tty.
583 * [**] HD is shown instead of level and exp if Upolyd.
586 update_fancy_status(wp
)
589 struct X_status_value
*sv
;
594 return; /* do a complete update when line 0 is done */
596 for (i
= 0, sv
= shown_stats
; i
< NUM_STATS
; i
++, sv
++) {
602 val
= (long) ACURR(A_STR
);
605 val
= (long) ACURR(A_DEX
);
608 val
= (long) ACURR(A_CON
);
611 val
= (long) ACURR(A_INT
);
614 val
= (long) ACURR(A_WIS
);
617 val
= (long) ACURR(A_CHA
);
620 * Label stats. With the exceptions of hunger, encumbrance, sick
621 * these are either on or off. Pleae leave the ternary operators
622 * the way they are. I want to specify 0 or 1, not a boolean.
628 val
= (long) near_capacity();
631 val
= Levitation
? 1L : 0L;
634 val
= Flying
? 1L : 0L;
637 val
= u
.usteed
? 1L : 0L;
639 /* fatal status conditions */
641 val
= Stoned
? 1L : 0L;
644 val
= Slimed
? 1L : 0L;
647 val
= Strangled
? 1L : 0L;
650 val
= (Sick
&& (u
.usick_type
& SICK_VOMITABLE
)) ? 1L : 0L;
653 val
= (Sick
&& (u
.usick_type
& SICK_NONVOMITABLE
)) ? 1L : 0L;
655 /* non-fatal status conditions */
657 val
= Blind
? 1L : 0L;
660 val
= Deaf
? 1L : 0L;
663 val
= Stunned
? 1L : 0L;
666 val
= Confusion
? 1L : 0L;
669 val
= Hallucination
? 1L : 0L;
679 val
= money_cnt(invent
);
681 val
= 0L; /* ought to issue impossible() and discard gold */
684 val
= (long) (Upolyd
? (u
.mh
> 0 ? u
.mh
: 0)
685 : (u
.uhp
> 0 ? u
.uhp
: 0));
688 val
= (long) (Upolyd
? u
.mhmax
: u
.uhpmax
);
694 val
= (long) u
.uenmax
;
700 val
= (long) (Upolyd
? mons
[u
.umonnum
].mlevel
: u
.ulevel
);
703 val
= flags
.showexp
? u
.uexp
: 0L;
706 val
= (long) u
.ualign
.type
;
709 val
= flags
.time
? (long) moves
: 0L;
713 val
= flags
.showscore
? botl_score() : 0L;
720 * There is a possible infinite loop that occurs with:
722 * impossible->pline->flush_screen->bot->bot{1,2}->
723 * putstr->adjust_status->update_other->impossible
725 * Break out with this.
727 static boolean active
= FALSE
;
731 impossible("update_other: unknown shown value");
743 * Turn off hilighted status values after a certain amount of turns.
749 struct X_status_value
*sv
;
751 for (sv
= shown_stats
, i
= 0; i
< NUM_STATS
; i
++, sv
++) {
755 if (sv
->turn_count
++ >= hilight_time
) {
756 if (sv
->type
== SV_LABEL
)
757 hilight_label(sv
->w
);
759 hilight_value(sv
->w
);
765 /* Initialize alternate status =============================================
768 /* Return a string for the initial width. */
770 width_string(sv_index
)
784 return "088"; /* all but str never get bigger */
804 return shown_stats
[sv_index
].name
;
820 /* strongest hero can pick up roughly 30% of this much */
821 return "999999"; /* same limit as tty */
825 return "123456789"; /* a tenth digit will still fit legibly */
829 impossible("width_string: unknown index %d\n", sv_index
);
834 create_widget(parent
, sv
, sv_index
)
836 struct X_status_value
*sv
;
844 sv
->w
= create_value(parent
, sv
->name
);
845 set_value(sv
->w
, width_string(sv_index
));
848 /* Labels get their own buffer. */
849 sv
->name
= (char *) alloc(BUFSZ
);
850 /* we need to cast away 'const' when assigning a value */
851 *(char *) (sv
->name
) = '\0';
854 XtSetArg(args
[num_args
], XtNborderWidth
, 0);
856 XtSetArg(args
[num_args
], XtNinternalHeight
, 0);
858 sv
->w
= XtCreateManagedWidget((sv_index
== F_NAME
)
861 labelWidgetClass
, parent
,
866 XtSetArg(args
[0], XtNlabel
, width_string(sv_index
)); num_args
++;
867 XtSetArg(args
[num_args
], XtNborderWidth
, 0); num_args
++;
868 XtSetArg(args
[num_args
], XtNinternalHeight
, 0); num_args
++;
869 sv
->w
= XtCreateManagedWidget(sv
->name
, labelWidgetClass
, parent
,
873 panic("create_widget: unknown type %d", sv
->type
);
878 * Get current width of value. width2p is only valid for SV_VALUE types.
881 get_widths(sv
, width1p
, width2p
)
882 struct X_status_value
*sv
;
883 int *width1p
, *width2p
;
890 *width1p
= get_name_width(sv
->w
);
891 *width2p
= get_value_width(sv
->w
);
895 XtSetArg(args
[0], XtNwidth
, &width
);
896 XtGetValues(sv
->w
, args
, ONE
);
901 panic("get_widths: unknown type %d", sv
->type
);
906 set_widths(sv
, width1
, width2
)
907 struct X_status_value
*sv
;
914 set_name_width(sv
->w
, width1
);
915 set_value_width(sv
->w
, width2
);
919 XtSetArg(args
[0], XtNwidth
, (width1
+ width2
));
920 XtSetValues(sv
->w
, args
, ONE
);
923 panic("set_widths: unknown type %d", sv
->type
);
928 init_column(name
, parent
, top
, left
, col_indices
)
930 Widget parent
, top
, left
;
936 int max_width1
, width1
, max_width2
, width2
;
938 struct X_status_value
*sv
;
941 if (top
!= (Widget
) 0) {
942 XtSetArg(args
[num_args
], nhStr(XtNfromVert
), top
);
945 if (left
!= (Widget
) 0) {
946 XtSetArg(args
[num_args
], nhStr(XtNfromHoriz
), left
);
949 XtSetArg(args
[num_args
], nhStr(XtNdefaultDistance
), 0);
951 form
= XtCreateManagedWidget(name
, formWidgetClass
, parent
,
954 max_width1
= max_width2
= 0;
955 for (ip
= col_indices
; *ip
>= 0; ip
++) {
956 sv
= &shown_stats
[*ip
];
957 create_widget(form
, sv
, *ip
); /* will set init width */
958 if (ip
!= col_indices
) { /* not first */
960 XtSetArg(args
[num_args
], nhStr(XtNfromVert
),
961 shown_stats
[*(ip
- 1)].w
);
963 XtSetValues(sv
->w
, args
, num_args
);
965 get_widths(sv
, &width1
, &width2
);
966 if (width1
> max_width1
)
968 if (width2
> max_width2
)
971 for (ip
= col_indices
; *ip
>= 0; ip
++) {
972 set_widths(&shown_stats
[*ip
], max_width1
, max_width2
);
975 /* There is room behind the end marker for the two widths. */
983 * These are the orders of the displayed columns. Change to suit. The -1
984 * indicates the end of the column. The two numbers after that are used
985 * to store widths that are calculated at run-time.
987 static int attrib_indices
[] = { F_STR
, F_DEX
, F_CON
, F_INT
, F_WIS
, F_CHA
,
989 /* including F_DUMMY makes the three status condition columns evenly
990 spaced with regard to the adjacent characteristics (Str,Dex,&c) column;
991 we lose track of the Widget pointer for them, each use clobbering the
992 one before, leaving the one from leftover_indices[]; since they're never
993 updated, that shouldn't matter */
994 static int status_indices
[3][9] = { { F_STONE
, F_SLIME
, F_STRNGL
,
995 F_FOODPOIS
, F_TERMILL
, F_DUMMY
,
997 { F_HUNGER
, F_ENCUMBER
,
998 F_LEV
, F_FLY
, F_RIDE
, F_DUMMY
,
1000 { F_BLIND
, F_DEAF
, F_STUN
,
1001 F_CONF
, F_HALLU
, F_DUMMY
,
1003 /* used to fill up the empty space to right of 3rd status condition column */
1004 static int leftover_indices
[] = { F_DUMMY
, -1, 0, 0 };
1006 static int col1_indices
[] = { F_HP
, F_POWER
, F_AC
, F_LEVEL
, F_GOLD
,
1007 F_SCORE
, -1, 0, 0 };
1008 static int col2_indices
[] = { F_MAXHP
, F_MAXPOWER
, F_ALIGN
, F_EXP
, F_TIME
,
1011 * Produce a form that looks like the following:
1015 * col1_indices[0] col2_indices[0]
1016 * col1_indices[1] col2_indices[1]
1019 * col1_indices[n] col2_indices[n]
1021 * TODO: increase the space between the two columns.
1024 init_info_form(parent
, top
, left
)
1025 Widget parent
, top
, left
;
1028 struct X_status_value
*sv_name
, *sv_dlevel
;
1031 int total_width
, *ip
;
1034 if (top
!= (Widget
) 0) {
1035 XtSetArg(args
[num_args
], nhStr(XtNfromVert
), top
);
1038 if (left
!= (Widget
) 0) {
1039 XtSetArg(args
[num_args
], nhStr(XtNfromHoriz
), left
);
1042 XtSetArg(args
[num_args
], nhStr(XtNdefaultDistance
), 0);
1044 form
= XtCreateManagedWidget("status_info", formWidgetClass
, parent
, args
,
1048 sv_name
= &shown_stats
[F_NAME
];
1049 create_widget(form
, sv_name
, F_NAME
);
1052 sv_dlevel
= &shown_stats
[F_DLEVEL
];
1053 create_widget(form
, sv_dlevel
, F_DLEVEL
);
1056 XtSetArg(args
[num_args
], nhStr(XtNfromVert
), sv_name
->w
);
1058 XtSetValues(sv_dlevel
->w
, args
, num_args
);
1060 /* two columns beneath */
1061 col1
= init_column("name_col1", form
, sv_dlevel
->w
, (Widget
) 0,
1063 (void) init_column("name_col2", form
, sv_dlevel
->w
, col1
, col2_indices
);
1065 /* Add calculated widths. */
1066 for (ip
= col1_indices
; *ip
>= 0; ip
++)
1068 total_width
= *++ip
;
1069 total_width
+= *++ip
;
1070 for (ip
= col2_indices
; *ip
>= 0; ip
++)
1072 total_width
+= *++ip
;
1073 total_width
+= *++ip
;
1075 XtSetArg(args
[0], XtNwidth
, total_width
);
1076 XtSetValues(sv_name
->w
, args
, ONE
);
1077 XtSetArg(args
[0], XtNwidth
, total_width
);
1078 XtSetValues(sv_dlevel
->w
, args
, ONE
);
1083 /* give the three status condition columns the same width */
1087 int pass
, i
, *ip
, w1
, w2
;
1090 for (pass
= 1; pass
<= 2; ++pass
) { /* two passes... */
1091 for (i
= 0; i
< 3; i
++) { /* three columns */
1092 for (ip
= status_indices
[i
]; *ip
!= -1; ++ip
) { /* X fields */
1093 /* pass 1: find -1; pass 2: update field widths, find -1 */
1095 set_widths(&shown_stats
[*ip
], w1
, w2
);
1097 /* found -1; the two slots beyond it contain column widths */
1098 if (pass
== 1) { /* pass 1: collect maxima */
1103 } else { /* pass 2: update column widths with maxima */
1108 /* ascetics: expand the maximum width to make cond columns wider */
1118 * Create the layout for the fancy status. Return a form widget that
1119 * contains everything.
1122 create_fancy_status(parent
, top
)
1125 Widget form
; /* The form that surrounds everything. */
1133 if (top
!= (Widget
) 0) {
1134 XtSetArg(args
[num_args
], nhStr(XtNfromVert
), top
);
1137 XtSetArg(args
[num_args
], nhStr(XtNdefaultDistance
), 0);
1139 XtSetArg(args
[num_args
], XtNborderWidth
, 0);
1141 XtSetArg(args
[num_args
], XtNorientation
, XtorientHorizontal
);
1143 form
= XtCreateManagedWidget("fancy_status", panedWidgetClass
, parent
,
1146 w
= init_info_form(form
, (Widget
) 0, (Widget
) 0);
1147 w
= init_column("status_attributes", form
, (Widget
) 0, w
, attrib_indices
);
1148 for (i
= 0; i
< 3; i
++) {
1149 Sprintf(buf
, "status_condition%d", i
+ 1);
1150 w
= init_column(buf
, form
, (Widget
) 0, w
, status_indices
[i
]);
1152 fixup_cond_widths(); /* make all 3 status_conditionN columns same width */
1153 w
= init_column("status_leftover", form
, (Widget
) 0, w
, leftover_indices
);
1159 destroy_fancy_status(wp
)
1163 struct X_status_value
*sv
;
1165 if (!wp
->keep_window
)
1166 XtDestroyWidget(wp
->w
), wp
->w
= (Widget
) 0;
1168 for (i
= 0, sv
= shown_stats
; i
< NUM_STATS
; i
++, sv
++)
1169 if (sv
->type
== SV_LABEL
) {
1170 free((genericptr_t
) sv
->name
);