1 /* NetHack 3.6 winmisc.c $NHDT-Date: 1457079197 2016/03/04 08:13:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.25 $ */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
6 * Misc. popup windows: player selection and extended commands.
8 * + Global functions: player_selection() and get_ext_cmd().
12 ** Japanese version Copyright (C) Issei Numata, 1994-1999
13 ** changing point is marked `JP' (94/6/7) or XI18N (96/7/19)
14 ** For 3.4.0, Copyright (c) Kentaro Shirakata, 2002
15 ** JNetHack may be freely redistributed. See license for details.
19 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
22 #include <X11/Intrinsic.h>
23 #include <X11/StringDefs.h>
24 #include <X11/Shell.h>
25 #include <X11/Xaw/Command.h>
26 #include <X11/Xaw/Form.h>
27 #include <X11/Xaw/Label.h>
28 #include <X11/Xaw/AsciiText.h>
29 #include <X11/Xaw/Scrollbar.h>
30 #include <X11/Xaw/Toggle.h>
31 #include <X11/Xaw/Viewport.h>
32 #include <X11/Xaw/Cardinals.h>
33 #include <X11/Xaw/List.h>
34 #include <X11/Xos.h> /* for index() */
35 #include <X11/Xatom.h>
37 #ifdef PRESERVE_NO_SYSV
41 #undef PRESERVE_NO_SYSV
48 static Widget extended_command_popup = 0;
49 static Widget extended_command_form;
50 static Widget *extended_commands = 0;
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_active = FALSE;
61 static int ec_nchars = 0;
62 static char ec_chars[EC_NCHARS];
65 boolean plsel_ask_name;
67 static const char plsel_dialog_translations[] = "#override\n\
68 <Key>Escape: plsel_quit()\n\
69 <Key>Return: plsel_play()";
71 static const char plsel_input_accelerators[] = "#override\n\
72 <Key>Escape: plsel_quit()\n\
73 <Key>Return: plsel_play()\n\
76 static const char extended_command_translations[] = "#override\n\
77 <Key>Left: scroll(4)\n\
78 <Key>Right: scroll(6)\n\
80 <Key>Down: scroll(2)\n\
83 static const char player_select_translations[] = "#override\n\
85 static const char race_select_translations[] = "#override\n\
87 static const char gend_select_translations[] = "#override\n\
89 static const char algn_select_translations[] = "#override\n\
92 static void FDECL(ps_quit, (Widget, XtPointer, XtPointer));
93 static void FDECL(ps_random, (Widget, XtPointer, XtPointer));
94 static void FDECL(ps_select, (Widget, XtPointer, XtPointer));
95 static void FDECL(extend_select, (Widget, XtPointer, XtPointer));
96 static void FDECL(extend_dismiss, (Widget, XtPointer, XtPointer));
97 static void FDECL(extend_help, (Widget, XtPointer, XtPointer));
98 static void FDECL(popup_delete, (Widget, XEvent *, String *, Cardinal *));
99 static void NDECL(ec_dismiss);
100 static void FDECL(ec_scroll_to_view, (int));
101 static void NDECL(init_extended_commands_popup);
102 static Widget FDECL(make_menu, (const char *, const char *, const char *,
103 const char *, XtCallbackProc, const char *,
104 XtCallbackProc, int, const char **,
105 Widget **, XtCallbackProc, Widget *));
107 void NDECL(X11_player_selection_setupOthers);
108 void NDECL(X11_player_selection_randomize);
110 /* Bad Hack alert. Using integers instead of XtPointers */
115 return (XtPointer)(long)i;
124 /* Player Selection --------------------------------------------------------
128 ps_quit(w, client_data, call_data)
130 XtPointer client_data, call_data;
136 ps_selected = PS_QUIT;
137 exit_x_event = TRUE; /* leave event loop */
142 ps_random(w, client_data, call_data)
144 XtPointer client_data, call_data;
150 ps_selected = PS_RANDOM;
151 exit_x_event = TRUE; /* leave event loop */
156 ps_select(w, client_data, call_data)
158 XtPointer client_data, call_data;
163 ps_selected = (int) (ptrdiff_t) client_data;
164 exit_x_event = TRUE; /* leave event loop */
169 ps_key(w, event, params, num_params)
173 Cardinal *num_params;
176 char rolechars[QBUFSZ];
183 (void) memset(rolechars, '\0', sizeof rolechars); /* for index() */
184 for (i = 0; roles[i].name.m; ++i) {
185 ch = lowc(*roles[i].name.m);
186 /* if (flags.female && roles[i].name.f) ch = lowc(*roles[i].name.f);
188 /* this supports at most two roles with the same first letter */
189 if (index(rolechars, ch))
193 ch = key_event_to_char((XKeyEvent *) event);
194 if (ch == '\0') { /* don't accept nul char/modifier event */
198 mark = index(rolechars, ch);
200 mark = index(rolechars, lowc(ch));
202 mark = index(rolechars, highc(ch));
204 if (index(ps_randchars, ch))
205 ps_selected = PS_RANDOM;
206 else if (index(ps_quitchars, ch))
207 ps_selected = PS_QUIT;
209 X11_nhbell(); /* no such class */
213 ps_selected = (int) (mark - rolechars);
219 race_key(w, event, params, num_params)
223 Cardinal *num_params;
226 char racechars[QBUFSZ];
233 (void) memset(racechars, '\0', sizeof racechars); /* for index() */
234 for (i = 0; races[i].noun; ++i) {
235 ch = lowc(*races[i].noun);
236 /* this supports at most two races with the same first letter */
237 if (index(racechars, ch))
241 ch = key_event_to_char((XKeyEvent *) event);
242 if (ch == '\0') { /* don't accept nul char/modifier event */
246 mark = index(racechars, ch);
248 mark = index(racechars, lowc(ch));
250 mark = index(racechars, highc(ch));
252 if (index(ps_randchars, ch))
253 ps_selected = PS_RANDOM;
254 else if (index(ps_quitchars, ch))
255 ps_selected = PS_QUIT;
257 X11_nhbell(); /* no such race */
261 ps_selected = (int) (mark - racechars);
267 gend_key(w, event, params, num_params)
271 Cardinal *num_params;
274 static char gendchars[] = "mf";
280 ch = key_event_to_char((XKeyEvent *) event);
281 if (ch == '\0') { /* don't accept nul char/modifier event */
285 mark = index(gendchars, ch);
287 mark = index(gendchars, lowc(ch));
289 if (index(ps_randchars, ch))
290 ps_selected = PS_RANDOM;
291 else if (index(ps_quitchars, ch))
292 ps_selected = PS_QUIT;
294 X11_nhbell(); /* no such gender */
298 ps_selected = (int) (mark - gendchars);
304 algn_key(w, event, params, num_params)
308 Cardinal *num_params;
311 static char algnchars[] = "LNC";
317 ch = key_event_to_char((XKeyEvent *) event);
318 if (ch == '\0') { /* don't accept nul char/modifier event */
322 mark = index(algnchars, ch);
324 mark = index(algnchars, highc(ch));
326 if (index(ps_randchars, ch))
327 ps_selected = PS_RANDOM;
328 else if (index(ps_quitchars, ch))
329 ps_selected = PS_QUIT;
331 X11_nhbell(); /* no such alignment */
335 ps_selected = (int) (mark - algnchars);
339 int plsel_n_races, plsel_n_roles;
340 Widget *plsel_race_radios = (Widget *) 0;
341 Widget *plsel_role_radios = (Widget *) 0;
342 Widget *plsel_gend_radios = (Widget *) 0;
343 Widget *plsel_align_radios = (Widget *) 0;
345 Widget plsel_name_input;
347 Widget plsel_btn_play;
350 plsel_dialog_acceptvalues()
355 flags.initrace = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
356 flags.initrole = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
357 flags.initgend = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1;
358 flags.initalign = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1;
360 XtSetArg(args[0], nhStr(XtNstring), &s);
361 XtGetValues(plsel_name_input, args, ONE);
363 (void) strncpy(plname, (char *) s, sizeof plname - 1);
364 plname[sizeof plname - 1] = '\0';
365 (void) mungspaces(plname);
366 if (strlen(plname) < 1)
367 (void) strcpy(plname, "Mumbles");
368 iflags.renameinprogress = FALSE;
373 plsel_quit(w, event, params, num_params)
377 Cardinal *num_params;
384 ps_selected = PS_QUIT;
385 exit_x_event = TRUE; /* leave event loop */
390 plsel_play(w, event, params, num_params)
394 Cardinal *num_params;
404 XtSetArg(args[0], nhStr(XtNsensitive), &state);
405 XtGetValues(plsel_btn_play, args, ONE);
408 plsel_dialog_acceptvalues();
409 exit_x_event = TRUE; /* leave event loop */
417 plsel_randomize(w, event, params, num_params)
421 Cardinal *num_params;
428 X11_player_selection_randomize();
431 /* enable or disable the Play button */
433 plsel_set_play_button(state)
438 XtSetArg(args[0], nhStr(XtNsensitive), !state);
439 XtSetValues(plsel_btn_play, args, ONE);
443 plsel_set_sensitivities(setcurr)
449 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1;
450 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1;
452 plsel_set_play_button(ra < 0 || ro < 0);
454 if (ra < 0 || ro < 0)
459 for (j = 0; roles[j].name.m; j++) {
460 boolean v = validrace(j, ra);
464 XtSetArg(args[0], nhStr(XtNsensitive), v);
465 XtSetValues(plsel_role_radios[j], args, ONE);
469 if (!validrace(ro, c))
473 XawToggleSetCurrent(plsel_role_radios[0], i2xtp(c + 1));
477 for (j = 0; races[j].noun; j++) {
478 boolean v = validrace(ro, j);
482 XtSetArg(args[0], nhStr(XtNsensitive), v);
483 XtSetValues(plsel_race_radios[j], args, ONE);
487 if (!validrace(ro, c))
491 XawToggleSetCurrent(plsel_race_radios[0], i2xtp(c + 1));
493 X11_player_selection_setupOthers();
497 X11_player_selection_randomize()
499 int nrole = plsel_n_roles;
500 int nrace = plsel_n_races;
502 boolean fully_specified_role, choose_race_first;
503 boolean picksomething = (flags.initrole == ROLE_NONE
504 || flags.initrace == ROLE_NONE
505 || flags.initgend == ROLE_NONE
506 || flags.initalign == ROLE_NONE);
508 if (flags.randomall && picksomething) {
509 if (flags.initrole == ROLE_NONE)
510 flags.initrole = ROLE_RANDOM;
511 if (flags.initrace == ROLE_NONE)
512 flags.initrace = ROLE_RANDOM;
513 if (flags.initgend == ROLE_NONE)
514 flags.initgend = ROLE_RANDOM;
515 if (flags.initalign == ROLE_NONE)
516 flags.initalign = ROLE_RANDOM;
521 /* Randomize race and role, unless specified in config */
523 if (ro == ROLE_NONE || ro == ROLE_RANDOM) {
525 if (flags.initrole != ROLE_RANDOM) {
526 fully_specified_role = FALSE;
530 if (ra == ROLE_NONE || ra == ROLE_RANDOM) {
532 if (flags.initrace != ROLE_RANDOM) {
533 fully_specified_role = FALSE;
537 /* make sure we have a valid combination, honoring
538 the users request if possible. */
539 choose_race_first = FALSE;
540 if (flags.initrace >= 0 && flags.initrole < 0) {
541 choose_race_first = TRUE;
544 while (!validrace(ro,ra)) {
545 if (choose_race_first) {
547 if (flags.initrole != ROLE_RANDOM) {
548 fully_specified_role = FALSE;
552 if (flags.initrace != ROLE_RANDOM) {
553 fully_specified_role = FALSE;
559 if (g == ROLE_NONE) {
560 g = rn2(ROLE_GENDERS);
561 fully_specified_role = FALSE;
563 while (!validgend(ro,ra,g)) {
564 g = rn2(ROLE_GENDERS);
568 if (a == ROLE_NONE) {
569 a = rn2(ROLE_ALIGNS);
570 fully_specified_role = FALSE;
572 while (!validalign(ro,ra,a)) {
573 a = rn2(ROLE_ALIGNS);
576 XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(g + 1));
577 XawToggleSetCurrent(plsel_align_radios[0], i2xtp(a + 1));
578 XawToggleSetCurrent(plsel_race_radios[0], i2xtp(ra + 1));
579 XawToggleSetCurrent(plsel_role_radios[0], i2xtp(ro + 1));
580 plsel_set_sensitivities(FALSE);
584 X11_player_selection_setupOthers()
587 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
588 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
589 int valid = -1, c = 0, j;
590 int gchecked = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1;
591 int achecked = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1;
593 if (ro < 0 || ra < 0)
596 for (j = 0; j < ROLE_GENDERS; j++) {
597 boolean v = validgend(ro, ra, j);
601 XtSetArg(args[0], nhStr(XtNsensitive), v);
602 XtSetValues(plsel_gend_radios[j], args, ONE);
606 if (!validgend(ro, ra, c))
609 XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(c + 1));
613 for (j = 0; j < ROLE_ALIGNS; j++) {
614 boolean v = validalign(ro, ra, j);
618 XtSetArg(args[0], nhStr(XtNsensitive), v);
619 XtSetValues(plsel_align_radios[j], args, ONE);
623 if (!validalign(ro, ra, c))
626 XawToggleSetCurrent(plsel_align_radios[0], i2xtp(c + 1));
630 racetoggleCallback(w, client, call)
632 XtPointer client, call;
637 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
638 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
644 plsel_set_play_button(ra < 0 || ro < 0);
646 if (ra < 0 || ro < 0)
651 for (j = 0; roles[j].name.m; j++) {
652 boolean v = validrace(j, ra);
656 XtSetArg(args[0], nhStr(XtNsensitive), v);
657 XtSetValues(plsel_role_radios[j], args, ONE);
661 if (!validrace(c, ra))
665 XawToggleSetCurrent(plsel_role_radios[0], i2xtp(j));
667 X11_player_selection_setupOthers();
671 roletoggleCallback(w, client, call)
673 XtPointer client, call;
678 int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1;
679 int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1;
685 plsel_set_play_button(ra < 0 || ro < 0);
687 if (ra < 0 || ro < 0)
692 for (j = 0; races[j].noun; j++) {
693 boolean v = validrace(ro, j);
697 XtSetArg(args[0], nhStr(XtNsensitive), v);
698 XtSetValues(plsel_race_radios[j], args, ONE);
702 if (!validrace(ro, c))
706 XawToggleSetCurrent(plsel_race_radios[0], i2xtp(j));
708 X11_player_selection_setupOthers();
712 gendertoggleCallback(w, client, call)
714 XtPointer client, call;
716 int i, r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1;
722 plsel_set_play_button(r < 0);
724 for (i = 0; roles[i].name.m; i++) {
725 if (roles[i].name.f) {
728 XtSetArg(args[0], XtNlabel,
729 (r < 1) ? roles[i].name.m : roles[i].name.f);
730 XtSetValues(plsel_role_radios[i], args, ONE);
736 aligntoggleCallback(w, client, call)
738 XtPointer client, call;
740 int r = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1;
746 plsel_set_play_button(r < 0);
750 plsel_random_btn_callback(w, client, call)
759 X11_player_selection_randomize();
763 plsel_play_btn_callback(w, client, call)
772 plsel_dialog_acceptvalues();
773 exit_x_event = TRUE; /* leave event loop */
777 plsel_quit_btn_callback(w, client, call)
786 ps_selected = PS_QUIT;
787 exit_x_event = TRUE; /* leave event loop */
791 X11_create_player_selection_name(form)
794 Widget namelabel, name_vp, name_form;
800 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
801 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
802 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
803 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
804 XtSetArg(args[num_args], XtNallowVert, False); num_args++;
805 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
806 name_vp = XtCreateManagedWidget("name_vp", viewportWidgetClass, form,
810 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
811 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
812 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
813 name_form = XtCreateManagedWidget("name_form", formWidgetClass, name_vp,
817 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
818 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
819 XtSetArg(args[num_args], nhStr(XtNlabel), "Name"); num_args++;
820 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
822 namelabel = XtCreateManagedWidget("name_label",
823 labelWidgetClass, name_form,
827 XtSetArg(args[num_args], nhStr(XtNfromVert), namelabel); num_args++;
828 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
829 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
830 XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++;
831 XtSetArg(args[num_args], nhStr(XtNeditType),
832 !plsel_ask_name ? XawtextRead : XawtextEdit); num_args++;
833 XtSetArg(args[num_args], nhStr(XtNresize), XawtextResizeWidth); num_args++;
834 XtSetArg(args[num_args], nhStr(XtNstring), plname); num_args++;
835 XtSetArg(args[num_args], XtNinsertPosition, strlen(plname)); num_args++;
836 XtSetArg(args[num_args], nhStr(XtNaccelerators),
837 XtParseAcceleratorTable(plsel_input_accelerators)); num_args++;
838 plsel_name_input = XtCreateManagedWidget("name_input",
839 asciiTextWidgetClass, name_form,
842 XtInstallAccelerators(plsel_name_input, plsel_name_input);
843 if (plsel_ask_name) {
844 XtSetKeyboardFocus(form, plsel_name_input);
846 XtSetArg(args[0], nhStr(XtNdisplayCaret), False);
847 XtSetValues(plsel_name_input, args, ONE);
854 X11_player_selection_dialog()
856 Widget popup, popup_vp;
859 Widget racelabel, race_form, race_vp, race_form2;
860 Widget rolelabel, role_form, role_vp, role_form2;
861 Widget gendlabel, gend_form,
862 gend_radio_m, gend_radio_f, gend_vp, gend_form2;
863 Widget alignlabel, align_form,
864 align_radio_l, align_radio_n, align_radio_c, align_vp, align_form2;
865 Widget btn_vp, btn_form, random_btn, play_btn, quit_btn;
871 int cwid = (winwid / 3) - 14;
874 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
875 XtSetArg(args[num_args], XtNtitle, "Player Selection"); num_args++;
876 popup = XtCreatePopupShell("player_selection_dialog",
877 transientShellWidgetClass,
878 toplevel, args, num_args);
881 XtSetArg(args[num_args], XtNtranslations,
882 XtParseTranslationTable(plsel_dialog_translations)); num_args++;
883 popup_vp = XtCreateManagedWidget("plsel_vp", viewportWidgetClass,
884 popup, args, num_args);
887 XtSetArg(args[num_args], XtNtranslations,
888 XtParseTranslationTable(plsel_dialog_translations)); num_args++;
889 form = XtCreateManagedWidget("plsel_form", formWidgetClass, popup_vp,
892 name_vp = X11_create_player_selection_name(form);
895 XtSetArg(args[num_args], XtNwidth, winwid); num_args++;
896 XtSetValues(name_vp, args, num_args);
899 * Layout; role is centered rather than first:
901 * +------------------------------------+
903 * +------------------------------------+
904 * +--------+ +------------+ +---------+
905 * | human | |archeologist| | male |
906 * | elf | | barbarian | | female |
907 * | dwarf | | caveman | +---------+
908 * | gnome | | healer | +---------+
909 * | orc | | knight | | lawful |
910 * +--------+ | monk | | neutral |
911 * | priest | | chaotic |
912 * | rogue | +---------+
913 * | ranger | +--------+
914 * | samurai | + Random +
915 * | tourist | + Play +
916 * | valkyrie | + Quit +
917 * | wizard | +--------+
921 * make name box same width as race+gap+role+gap+gender/alignment
922 * (resize it after the other boxes have been placed);
923 * make Random/Play/Quit buttons same width as gender/alignment and
924 * align bottom of them with bottom of role (they already specify
925 * the same width for the label text but different decorations--
926 * room for radio button box--of the other widgets results in the
927 * total width being different);
928 * add 'random' to each of the four boxes and Choose to the Random/
929 * Play/Quit buttons; if none of the four 'random's are currently
930 * selected, gray-out Choose; conversely, when Choose or Play is
931 * clicked on, make the random assignments for any/all of the four
932 * boxes which have 'random' selected.
933 * Maybe: move gender box underneath race, bottom aligned with role
934 * and move alignment up to where gender currently is. If that's
935 * done, move role column first and race+gender to middle.
938 /********************************************/
943 XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++;
944 race_form = XtCreateManagedWidget("race_form", formWidgetClass, form,
949 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
950 XtSetArg(args[num_args], nhStr(XtNlabel), "Race"); num_args++;
951 racelabel = XtCreateManagedWidget("race_label",
952 labelWidgetClass, race_form,
956 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
957 XtSetArg(args[num_args], nhStr(XtNfromVert), racelabel); num_args++;
958 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
959 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
960 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
961 race_vp = XtCreateManagedWidget("race_vp", viewportWidgetClass, race_form,
965 race_form2 = XtCreateManagedWidget("race_form2", formWidgetClass, race_vp,
968 for (i = 0; races[i].noun; i++)
972 plsel_race_radios = (Widget *) alloc(sizeof (Widget) * plsel_n_races);
974 /* race radio buttons */
975 for (i = 0; races[i].noun; i++) {
980 XtSetArg(args[num_args], nhStr(XtNfromVert),
981 tmpwidget); num_args++;
982 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
984 XtSetArg(args[num_args], nhStr(XtNradioGroup),
985 plsel_race_radios[0]); num_args++;
986 XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++;
988 racewidget = XtCreateManagedWidget(races[i].noun,
992 XtAddCallback(racewidget, XtNcallback, racetoggleCallback, i2xtp(i));
993 tmpwidget = racewidget;
994 plsel_race_radios[i] = racewidget;
997 XawToggleUnsetCurrent(plsel_race_radios[0]);
999 /********************************************/
1003 XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++;
1004 XtSetArg(args[num_args], nhStr(XtNfromHoriz), race_form); num_args++;
1005 role_form = XtCreateManagedWidget("role_form", formWidgetClass, form,
1010 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1011 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
1012 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
1013 XtSetArg(args[num_args], nhStr(XtNlabel), "Role"); num_args++;
1014 rolelabel = XtCreateManagedWidget("role_label", labelWidgetClass,
1015 role_form, args, num_args);
1018 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
1019 XtSetArg(args[num_args], nhStr(XtNfromVert), rolelabel); num_args++;
1020 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1021 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
1022 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1023 role_vp = XtCreateManagedWidget("role_vp", viewportWidgetClass, role_form,
1027 role_form2 = XtCreateManagedWidget("role_form2", formWidgetClass, role_vp,
1030 for (i = 0; roles[i].name.m; i++)
1034 plsel_role_radios = (Widget *) alloc(sizeof (Widget) * plsel_n_roles);
1036 /* role radio buttons */
1037 for (i = 0; roles[i].name.m; i++) {
1042 XtSetArg(args[num_args], nhStr(XtNfromVert),
1043 tmpwidget); num_args++;
1044 XtSetArg(args[num_args], nhStr(XtNwidth), cwid); num_args++;
1046 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1047 plsel_role_radios[0]); num_args++;
1048 XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++;
1050 rolewidget = XtCreateManagedWidget(roles[i].name.m, toggleWidgetClass,
1051 role_form2, args, num_args);
1052 XtAddCallback(rolewidget, XtNcallback, roletoggleCallback, i2xtp(i));
1053 tmpwidget = rolewidget;
1054 plsel_role_radios[i] = rolewidget;
1056 XawToggleUnsetCurrent(plsel_role_radios[0]);
1058 /********************************************/
1062 plsel_gend_radios = (Widget *) alloc(sizeof (Widget) * ROLE_GENDERS);
1065 XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++;
1066 XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++;
1067 gend_form = XtCreateManagedWidget("gender_form", formWidgetClass, form,
1072 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1073 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
1074 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
1075 XtSetArg(args[num_args], nhStr(XtNlabel), "Gender"); num_args++;
1076 gendlabel = XtCreateManagedWidget("gender_label", labelWidgetClass,
1077 gend_form, args, num_args);
1080 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
1081 XtSetArg(args[num_args], nhStr(XtNfromVert), gendlabel); num_args++;
1082 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1083 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
1084 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1085 gend_vp = XtCreateManagedWidget("gender_vp", viewportWidgetClass,
1086 gend_form, args, num_args);
1089 gend_form2 = XtCreateManagedWidget("gender_form2", formWidgetClass,
1090 gend_vp, args, num_args);
1092 /* gender radio buttons */
1094 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1095 XtSetArg(args[num_args], nhStr(XtNradioData), 1); num_args++;
1096 plsel_gend_radios[0] = gend_radio_m
1097 = XtCreateManagedWidget("Male", toggleWidgetClass,
1098 gend_form2, args, num_args);
1100 XtSetArg(args[num_args], nhStr(XtNfromVert), gend_radio_m); num_args++;
1101 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1102 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1103 plsel_gend_radios[0]); num_args++;
1104 XtSetArg(args[num_args], nhStr(XtNradioData), 2); num_args++;
1105 plsel_gend_radios[1] = gend_radio_f
1106 = XtCreateManagedWidget("Female", toggleWidgetClass,
1107 gend_form2, args, num_args);
1109 XawToggleUnsetCurrent(plsel_gend_radios[0]);
1111 XtAddCallback(gend_radio_m, XtNcallback,
1112 gendertoggleCallback, (XtPointer) (1));
1113 XtAddCallback(gend_radio_f, XtNcallback,
1114 gendertoggleCallback, (XtPointer) (2));
1116 /********************************************/
1120 plsel_align_radios = (Widget *) alloc(sizeof (Widget) * ROLE_ALIGNS);
1123 XtSetArg(args[num_args], nhStr(XtNfromVert), gend_form); num_args++;
1124 XtSetArg(args[num_args], nhStr(XtNvertDistance), 30); num_args++;
1125 XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++;
1126 align_form = XtCreateManagedWidget("align_form", formWidgetClass, form,
1131 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1132 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
1133 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
1134 XtSetArg(args[num_args], nhStr(XtNlabel), "Alignment"); num_args++;
1135 alignlabel = XtCreateManagedWidget("align_label", labelWidgetClass,
1136 align_form, args, num_args);
1139 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
1140 XtSetArg(args[num_args], nhStr(XtNfromVert), alignlabel); num_args++;
1141 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1142 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
1143 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1144 align_vp = XtCreateManagedWidget("align_vp", viewportWidgetClass,
1145 align_form, args, num_args);
1148 align_form2 = XtCreateManagedWidget("align_form2", formWidgetClass,
1149 align_vp, args, num_args);
1152 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1153 XtSetArg(args[num_args], nhStr(XtNradioData), 1); num_args++;
1154 plsel_align_radios[0] = align_radio_l
1155 = XtCreateManagedWidget("Lawful", toggleWidgetClass,
1156 align_form2, args, num_args);
1158 XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_l); num_args++;
1159 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1160 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1161 plsel_align_radios[0]); num_args++;
1162 XtSetArg(args[num_args], nhStr(XtNradioData), 2); num_args++;
1163 plsel_align_radios[1] = align_radio_n
1164 = XtCreateManagedWidget("Neutral", toggleWidgetClass,
1165 align_form2, args, num_args);
1167 XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_n); num_args++;
1168 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1169 XtSetArg(args[num_args], nhStr(XtNradioGroup),
1170 plsel_align_radios[0]); num_args++;
1171 XtSetArg(args[num_args], nhStr(XtNradioData), 3); num_args++;
1172 plsel_align_radios[2] = align_radio_c
1173 = XtCreateManagedWidget("Chaotic", toggleWidgetClass,
1174 align_form2, args, num_args);
1176 XawToggleUnsetCurrent(plsel_align_radios[0]);
1178 XtAddCallback(align_radio_l, XtNcallback,
1179 aligntoggleCallback, (XtPointer) (1));
1180 XtAddCallback(align_radio_n, XtNcallback,
1181 aligntoggleCallback, (XtPointer) (2));
1182 XtAddCallback(align_radio_c, XtNcallback,
1183 aligntoggleCallback, (XtPointer) (3));
1185 /********************************************/
1190 XtSetArg(args[num_args], nhStr(XtNfromVert), align_form); num_args++;
1191 XtSetArg(args[num_args], nhStr(XtNvertDistance), 30); num_args++;
1192 XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++;
1193 XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++;
1194 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
1195 XtSetArg(args[num_args], XtNallowVert, False); num_args++;
1196 XtSetArg(args[num_args], XtNallowHoriz, False); num_args++;
1197 btn_vp = XtCreateManagedWidget("btn_vp", viewportWidgetClass, form,
1201 btn_form = XtCreateManagedWidget("btn_form", formWidgetClass, btn_vp,
1204 /* "Random" button */
1207 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
1208 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1209 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
1210 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1211 XtSetArg(args[num_args], nhStr(XtNlabel), "Random"); num_args++;
1212 random_btn = XtCreateManagedWidget("random", commandWidgetClass, btn_form,
1214 XtAddCallback(random_btn, XtNcallback, plsel_random_btn_callback, form);
1219 XtSetArg(args[num_args], nhStr(XtNfromVert), random_btn); num_args++;
1220 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1221 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
1222 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1223 XtSetArg(args[num_args], nhStr(XtNlabel), "Play"); num_args++;
1224 plsel_btn_play = play_btn
1225 = XtCreateManagedWidget("play", commandWidgetClass, btn_form,
1227 XtAddCallback(play_btn, XtNcallback, plsel_play_btn_callback, form);
1232 XtSetArg(args[num_args], nhStr(XtNfromVert), play_btn); num_args++;
1233 XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++;
1234 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
1235 XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++;
1236 XtSetArg(args[num_args], XtNwidth, cwid); num_args++;
1237 XtSetArg(args[num_args], nhStr(XtNlabel), "Quit"); num_args++;
1238 quit_btn = XtCreateManagedWidget("quit", commandWidgetClass, btn_form,
1240 XtAddCallback(quit_btn, XtNcallback, plsel_quit_btn_callback, form);
1242 /********************************************/
1244 XtRealizeWidget(popup);
1245 X11_player_selection_randomize();
1249 nh_XtPopup(popup, (int) XtGrabExclusive, form);
1251 /* The callback will enable the event loop exit. */
1252 (void) x_event(EXIT_ON_EXIT);
1254 nh_XtPopdown(popup);
1255 XtDestroyWidget(popup);
1257 if (plsel_race_radios)
1258 free(plsel_race_radios);
1260 if (plsel_role_radios)
1261 free(plsel_role_radios);
1263 if (plsel_gend_radios)
1264 free(plsel_gend_radios);
1266 if (plsel_align_radios)
1267 free(plsel_align_radios);
1269 if (ps_selected == PS_QUIT || program_state.done_hup) {
1271 X11_exit_nhwindows((char *) 0);
1276 /* Global functions =========================================================
1279 X11_player_selection_prompts()
1281 int num_roles, num_races, num_gends, num_algns, i, availcount, availindex;
1282 Widget popup, player_form;
1283 const char **choices;
1284 char qbuf[QBUFSZ], plbuf[QBUFSZ];
1291 /* avoid unnecessary prompts further down */
1292 rigid_role_checks();
1294 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1295 flags.initrace, flags.initgend,
1298 while (flags.initrole < 0) {
1299 if (flags.initrole == ROLE_RANDOM || flags.randomall) {
1300 flags.initrole = pick_role(flags.initrace, flags.initgend,
1301 flags.initalign, PICK_RANDOM);
1306 for (num_roles = 0; roles[num_roles].name.m; ++num_roles)
1308 choices = (const char **) alloc(sizeof (char *) * num_roles);
1311 for (i = 0; i < num_roles; i++) {
1313 if (ok_role(i, flags.initrace, flags.initgend,
1315 choices[i] = roles[i].name.m;
1316 if (flags.initgend >= 0 && flags.female
1318 choices[i] = roles[i].name.f;
1324 else if (flags.initalign >= 0)
1325 flags.initalign = -1; /* reset */
1326 else if (flags.initgend >= 0)
1327 flags.initgend = -1;
1328 else if (flags.initrace >= 0)
1329 flags.initrace = -1;
1331 panic("no available ROLE+race+gender+alignment combinations");
1334 Sprintf(qbuf, "Choose your %s Role", s_suffix(plbuf));
1336 Sprintf(qbuf, "%s
\90E
\8bÆ
\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1340 make_menu("player_selection", qbuf, player_select_translations,
1341 "quit", ps_quit, "random", ps_random, num_roles,
1342 choices, (Widget **) 0, ps_select, &player_form);
1344 make_menu("player_selection", qbuf, player_select_translations,
1345 "
\94²
\82¯
\82é", ps_quit, "
\83\89\83\93\83_
\83\80", ps_random, num_roles,
1346 choices, (Widget **) 0, ps_select, &player_form);
1350 positionpopup(popup, FALSE);
1351 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1353 /* The callbacks will enable the event loop exit. */
1354 (void) x_event(EXIT_ON_EXIT);
1356 nh_XtPopdown(popup);
1357 XtDestroyWidget(popup);
1358 free((genericptr_t) choices), choices = 0;
1360 if (ps_selected == PS_QUIT || program_state.done_hup) {
1362 X11_exit_nhwindows((char *) 0);
1364 } else if (ps_selected == PS_RANDOM) {
1365 flags.initrole = ROLE_RANDOM;
1366 } else if (ps_selected < 0 || ps_selected >= num_roles) {
1367 panic("player_selection: bad role select value %d", ps_selected);
1369 flags.initrole = ps_selected;
1373 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1374 flags.initrace, flags.initgend,
1377 while (!validrace(flags.initrole, flags.initrace)) {
1378 if (flags.initrace == ROLE_RANDOM || flags.randomall) {
1379 flags.initrace = pick_race(flags.initrole, flags.initgend,
1380 flags.initalign, PICK_RANDOM);
1384 for (num_races = 0; races[num_races].noun; ++num_races)
1386 choices = (const char **) alloc(sizeof(char *) * num_races);
1388 availcount = availindex = 0;
1389 for (i = 0; i < num_races; i++) {
1391 if (ok_race(flags.initrole, i, flags.initgend,
1393 choices[i] = races[i].noun;
1395 availindex = i; /* used iff only one */
1400 else if (flags.initalign >= 0)
1401 flags.initalign = -1; /* reset */
1402 else if (flags.initgend >= 0)
1403 flags.initgend = -1;
1405 panic("no available role+RACE+gender+alignment combinations");
1408 if (availcount == 1) {
1409 flags.initrace = availindex;
1410 free((genericptr_t) choices), choices = 0;
1413 Sprintf(qbuf, "Pick your %s race", s_suffix(plbuf));
1415 Sprintf(qbuf, "%s
\8eí
\91°
\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1419 make_menu("race_selection", qbuf, race_select_translations,
1420 "quit", ps_quit, "random", ps_random, num_races,
1421 choices, (Widget **) 0, ps_select, &player_form);
1424 make_menu("race_selection", qbuf, race_select_translations,
1425 "
\94²
\82¯
\82é", ps_quit, "
\83\89\83\93\83_
\83\80", ps_random, num_races,
1426 choices, (Widget **) 0, ps_select, &player_form);
1430 positionpopup(popup, FALSE);
1431 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1433 /* The callbacks will enable the event loop exit. */
1434 (void) x_event(EXIT_ON_EXIT);
1436 nh_XtPopdown(popup);
1437 XtDestroyWidget(popup);
1438 free((genericptr_t) choices), choices = 0;
1440 if (ps_selected == PS_QUIT || program_state.done_hup) {
1442 X11_exit_nhwindows((char *) 0);
1444 } else if (ps_selected == PS_RANDOM) {
1445 flags.initrace = ROLE_RANDOM;
1446 } else if (ps_selected < 0 || ps_selected >= num_races) {
1447 panic("player_selection: bad race select value %d",
1450 flags.initrace = ps_selected;
1452 } /* more than one race choice available */
1455 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1456 flags.initrace, flags.initgend,
1459 while (!validgend(flags.initrole, flags.initrace, flags.initgend)) {
1460 if (flags.initgend == ROLE_RANDOM || flags.randomall) {
1461 flags.initgend = pick_gend(flags.initrole, flags.initrace,
1462 flags.initalign, PICK_RANDOM);
1465 /* select a gender */
1466 num_gends = 2; /* genders[2] isn't allowed */
1467 choices = (const char **) alloc(sizeof(char *) * num_gends);
1469 availcount = availindex = 0;
1470 for (i = 0; i < num_gends; i++) {
1472 if (ok_gend(flags.initrole, flags.initrace, i,
1474 choices[i] = genders[i].adj;
1476 availindex = i; /* used iff only one */
1481 else if (flags.initalign >= 0)
1482 flags.initalign = -1; /* reset */
1484 panic("no available role+race+GENDER+alignment combinations");
1487 if (availcount == 1) {
1488 flags.initgend = availindex;
1489 free((genericptr_t) choices), choices = 0;
1492 Sprintf(qbuf, "Your %s gender?", s_suffix(plbuf));
1494 Sprintf(qbuf, "%s
\90«
\95Ê
\82ð
\91I
\82ñ
\82Å
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1497 make_menu("gender_selection", qbuf, gend_select_translations,
1498 "quit", ps_quit, "random", ps_random, num_gends,
1499 choices, (Widget **) 0, ps_select, &player_form);
1502 make_menu("gender_selection", qbuf, gend_select_translations,
1503 "
\94²
\82¯
\82é", ps_quit, "
\83\89\83\93\83_
\83\80", ps_random, num_gends,
1504 choices, (Widget **) 0, ps_select, &player_form);
1508 positionpopup(popup, FALSE);
1509 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1511 /* The callbacks will enable the event loop exit. */
1512 (void) x_event(EXIT_ON_EXIT);
1514 nh_XtPopdown(popup);
1515 XtDestroyWidget(popup);
1516 free((genericptr_t) choices), choices = 0;
1518 if (ps_selected == PS_QUIT || program_state.done_hup) {
1520 X11_exit_nhwindows((char *) 0);
1522 } else if (ps_selected == PS_RANDOM) {
1523 flags.initgend = ROLE_RANDOM;
1524 } else if (ps_selected < 0 || ps_selected >= num_gends) {
1525 panic("player_selection: bad gender select value %d",
1528 flags.initgend = ps_selected;
1530 } /* more than one gender choice available */
1533 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
1534 flags.initrace, flags.initgend,
1537 while (!validalign(flags.initrole, flags.initrace, flags.initalign)) {
1538 if (flags.initalign == ROLE_RANDOM || flags.randomall) {
1539 flags.initalign = pick_align(flags.initrole, flags.initrace,
1540 flags.initgend, PICK_RANDOM);
1543 /* select an alignment */
1544 num_algns = 3; /* aligns[3] isn't allowed */
1545 choices = (const char **) alloc(sizeof(char *) * num_algns);
1547 availcount = availindex = 0;
1548 for (i = 0; i < num_algns; i++) {
1550 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
1552 choices[i] = aligns[i].adj;
1554 availindex = i; /* used iff only one */
1560 panic("no available role+race+gender+ALIGNMENT combinations");
1563 if (availcount == 1) {
1564 flags.initalign = availindex;
1565 free((genericptr_t) choices), choices = 0;
1568 Sprintf(qbuf, "Your %s alignment?", s_suffix(plbuf));
1570 Sprintf(qbuf, "%s
\91®
\90«
\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D", s_suffix(plbuf));
1572 popup = make_menu("alignment_selection", qbuf,
1573 algn_select_translations, "quit", ps_quit,
1574 "random", ps_random, num_algns, choices,
1575 (Widget **) 0, ps_select, &player_form);
1577 popup = make_menu("alignment_selection", qbuf,
1578 algn_select_translations, "
\94²
\82¯
\82é", ps_quit,
1579 "
\83\89\83\93\83_
\83\80", ps_random, num_algns, choices,
1580 (Widget **) 0, ps_select, &player_form);
1584 positionpopup(popup, FALSE);
1585 nh_XtPopup(popup, (int) XtGrabExclusive, player_form);
1587 /* The callbacks will enable the event loop exit. */
1588 (void) x_event(EXIT_ON_EXIT);
1590 nh_XtPopdown(popup);
1591 XtDestroyWidget(popup);
1592 free((genericptr_t) choices), choices = 0;
1594 if (ps_selected == PS_QUIT || program_state.done_hup) {
1596 X11_exit_nhwindows((char *) 0);
1598 } else if (ps_selected == PS_RANDOM) {
1599 flags.initalign = ROLE_RANDOM;
1600 } else if (ps_selected < 0 || ps_selected >= num_algns) {
1601 panic("player_selection: bad alignment select value %d",
1604 flags.initalign = ps_selected;
1606 } /* more than one alignment choice available */
1611 X11_player_selection()
1613 if (iflags.wc_player_selection == VIA_DIALOG) {
1616 char *defplname = get_login_name();
1618 char *defplname = (char *)0;
1620 (void) strncpy(plname, defplname ? defplname : "Mumbles",
1622 plname[sizeof plname - 1] = '\0';
1623 iflags.renameinprogress = TRUE;
1625 X11_player_selection_dialog();
1626 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
1627 X11_player_selection_prompts();
1634 if (!extended_commands)
1635 init_extended_commands_popup();
1637 extended_cmd_selected = -1; /* reset selected value */
1638 ec_scroll_to_view(-1); /* force scroll bar to top */
1640 positionpopup(extended_command_popup, FALSE); /* center on cursor */
1641 nh_XtPopup(extended_command_popup, (int) XtGrabExclusive,
1642 extended_command_form);
1644 /* The callbacks will enable the event loop exit. */
1645 (void) x_event(EXIT_ON_EXIT);
1647 return extended_cmd_selected;
1651 release_extended_cmds()
1653 if (extended_commands) {
1654 XtDestroyWidget(extended_command_popup);
1655 free((genericptr_t) extended_commands), extended_commands = 0;
1659 /* End global functions =====================================================
1662 /* Extended Command --------------------------------------------------------
1666 extend_select(w, client_data, call_data)
1668 XtPointer client_data, call_data;
1670 int selected = (int) (ptrdiff_t) client_data;
1675 if (extended_cmd_selected != selected) {
1676 /* visibly deselect old one */
1677 if (extended_cmd_selected >= 0)
1678 swap_fg_bg(extended_commands[extended_cmd_selected]);
1680 /* select new one */
1681 swap_fg_bg(extended_commands[selected]);
1682 extended_cmd_selected = selected;
1685 nh_XtPopdown(extended_command_popup);
1686 /* reset colors while popped down */
1687 swap_fg_bg(extended_commands[extended_cmd_selected]);
1689 exit_x_event = TRUE; /* leave event loop */
1694 extend_dismiss(w, client_data, call_data)
1696 XtPointer client_data, call_data;
1707 extend_help(w, client_data, call_data)
1709 XtPointer client_data, call_data;
1715 /* We might need to make it known that we already have one listed. */
1721 ec_delete(w, event, params, num_params)
1725 Cardinal *num_params;
1727 if (w == extended_command_popup) {
1730 popup_delete(w, event, params, num_params);
1736 popup_delete(w, event, params, num_params)
1740 Cardinal *num_params;
1746 ps_selected = PS_QUIT;
1748 exit_x_event = TRUE; /* leave event loop */
1754 /* unselect while still visible */
1755 if (extended_cmd_selected >= 0)
1756 swap_fg_bg(extended_commands[extended_cmd_selected]);
1757 extended_cmd_selected = -1; /* dismiss */
1758 nh_XtPopdown(extended_command_popup);
1760 exit_x_event = TRUE; /* leave event loop */
1763 /* scroll the extended command menu if necessary
1764 so that choices extended_cmd_selected through ec_indx will be visible */
1766 ec_scroll_to_view(ec_indx)
1767 int ec_indx; /* might be greater than extended_cmd_selected */
1769 Widget viewport, scrollbar, tmpw;
1772 Position lo_y, hi_y; /* ext cmd label y */
1773 float s_shown, s_top; /* scrollbar pos */
1775 Dimension h, hh, wh, vh; /* widget and viewport heights */
1776 Dimension border_width;
1778 boolean force_top = (ec_indx < 0);
1781 * If the extended command menu needs to be scrolled in order to move
1782 * either the highlighted entry (extended_cmd_selected) or the target
1783 * entry (ec_indx) into view, we want to make both end up visible.
1784 * [Highligthed one is the first matching entry when the user types
1785 * something, such as "adjust" after typing 'a', and will be chosen
1786 * by pressing <return>. Target entry is one past the last matching
1787 * entry (or last matching entry itself if at end of command list),
1788 * showing the user the other potential matches so far.]
1790 * If that's not possible (maybe menu has been resized so that it's
1791 * too small), the highlighted entry takes precedence and the target
1792 * will be decremented until close enough to fit.
1798 /* get viewport and scrollbar widgets */
1799 tmpw = extended_commands[ec_indx];
1800 viewport = XtParent(tmpw);
1802 scrollbar = XtNameToWidget(tmpw, "*vertical");
1805 tmpw = XtParent(tmpw);
1808 if (scrollbar && viewport) {
1809 /* get selected ext command label y position and height */
1811 XtSetArg(args[num_args], XtNy, &hi_y); num_args++;
1812 XtSetArg(args[num_args], XtNheight, &h); num_args++;
1813 XtSetArg(args[num_args], nhStr(XtNborderWidth), &border_width);
1815 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance);
1817 XtGetValues(extended_commands[ec_indx], args, num_args);
1818 if (distance < 1 || distance > 32766) /* defaultDistance is weird */
1820 /* vertical distance between top of one command widget and the next */
1821 hh = h + distance + 2 * border_width;
1822 /* location of the highlighted entry, if any */
1823 if (extended_cmd_selected >= 0) {
1824 XtSetArg(args[0], XtNy, &lo_y);
1825 XtGetValues(extended_commands[extended_cmd_selected], args, ONE);
1829 /* get menu widget and viewport heights */
1830 XtSetArg(args[0], XtNheight, &wh);
1831 XtGetValues(tmpw, args, ONE);
1832 XtSetArg(args[0], XtNheight, &vh);
1833 XtGetValues(viewport, args, ONE);
1835 /* widget might be too small if it has been resized or
1836 there are a very large number of ambiguous choices */
1837 if (hi_y - lo_y > wh) {
1838 ec_indx = extended_cmd_selected;
1840 ec_indx += (wh / hh);
1841 XtSetArg(args[0], XtNy, &hi_y);
1842 XtGetValues(extended_commands[ec_indx], args, num_args);
1845 /* get scrollbar "height" and "top" position; floats between 0-1 */
1847 XtSetArg(args[num_args], XtNshown, &s_shown); num_args++;
1848 XtSetArg(args[num_args], nhStr(XtNtopOfThumb), &s_top); num_args++;
1849 XtGetValues(scrollbar, args, num_args);
1852 s_max = (s_top + s_shown) * vh;
1854 /* scroll if outside the view */
1857 XtCallCallbacks(scrollbar, XtNjumpProc, &s_min);
1858 } else if ((int) lo_y <= (int) s_min) {
1859 s_min = (float) (lo_y / (float) vh);
1860 XtCallCallbacks(scrollbar, XtNjumpProc, &s_min);
1861 } else if ((int) (hi_y + h) >= (int) s_max) {
1862 s_min = (float) ((hi_y + h) / (float) vh) - s_shown;
1863 XtCallCallbacks(scrollbar, XtNjumpProc, &s_min);
1870 ec_key(w, event, params, num_params)
1874 Cardinal *num_params;
1879 XKeyEvent *xkey = (XKeyEvent *) event;
1885 ch = key_event_to_char(xkey);
1887 if (ch == '\0') { /* don't accept nul char/modifier event */
1890 } else if (ch == '?') {
1891 extend_help((Widget) 0, (XtPointer) 0, (XtPointer) 0);
1893 } else if (index("\033\n\r", ch)) {
1895 /* unselect while still visible */
1896 if (extended_cmd_selected >= 0)
1897 swap_fg_bg(extended_commands[extended_cmd_selected]);
1898 extended_cmd_selected = -1; /* dismiss */
1901 nh_XtPopdown(extended_command_popup);
1902 /* unselect while invisible */
1903 if (extended_cmd_selected >= 0)
1904 swap_fg_bg(extended_commands[extended_cmd_selected]);
1906 exit_x_event = TRUE; /* leave event loop */
1912 * If too much time has elapsed, treat current key as starting a new
1913 * choice, otherwise it is a continuation of the choice in progress.
1914 * Extra letters might be needed to disambiguate between choices
1915 * ("ride" vs "rub", for instance), or player may just be typing in
1918 if (ec_active && (xkey->time - ec_time) > 2500) /* 2.5 seconds */
1926 ec_time = xkey->time;
1927 ec_chars[ec_nchars++] = ch;
1928 if (ec_nchars >= EC_NCHARS)
1929 ec_nchars = EC_NCHARS - 1; /* don't overflow */
1931 for (pass = 0; pass < 2; pass++) {
1933 /* first pass finished, but no matching command was found */
1934 /* start a new one with the last char entered */
1935 if (extended_cmd_selected >= 0)
1936 swap_fg_bg(extended_commands[extended_cmd_selected]);
1937 extended_cmd_selected = -1; /* dismiss */
1938 ec_chars[0] = ec_chars[ec_nchars-1];
1941 for (i = 0; extcmdlist[i].ef_txt; i++) {
1942 if (extcmdlist[i].ef_txt[0] == '?')
1945 if (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars)) {
1946 if (extended_cmd_selected != i) {
1947 /* I should use set() and unset() actions, but how do */
1948 /* I send the an action to the widget? */
1949 if (extended_cmd_selected >= 0)
1950 swap_fg_bg(extended_commands[extended_cmd_selected]);
1951 extended_cmd_selected = i;
1952 swap_fg_bg(extended_commands[extended_cmd_selected]);
1954 /* advance to one past last matching entry, so that all
1955 ambiguous choices, plus one to show thare aren't any
1956 more such, will scroll into view */
1958 if (!extcmdlist[i + 1].ef_txt
1959 || *extcmdlist[i + 1].ef_txt == '?')
1960 break; /* end of list */
1962 } while (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars));
1964 ec_scroll_to_view(i);
1972 * Use our own home-brewed version menu because simpleMenu is designed to
1973 * be used from a menubox.
1976 init_extended_commands_popup()
1978 int i, num_commands;
1979 const char **command_list;
1981 /* count commands */
1982 for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++)
1985 /* If the last entry is "help", don't use it. */
1986 if (strcmp(extcmdlist[num_commands - 1].ef_txt, "?") == 0)
1990 (const char **) alloc((unsigned) num_commands * sizeof(char *));
1992 for (i = 0; i < num_commands; i++)
1993 command_list[i] = extcmdlist[i].ef_txt;
1996 extended_command_popup =
1997 make_menu("extended_commands", "Extended Commands",
1998 extended_command_translations, "dismiss", extend_dismiss,
1999 "help", extend_help, num_commands, command_list,
2000 &extended_commands, extend_select, &extended_command_form);
2002 extended_command_popup =
2003 make_menu("extended_commands", "
\8ag
\92£
\83R
\83}
\83\93\83h",
2004 extended_command_translations, "
\8eæ
\8fÁ", extend_dismiss,
2005 "
\83w
\83\8b\83v", extend_help, num_commands, command_list,
2006 &extended_commands, extend_select, &extended_command_form);
2009 free((char *) command_list);
2012 /* -------------------------------------------------------------------------
2016 * Create a popup widget of the following form:
2019 * ----------- ------------
2020 * |left_name| |right_name|
2021 * ----------- ------------
2022 * ------------------------
2024 * ------------------------
2025 * ------------------------
2027 * ------------------------
2030 * ------------------------
2032 * ------------------------
2035 make_menu(popup_name, popup_label, popup_translations, left_name,
2036 left_callback, right_name, right_callback, num_names, widget_names,
2037 command_widgets, name_callback, formp)
2038 const char *popup_name;
2039 const char *popup_label;
2040 const char *popup_translations;
2041 const char *left_name;
2042 XtCallbackProc left_callback;
2043 const char *right_name;
2044 XtCallbackProc right_callback;
2046 const char **widget_names; /* return array of command widgets */
2047 Widget **command_widgets;
2048 XtCallbackProc name_callback;
2049 Widget *formp; /* return */
2051 Widget popup, form, label, above, left, right, view;
2052 Widget *commands, *curr;
2056 Dimension width, other_width, max_width, border_width,
2057 height, cumulative_height, screen_height;
2060 commands = (Widget *) alloc((unsigned) num_names * sizeof (Widget));
2063 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
2064 popup = XtCreatePopupShell(popup_name, transientShellWidgetClass,
2065 toplevel, args, num_args);
2066 XtOverrideTranslations(
2067 popup, XtParseTranslationTable("<Message>WM_PROTOCOLS: ec_delete()"));
2070 XtSetArg(args[num_args], XtNforceBars, False); num_args++;
2071 XtSetArg(args[num_args], XtNallowVert, True); num_args++;
2072 XtSetArg(args[num_args], XtNtranslations,
2073 XtParseTranslationTable(popup_translations)); num_args++;
2074 view = XtCreateManagedWidget("menuformview", viewportWidgetClass, popup,
2078 XtSetArg(args[num_args], XtNtranslations,
2079 XtParseTranslationTable(popup_translations)); num_args++;
2080 *formp = form = XtCreateManagedWidget("menuform", formWidgetClass, view,
2084 * Get the default distance between objects in the viewport widget.
2085 * (Something is fishy here: 'distance' ends up being 0 but there
2086 * is a non-zero gap between the borders of the internal widgets.
2087 * It matches exactly the default value of 4 for defaultDistance.)
2090 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance); num_args++;
2091 XtSetArg(args[num_args], nhStr(XtNborderWidth), &border_width); num_args++;
2092 XtGetValues(view, args, num_args);
2093 if (distance < 1 || distance > 32766)
2100 #if defined(X11R6) && defined(XI18N)
2101 XtSetArg(args[num_args], XtNinternational, True); num_args++;
2103 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2104 label = XtCreateManagedWidget(popup_label, labelWidgetClass, form, args,
2107 cumulative_height = 0;
2108 XtSetArg(args[0], XtNheight, &height);
2109 XtGetValues(label, args, ONE);
2110 cumulative_height += distance + height; /* no border for label */
2113 * Create the left button.
2116 XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++;
2118 XtSetArg(args[num_args], nhStr(XtNshapeStyle),
2119 XmuShapeRoundedRectangle); num_args++;
2121 left = XtCreateManagedWidget(left_name, commandWidgetClass, form, args,
2123 XtAddCallback(left, XtNcallback, left_callback, (XtPointer) 0);
2124 skip = (distance < 4) ? 8 : 2 * distance;
2127 XtSetArg(args[0], XtNheight, &height);
2128 XtGetValues(left, args, ONE);
2129 cumulative_height += distance + height + 2 * border_width;
2132 * Create right button.
2135 XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
2136 XtSetArg(args[num_args], nhStr(XtNhorizDistance), skip); num_args++;
2137 XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++;
2139 XtSetArg(args[num_args], nhStr(XtNshapeStyle),
2140 XmuShapeRoundedRectangle); num_args++;
2142 #if defined(X11R6) && defined(XI18N)
2143 XtSetArg(args[num_args], XtNinternational, True); num_args++;
2145 right = XtCreateManagedWidget(right_name, commandWidgetClass, form, args,
2147 XtAddCallback(right, XtNcallback, right_callback, (XtPointer) 0);
2149 XtInstallAccelerators(form, left);
2150 XtInstallAccelerators(form, right);
2153 * Create and place the command widgets.
2155 for (i = 0, above = left, curr = commands; i < num_names; i++) {
2156 if (!widget_names[i])
2159 XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++;
2160 if (above == left) {
2161 /* if first, we are farther apart */
2162 XtSetArg(args[num_args], nhStr(XtNvertDistance), skip); num_args++;
2163 cumulative_height += skip;
2165 cumulative_height += distance;
2166 cumulative_height += height + 2 * border_width;
2168 #if defined(X11R6) && defined(XI18N)
2169 XtSetArg(args[num_args], XtNinternational, True);
2172 *curr = XtCreateManagedWidget(widget_names[i], commandWidgetClass,
2173 form, args, num_args);
2174 XtAddCallback(*curr, XtNcallback, name_callback,
2175 (XtPointer) (ptrdiff_t) i);
2178 cumulative_height += distance; /* space at bottom of form */
2181 * Now find the largest width. Start with width of left + right buttons
2182 * ('dismiss' + 'help' or 'quit' + 'random'), since they are adjacent.
2184 XtSetArg(args[0], XtNwidth, &max_width);
2185 XtGetValues(left, args, ONE);
2186 XtSetArg(args[0], XtNwidth, &width);
2187 XtGetValues(right, args, ONE);
2188 /* doesn't count leftmost 'distance + border_width' and
2189 rightmost 'border_width + distance' since all entries have those */
2190 max_width = max_width + border_width + skip + border_width + width;
2192 /* Next, the title. */
2193 XtSetArg(args[0], XtNwidth, &width);
2194 XtGetValues(label, args, ONE);
2195 if (width > max_width)
2198 /* Finally, the commands. */
2199 for (i = 0, curr = commands; i < num_names; i++) {
2200 if (!widget_names[i])
2202 XtSetArg(args[0], XtNwidth, &width);
2203 XtGetValues(*curr, args, ONE);
2204 if (width > max_width)
2210 * Re-do the two side-by-side widgets to take up half the width each.
2212 * With max_width and skip both having even values, we never have to
2213 * tweak left or right to maybe be one pixel wider than the other.
2217 XtSetArg(args[0], XtNwidth, &width);
2218 XtGetValues(left, args, ONE);
2219 XtSetArg(args[0], XtNwidth, &other_width);
2220 XtGetValues(right, args, ONE);
2221 if (width + border_width + skip / 2 < max_width / 2
2222 && other_width + border_width + skip / 2 < max_width / 2) {
2223 /* both are narrower than half */
2224 width = other_width = max_width / 2 - border_width - skip / 2;
2225 XtSetArg(args[0], XtNwidth, width);
2226 XtSetValues(left, args, ONE);
2227 XtSetArg(args[0], XtNwidth, other_width);
2228 XtSetValues(right, args, ONE);
2229 } else if (width + border_width + skip / 2 < max_width / 2) {
2230 /* 'other_width' (right) is half or more */
2231 width = max_width - other_width - 2 * border_width - skip;
2232 XtSetArg(args[0], XtNwidth, width);
2233 XtSetValues(left, args, ONE);
2234 } else if (other_width + border_width + skip / 2 < max_width / 2) {
2235 /* 'width' (left) is half or more */
2236 other_width = max_width - width - 2 * border_width - skip;
2237 XtSetArg(args[0], XtNwidth, other_width);
2238 XtSetValues(right, args, ONE);
2240 ; /* both are exactly half... */
2244 * Finally, set all of the single line widgets to the largest width.
2246 XtSetArg(args[0], XtNwidth, max_width);
2247 XtSetValues(label, args, ONE);
2249 for (i = 0, curr = commands; i < num_names; i++) {
2250 if (!widget_names[i])
2252 XtSetArg(args[0], XtNwidth, max_width);
2253 XtSetValues(*curr, args, ONE);
2257 if (command_widgets)
2258 *command_widgets = commands;
2260 free((char *) commands);
2263 * If the menu's complete height is too big for the display,
2264 * forcing the height to be smaller will cause the vertical
2265 * scroll bar (enabled but not forced above) to be included.
2267 screen_height = XHeightOfScreen(XtScreen(popup));
2268 screen_height -= appResources.extcmd_height_delta; /* NetHack.ad */
2269 if (cumulative_height >= screen_height) {
2270 /* 25 is a guesstimate for scrollbar width;
2271 window manager might override the request for y==1 */
2273 XtSetArg(args[num_args], XtNy, 1); num_args++;
2274 XtSetArg(args[num_args], XtNwidth, max_width + 25); num_args++;
2275 XtSetArg(args[num_args], XtNheight, screen_height - 1); num_args++;
2276 XtSetValues(popup, args, num_args);
2278 XtRealizeWidget(popup);
2279 XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1);
2281 /* during role selection, highlight "random" as pre-selected choice */
2282 if (right_callback == ps_random && index(ps_randchars, '\n'))