1 /* NetHack 3.6 winmisc.c $NHDT-Date: 1554135506 2019/04/01 16:18:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.44 $ */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata 1994-1999 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
8 /* JNetHack may be freely redistributed. See license for details. */
11 * Misc. popup windows: player selection and extended commands.
13 * + Global functions: player_selection() and get_ext_cmd().
17 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
20 #include <X11/Intrinsic.h>
21 #include <X11/StringDefs.h>
22 #include <X11/Shell.h>
23 #include <X11/Xaw/Command.h>
24 #include <X11/Xaw/Form.h>
25 #include <X11/Xaw/Label.h>
26 #include <X11/Xaw/AsciiText.h>
27 #include <X11/Xaw/Scrollbar.h>
28 #include <X11/Xaw/Toggle.h>
29 #include <X11/Xaw/Viewport.h>
30 #include <X11/Xaw/Cardinals.h>
31 #include <X11/Xaw/List.h>
32 #include <X11/Xos.h> /* for index() */
33 #include <X11/Xatom.h>
35 #ifdef PRESERVE_NO_SYSV
39 #undef PRESERVE_NO_SYSV
46 static Widget extended_command_popup = 0;
47 static Widget extended_command_form;
48 static Widget *extended_commands = 0;
49 static const char **command_list;
50 static short *command_indx;
51 static int extended_cmd_selected; /* index of the selected command; */
52 static int ps_selected; /* index of selected role */
53 #define PS_RANDOM (-50)
55 /* 'r' for random won't work for role but will for race, gender, alignment */
56 static const char ps_randchars[] = "*@\n\rrR";
57 static const char ps_quitchars[] = "\033qQ";
60 static boolean ec_full_list = FALSE;
61 static boolean ec_active = FALSE;
62 static int ec_nchars = 0;
63 static char ec_chars[EC_NCHARS];
66 boolean plsel_ask_name;
68 static const char plsel_dialog_translations[] = "#override\n\
69 <Key>Escape: plsel_quit()\n\
70 <Key>Return: plsel_play()";
72 static const char plsel_input_accelerators[] = "#override\n\
73 <Key>Escape: plsel_quit()\n\
74 <Key>Return: plsel_play()\n\
77 static const char extended_command_translations[] = "#override\n\
78 <Key>Left: scroll(4)\n\
79 <Key>Right: scroll(6)\n\
81 <Key>Down: scroll(2)\n\
82 <Btn4Down>: scroll(8)\n\
83 <Btn5Down>: scroll(2)\n\
86 static const char player_select_translations[] = "#override\n\
88 static const char race_select_translations[] = "#override\n\
90 static const char gend_select_translations[] = "#override\n\
92 static const char algn_select_translations[] = "#override\n\
95 static const char popup_entry_translations[] = "#override\n\
96 <Btn4Down>: scroll(8)\n\
97 <Btn5Down>: scroll(2)";
99 static void FDECL(ps_quit, (Widget, XtPointer, XtPointer));
100 static void FDECL(ps_random, (Widget, XtPointer, XtPointer));
101 static void FDECL(ps_select, (Widget, XtPointer, XtPointer));
102 static void FDECL(extend_select, (Widget, XtPointer, XtPointer));
103 static void FDECL(extend_dismiss, (Widget, XtPointer, XtPointer));
104 static void FDECL(extend_help, (Widget, XtPointer, XtPointer));
105 static void FDECL(popup_delete, (Widget, XEvent *, String *, Cardinal *));
106 static void NDECL(ec_dismiss);
107 static void FDECL(ec_scroll_to_view, (int));
108 static void NDECL(init_extended_commands_popup);
109 static Widget FDECL(make_menu, (const char *, const char *, const char *,
110 const char *, XtCallbackProc, const char *,
111 XtCallbackProc, int, const char **,
112 Widget **, XtCallbackProc, Widget *));
114 void NDECL(X11_player_selection_setupOthers);
115 void NDECL(X11_player_selection_randomize);
117 /* Bad Hack alert. Using integers instead of XtPointers */
122 return (XtPointer) (ptrdiff_t) i;
129 return (int) (ptrdiff_t) x;
132 /* Player Selection ------------------------------------------------------- */
135 ps_quit(w, client_data, call_data)
137 XtPointer client_data, call_data;
143 ps_selected = PS_QUIT;
144 exit_x_event = TRUE; /* leave event loop */
149 ps_random(w, client_data, call_data)
151 XtPointer client_data, call_data;
157 ps_selected = PS_RANDOM;
158 exit_x_event = TRUE; /* leave event loop */
163 ps_select(w, client_data, call_data)
165 XtPointer client_data, call_data;
170 ps_selected = (int) (ptrdiff_t) client_data;
171 exit_x_event = TRUE; /* leave event loop */
176 ps_key(w, event, params, num_params)
180 Cardinal *num_params;
183 char rolechars[QBUFSZ];
190 (void) memset(rolechars, '\0', sizeof rolechars); /* for index() */
191 for (i = 0; roles[i].name.m; ++i) {
192 ch = lowc(*roles[i].name.m);
193 /* if (flags.female && roles[i].name.f) ch = lowc(*roles[i].name.f);
195 /* this supports at most two roles with the same first letter */
196 if (index(rolechars, ch))
200 ch = key_event_to_char((XKeyEvent *) event);
201 if (ch == '\0') { /* don't accept nul char/modifier event */
205 mark = index(rolechars, ch);
207 mark = index(rolechars, lowc(ch));
209 mark = index(rolechars, highc(ch));
211 if (index(ps_randchars, ch))
212 ps_selected = PS_RANDOM;
213 else if (index(ps_quitchars, ch))
214 ps_selected = PS_QUIT;
216 X11_nhbell(); /* no such class */
220 ps_selected = (int) (mark - rolechars);
226 race_key(w, event, params, num_params)
230 Cardinal *num_params;
233 char racechars[QBUFSZ];
240 (void) memset(racechars, '\0', sizeof racechars); /* for index() */
241 for (i = 0; races[i].noun; ++i) {
242 ch = lowc(*races[i].noun);
243 /* this supports at most two races with the same first letter */
244 if (index(racechars, ch))
248 ch = key_event_to_char((XKeyEvent *) event);
249 if (ch == '\0') { /* don't accept nul char/modifier event */
253 mark = index(racechars, ch);
255 mark = index(racechars, lowc(ch));
257 mark = index(racechars, highc(ch));
259 if (index(ps_randchars, ch))
260 ps_selected = PS_RANDOM;
261 else if (index(ps_quitchars, ch))
262 ps_selected = PS_QUIT;
264 X11_nhbell(); /* no such race */
268 ps_selected = (int) (mark - racechars);
274 gend_key(w, event, params, num_params)
278 Cardinal *num_params;
281 static char gendchars[] = "mf";
287 ch = key_event_to_char((XKeyEvent *) event);
288 if (ch == '\0') { /* don't accept nul char/modifier event */
292 mark = index(gendchars, ch);
294 mark = index(gendchars, lowc(ch));
296 if (index(ps_randchars, ch))
297 ps_selected = PS_RANDOM;
298 else if (index(ps_quitchars, ch))
299 ps_selected = PS_QUIT;
301 X11_nhbell(); /* no such gender */
305 ps_selected = (int) (mark - gendchars);
311 algn_key(w, event, params, num_params)
315 Cardinal *num_params;
318 static char algnchars[] = "LNC";
324 ch = key_event_to_char((XKeyEvent *) event);
325 if (ch == '\0') { /* don't accept nul char/modifier event */
329 mark = index(algnchars, ch);
331 mark = index(algnchars, highc(ch));
333 if (index(ps_randchars, ch))
334 ps_selected = PS_RANDOM;
335 else if (index(ps_quitchars, ch))
336 ps_selected = PS_QUIT;
338 X11_nhbell(); /* no such alignment */
342 ps_selected = (int) (mark - algnchars);
346 int plsel_n_races, plsel_n_roles;
347 Widget *plsel_race_radios = (Widget *) 0;
348 Widget *plsel_role_radios = (Widget *) 0;
349 Widget *plsel_gend_radios = (Widget *) 0;
350 Widget *plsel_align_radios = (Widget *) 0;
352 Widget plsel_name_input;
354 Widget plsel_btn_play;
357 plsel_dialog_acceptvalues()
362 flags.initrace = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
363 flags.initrole = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
364 flags.initgend = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1;
365 flags.initalign = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1;
367 XtSetArg(args[0], nhStr(XtNstring), &s);
368 XtGetValues(plsel_name_input, args, ONE);
370 (void) strncpy(plname, (char *) s, sizeof plname - 1);
371 plname[sizeof plname - 1] = '\0';
372 (void) mungspaces(plname);
373 if (strlen(plname) < 1)
374 (void) strcpy(plname, "Mumbles");
375 iflags.renameinprogress = FALSE;
380 plsel_quit(w, event, params, num_params)
384 Cardinal *num_params;
391 ps_selected = PS_QUIT;
392 exit_x_event = TRUE; /* leave event loop */
397 plsel_play(w, event, params, num_params)
401 Cardinal *num_params;
411 XtSetArg(args[0], nhStr(XtNsensitive), &state);
412 XtGetValues(plsel_btn_play, args, ONE);
415 plsel_dialog_acceptvalues();
416 exit_x_event = TRUE; /* leave event loop */
424 plsel_randomize(w, event, params, num_params)
428 Cardinal *num_params;
435 X11_player_selection_randomize();
438 /* enable or disable the Play button */
440 plsel_set_play_button(state)
445 XtSetArg(args[0], nhStr(XtNsensitive), !state);
446 XtSetValues(plsel_btn_play, args, ONE);
450 plsel_set_sensitivities(setcurr)
456 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1;
457 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1;
459 plsel_set_play_button(ra < 0 || ro < 0);
461 if (ra < 0 || ro < 0)
466 for (j = 0; roles[j].name.m; j++) {
467 boolean v = validrace(j, ra);
471 XtSetArg(args[0], nhStr(XtNsensitive), v);
472 XtSetValues(plsel_role_radios[j], args, ONE);
476 if (!validrace(ro, c))
480 XawToggleSetCurrent(plsel_role_radios[0], i2xtp(c + 1));
484 for (j = 0; races[j].noun; j++) {
485 boolean v = validrace(ro, j);
489 XtSetArg(args[0], nhStr(XtNsensitive), v);
490 XtSetValues(plsel_race_radios[j], args, ONE);
494 if (!validrace(ro, c))
498 XawToggleSetCurrent(plsel_race_radios[0], i2xtp(c + 1));
500 X11_player_selection_setupOthers();
504 X11_player_selection_randomize()
506 int nrole = plsel_n_roles;
507 int nrace = plsel_n_races;
509 boolean fully_specified_role, choose_race_first;
510 boolean picksomething = (flags.initrole == ROLE_NONE
511 || flags.initrace == ROLE_NONE
512 || flags.initgend == ROLE_NONE
513 || flags.initalign == ROLE_NONE);
515 if (flags.randomall && picksomething) {
516 if (flags.initrole == ROLE_NONE)
517 flags.initrole = ROLE_RANDOM;
518 if (flags.initrace == ROLE_NONE)
519 flags.initrace = ROLE_RANDOM;
520 if (flags.initgend == ROLE_NONE)
521 flags.initgend = ROLE_RANDOM;
522 if (flags.initalign == ROLE_NONE)
523 flags.initalign = ROLE_RANDOM;
528 /* Randomize race and role, unless specified in config */
530 if (ro == ROLE_NONE || ro == ROLE_RANDOM) {
532 if (flags.initrole != ROLE_RANDOM) {
533 fully_specified_role = FALSE;
537 if (ra == ROLE_NONE || ra == ROLE_RANDOM) {
539 if (flags.initrace != ROLE_RANDOM) {
540 fully_specified_role = FALSE;
544 /* make sure we have a valid combination, honoring
545 the users request if possible. */
546 choose_race_first = FALSE;
547 if (flags.initrace >= 0 && flags.initrole < 0) {
548 choose_race_first = TRUE;
551 while (!validrace(ro,ra)) {
552 if (choose_race_first) {
554 if (flags.initrole != ROLE_RANDOM) {
555 fully_specified_role = FALSE;
559 if (flags.initrace != ROLE_RANDOM) {
560 fully_specified_role = FALSE;
566 if (g == ROLE_NONE) {
567 g = rn2(ROLE_GENDERS);
568 fully_specified_role = FALSE;
570 while (!validgend(ro,ra,g)) {
571 g = rn2(ROLE_GENDERS);
575 if (a == ROLE_NONE) {
576 a = rn2(ROLE_ALIGNS);
577 fully_specified_role = FALSE;
579 while (!validalign(ro,ra,a)) {
580 a = rn2(ROLE_ALIGNS);
583 XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(g + 1));
584 XawToggleSetCurrent(plsel_align_radios[0], i2xtp(a + 1));
585 XawToggleSetCurrent(plsel_race_radios[0], i2xtp(ra + 1));
586 XawToggleSetCurrent(plsel_role_radios[0], i2xtp(ro + 1));
587 plsel_set_sensitivities(FALSE);
591 X11_player_selection_setupOthers()
594 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
595 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
596 int valid = -1, c = 0, j;
597 int gchecked = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1;
598 int achecked = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1;
600 if (ro < 0 || ra < 0)
603 for (j = 0; j < ROLE_GENDERS; j++) {
604 boolean v = validgend(ro, ra, j);
608 XtSetArg(args[0], nhStr(XtNsensitive), v);
609 XtSetValues(plsel_gend_radios[j], args, ONE);
613 if (!validgend(ro, ra, c))
616 XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(c + 1));
620 for (j = 0; j < ROLE_ALIGNS; j++) {
621 boolean v = validalign(ro, ra, j);
625 XtSetArg(args[0], nhStr(XtNsensitive), v);
626 XtSetValues(plsel_align_radios[j], args, ONE);
630 if (!validalign(ro, ra, c))
633 XawToggleSetCurrent(plsel_align_radios[0], i2xtp(c + 1));
637 racetoggleCallback(w, client, call)
639 XtPointer client, call;
644 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
645 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
651 plsel_set_play_button(ra < 0 || ro < 0);
653 if (ra < 0 || ro < 0)
658 for (j = 0; roles[j].name.m; j++) {
659 boolean v = validrace(j, ra);
663 XtSetArg(args[0], nhStr(XtNsensitive), v);
664 XtSetValues(plsel_role_radios[j], args, ONE);
668 if (!validrace(c, ra))
672 XawToggleSetCurrent(plsel_role_radios[0], i2xtp(j));
674 X11_player_selection_setupOthers();
678 roletoggleCallback(w, client, call)
680 XtPointer client, call;
685 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
686 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
692 plsel_set_play_button(ra < 0 || ro < 0);
694 if (ra < 0 || ro < 0)
699 for (j = 0; races[j].noun; j++) {
700 boolean v = validrace(ro, j);
704 XtSetArg(args[0], nhStr(XtNsensitive), v);
705 XtSetValues(plsel_race_radios[j], args, ONE);
709 if (!validrace(ro, c))
713 XawToggleSetCurrent(plsel_race_radios[0], i2xtp(j));
715 X11_player_selection_setupOthers();
719 gendertoggleCallback(w, client, call)
721 XtPointer client, call;
723 int i, r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1;
729 plsel_set_play_button(r < 0);
731 for (i = 0; roles[i].name.m; i++) {
732 if (roles[i].name.f) {
735 XtSetArg(args[0], XtNlabel,
736 (r < 1) ? roles[i].name.m : roles[i].name.f);
737 XtSetValues(plsel_role_radios[i], args, ONE);
743 aligntoggleCallback(w, client, call)
745 XtPointer client, call;
747 int r = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1;
753 plsel_set_play_button(r < 0);
757 plsel_random_btn_callback(w, client, call)
766 X11_player_selection_randomize();
770 plsel_play_btn_callback(w, client, call)
779 plsel_dialog_acceptvalues();
780 exit_x_event = TRUE; /* leave event loop */
784 plsel_quit_btn_callback(w, client, call)
793 ps_selected = PS_QUIT;
794 exit_x_event = TRUE; /* leave event loop */
798 X11_create_player_selection_name(form)
801 Widget namelabel, name_vp, name_form;
807 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
808 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
809 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
810 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
811 XtSetArg(args[num_args], XtNallowVert, False); num_args++;
812 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
813 name_vp = XtCreateManagedWidget("name_vp", viewportWidgetClass, form,
817 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
818 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
819 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
820 name_form = XtCreateManagedWidget("name_form", formWidgetClass, name_vp,
824 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
825 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
826 XtSetArg(args[num_args], nhStr(XtNlabel), "Name"); num_args++;
827 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
829 namelabel = XtCreateManagedWidget("name_label",
830 labelWidgetClass, name_form,
834 XtSetArg(args[num_args], nhStr(XtNfromVert), namelabel); num_args++;
835 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
836 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
837 XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++;
838 XtSetArg(args[num_args], nhStr(XtNeditType),
839 !plsel_ask_name ? XawtextRead : XawtextEdit); num_args++;
840 XtSetArg(args[num_args], nhStr(XtNresize), XawtextResizeWidth); num_args++;
841 XtSetArg(args[num_args], nhStr(XtNstring), plname); num_args++;
842 XtSetArg(args[num_args], XtNinsertPosition, strlen(plname)); num_args++;
843 XtSetArg(args[num_args], nhStr(XtNaccelerators),
844 XtParseAcceleratorTable(plsel_input_accelerators)); num_args++;
845 plsel_name_input = XtCreateManagedWidget("name_input",
846 asciiTextWidgetClass, name_form,
849 XtInstallAccelerators(plsel_name_input, plsel_name_input);
850 if (plsel_ask_name) {
851 XtSetKeyboardFocus(form, plsel_name_input);
853 XtSetArg(args[0], nhStr(XtNdisplayCaret), False);
854 XtSetValues(plsel_name_input, args, ONE);
861 X11_player_selection_dialog()
863 Widget popup, popup_vp;
866 Widget racelabel, race_form, race_vp, race_form2;
867 Widget rolelabel, role_form, role_vp, role_form2;
868 Widget gendlabel, gend_form,
869 gend_radio_m, gend_radio_f, gend_vp, gend_form2;
870 Widget alignlabel, align_form,
871 align_radio_l, align_radio_n, align_radio_c, align_vp, align_form2;
872 Widget btn_vp, btn_form, random_btn, play_btn, quit_btn;
878 int cwid = (winwid / 3) - 14;
881 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
882 XtSetArg(args[num_args], XtNtitle, "Player Selection"); num_args++;
883 popup = XtCreatePopupShell("player_selection_dialog",
884 transientShellWidgetClass,
885 toplevel, args, num_args);
888 XtSetArg(args[num_args], XtNtranslations,
889 XtParseTranslationTable(plsel_dialog_translations)); num_args++;
890 popup_vp = XtCreateManagedWidget("plsel_vp", viewportWidgetClass,
891 popup, args, num_args);
894 XtSetArg(args[num_args], XtNtranslations,
895 XtParseTranslationTable(plsel_dialog_translations)); num_args++;
896 form = XtCreateManagedWidget("plsel_form", formWidgetClass, popup_vp,
899 name_vp = X11_create_player_selection_name(form);
902 XtSetArg(args[num_args], XtNwidth, winwid); num_args++;
903 XtSetValues(name_vp, args, num_args);
906 * Layout; role is centered rather than first:
908 * +------------------------------------+
910 * +------------------------------------+
911 * +--------+ +------------+ +---------+
912 * | human | |archeologist| | male |
913 * | elf | | barbarian | | female |
914 * | dwarf | | caveman | +---------+
915 * | gnome | | healer | +---------+
916 * | orc | | knight | | lawful |
917 * +--------+ | monk | | neutral |
918 * | priest | | chaotic |
919 * | rogue | +---------+
920 * | ranger | +--------+
921 * | samurai | + Random +
922 * | tourist | + Play +
923 * | valkyrie | + Quit +
924 * | wizard | +--------+
928 * make name box same width as race+gap+role+gap+gender/alignment
929 * (resize it after the other boxes have been placed);
930 * make Random/Play/Quit buttons same width as gender/alignment and
931 * align bottom of them with bottom of role (they already specify
932 * the same width for the label text but different decorations--
933 * room for radio button box--of the other widgets results in the
934 * total width being different);
935 * add 'random' to each of the four boxes and Choose to the Random/
936 * Play/Quit buttons; if none of the four 'random's are currently
937 * selected, gray-out Choose; conversely, when Choose or Play is
938 * clicked on, make the random assignments for any/all of the four
939 * boxes which have 'random' selected.
940 * Maybe: move gender box underneath race, bottom aligned with role
941 * and move alignment up to where gender currently is. If that's
942 * done, move role column first and race+gender to middle.
945 /********************************************/
950 XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++;
951 race_form = XtCreateManagedWidget("race_form", formWidgetClass, form,
956 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
957 XtSetArg(args[num_args], nhStr(XtNlabel), "Race"); num_args++;
958 racelabel = XtCreateManagedWidget("race_label",
959 labelWidgetClass, race_form,
963 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
964 XtSetArg(args[num_args], nhStr(XtNfromVert), racelabel); num_args++;
965 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
966 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
967 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
968 race_vp = XtCreateManagedWidget("race_vp", viewportWidgetClass, race_form,
972 race_form2 = XtCreateManagedWidget("race_form2", formWidgetClass, race_vp,
975 for (i = 0; races[i].noun; i++)
979 plsel_race_radios = (Widget *) alloc(sizeof (Widget) * plsel_n_races);
981 /* race radio buttons */
982 for (i = 0; races[i].noun; i++) {
987 XtSetArg(args[num_args], nhStr(XtNfromVert),
988 tmpwidget); num_args++;
989 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
991 XtSetArg(args[num_args], nhStr(XtNradioGroup),
992 plsel_race_radios[0]); num_args++;
993 XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++;
995 racewidget = XtCreateManagedWidget(races[i].noun,
999 XtAddCallback(racewidget, XtNcallback, racetoggleCallback, i2xtp(i));
1000 tmpwidget = racewidget;
1001 plsel_race_radios[i] = racewidget;
1004 XawToggleUnsetCurrent(plsel_race_radios[0]);
1006 /********************************************/
1010 XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++;
1011 XtSetArg(args[num_args], nhStr(XtNfromHoriz), race_form); num_args++;
1012 role_form = XtCreateManagedWidget("role_form", formWidgetClass, form,
1017 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1018 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
1019 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
1020 XtSetArg(args[num_args], nhStr(XtNlabel), "Role"); num_args++;
1021 rolelabel = XtCreateManagedWidget("role_label", labelWidgetClass,
1022 role_form, args, num_args);
1025 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
1026 XtSetArg(args[num_args], nhStr(XtNfromVert), rolelabel); num_args++;
1027 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1028 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
1029 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1030 role_vp = XtCreateManagedWidget("role_vp", viewportWidgetClass, role_form,
1034 role_form2 = XtCreateManagedWidget("role_form2", formWidgetClass, role_vp,
1037 for (i = 0; roles[i].name.m; i++)
1041 plsel_role_radios = (Widget *) alloc(sizeof (Widget) * plsel_n_roles);
1043 /* role radio buttons */
1044 for (i = 0; roles[i].name.m; i++) {
1049 XtSetArg(args[num_args], nhStr(XtNfromVert),
1050 tmpwidget); num_args++;
1051 XtSetArg(args[num_args], nhStr(XtNwidth), cwid); num_args++;
1053 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1054 plsel_role_radios[0]); num_args++;
1055 XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++;
1057 rolewidget = XtCreateManagedWidget(roles[i].name.m, toggleWidgetClass,
1058 role_form2, args, num_args);
1059 XtAddCallback(rolewidget, XtNcallback, roletoggleCallback, i2xtp(i));
1060 tmpwidget = rolewidget;
1061 plsel_role_radios[i] = rolewidget;
1063 XawToggleUnsetCurrent(plsel_role_radios[0]);
1065 /********************************************/
1069 plsel_gend_radios = (Widget *) alloc(sizeof (Widget) * ROLE_GENDERS);
1072 XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++;
1073 XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++;
1074 gend_form = XtCreateManagedWidget("gender_form", formWidgetClass, form,
1079 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1080 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
1081 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
1082 XtSetArg(args[num_args], nhStr(XtNlabel), "Gender"); num_args++;
1083 gendlabel = XtCreateManagedWidget("gender_label", labelWidgetClass,
1084 gend_form, args, num_args);
1087 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
1088 XtSetArg(args[num_args], nhStr(XtNfromVert), gendlabel); num_args++;
1089 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1090 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
1091 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1092 gend_vp = XtCreateManagedWidget("gender_vp", viewportWidgetClass,
1093 gend_form, args, num_args);
1096 gend_form2 = XtCreateManagedWidget("gender_form2", formWidgetClass,
1097 gend_vp, args, num_args);
1099 /* gender radio buttons */
1101 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1102 XtSetArg(args[num_args], nhStr(XtNradioData), 1); num_args++;
1103 plsel_gend_radios[0] = gend_radio_m
1104 = XtCreateManagedWidget("Male", toggleWidgetClass,
1105 gend_form2, args, num_args);
1107 XtSetArg(args[num_args], nhStr(XtNfromVert), gend_radio_m); num_args++;
1108 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1109 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1110 plsel_gend_radios[0]); num_args++;
1111 XtSetArg(args[num_args], nhStr(XtNradioData), 2); num_args++;
1112 plsel_gend_radios[1] = gend_radio_f
1113 = XtCreateManagedWidget("Female", toggleWidgetClass,
1114 gend_form2, args, num_args);
1116 XawToggleUnsetCurrent(plsel_gend_radios[0]);
1118 XtAddCallback(gend_radio_m, XtNcallback,
1119 gendertoggleCallback, (XtPointer) (1));
1120 XtAddCallback(gend_radio_f, XtNcallback,
1121 gendertoggleCallback, (XtPointer) (2));
1123 /********************************************/
1127 plsel_align_radios = (Widget *) alloc(sizeof (Widget) * ROLE_ALIGNS);
1130 XtSetArg(args[num_args], nhStr(XtNfromVert), gend_form); num_args++;
1131 XtSetArg(args[num_args], nhStr(XtNvertDistance), 30); num_args++;
1132 XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++;
1133 align_form = XtCreateManagedWidget("align_form", formWidgetClass, form,
1138 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1139 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
1140 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
1141 XtSetArg(args[num_args], nhStr(XtNlabel), "Alignment"); num_args++;
1142 alignlabel = XtCreateManagedWidget("align_label", labelWidgetClass,
1143 align_form, args, num_args);
1146 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
1147 XtSetArg(args[num_args], nhStr(XtNfromVert), alignlabel); num_args++;
1148 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1149 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
1150 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1151 align_vp = XtCreateManagedWidget("align_vp", viewportWidgetClass,
1152 align_form, args, num_args);
1155 align_form2 = XtCreateManagedWidget("align_form2", formWidgetClass,
1156 align_vp, args, num_args);
1159 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1160 XtSetArg(args[num_args], nhStr(XtNradioData), 1); num_args++;
1161 plsel_align_radios[0] = align_radio_l
1162 = XtCreateManagedWidget("Lawful", toggleWidgetClass,
1163 align_form2, args, num_args);
1165 XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_l); num_args++;
1166 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1167 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1168 plsel_align_radios[0]); num_args++;
1169 XtSetArg(args[num_args], nhStr(XtNradioData), 2); num_args++;
1170 plsel_align_radios[1] = align_radio_n
1171 = XtCreateManagedWidget("Neutral", toggleWidgetClass,
1172 align_form2, args, num_args);
1174 XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_n); num_args++;
1175 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1176 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1177 plsel_align_radios[0]); num_args++;
1178 XtSetArg(args[num_args], nhStr(XtNradioData), 3); num_args++;
1179 plsel_align_radios[2] = align_radio_c
1180 = XtCreateManagedWidget("Chaotic", toggleWidgetClass,
1181 align_form2, args, num_args);
1183 XawToggleUnsetCurrent(plsel_align_radios[0]);
1185 XtAddCallback(align_radio_l, XtNcallback,
1186 aligntoggleCallback, (XtPointer) (1));
1187 XtAddCallback(align_radio_n, XtNcallback,
1188 aligntoggleCallback, (XtPointer) (2));
1189 XtAddCallback(align_radio_c, XtNcallback,
1190 aligntoggleCallback, (XtPointer) (3));
1192 /********************************************/
1197 XtSetArg(args[num_args], nhStr(XtNfromVert), align_form); num_args++;
1198 XtSetArg(args[num_args], nhStr(XtNvertDistance), 30); num_args++;
1199 XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++;
1200 XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++;
1201 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1202 XtSetArg(args[num_args], XtNallowVert, False); num_args++;
1203 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1204 btn_vp = XtCreateManagedWidget("btn_vp", viewportWidgetClass, form,
1208 btn_form = XtCreateManagedWidget("btn_form", formWidgetClass, btn_vp,
1211 /* "Random" button */
1214 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
1215 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1216 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
1217 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1218 XtSetArg(args[num_args], nhStr(XtNlabel), "Random"); num_args++;
1219 random_btn = XtCreateManagedWidget("random", commandWidgetClass, btn_form,
1221 XtAddCallback(random_btn, XtNcallback, plsel_random_btn_callback, form);
1226 XtSetArg(args[num_args], nhStr(XtNfromVert), random_btn); num_args++;
1227 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1228 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
1229 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1230 XtSetArg(args[num_args], nhStr(XtNlabel), "Play"); num_args++;
1231 plsel_btn_play = play_btn
1232 = XtCreateManagedWidget("play", commandWidgetClass, btn_form,
1234 XtAddCallback(play_btn, XtNcallback, plsel_play_btn_callback, form);
1239 XtSetArg(args[num_args], nhStr(XtNfromVert), play_btn); num_args++;
1240 XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++;
1241 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1242 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
1243 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1244 XtSetArg(args[num_args], nhStr(XtNlabel), "Quit"); num_args++;
1245 quit_btn = XtCreateManagedWidget("quit", commandWidgetClass, btn_form,
1247 XtAddCallback(quit_btn, XtNcallback, plsel_quit_btn_callback, form);
1249 /********************************************/
1251 XtRealizeWidget(popup);
1252 X11_player_selection_randomize();
1254 if (flags.randomall) {
1255 plsel_dialog_acceptvalues();
1258 nh_XtPopup(popup, (int) XtGrabExclusive, form);
1259 /* The callback will enable the event loop exit. */
1260 (void) x_event(EXIT_ON_EXIT);
1263 nh_XtPopdown(popup);
1264 XtDestroyWidget(popup);
1266 if (plsel_race_radios)
1267 free(plsel_race_radios);
1269 if (plsel_role_radios)
1270 free(plsel_role_radios);
1272 if (plsel_gend_radios)
1273 free(plsel_gend_radios);
1275 if (plsel_align_radios)
1276 free(plsel_align_radios);
1278 if (ps_selected == PS_QUIT || program_state.done_hup) {
1280 X11_exit_nhwindows((char *) 0);
1285 /* Global functions ======================================================== */
1287 X11_player_selection_prompts()
1289 int num_roles, num_races, num_gends, num_algns, i, availcount, availindex;
1290 Widget popup, player_form;
1291 const char **choices;
1292 char qbuf[QBUFSZ], plbuf[QBUFSZ];
1299 /* avoid unnecessary prompts further down */
1300 rigid_role_checks();
1302 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1303 flags.initrace, flags.initgend,
1306 while (flags.initrole < 0) {
1307 if (flags.initrole == ROLE_RANDOM || flags.randomall) {
1308 flags.initrole = pick_role(flags.initrace, flags.initgend,
1309 flags.initalign, PICK_RANDOM);
1314 for (num_roles = 0; roles[num_roles].name.m; ++num_roles)
1316 choices = (const char **) alloc(sizeof (char *) * num_roles);
1319 for (i = 0; i < num_roles; i++) {
1321 if (ok_role(i, flags.initrace, flags.initgend,
1323 choices[i] = roles[i].name.m;
1324 if (flags.initgend >= 0 && flags.female
1326 choices[i] = roles[i].name.f;
1332 else if (flags.initalign >= 0)
1333 flags.initalign = -1; /* reset */
1334 else if (flags.initgend >= 0)
1335 flags.initgend = -1;
1336 else if (flags.initrace >= 0)
1337 flags.initrace = -1;
1339 panic("no available ROLE+race+gender+alignment combinations");
1342 Sprintf(qbuf, "Choose your %s Role", s_suffix(plbuf));
1344 Sprintf(qbuf, "%s
\90E
\8bÆ
\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1348 make_menu("player_selection", qbuf, player_select_translations,
1349 "quit", ps_quit, "random", ps_random, num_roles,
1350 choices, (Widget **) 0, ps_select, &player_form);
1352 make_menu("player_selection", qbuf, player_select_translations,
1353 "
\94²
\82¯
\82é", ps_quit, "
\83\89\83\93\83_
\83\80", ps_random, num_roles,
1354 choices, (Widget **) 0, ps_select, &player_form);
1358 positionpopup(popup, FALSE);
1359 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1361 /* The callbacks will enable the event loop exit. */
1362 (void) x_event(EXIT_ON_EXIT);
1364 nh_XtPopdown(popup);
1365 XtDestroyWidget(popup);
1366 free((genericptr_t) choices), choices = 0;
1368 if (ps_selected == PS_QUIT || program_state.done_hup) {
1370 X11_exit_nhwindows((char *) 0);
1372 } else if (ps_selected == PS_RANDOM) {
1373 flags.initrole = ROLE_RANDOM;
1374 } else if (ps_selected < 0 || ps_selected >= num_roles) {
1375 panic("player_selection: bad role select value %d", ps_selected);
1377 flags.initrole = ps_selected;
1381 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1382 flags.initrace, flags.initgend,
1385 while (!validrace(flags.initrole, flags.initrace)) {
1386 if (flags.initrace == ROLE_RANDOM || flags.randomall) {
1387 flags.initrace = pick_race(flags.initrole, flags.initgend,
1388 flags.initalign, PICK_RANDOM);
1392 for (num_races = 0; races[num_races].noun; ++num_races)
1394 choices = (const char **) alloc(sizeof(char *) * num_races);
1396 availcount = availindex = 0;
1397 for (i = 0; i < num_races; i++) {
1399 if (ok_race(flags.initrole, i, flags.initgend,
1401 choices[i] = races[i].noun;
1403 availindex = i; /* used iff only one */
1408 else if (flags.initalign >= 0)
1409 flags.initalign = -1; /* reset */
1410 else if (flags.initgend >= 0)
1411 flags.initgend = -1;
1413 panic("no available role+RACE+gender+alignment combinations");
1416 if (availcount == 1) {
1417 flags.initrace = availindex;
1418 free((genericptr_t) choices), choices = 0;
1421 Sprintf(qbuf, "Pick your %s race", s_suffix(plbuf));
1423 Sprintf(qbuf, "%s
\8eí
\91°
\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1427 make_menu("race_selection", qbuf, race_select_translations,
1428 "quit", ps_quit, "random", ps_random, num_races,
1429 choices, (Widget **) 0, ps_select, &player_form);
1432 make_menu("race_selection", qbuf, race_select_translations,
1433 "
\94²
\82¯
\82é", ps_quit, "
\83\89\83\93\83_
\83\80", ps_random, num_races,
1434 choices, (Widget **) 0, ps_select, &player_form);
1438 positionpopup(popup, FALSE);
1439 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1441 /* The callbacks will enable the event loop exit. */
1442 (void) x_event(EXIT_ON_EXIT);
1444 nh_XtPopdown(popup);
1445 XtDestroyWidget(popup);
1446 free((genericptr_t) choices), choices = 0;
1448 if (ps_selected == PS_QUIT || program_state.done_hup) {
1450 X11_exit_nhwindows((char *) 0);
1452 } else if (ps_selected == PS_RANDOM) {
1453 flags.initrace = ROLE_RANDOM;
1454 } else if (ps_selected < 0 || ps_selected >= num_races) {
1455 panic("player_selection: bad race select value %d",
1458 flags.initrace = ps_selected;
1460 } /* more than one race choice available */
1463 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1464 flags.initrace, flags.initgend,
1467 while (!validgend(flags.initrole, flags.initrace, flags.initgend)) {
1468 if (flags.initgend == ROLE_RANDOM || flags.randomall) {
1469 flags.initgend = pick_gend(flags.initrole, flags.initrace,
1470 flags.initalign, PICK_RANDOM);
1473 /* select a gender */
1474 num_gends = 2; /* genders[2] isn't allowed */
1475 choices = (const char **) alloc(sizeof(char *) * num_gends);
1477 availcount = availindex = 0;
1478 for (i = 0; i < num_gends; i++) {
1480 if (ok_gend(flags.initrole, flags.initrace, i,
1482 choices[i] = genders[i].adj;
1484 availindex = i; /* used iff only one */
1489 else if (flags.initalign >= 0)
1490 flags.initalign = -1; /* reset */
1492 panic("no available role+race+GENDER+alignment combinations");
1495 if (availcount == 1) {
1496 flags.initgend = availindex;
1497 free((genericptr_t) choices), choices = 0;
1500 Sprintf(qbuf, "Your %s gender?", s_suffix(plbuf));
1502 Sprintf(qbuf, "%s
\90«
\95Ê
\82ð
\91I
\82ñ
\82Å
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1505 make_menu("gender_selection", qbuf, gend_select_translations,
1506 "quit", ps_quit, "random", ps_random, num_gends,
1507 choices, (Widget **) 0, ps_select, &player_form);
1510 make_menu("gender_selection", qbuf, gend_select_translations,
1511 "
\94²
\82¯
\82é", ps_quit, "
\83\89\83\93\83_
\83\80", ps_random, num_gends,
1512 choices, (Widget **) 0, ps_select, &player_form);
1516 positionpopup(popup, FALSE);
1517 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1519 /* The callbacks will enable the event loop exit. */
1520 (void) x_event(EXIT_ON_EXIT);
1522 nh_XtPopdown(popup);
1523 XtDestroyWidget(popup);
1524 free((genericptr_t) choices), choices = 0;
1526 if (ps_selected == PS_QUIT || program_state.done_hup) {
1528 X11_exit_nhwindows((char *) 0);
1530 } else if (ps_selected == PS_RANDOM) {
1531 flags.initgend = ROLE_RANDOM;
1532 } else if (ps_selected < 0 || ps_selected >= num_gends) {
1533 panic("player_selection: bad gender select value %d",
1536 flags.initgend = ps_selected;
1538 } /* more than one gender choice available */
1541 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1542 flags.initrace, flags.initgend,
1545 while (!validalign(flags.initrole, flags.initrace, flags.initalign)) {
1546 if (flags.initalign == ROLE_RANDOM || flags.randomall) {
1547 flags.initalign = pick_align(flags.initrole, flags.initrace,
1548 flags.initgend, PICK_RANDOM);
1551 /* select an alignment */
1552 num_algns = 3; /* aligns[3] isn't allowed */
1553 choices = (const char **) alloc(sizeof(char *) * num_algns);
1555 availcount = availindex = 0;
1556 for (i = 0; i < num_algns; i++) {
1558 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
1560 choices[i] = aligns[i].adj;
1562 availindex = i; /* used iff only one */
1568 panic("no available role+race+gender+ALIGNMENT combinations");
1571 if (availcount == 1) {
1572 flags.initalign = availindex;
1573 free((genericptr_t) choices), choices = 0;
1576 Sprintf(qbuf, "Your %s alignment?", s_suffix(plbuf));
1578 Sprintf(qbuf, "%s
\91®
\90«
\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1580 popup = make_menu("alignment_selection", qbuf,
1581 algn_select_translations, "quit", ps_quit,
1582 "random", ps_random, num_algns, choices,
1583 (Widget **) 0, ps_select, &player_form);
1585 popup = make_menu("alignment_selection", qbuf,
1586 algn_select_translations, "
\94²
\82¯
\82é", ps_quit,
1587 "
\83\89\83\93\83_
\83\80", ps_random, num_algns, choices,
1588 (Widget **) 0, ps_select, &player_form);
1592 positionpopup(popup, FALSE);
1593 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1595 /* The callbacks will enable the event loop exit. */
1596 (void) x_event(EXIT_ON_EXIT);
1598 nh_XtPopdown(popup);
1599 XtDestroyWidget(popup);
1600 free((genericptr_t) choices), choices = 0;
1602 if (ps_selected == PS_QUIT || program_state.done_hup) {
1604 X11_exit_nhwindows((char *) 0);
1606 } else if (ps_selected == PS_RANDOM) {
1607 flags.initalign = ROLE_RANDOM;
1608 } else if (ps_selected < 0 || ps_selected >= num_algns) {
1609 panic("player_selection: bad alignment select value %d",
1612 flags.initalign = ps_selected;
1614 } /* more than one alignment choice available */
1619 X11_player_selection()
1621 if (iflags.wc_player_selection == VIA_DIALOG) {
1624 char *defplname = get_login_name();
1626 char *defplname = (char *)0;
1628 (void) strncpy(plname, defplname ? defplname : "Mumbles",
1630 plname[sizeof plname - 1] = '\0';
1631 iflags.renameinprogress = TRUE;
1633 X11_player_selection_dialog();
1634 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
1635 X11_player_selection_prompts();
1639 /* called by core to have the player pick an extended command */
1643 if (iflags.extmenu != ec_full_list) {
1644 /* player has toggled the 'extmenu' option, toss the old widgets */
1645 if (extended_commands)
1646 release_extended_cmds(); /* will set extended_commands to Null */
1647 ec_full_list = iflags.extmenu;
1649 if (!extended_commands)
1650 init_extended_commands_popup();
1652 extended_cmd_selected = -1; /* reset selected value */
1653 ec_scroll_to_view(-1); /* force scroll bar to top */
1655 positionpopup(extended_command_popup, FALSE); /* center on cursor */
1656 nh_XtPopup(extended_command_popup, (int) XtGrabExclusive,
1657 extended_command_form);
1659 /* The callbacks will enable the event loop exit. */
1660 (void) x_event(EXIT_ON_EXIT);
1662 if (extended_cmd_selected < 0)
1664 return command_indx[extended_cmd_selected];
1668 release_extended_cmds()
1670 if (extended_commands) {
1671 XtDestroyWidget(extended_command_popup), extended_command_popup = 0;
1672 free((genericptr_t) extended_commands), extended_commands = 0;
1673 free((genericptr_t) command_list), command_list = (const char **) 0;
1674 free((genericptr_t) command_indx), command_indx = (short *) 0;
1678 /* End global functions =================================================== */
1680 /* Extended Command ------------------------------------------------------- */
1683 extend_select(w, client_data, call_data)
1685 XtPointer client_data, call_data;
1687 int selected = (int) (ptrdiff_t) client_data;
1692 if (extended_cmd_selected != selected) {
1693 /* visibly deselect old one */
1694 if (extended_cmd_selected >= 0)
1695 swap_fg_bg(extended_commands[extended_cmd_selected]);
1697 /* select new one */
1698 swap_fg_bg(extended_commands[selected]);
1699 extended_cmd_selected = selected;
1702 nh_XtPopdown(extended_command_popup);
1703 /* reset colors while popped down */
1704 swap_fg_bg(extended_commands[extended_cmd_selected]);
1706 exit_x_event = TRUE; /* leave event loop */
1711 extend_dismiss(w, client_data, call_data)
1713 XtPointer client_data, call_data;
1724 extend_help(w, client_data, call_data)
1726 XtPointer client_data, call_data;
1732 /* We might need to make it known that we already have one listed. */
1738 ec_delete(w, event, params, num_params)
1742 Cardinal *num_params;
1744 if (w == extended_command_popup) {
1747 popup_delete(w, event, params, num_params);
1753 popup_delete(w, event, params, num_params)
1757 Cardinal *num_params;
1763 ps_selected = PS_QUIT;
1765 exit_x_event = TRUE; /* leave event loop */
1771 /* unselect while still visible */
1772 if (extended_cmd_selected >= 0)
1773 swap_fg_bg(extended_commands[extended_cmd_selected]);
1774 extended_cmd_selected = -1; /* dismiss */
1775 nh_XtPopdown(extended_command_popup);
1777 exit_x_event = TRUE; /* leave event loop */
1780 /* scroll the extended command menu if necessary
1781 so that choices extended_cmd_selected through ec_indx will be visible */
1783 ec_scroll_to_view(ec_indx)
1784 int ec_indx; /* might be greater than extended_cmd_selected */
1786 Widget viewport, scrollbar, tmpw;
1789 Position lo_y, hi_y; /* ext cmd label y */
1790 float s_shown, s_top; /* scrollbar pos */
1792 Dimension h, hh, wh, vh; /* widget and viewport heights */
1793 Dimension border_width;
1795 boolean force_top = (ec_indx < 0);
1798 * If the extended command menu needs to be scrolled in order to move
1799 * either the highlighted entry (extended_cmd_selected) or the target
1800 * entry (ec_indx) into view, we want to make both end up visible.
1801 * [Highligthed one is the first matching entry when the user types
1802 * something, such as "adjust" after typing 'a', and will be chosen
1803 * by pressing <return>. Target entry is one past the last matching
1804 * entry (or last matching entry itself if at end of command list),
1805 * showing the user the other potential matches so far.]
1807 * If that's not possible (maybe menu has been resized so that it's
1808 * too small), the highlighted entry takes precedence and the target
1809 * will be decremented until close enough to fit.
1815 /* get viewport and scrollbar widgets */
1816 tmpw = extended_commands[ec_indx];
1817 viewport = XtParent(tmpw);
1819 scrollbar = XtNameToWidget(tmpw, "*vertical");
1822 tmpw = XtParent(tmpw);
1825 if (scrollbar && viewport) {
1826 /* get selected ext command label y position and height */
1828 XtSetArg(args[num_args], XtNy, &hi_y); num_args++;
1829 XtSetArg(args[num_args], XtNheight, &h); num_args++;
1830 XtSetArg(args[num_args], nhStr(XtNborderWidth), &border_width);
1832 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance);
1834 XtGetValues(extended_commands[ec_indx], args, num_args);
1835 if (distance < 1 || distance > 32766) /* defaultDistance is weird */
1837 /* vertical distance between top of one command widget and the next */
1838 hh = h + distance + 2 * border_width;
1839 /* location of the highlighted entry, if any */
1840 if (extended_cmd_selected >= 0) {
1841 XtSetArg(args[0], XtNy, &lo_y);
1842 XtGetValues(extended_commands[extended_cmd_selected], args, ONE);
1846 /* get menu widget and viewport heights */
1847 XtSetArg(args[0], XtNheight, &wh);
1848 XtGetValues(tmpw, args, ONE);
1849 XtSetArg(args[0], XtNheight, &vh);
1850 XtGetValues(viewport, args, ONE);
1852 /* widget might be too small if it has been resized or
1853 there are a very large number of ambiguous choices */
1854 if (hi_y - lo_y > wh) {
1855 ec_indx = extended_cmd_selected;
1857 ec_indx += (wh / hh);
1858 XtSetArg(args[0], XtNy, &hi_y);
1859 XtGetValues(extended_commands[ec_indx], args, num_args);
1862 /* get scrollbar "height" and "top" position; floats between 0-1 */
1864 XtSetArg(args[num_args], XtNshown, &s_shown); num_args++;
1865 XtSetArg(args[num_args], nhStr(XtNtopOfThumb), &s_top); num_args++;
1866 XtGetValues(scrollbar, args, num_args);
1869 s_max = (s_top + s_shown) * vh;
1871 /* scroll if outside the view */
1874 XtCallCallbacks(scrollbar, XtNjumpProc, &s_min);
1875 } else if ((int) lo_y <= (int) s_min) {
1876 s_min = (float) (lo_y / (float) vh);
1877 XtCallCallbacks(scrollbar, XtNjumpProc, &s_min);
1878 } else if ((int) (hi_y + h) >= (int) s_max) {
1879 s_min = (float) ((hi_y + h) / (float) vh) - s_shown;
1880 XtCallCallbacks(scrollbar, XtNjumpProc, &s_min);
1885 /* decide whether extcmdlist[idx] should be part of extended commands menu */
1890 /* #shell or #suspect might not be available;
1891 'extmenu' option controls whether we show full list
1892 or just the traditional extended commands */
1893 if ((extcmdlist[idx].flags & CMD_NOT_AVAILABLE) != 0
1894 || ((extcmdlist[idx].flags & AUTOCOMPLETE) == 0 && !ec_full_list)
1895 || strlen(extcmdlist[idx].ef_txt) < 2) /* ignore "#" and "?" */
1903 ec_key(w, event, params, num_params)
1907 Cardinal *num_params;
1914 XKeyEvent *xkey = (XKeyEvent *) event;
1919 ch = key_event_to_char(xkey);
1921 if (ch == '\0') { /* don't accept nul char/modifier event */
1924 } else if (ch == '?') {
1925 extend_help((Widget) 0, (XtPointer) 0, (XtPointer) 0);
1927 } else if (index("\033\n\r", ch)) {
1929 /* unselect while still visible */
1930 if (extended_cmd_selected >= 0)
1931 swap_fg_bg(extended_commands[extended_cmd_selected]);
1932 extended_cmd_selected = -1; /* dismiss */
1935 nh_XtPopdown(extended_command_popup);
1936 /* unselect while invisible */
1937 if (extended_cmd_selected >= 0)
1938 swap_fg_bg(extended_commands[extended_cmd_selected]);
1940 exit_x_event = TRUE; /* leave event loop */
1943 } else if (ch == MENU_FIRST_PAGE || ch == MENU_LAST_PAGE) {
1944 hbar = vbar = (Widget) 0;
1945 find_scrollbars(w, &hbar, &vbar);
1947 top = (ch == MENU_FIRST_PAGE) ? 0.0 : 1.0;
1948 XtCallCallbacks(vbar, XtNjumpProc, &top);
1951 } else if (ch == MENU_NEXT_PAGE || ch == MENU_PREVIOUS_PAGE) {
1952 hbar = vbar = (Widget) 0;
1953 find_scrollbars(w, &hbar, &vbar);
1955 XtSetArg(arg[0], nhStr(XtNshown), &shown);
1956 XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top);
1957 XtGetValues(vbar, arg, TWO);
1958 top += ((ch == MENU_NEXT_PAGE) ? shown : -shown);
1959 XtCallCallbacks(vbar, XtNjumpProc, &top);
1965 * If too much time has elapsed, treat current key as starting a new
1966 * choice, otherwise it is a continuation of the choice in progress.
1967 * Extra letters might be needed to disambiguate between choices
1968 * ("ride" vs "rub", for instance), or player may just be typing in
1971 if (ec_active && (xkey->time - ec_time) > 2500) /* 2.5 seconds */
1979 ec_time = xkey->time;
1980 ec_chars[ec_nchars++] = ch;
1981 if (ec_nchars >= EC_NCHARS)
1982 ec_nchars = EC_NCHARS - 1; /* don't overflow */
1984 for (pass = 0; pass < 2; pass++) {
1986 /* first pass finished, but no matching command was found */
1987 /* start a new one with the last char entered */
1988 if (extended_cmd_selected >= 0)
1989 swap_fg_bg(extended_commands[extended_cmd_selected]);
1990 extended_cmd_selected = -1; /* dismiss */
1991 ec_chars[0] = ec_chars[ec_nchars - 1];
1994 for (i = 0; command_list[i]; ++i) {
1995 if (!strncmp(ec_chars, command_list[i], ec_nchars)) {
1996 if (extended_cmd_selected != i) {
1997 /* I should use set() and unset() actions, but how do
1998 I send the an action to the widget? */
1999 if (extended_cmd_selected >= 0)
2000 swap_fg_bg(extended_commands[extended_cmd_selected]);
2001 extended_cmd_selected = i;
2002 swap_fg_bg(extended_commands[extended_cmd_selected]);
2004 /* advance to one past last matching entry, so that all
2005 ambiguous choices, plus one to show thare aren't any
2006 more such, will scroll into view */
2008 if (!command_list[i + 1])
2009 break; /* end of list */
2011 } while (!strncmp(ec_chars, command_list[i], ec_nchars));
2013 ec_scroll_to_view(i);
2021 * Use our own home-brewed version menu because simpleMenu is designed to
2022 * be used from a menubox.
2025 init_extended_commands_popup()
2027 int i, j, num_commands, ignore_cmds = 0;
2029 /* count commands */
2030 for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++)
2031 if (ignore_extcmd(num_commands))
2034 j = num_commands - ignore_cmds;
2035 command_list = (const char **) alloc((unsigned) (j * sizeof (char *) + 1));
2036 command_indx = (short *) alloc((unsigned) (j * sizeof (short) + 1));
2038 for (i = j = 0; i < num_commands; i++) {
2039 if (ignore_extcmd(i))
2041 command_indx[j] = (short) i;
2042 command_list[j++] = extcmdlist[i].ef_txt;
2044 command_list[j] = (char *) 0;
2045 command_indx[j] = -1;
2049 extended_command_popup =
2050 make_menu("extended_commands", "Extended Commands",
2051 extended_command_translations, "dismiss", extend_dismiss,
2052 "help", extend_help, num_commands, command_list,
2053 &extended_commands, extend_select, &extended_command_form);
2055 extended_command_popup =
2056 make_menu("extended_commands", "
\8ag
\92£
\83R
\83}
\83\93\83h",
2057 extended_command_translations, "
\8eæ
\8fÁ", extend_dismiss,
2058 "
\83w
\83\8b\83v", extend_help, num_commands, command_list,
2059 &extended_commands, extend_select, &extended_command_form);
2063 /* ------------------------------------------------------------------------ */
2066 * Create a popup widget of the following form:
2069 * ----------- ------------
2070 * |left_name| |right_name|
2071 * ----------- ------------
2072 * ------------------------
2074 * ------------------------
2075 * ------------------------
2077 * ------------------------
2080 * ------------------------
2082 * ------------------------
2085 make_menu(popup_name, popup_label, popup_translations, left_name,
2086 left_callback, right_name, right_callback, num_names, widget_names,
2087 command_widgets, name_callback, formp)
2088 const char *popup_name;
2089 const char *popup_label;
2090 const char *popup_translations;
2091 const char *left_name;
2092 XtCallbackProc left_callback;
2093 const char *right_name;
2094 XtCallbackProc right_callback;
2096 const char **widget_names; /* return array of command widgets */
2097 Widget **command_widgets;
2098 XtCallbackProc name_callback;
2099 Widget *formp; /* return */
2101 Widget popup, popform, form, label, above, left, right, view;
2102 Widget *commands, *curr;
2106 Dimension width, other_width, max_width, border_width,
2107 height, cumulative_height, screen_height;
2109 char btnname[BUFSZ];
2111 commands = (Widget *) alloc((unsigned) num_names * sizeof (Widget));
2114 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
2115 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2116 popup = XtCreatePopupShell(popup_name, transientShellWidgetClass,
2117 toplevel, args, num_args);
2118 XtOverrideTranslations(
2119 popup, XtParseTranslationTable("<Message>WM_PROTOCOLS: ec_delete()"));
2122 XtSetArg(args[num_args], XtNtranslations,
2123 XtParseTranslationTable(popup_translations)); num_args++;
2124 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2125 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++;
2126 popform = XtCreateManagedWidget("topmenuform", formWidgetClass, popup,
2131 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
2132 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
2133 /*XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;*/
2134 XtSetArg(args[num_args], nhStr(XtNuseBottom), True); num_args++;
2135 XtSetArg(args[num_args], nhStr(XtNuseRight), True); num_args++;
2136 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
2137 XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++;
2138 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
2139 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
2140 XtSetArg(args[num_args], XtNtranslations,
2141 XtParseTranslationTable(popup_translations)); num_args++;
2142 view = XtCreateManagedWidget("menuformview", viewportWidgetClass, popform,
2146 XtSetArg(args[num_args], XtNtranslations,
2147 XtParseTranslationTable(popup_translations)); num_args++;
2148 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2149 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++;
2150 *formp = form = XtCreateManagedWidget("menuform", formWidgetClass, view,
2154 * Get the default distance between objects in the viewport widget.
2155 * (Something is fishy here: 'distance' ends up being 0 but there
2156 * is a non-zero gap between the borders of the internal widgets.
2157 * It matches exactly the default value of 4 for defaultDistance.)
2160 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance); num_args++;
2161 XtSetArg(args[num_args], nhStr(XtNborderWidth), &border_width); num_args++;
2162 XtGetValues(view, args, num_args);
2163 if (distance < 1 || distance > 32766)
2170 #if defined(X11R6) && defined(XI18N)
2171 XtSetArg(args[num_args], XtNinternational, True); num_args++;
2173 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2174 label = XtCreateManagedWidget(popup_label, labelWidgetClass, form, args,
2177 cumulative_height = 0;
2178 XtSetArg(args[0], XtNheight, &height);
2179 XtGetValues(label, args, ONE);
2180 cumulative_height += distance + height; /* no border for label */
2183 * Create the left button.
2186 XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++;
2187 XtSetArg(args[num_args], nhStr(XtNlabel), left_name); num_args++;
2189 XtSetArg(args[num_args], nhStr(XtNshapeStyle),
2190 XmuShapeRoundedRectangle); num_args++;
2192 Sprintf(btnname, "btn_%s", left_name);
2193 left = XtCreateManagedWidget(btnname, commandWidgetClass, form, args,
2195 XtAddCallback(left, XtNcallback, left_callback, (XtPointer) 0);
2196 skip = (distance < 4) ? 8 : 2 * distance;
2199 XtSetArg(args[0], XtNheight, &height);
2200 XtGetValues(left, args, ONE);
2201 cumulative_height += distance + height + 2 * border_width;
2204 * Create right button.
2207 XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
2208 XtSetArg(args[num_args], nhStr(XtNhorizDistance), skip); num_args++;
2209 XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++;
2210 XtSetArg(args[num_args], nhStr(XtNlabel), right_name); num_args++;
2212 XtSetArg(args[num_args], nhStr(XtNshapeStyle),
2213 XmuShapeRoundedRectangle); num_args++;
2215 #if defined(X11R6) && defined(XI18N)
2216 XtSetArg(args[num_args], XtNinternational, True); num_args++;
2218 Sprintf(btnname, "btn_%s", right_name);
2219 right = XtCreateManagedWidget(btnname, commandWidgetClass, form, args,
2221 XtAddCallback(right, XtNcallback, right_callback, (XtPointer) 0);
2223 XtInstallAccelerators(form, left);
2224 XtInstallAccelerators(form, right);
2227 * Create and place the command widgets.
2229 for (i = 0, above = left, curr = commands; i < num_names; i++) {
2230 if (!widget_names[i])
2233 XtSetArg(args[num_args], XtNtranslations,
2234 XtParseTranslationTable(popup_entry_translations)); num_args++;
2235 XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++;
2236 if (above == left) {
2237 /* if first, we are farther apart */
2238 XtSetArg(args[num_args], nhStr(XtNvertDistance), skip); num_args++;
2239 cumulative_height += skip;
2241 cumulative_height += distance;
2242 cumulative_height += height + 2 * border_width;
2244 #if defined(X11R6) && defined(XI18N)
2245 XtSetArg(args[num_args], XtNinternational, True);
2248 *curr = XtCreateManagedWidget(widget_names[i], commandWidgetClass,
2249 form, args, num_args);
2250 XtAddCallback(*curr, XtNcallback, name_callback,
2251 (XtPointer) (ptrdiff_t) i);
2254 cumulative_height += distance; /* space at bottom of form */
2257 * Now find the largest width. Start with width of left + right buttons
2258 * ('dismiss' + 'help' or 'quit' + 'random'), since they are adjacent.
2260 XtSetArg(args[0], XtNwidth, &max_width);
2261 XtGetValues(left, args, ONE);
2262 XtSetArg(args[0], XtNwidth, &width);
2263 XtGetValues(right, args, ONE);
2264 /* doesn't count leftmost 'distance + border_width' and
2265 rightmost 'border_width + distance' since all entries have those */
2266 max_width = max_width + border_width + skip + border_width + width;
2268 /* Next, the title. */
2269 XtSetArg(args[0], XtNwidth, &width);
2270 XtGetValues(label, args, ONE);
2271 if (width > max_width)
2274 /* Finally, the commands. */
2275 for (i = 0, curr = commands; i < num_names; i++) {
2276 if (!widget_names[i])
2278 XtSetArg(args[0], XtNwidth, &width);
2279 XtGetValues(*curr, args, ONE);
2280 if (width > max_width)
2286 * Re-do the two side-by-side widgets to take up half the width each.
2288 * With max_width and skip both having even values, we never have to
2289 * tweak left or right to maybe be one pixel wider than the other.
2293 XtSetArg(args[0], XtNwidth, &width);
2294 XtGetValues(left, args, ONE);
2295 XtSetArg(args[0], XtNwidth, &other_width);
2296 XtGetValues(right, args, ONE);
2297 if (width + border_width + skip / 2 < max_width / 2
2298 && other_width + border_width + skip / 2 < max_width / 2) {
2299 /* both are narrower than half */
2300 width = other_width = max_width / 2 - border_width - skip / 2;
2301 XtSetArg(args[0], XtNwidth, width);
2302 XtSetValues(left, args, ONE);
2303 XtSetArg(args[0], XtNwidth, other_width);
2304 XtSetValues(right, args, ONE);
2305 } else if (width + border_width + skip / 2 < max_width / 2) {
2306 /* 'other_width' (right) is half or more */
2307 width = max_width - other_width - 2 * border_width - skip;
2308 XtSetArg(args[0], XtNwidth, width);
2309 XtSetValues(left, args, ONE);
2310 } else if (other_width + border_width + skip / 2 < max_width / 2) {
2311 /* 'width' (left) is half or more */
2312 other_width = max_width - width - 2 * border_width - skip;
2313 XtSetArg(args[0], XtNwidth, other_width);
2314 XtSetValues(right, args, ONE);
2316 ; /* both are exactly half... */
2320 * Finally, set all of the single line widgets to the largest width.
2322 XtSetArg(args[0], XtNwidth, max_width);
2323 XtSetValues(label, args, ONE);
2325 for (i = 0, curr = commands; i < num_names; i++) {
2326 if (!widget_names[i])
2328 XtSetArg(args[0], XtNwidth, max_width);
2329 XtSetValues(*curr, args, ONE);
2333 if (command_widgets)
2334 *command_widgets = commands;
2336 free((char *) commands);
2339 * If the menu's complete height is too big for the display,
2340 * forcing the height to be smaller will cause the vertical
2341 * scroll bar (enabled but not forced above) to be included.
2343 screen_height = XHeightOfScreen(XtScreen(popup));
2344 screen_height -= appResources.extcmd_height_delta; /* NetHack.ad */
2345 if (cumulative_height >= screen_height) {
2346 /* 25 is a guesstimate for scrollbar width;
2347 window manager might override the request for y==1 */
2349 XtSetArg(args[num_args], XtNy, 1); num_args++;
2350 XtSetArg(args[num_args], XtNwidth, max_width + 25); num_args++;
2351 XtSetArg(args[num_args], XtNheight, screen_height - 1); num_args++;
2352 XtSetValues(popup, args, num_args);
2354 XtRealizeWidget(popup);
2355 XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1);
2357 /* during role selection, highlight "random" as pre-selected choice */
2358 if (right_callback == ps_random && index(ps_randchars, '\n'))