1 /* SCCS Id: @(#)winstat.c 3.4 1996/04/05 */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /*
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.
11 */
12
13 #ifndef SYSV
14 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
15 #endif
16
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>
26
27 #ifdef PRESERVE_NO_SYSV
28 # ifdef SYSV
29 # undef SYSV
30 # endif
31 # undef PRESERVE_NO_SYSV
32 #endif
33
34 #include "hack.h"
35 #include "winX.h"
36
37 extern const char *hu_stat[]; /* from eat.c */
38 extern const char *enc_stat[]; /* from botl.c */
39
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 *));
43
44 void
create_status_window(wp,create_popup,parent)45 create_status_window(wp, create_popup, parent)
46 struct xwindow *wp; /* window pointer */
47 boolean create_popup;
48 Widget parent;
49 {
50 XFontStruct *fs;
51 Arg args[8];
52 Cardinal num_args;
53 Position top_margin, bottom_margin, left_margin, right_margin;
54
55 wp->type = NHW_STATUS;
56
57 if (!create_popup) {
58 /*
59 * If we are not creating a popup, then we must be the "main" status
60 * window.
61 */
62 if (!parent)
63 panic("create_status_window: no parent for fancy status");
64 wp->status_information = 0;
65 wp->w = create_fancy_status(parent, (Widget) 0);
66 return;
67 }
68
69 wp->status_information =
70 (struct status_info_t *) alloc(sizeof(struct status_info_t));
71
72 init_text_buffer(&wp->status_information->text);
73
74 num_args = 0;
75 XtSetArg(args[num_args], XtNallowShellResize, False); num_args++;
76 XtSetArg(args[num_args], XtNinput, False); num_args++;
77
78 wp->popup = parent = XtCreatePopupShell("status_popup",
79 topLevelShellWidgetClass,
80 toplevel, args, num_args);
81 /*
82 * If we're here, then this is an auxiliary status window. If we're
83 * cancelled via a delete window message, we should just pop down.
84 */
85
86 num_args = 0;
87 XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++;
88 XtSetArg(args[num_args], XtNscrollHorizontal,
89 XawtextScrollWhenNeeded); num_args++;
90 XtSetArg(args[num_args], XtNscrollVertical,
91 XawtextScrollWhenNeeded); num_args++;
92
93 wp->w = XtCreateManagedWidget(
94 "status", /* name */
95 asciiTextWidgetClass,
96 parent, /* parent widget */
97 args, /* set some values */
98 num_args); /* number of values to set */
99
100 /*
101 * Adjust the height and width of the message window so that it
102 * is two lines high and COLNO of the widest characters wide.
103 */
104
105 /* Get the font and margin information. */
106 num_args = 0;
107 XtSetArg(args[num_args], XtNfont, &fs); num_args++;
108 XtSetArg(args[num_args], XtNtopMargin, &top_margin); num_args++;
109 XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
110 XtSetArg(args[num_args], XtNleftMargin, &left_margin); num_args++;
111 XtSetArg(args[num_args], XtNrightMargin, &right_margin); num_args++;
112 XtGetValues(wp->w, args, num_args);
113
114 wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin;
115 wp->pixel_width = COLNO * fs->max_bounds.width +
116 left_margin + right_margin;
117
118 /* Set the new width and height. */
119 num_args = 0;
120 XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++;
121 XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
122 XtSetValues(wp->w, args, num_args);
123 }
124
125 void
destroy_status_window(wp)126 destroy_status_window(wp)
127 struct xwindow *wp;
128 {
129 /* If status_information is defined, then it a "text" status window. */
130 if (wp->status_information) {
131 if (wp->popup) {
132 nh_XtPopdown(wp->popup);
133 if (!wp->keep_window)
134 XtDestroyWidget(wp->popup), wp->popup = (Widget)0;
135 }
136 free((genericptr_t)wp->status_information);
137 wp->status_information = 0;
138 } else {
139 destroy_fancy_status(wp);
140 }
141 if (!wp->keep_window)
142 wp->type = NHW_NONE;
143 }
144
145
146 /*
147 * This assumes several things:
148 * + Status has only 2 lines
149 * + That both lines are updated in succession in line order.
150 * + We didn't set stringInPlace on the widget.
151 */
152 void
adjust_status(wp,str)153 adjust_status(wp, str)
154 struct xwindow *wp;
155 const char *str;
156 {
157 Arg args[2];
158 Cardinal num_args;
159
160 if (!wp->status_information) {
161 update_fancy_status(wp);
162 return;
163 }
164
165 if (wp->cursy == 0) {
166 clear_text_buffer(&wp->status_information->text);
167 append_text_buffer(&wp->status_information->text, str, FALSE);
168 return;
169 }
170 append_text_buffer(&wp->status_information->text, str, FALSE);
171
172 /* Set new buffer as text. */
173 num_args = 0;
174 XtSetArg(args[num_args], XtNstring, wp->status_information->text.text);
175 num_args++;
176 XtSetValues(wp->w, args, num_args);
177 }
178
179
180 /* Fancy Status -------------------------------------------------------------*/
181 static int hilight_time = 1; /* number of turns to hilight a changed value */
182
183 struct X_status_value {
184 char *name; /* text name */
185 int type; /* status type */
186 Widget w; /* widget of name/value pair */
187 long last_value; /* value displayed */
188 int turn_count; /* last time the value changed */
189 boolean set; /* if hilighed */
190 boolean after_init; /* don't hilight on first change (init) */
191 };
192
193 /* valid type values */
194 #define SV_VALUE 0 /* displays a label:value pair */
195 #define SV_LABEL 1 /* displays a changable label */
196 #define SV_NAME 2 /* displays an unchangeable name */
197
198 static void FDECL(hilight_label, (Widget));
199 static void FDECL(update_val, (struct X_status_value *,long));
200 static const char *FDECL(width_string, (int));
201 static void FDECL(create_widget, (Widget,struct X_status_value *,int));
202 static void FDECL(get_widths, (struct X_status_value *,int *,int *));
203 static void FDECL(set_widths, (struct X_status_value *,int,int));
204 static Widget FDECL(init_column, (char *,Widget,Widget,Widget,int *));
205 static Widget FDECL(init_info_form, (Widget,Widget,Widget));
206
207 /*
208 * Form entry storage indices.
209 */
210 #define F_STR 0
211 #define F_DEX 1
212 #define F_CON 2
213 #define F_INT 3
214 #define F_WIS 4
215 #define F_CHA 5
216
217 #define F_NAME 6
218 #define F_DLEVEL 7
219 #define F_GOLD 8
220 #define F_HP 9
221 #define F_MAXHP 10
222 #define F_POWER 11
223 #define F_MAXPOWER 12
224 #define F_AC 13
225 #define F_LEVEL 14
226 #define F_EXP 15
227 #define F_ALIGN 16
228 #define F_TIME 17
229 #define F_SCORE 18
230
231 #define F_HUNGER 19
232 #define F_CONFUSED 20
233 #define F_SICK 21
234 #define F_BLIND 22
235 #define F_STUNNED 23
236 #define F_HALLU 24
237 #define F_ENCUMBER 25
238
239 #define NUM_STATS 26
240
241 /*
242 * Notes:
243 * + Alignment needs a different init value, because -1 is an alignment.
244 * + Armor Class is an schar, so 256 is out of range.
245 * + Blank value is 0 and should never change.
246 */
247 static struct X_status_value shown_stats[NUM_STATS] = {
248 { "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0*/
249 { "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
250 { "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
251 { "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
252 { "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
253 { "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/
254
255 { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */
256 { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */
257 { "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
258 { "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
259 { "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/
260 { "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
261 { "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
262 { "Armor Class", SV_VALUE, (Widget) 0,256, 0, FALSE, FALSE },
263 { "Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
264 { "Experience", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/
265 { "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
266 { "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
267 { "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
268
269 { "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /* hunger*/
270 { "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/
271 { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* sick */
272 { "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
273 { "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
274 { "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
275 { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*encumbr*/
276 };
277
278
279 /*
280 * Set all widget values to a null string. This is used after all spacings
281 * have been calculated so that when the window is popped up we don't get all
282 * kinds of funny values being displayed.
283 */
284 void
null_out_status()285 null_out_status()
286 {
287 int i;
288 struct X_status_value *sv;
289 Arg args[1];
290
291 for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
292 switch (sv->type) {
293 case SV_VALUE:
294 set_value(sv->w, "");
295 break;
296
297 case SV_LABEL:
298 case SV_NAME:
299 XtSetArg(args[0], XtNlabel, "");
300 XtSetValues(sv->w, args, ONE);
301 break;
302
303 default:
304 impossible("null_out_status: unknown type %d\n", sv->type);
305 break;
306 }
307 }
308 }
309
310 /* This is almost an exact duplicate of hilight_value() */
311 static void
hilight_label(w)312 hilight_label(w)
313 Widget w; /* label widget */
314 {
315 Arg args[2];
316 Pixel fg, bg;
317
318 XtSetArg(args[0], XtNforeground, &fg);
319 XtSetArg(args[1], XtNbackground, &bg);
320 XtGetValues(w, args, TWO);
321
322 XtSetArg(args[0], XtNforeground, bg);
323 XtSetArg(args[1], XtNbackground, fg);
324 XtSetValues(w, args, TWO);
325 }
326
327
328 static void
update_val(attr_rec,new_value)329 update_val(attr_rec, new_value)
330 struct X_status_value *attr_rec;
331 long new_value;
332 {
333 char buf[BUFSZ];
334 Arg args[4];
335
336 if (attr_rec->type == SV_LABEL) {
337
338 if (attr_rec == &shown_stats[F_NAME]) {
339
340 Strcpy(buf, plname);
341 if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
342 Strcat(buf, " the ");
343 if (u.mtimedone) {
344 char mname[BUFSZ];
345 int k = 0;
346
347 Strcpy(mname, mons[u.umonnum].mname);
348 while(mname[k] != 0) {
349 if ((k == 0 || (k > 0 && mname[k-1] == ' ')) &&
350 'a' <= mname[k] && mname[k] <= 'z')
351 mname[k] += 'A' - 'a';
352 k++;
353 }
354 Strcat(buf, mname);
355 } else
356 Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
357
358 } else if (attr_rec == &shown_stats[F_DLEVEL]) {
359 if (!describe_level(buf)) {
360 Strcpy(buf, dungeons[u.uz.dnum].dname);
361 Sprintf(eos(buf), ", level %d", depth(&u.uz));
362 }
363 } else {
364 impossible("update_val: unknown label type \"%s\"",
365 attr_rec->name);
366 return;
367 }
368
369 if (strcmp(buf, attr_rec->name) == 0) return; /* same */
370
371 /* Set the label. */
372 Strcpy(attr_rec->name, buf);
373 XtSetArg(args[0], XtNlabel, buf);
374 XtSetValues(attr_rec->w, args, ONE);
375
376 } else if (attr_rec->type == SV_NAME) {
377
378 if (attr_rec->last_value == new_value) return; /* no change */
379
380 attr_rec->last_value = new_value;
381
382 /* special cases: hunger, encumbrance, sickness */
383 if (attr_rec == &shown_stats[F_HUNGER]) {
384 XtSetArg(args[0], XtNlabel, hu_stat[new_value]);
385 } else if (attr_rec == &shown_stats[F_ENCUMBER]) {
386 XtSetArg(args[0], XtNlabel, enc_stat[new_value]);
387 } else if (attr_rec == &shown_stats[F_SICK]) {
388 buf[0] = 0;
389 if (Sick) {
390 if (u.usick_type & SICK_VOMITABLE)
391 Strcat(buf, "FoodPois");
392 if (u.usick_type & SICK_NONVOMITABLE) {
393 if (u.usick_type & SICK_VOMITABLE)
394 Strcat(buf, " ");
395 Strcat(buf, "Ill");
396 }
397 }
398 XtSetArg(args[0], XtNlabel, buf);
399 } else if (new_value) {
400 XtSetArg(args[0], XtNlabel, attr_rec->name);
401 } else {
402 XtSetArg(args[0], XtNlabel, "");
403 }
404 XtSetValues(attr_rec->w, args, ONE);
405
406 } else { /* a value pair */
407 boolean force_update = FALSE;
408
409 /* special case: time can be enabled & disabled */
410 if (attr_rec == &shown_stats[F_TIME]) {
411 static boolean flagtime = TRUE;
412
413 if(flags.time && !flagtime) {
414 set_name(attr_rec->w, shown_stats[F_TIME].name);
415 force_update = TRUE;
416 flagtime = flags.time;
417 } else if(!flags.time && flagtime) {
418 set_name(attr_rec->w, "");
419 set_value(attr_rec->w, "");
420 flagtime = flags.time;
421 }
422 if(!flagtime) return;
423 }
424
425 /* special case: exp can be enabled & disabled */
426 else if (attr_rec == &shown_stats[F_EXP]) {
427 static boolean flagexp = TRUE;
428 #ifdef EXP_ON_BOTL
429
430 if (flags.showexp && !flagexp) {
431 set_name(attr_rec->w, shown_stats[F_EXP].name);
432 force_update = TRUE;
433 flagexp = flags.showexp;
434 } else if(!flags.showexp && flagexp) {
435 set_name(attr_rec->w, "");
436 set_value(attr_rec->w, "");
437 flagexp = flags.showexp;
438 }
439 if (!flagexp) return;
440 #else
441 if (flagexp) {
442 set_name(attr_rec->w, "");
443 set_value(attr_rec->w, "");
444 flagexp = FALSE;
445 }
446 return; /* don't show it at all */
447 #endif
448 }
449
450 /* special case: score can be enabled & disabled */
451 else if (attr_rec == &shown_stats[F_SCORE]) {
452 static boolean flagscore = TRUE;
453 #ifdef SCORE_ON_BOTL
454
455 if(flags.showscore && !flagscore) {
456 set_name(attr_rec->w, shown_stats[F_SCORE].name);
457 force_update = TRUE;
458 flagscore = flags.showscore;
459 } else if(!flags.showscore && flagscore) {
460 set_name(attr_rec->w, "");
461 set_value(attr_rec->w, "");
462 flagscore = flags.showscore;
463 }
464 if(!flagscore) return;
465 #else
466 if (flagscore) {
467 set_name(attr_rec->w, "");
468 set_value(attr_rec->w, "");
469 flagscore = FALSE;
470 }
471 return;
472 #endif
473 }
474
475 /* special case: when polymorphed, show "HD", disable exp */
476 else if (attr_rec == &shown_stats[F_LEVEL]) {
477 static boolean lev_was_poly = FALSE;
478
479 if (u.mtimedone && !lev_was_poly) {
480 force_update = TRUE;
481 set_name(attr_rec->w, "HD");
482 lev_was_poly = TRUE;
483 } else if (!u.mtimedone && lev_was_poly) {
484 force_update = TRUE;
485 set_name(attr_rec->w, shown_stats[F_LEVEL].name);
486 lev_was_poly = FALSE;
487 }
488 } else if (attr_rec == &shown_stats[F_EXP]) {
489 static boolean exp_was_poly = FALSE;
490
491 if (u.mtimedone && !exp_was_poly) {
492 force_update = TRUE;
493 set_name(attr_rec->w, "");
494 set_value(attr_rec->w, "");
495 exp_was_poly = TRUE;
496 } else if (!u.mtimedone && exp_was_poly) {
497 force_update = TRUE;
498 set_name(attr_rec->w, shown_stats[F_EXP].name);
499 exp_was_poly = FALSE;
500 }
501 if (u.mtimedone) return; /* no display for exp when poly */
502 }
503
504 if (attr_rec->last_value == new_value && !force_update) /* same */
505 return;
506
507 attr_rec->last_value = new_value;
508
509 /* Special cases: strength, alignment and "clear". */
510 if (attr_rec == &shown_stats[F_STR]) {
511 if(new_value > 18) {
512 if (new_value > 118)
513 Sprintf(buf,"%ld", new_value-100);
514 else if(new_value < 118)
515 Sprintf(buf, "18/%02ld", new_value-18);
516 else
517 Strcpy(buf, "18/**");
518 } else {
519 Sprintf(buf, "%ld", new_value);
520 }
521 } else if (attr_rec == &shown_stats[F_ALIGN]) {
522
523 Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" :
524 (new_value == A_NEUTRAL) ? "Neutral" :
525 "Lawful" );
526 } else {
527 Sprintf(buf, "%ld", new_value);
528 }
529 set_value(attr_rec->w, buf);
530 }
531
532 /*
533 * Now hilight the changed information. Names, time and score don't
534 * hilight. If first time, don't hilight. If already lit, don't do
535 * it again.
536 */
537 if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) {
538 if (attr_rec->after_init) {
539 if(!attr_rec->set) {
540 if (attr_rec->type == SV_LABEL)
541 hilight_label(attr_rec->w);
542 else
543 hilight_value(attr_rec->w);
544 attr_rec->set = TRUE;
545 }
546 attr_rec->turn_count = 0;
547 } else {
548 attr_rec->after_init = TRUE;
549 }
550 }
551 }
552
553 /*
554 * Update the displayed status. The current code in botl.c updates
555 * two lines of information. Both lines are always updated one after
556 * the other. So only do our update when we update the second line.
557 *
558 * Information on the first line:
559 * name, attributes, alignment, score
560 *
561 * Information on the second line:
562 * dlvl, gold, hp, power, ac, {level & exp or HD **}
563 * status (hunger, conf, halu, stun, sick, blind), time, encumbrance
564 *
565 * [**] HD is shown instead of level and exp if mtimedone is non-zero.
566 */
567 static void
update_fancy_status(wp)568 update_fancy_status(wp)
569 struct xwindow *wp;
570 {
571 struct X_status_value *sv;
572 long val;
573 int i;
574
575 if (wp->cursy != 0) return; /* do a complete update when line 0 is done */
576
577 for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
578 switch (i) {
579 case F_STR: val = (long) ACURR(A_STR); break;
580 case F_DEX: val = (long) ACURR(A_DEX); break;
581 case F_CON: val = (long) ACURR(A_CON); break;
582 case F_INT: val = (long) ACURR(A_INT); break;
583 case F_WIS: val = (long) ACURR(A_WIS); break;
584 case F_CHA: val = (long) ACURR(A_CHA); break;
585 /*
586 * Label stats. With the exceptions of hunger, encumbrance, sick
587 * these are either on or off. Pleae leave the ternary operators
588 * the way they are. I want to specify 0 or 1, not a boolean.
589 */
590 case F_HUNGER: val = (long) u.uhs; break;
591 case F_CONFUSED: val = (long) Confusion ? 1L : 0L; break;
592 case F_SICK: val = (long) Sick ? (long)u.usick_type
593 : 0L; break;
594 case F_BLIND: val = (long) Blind ? 1L : 0L; break;
595 case F_STUNNED: val = (long) Stunned ? 1L : 0L; break;
596 case F_HALLU: val = (long) Hallucination ? 1L : 0L; break;
597 case F_ENCUMBER: val = (long) near_capacity(); break;
598
599 case F_NAME: val = (long) 0L; break; /* special */
600 case F_DLEVEL: val = (long) 0L; break; /* special */
601 #ifndef GOLDOBJ
602 case F_GOLD: val = (long) u.ugold; break;
603 #else
604 case F_GOLD: val = money_cnt(invent); break;
605 #endif
606 case F_HP: val = (long) (u.mtimedone ?
607 (u.mh > 0 ? u.mh : 0):
608 (u.uhp > 0 ? u.uhp : 0)); break;
609 case F_MAXHP: val = (long) (u.mtimedone ? u.mhmax :
610 u.uhpmax); break;
611 case F_POWER: val = (long) u.uen; break;
612 case F_MAXPOWER: val = (long) u.uenmax; break;
613 case F_AC: val = (long) u.uac; break;
614 case F_LEVEL: val = (long) (u.mtimedone ?
615 mons[u.umonnum].mlevel :
616 u.ulevel); break;
617 #ifdef EXP_ON_BOTL
618 case F_EXP: val = flags.showexp ? u.uexp : 0L; break;
619 #else
620 case F_EXP: val = 0L; break;
621 #endif
622 case F_ALIGN: val = (long) u.ualign.type; break;
623 case F_TIME: val = flags.time ? (long) moves : 0L; break;
624 #ifdef SCORE_ON_BOTL
625 case F_SCORE: val = flags.showscore ? botl_score():0L; break;
626 #else
627 case F_SCORE: val = 0L; break;
628 #endif
629 default:
630 {
631 /*
632 * There is a possible infinite loop that occurs with:
633 *
634 * impossible->pline->flush_screen->bot->bot{1,2}->
635 * putstr->adjust_status->update_other->impossible
636 *
637 * Break out with this.
638 */
639 static boolean active = FALSE;
640 if (!active) {
641 active = TRUE;
642 impossible("update_other: unknown shown value");
643 active = FALSE;
644 }
645 val = 0;
646 break;
647 }
648 }
649 update_val(sv, val);
650 }
651 }
652
653 /*
654 * Turn off hilighted status values after a certain amount of turns.
655 */
656 void
check_turn_events()657 check_turn_events()
658 {
659 int i;
660 struct X_status_value *sv;
661
662 for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
663 if (!sv->set) continue;
664
665 if (sv->turn_count++ >= hilight_time) {
666 if (sv->type == SV_LABEL)
667 hilight_label(sv->w);
668 else
669 hilight_value(sv->w);
670 sv->set = FALSE;
671 }
672 }
673 }
674
675 /* Initialize alternate status ============================================= */
676
677 /* Return a string for the initial width. */
678 static const char *
width_string(sv_index)679 width_string(sv_index)
680 int sv_index;
681 {
682 switch (sv_index) {
683 case F_STR: return "018/**";
684 case F_DEX:
685 case F_CON:
686 case F_INT:
687 case F_WIS:
688 case F_CHA: return "088"; /* all but str never get bigger */
689
690 case F_HUNGER: return shown_stats[F_HUNGER].name;
691 case F_CONFUSED:return shown_stats[F_CONFUSED].name;
692 case F_SICK: return shown_stats[F_SICK].name;
693 case F_BLIND: return shown_stats[F_BLIND].name;
694 case F_STUNNED: return shown_stats[F_STUNNED].name;
695 case F_HALLU: return shown_stats[F_HALLU].name;
696 case F_ENCUMBER:return shown_stats[F_ENCUMBER].name;
697
698 case F_NAME:
699 case F_DLEVEL: return "";
700 case F_HP:
701 case F_MAXHP: return "9999";
702 case F_POWER:
703 case F_MAXPOWER:return "999";
704 case F_AC: return "-99";
705 case F_LEVEL: return "99";
706 case F_GOLD:
707 case F_EXP: return "4294967295"; /* max ulong */
708 case F_ALIGN: return "Neutral";
709 case F_TIME: return "4294967295"; /* max ulong */
710 case F_SCORE: return "4294967295"; /* max ulong */
711 }
712 impossible("width_string: unknown index %d\n", sv_index);
713 return "";
714 }
715
716 static void
create_widget(parent,sv,sv_index)717 create_widget(parent, sv, sv_index)
718 Widget parent;
719 struct X_status_value *sv;
720 int sv_index;
721 {
722 Arg args[4];
723 Cardinal num_args;
724
725 switch (sv->type) {
726 case SV_VALUE:
727 sv->w = create_value(parent, sv->name);
728 set_value(sv->w, width_string(sv_index));
729 break;
730 case SV_LABEL:
731 /* Labels get their own buffer. */
732 sv->name = (char *) alloc(BUFSZ);
733 sv->name[0] = '\0';
734
735 num_args = 0;
736 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
737 XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++;
738 sv->w = XtCreateManagedWidget(
739 sv_index == F_NAME ? "name" : "dlevel",
740 labelWidgetClass,
741 parent,
742 args, num_args);
743 break;
744 case SV_NAME:
745 num_args = 0;
746 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
747 XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++;
748 sv->w = XtCreateManagedWidget(sv->name,
749 labelWidgetClass,
750 parent,
751 args, num_args);
752 break;
753 default:
754 panic("create_widget: unknown type %d", sv->type);
755 }
756 }
757
758 /*
759 * Get current width of value. width2p is only valid for SV_LABEL types.
760 */
761 static void
get_widths(sv,width1p,width2p)762 get_widths(sv, width1p, width2p)
763 struct X_status_value *sv;
764 int *width1p, *width2p;
765 {
766 Arg args[1];
767 Dimension width;
768
769 switch (sv->type) {
770 case SV_VALUE:
771 *width1p = get_name_width(sv->w);
772 *width2p = get_value_width(sv->w);
773 break;
774 case SV_LABEL:
775 case SV_NAME:
776 XtSetArg(args[0], XtNwidth, &width);
777 XtGetValues(sv->w, args, ONE);
778 *width1p = width;
779 *width2p = 0;
780 break;
781 default:
782 panic("get_widths: unknown type %d", sv->type);
783 }
784 }
785
786 static void
set_widths(sv,width1,width2)787 set_widths(sv, width1, width2)
788 struct X_status_value *sv;
789 int width1, width2;
790 {
791 Arg args[1];
792
793 switch (sv->type) {
794 case SV_VALUE:
795 set_name_width(sv->w, width1);
796 set_value_width(sv->w, width2);
797 break;
798 case SV_LABEL:
799 case SV_NAME:
800 XtSetArg(args[0], XtNwidth, (width1+width2));
801 XtSetValues(sv->w, args, ONE);
802 break;
803 default:
804 panic("set_widths: unknown type %d", sv->type);
805 }
806 }
807
808 static Widget
init_column(name,parent,top,left,col_indices)809 init_column(name, parent, top, left, col_indices)
810 char *name;
811 Widget parent, top, left;
812 int *col_indices;
813 {
814 Widget form;
815 Arg args[4];
816 Cardinal num_args;
817 int max_width1, width1, max_width2, width2;
818 int *ip;
819 struct X_status_value *sv;
820
821 num_args = 0;
822 if (top != (Widget) 0) {
823 XtSetArg(args[num_args], XtNfromVert, top); num_args++;
824 }
825 if (left != (Widget) 0) {
826 XtSetArg(args[num_args], XtNfromHoriz, left); num_args++;
827 }
828 XtSetArg(args[num_args], XtNdefaultDistance, 0); num_args++;
829 form = XtCreateManagedWidget(name,
830 formWidgetClass,
831 parent, args, num_args);
832
833 max_width1 = max_width2 = 0;
834 for (ip = col_indices; *ip >= 0; ip++) {
835 sv = &shown_stats[*ip];
836 create_widget(form, sv, *ip); /* will set init width */
837 if (ip != col_indices) { /* not first */
838 num_args = 0;
839 XtSetArg(args[num_args], XtNfromVert, shown_stats[*(ip-1)].w);
840 num_args++;
841 XtSetValues(sv->w, args, num_args);
842 }
843 get_widths(sv, &width1, &width2);
844 if (width1 > max_width1) max_width1 = width1;
845 if (width2 > max_width2) max_width2 = width2;
846 }
847 for (ip = col_indices; *ip >= 0 ; ip++) {
848 set_widths(&shown_stats[*ip], max_width1, max_width2);
849 }
850
851 /* There is room behind the end marker for the two widths. */
852 *++ip = max_width1;
853 *++ip = max_width2;
854
855 return form;
856 }
857
858 /*
859 * These are the orders of the displayed columns. Change to suit. The -1
860 * indicates the end of the column. The two numbers after that are used
861 * to store widths that are calculated at run-time.
862 */
863 static int attrib_indices[] = { F_STR,F_DEX,F_CON,F_INT,F_WIS,F_CHA, -1,0,0 };
864 static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND,
865 F_STUNNED, F_HALLU, F_ENCUMBER, -1,0,0 };
866
867 static int col2_indices[] = { F_MAXHP, F_ALIGN, F_TIME, F_EXP,
868 F_MAXPOWER, -1,0,0 };
869 static int col1_indices[] = { F_HP, F_AC, F_GOLD, F_LEVEL,
870 F_POWER, F_SCORE, -1,0,0 };
871
872
873 /*
874 * Produce a form that looks like the following:
875 *
876 * name
877 * dlevel
878 * col1_indices[0] col2_indices[0]
879 * col1_indices[1] col2_indices[1]
880 * . .
881 * . .
882 * col1_indices[n] col2_indices[n]
883 */
884 static Widget
init_info_form(parent,top,left)885 init_info_form(parent, top, left)
886 Widget parent, top, left;
887 {
888 Widget form, col1;
889 struct X_status_value *sv_name, *sv_dlevel;
890 Arg args[6];
891 Cardinal num_args;
892 int total_width, *ip;
893
894 num_args = 0;
895 if (top != (Widget) 0) {
896 XtSetArg(args[num_args], XtNfromVert, top); num_args++;
897 }
898 if (left != (Widget) 0) {
899 XtSetArg(args[num_args], XtNfromHoriz, left); num_args++;
900 }
901 XtSetArg(args[num_args], XtNdefaultDistance, 0); num_args++;
902 form = XtCreateManagedWidget("status_info",
903 formWidgetClass,
904 parent,
905 args, num_args);
906
907 /* top of form */
908 sv_name = &shown_stats[F_NAME];
909 create_widget(form, sv_name, F_NAME);
910
911 /* second */
912 sv_dlevel = &shown_stats[F_DLEVEL];
913 create_widget(form, sv_dlevel, F_DLEVEL);
914
915 num_args = 0;
916 XtSetArg(args[num_args], XtNfromVert, sv_name->w); num_args++;
917 XtSetValues(sv_dlevel->w, args, num_args);
918
919 /* two columns beneath */
920 col1 = init_column("name_col1", form, sv_dlevel->w,
921 (Widget) 0, col1_indices);
922 (void) init_column("name_col2", form, sv_dlevel->w,
923 col1, col2_indices);
924
925 /* Add calculated widths. */
926 for (ip = col1_indices; *ip >= 0; ip++)
927 ; /* skip to end */
928 total_width = *++ip;
929 total_width += *++ip;
930 for (ip = col2_indices; *ip >= 0; ip++)
931 ; /* skip to end */
932 total_width += *++ip;
933 total_width += *++ip;
934
935 XtSetArg(args[0], XtNwidth, total_width);
936 XtSetValues(sv_name->w, args, ONE);
937 XtSetArg(args[0], XtNwidth, total_width);
938 XtSetValues(sv_dlevel->w, args, ONE);
939
940 return form;
941 }
942
943 /*
944 * Create the layout for the fancy status. Return a form widget that
945 * contains everything.
946 */
947 static Widget
create_fancy_status(parent,top)948 create_fancy_status(parent, top)
949 Widget parent, top;
950 {
951 Widget form; /* The form that surrounds everything. */
952 Widget w;
953 Arg args[8];
954 Cardinal num_args;
955
956 num_args = 0;
957 if (top != (Widget) 0) {
958 XtSetArg(args[num_args], XtNfromVert, top); num_args++;
959 }
960 XtSetArg(args[num_args], XtNdefaultDistance, 0); num_args++;
961 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
962 XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++;
963 form = XtCreateManagedWidget("fancy_status",
964 panedWidgetClass,
965 parent,
966 args, num_args);
967
968 w = init_info_form(form, (Widget) 0, (Widget) 0);
969 w = init_column("status_attributes",form, (Widget) 0, w, attrib_indices);
970 (void) init_column("status_condition", form, (Widget) 0, w, status_indices);
971 return form;
972 }
973
974 static void
destroy_fancy_status(wp)975 destroy_fancy_status(wp)
976 struct xwindow *wp;
977 {
978 int i;
979 struct X_status_value *sv;
980
981 if (!wp->keep_window)
982 XtDestroyWidget(wp->w), wp->w = (Widget)0;
983
984 for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++)
985 if (sv->type == SV_LABEL) {
986 free((genericptr_t)sv->name);
987 sv->name = 0;
988 }
989 }
990
991 /*winstat.c*/
992