65a154e7ebb267a75a266a072f0e021f4bdfc19b
[xboard.git] / menus.c
1 /*
2  * menus.c -- platform-indendent menu handling code for XBoard
3  *
4  * Copyright 1991 by Digital Equipment Corporation, Maynard,
5  * Massachusetts.
6  *
7  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
9  *
10  * The following terms apply to Digital Equipment Corporation's copyright
11  * interest in XBoard:
12  * ------------------------------------------------------------------------
13  * All Rights Reserved
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted,
17  * provided that the above copyright notice appear in all copies and that
18  * both that copyright notice and this permission notice appear in
19  * supporting documentation, and that the name of Digital not be
20  * used in advertising or publicity pertaining to distribution of the
21  * software without specific, written prior permission.
22  *
23  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29  * SOFTWARE.
30  * ------------------------------------------------------------------------
31  *
32  * The following terms apply to the enhanced version of XBoard
33  * distributed by the Free Software Foundation:
34  * ------------------------------------------------------------------------
35  *
36  * GNU XBoard is free software: you can redistribute it and/or modify
37  * it under the terms of the GNU General Public License as published by
38  * the Free Software Foundation, either version 3 of the License, or (at
39  * your option) any later version.
40  *
41  * GNU XBoard is distributed in the hope that it will be useful, but
42  * WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44  * General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program. If not, see http://www.gnu.org/licenses/.  *
48  *
49  *------------------------------------------------------------------------
50  ** See the file ChangeLog for a revision history.  */
51
52 #define HIGHDRAG 1
53
54 #include "config.h"
55
56 #include <stdio.h>
57 #include <ctype.h>
58 #include <signal.h>
59 #include <errno.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <pwd.h>
63 #include <math.h>
64
65 #if STDC_HEADERS
66 # include <stdlib.h>
67 # include <string.h>
68 #else /* not STDC_HEADERS */
69 extern char *getenv();
70 # if HAVE_STRING_H
71 #  include <string.h>
72 # else /* not HAVE_STRING_H */
73 #  include <strings.h>
74 # endif /* not HAVE_STRING_H */
75 #endif /* not STDC_HEADERS */
76
77 #if HAVE_UNISTD_H
78 # include <unistd.h>
79 #endif
80
81 #if ENABLE_NLS
82 #include <locale.h>
83 #endif
84
85 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
86 #include "common.h"
87
88 #include "frontend.h"
89 #include "backend.h"
90 #include "menus.h"
91 #include "gettext.h"
92
93 #ifdef ENABLE_NLS
94 # define  _(s) gettext (s)
95 # define N_(s) gettext_noop (s)
96 #else
97 # define  _(s) (s)
98 # define N_(s)  s
99 #endif
100
101 /*
102  * Button/menu procedures
103  */
104
105 char  *gameCopyFilename, *gamePasteFilename;
106 Boolean saveSettingsOnExit;
107 char *settingsFileName;
108
109 static int
110 LoadGamePopUp (FILE *f, int gameNumber, char *title)
111 {
112     cmailMsgLoaded = FALSE;
113     if (gameNumber == 0) {
114         int error = GameListBuild(f);
115         if (error) {
116             DisplayError(_("Cannot build game list"), error);
117         } else if (!ListEmpty(&gameList) &&
118                    ((ListGame *) gameList.tailPred)->number > 1) {
119             GameListPopUp(f, title);
120             return TRUE;
121         }
122         GameListDestroy();
123         gameNumber = 1;
124     }
125     return LoadGame(f, gameNumber, title, FALSE);
126 }
127
128 void
129 LoadGameProc ()
130 {
131     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
132         Reset(FALSE, TRUE);
133     }
134     FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
135 }
136
137 void
138 LoadNextGameProc ()
139 {
140     ReloadGame(1);
141 }
142
143 void
144 LoadPrevGameProc ()
145 {
146     ReloadGame(-1);
147 }
148
149 void
150 ReloadGameProc ()
151 {
152     ReloadGame(0);
153 }
154
155 void
156 LoadNextPositionProc ()
157 {
158     ReloadPosition(1);
159 }
160
161 void
162 LoadPrevPositionProc ()
163 {
164     ReloadPosition(-1);
165 }
166
167 void
168 ReloadPositionProc ()
169 {
170     ReloadPosition(0);
171 }
172
173 void
174 LoadPositionProc()
175 {
176     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
177         Reset(FALSE, TRUE);
178     }
179     FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
180 }
181
182 void
183 SaveGameProc ()
184 {
185     FileNamePopUp(_("Save game file name?"),
186                   DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
187                   appData.oldSaveStyle ? ".game" : ".pgn",
188                   SaveGame, "a");
189 }
190
191 void
192 SavePositionProc ()
193 {
194     FileNamePopUp(_("Save position file name?"),
195                   DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
196                   appData.oldSaveStyle ? ".pos" : ".fen",
197                   SavePosition, "a");
198 }
199
200 void
201 ReloadCmailMsgProc ()
202 {
203     ReloadCmailMsgEvent(FALSE);
204 }
205
206 void
207 CopyFENToClipboard ()
208 { // wrapper to make call from back-end possible
209   CopyPositionProc();
210 }
211
212 void
213 CopyPositionProc ()
214 {
215     static char *selected_fen_position=NULL;
216     if(gameMode == EditPosition) EditPositionDone(TRUE);
217     if (selected_fen_position) free(selected_fen_position);
218     selected_fen_position = (char *)PositionToFEN(currentMove, NULL, 1);
219     if (!selected_fen_position) return;
220     CopySomething(selected_fen_position);
221 }
222
223 void
224 CopyGameProc ()
225 {
226   int ret;
227
228   ret = SaveGameToFile(gameCopyFilename, FALSE);
229   if (!ret) return;
230
231   CopySomething(NULL);
232 }
233
234 void
235 CopyGameListProc ()
236 {
237   if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
238   CopySomething(NULL);
239 }
240
241 void
242 AutoSaveGame ()
243 {
244     SaveGameProc();
245 }
246
247
248 void
249 QuitProc ()
250 {
251     ExitEvent(0);
252 }
253
254 void
255 MatchProc ()
256 {
257     MatchEvent(2);
258 }
259
260 void
261 AdjuWhiteProc ()
262 {
263     UserAdjudicationEvent(+1);
264 }
265
266 void
267 AdjuBlackProc ()
268 {
269     UserAdjudicationEvent(-1);
270 }
271
272 void
273 AdjuDrawProc ()
274 {
275     UserAdjudicationEvent(0);
276 }
277
278 void
279 RevertProc ()
280 {
281     RevertEvent(False);
282 }
283
284 void
285 AnnotateProc ()
286 {
287     RevertEvent(True);
288 }
289
290 void
291 FlipViewProc ()
292 {
293     if(twoBoards) { partnerUp = 1; DrawPosition(True, NULL); partnerUp = 0; }
294     flipView = !flipView;
295     DrawPosition(True, NULL);
296 }
297
298 void
299 SaveOnExitProc ()
300 {
301   saveSettingsOnExit = !saveSettingsOnExit;
302
303   MarkMenuItem("Options.SaveSettingsonExit", saveSettingsOnExit);
304 }
305
306 void
307 SaveSettingsProc ()
308 {
309   SaveSettings(settingsFileName);
310 }
311
312 void
313 InfoProc ()
314 {
315     char buf[MSG_SIZ];
316     snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
317             INFODIR, INFOFILE);
318     system(buf);
319 }
320
321 void
322 BugReportProc ()
323 {
324     char buf[MSG_SIZ];
325     snprintf(buf, MSG_SIZ, "%s mailto:bug-xboard@gnu.org", appData.sysOpen);
326     system(buf);
327 }
328
329 void
330 GuideProc ()
331 {
332     char buf[MSG_SIZ];
333     snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/user_guide/UserGuide.html", appData.sysOpen);
334     system(buf);
335 }
336
337 void
338 HomePageProc ()
339 {
340     char buf[MSG_SIZ];
341     snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/", appData.sysOpen);
342     system(buf);
343 }
344
345 void
346 NewsPageProc ()
347 {
348     char buf[MSG_SIZ];
349     snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/whats_new/portal.html", appData.sysOpen);
350     system(buf);
351 }
352
353 void
354 AboutProc ()
355 {
356     char buf[2 * MSG_SIZ];
357 #if ZIPPY
358     char *zippy = _(" (with Zippy code)");
359 #else
360     char *zippy = "";
361 #endif
362     snprintf(buf, sizeof(buf),
363 _("%s%s\n\n"
364 "Copyright 1991 Digital Equipment Corporation\n"
365 "Enhancements Copyright 1992-2014 Free Software Foundation\n"
366 "Enhancements Copyright 2005 Alessandro Scotti\n\n"
367 "%s is free software and carries NO WARRANTY;"
368 "see the file COPYING for more information.\n"
369 "The GTK build of this version is experimental and unstable\n\n"
370 "Visit XBoard on the web at: http://www.gnu.org/software/xboard/\n"
371 "Check out the newest features at: http://www.gnu.org/software/xboard/whats_new.html\n\n"
372 "Report bugs via email at: <bug-xboard@gnu.org>\n\n"
373   ),
374             programVersion, zippy, PACKAGE);
375     ErrorPopUp(_("About XBoard"), buf, FALSE);
376 }
377
378 void
379 DebugProc ()
380 {
381     appData.debugMode = !appData.debugMode;
382     if(!strcmp(appData.nameOfDebugFile, "stderr")) return; // stderr is already open, and should never be closed
383     if(!appData.debugMode) fclose(debugFP);
384     else {
385         debugFP = fopen(appData.nameOfDebugFile, "w");
386         if(debugFP == NULL) debugFP = stderr;
387         else setbuf(debugFP, NULL);
388     }
389 }
390
391 void
392 EditEngineProc ()
393 {
394     EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
395 }
396
397 void
398 NothingProc ()
399 {
400     return;
401 }
402
403 #ifdef OPTIONSDIALOG
404 #   define MARK_MENU_ITEM(X,Y)
405 #else
406 #   define MARK_MENU_ITEM(X,Y) MarkMenuItem(X, Y)
407 #endif
408
409 void
410 PonderNextMoveProc ()
411 {
412   PonderNextMoveEvent(!appData.ponderNextMove);
413   MARK_MENU_ITEM("Options.PonderNextMove", appData.ponderNextMove);
414 }
415
416 void
417 AlwaysQueenProc ()
418 {
419     appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
420     MARK_MENU_ITEM("Options.AlwaysQueen", appData.alwaysPromoteToQueen);
421 }
422
423 void
424 AnimateDraggingProc ()
425 {
426     appData.animateDragging = !appData.animateDragging;
427
428     if (appData.animateDragging) CreateAnimVars();
429     MARK_MENU_ITEM("Options.AnimateDragging", appData.animateDragging);
430 }
431
432 void
433 AnimateMovingProc ()
434 {
435     appData.animate = !appData.animate;
436     if (appData.animate) CreateAnimVars();
437     MARK_MENU_ITEM("Options.AnimateMoving", appData.animate);
438 }
439
440 void
441 AutoflagProc ()
442 {
443     appData.autoCallFlag = !appData.autoCallFlag;
444     MARK_MENU_ITEM("Options.AutoFlag", appData.autoCallFlag);
445 }
446
447 void
448 AutoflipProc ()
449 {
450     appData.autoFlipView = !appData.autoFlipView;
451     MARK_MENU_ITEM("Options.AutoFlipView", appData.autoFlipView);
452 }
453
454 void
455 BlindfoldProc ()
456 {
457     appData.blindfold = !appData.blindfold;
458     MARK_MENU_ITEM("Options.Blindfold", appData.blindfold);
459     DrawPosition(True, NULL);
460 }
461
462 void
463 TestLegalityProc ()
464 {
465     appData.testLegality = !appData.testLegality;
466     MARK_MENU_ITEM("Options.TestLegality", appData.testLegality);
467 }
468
469
470 void
471 FlashMovesProc ()
472 {
473     if (appData.flashCount == 0) {
474         appData.flashCount = 3;
475     } else {
476         appData.flashCount = -appData.flashCount;
477     }
478     MARK_MENU_ITEM("Options.FlashMoves", appData.flashCount > 0);
479 }
480
481 #if HIGHDRAG
482 void
483 HighlightDraggingProc ()
484 {
485     appData.highlightDragging = !appData.highlightDragging;
486     MARK_MENU_ITEM("Options.HighlightDragging", appData.highlightDragging);
487 }
488 #endif
489
490 void
491 HighlightLastMoveProc ()
492 {
493     appData.highlightLastMove = !appData.highlightLastMove;
494     MARK_MENU_ITEM("Options.HighlightLastMove", appData.highlightLastMove);
495 }
496
497 void
498 HighlightArrowProc ()
499 {
500     appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
501     MARK_MENU_ITEM("Options.HighlightWithArrow", appData.highlightMoveWithArrow);
502 }
503
504 void
505 IcsAlarmProc ()
506 {
507     appData.icsAlarm = !appData.icsAlarm;
508 //    MARK_MENU_ITEM("Options.ICSAlarm", appData.icsAlarm);
509 }
510
511 void
512 MoveSoundProc ()
513 {
514     appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
515     MARK_MENU_ITEM("Options.MoveSound", appData.ringBellAfterMoves);
516 }
517
518 void
519 OneClickProc ()
520 {
521     appData.oneClick = !appData.oneClick;
522     MARK_MENU_ITEM("Options.OneClickMoving", appData.oneClick);
523 }
524
525 void
526 PeriodicUpdatesProc ()
527 {
528     PeriodicUpdatesEvent(!appData.periodicUpdates);
529     MARK_MENU_ITEM("Options.PeriodicUpdates", appData.periodicUpdates);
530 }
531
532 void
533 PopupExitMessageProc ()
534 {
535     appData.popupExitMessage = !appData.popupExitMessage;
536     MARK_MENU_ITEM("Options.PopupExitMessage", appData.popupExitMessage);
537 }
538
539 void
540 PopupMoveErrorsProc ()
541 {
542     appData.popupMoveErrors = !appData.popupMoveErrors;
543     MARK_MENU_ITEM("Options.PopupMoveErrors", appData.popupMoveErrors);
544 }
545
546 void
547 PremoveProc ()
548 {
549     appData.premove = !appData.premove;
550 //    MARK_MENU_ITEM("Options.Premove", appData.premove);
551 }
552
553 void
554 ShowCoordsProc ()
555 {
556     appData.showCoords = !appData.showCoords;
557     MARK_MENU_ITEM("Options.ShowCoords", appData.showCoords);
558     DrawPosition(True, NULL);
559 }
560
561 void
562 ShowThinkingProc ()
563 {
564     appData.showThinking = !appData.showThinking; // [HGM] thinking: taken out of ShowThinkingEvent
565     ShowThinkingEvent();
566 }
567
568 void
569 HideThinkingProc ()
570 {
571   appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: taken out of ShowThinkingEvent
572   ShowThinkingEvent();
573
574   MARK_MENU_ITEM("Options.HideThinking", appData.hideThinkingFromHuman);
575 }
576
577 void
578 CreateBookDelayed ()
579 {
580   ScheduleDelayedEvent(CreateBookEvent, 50);
581 }
582
583 void
584 SaveSelectedProc ()
585 {
586   FileNamePopUp(_("Save game file name?"),
587                   "",
588                   ".pgn",
589                   SaveSelected, "a");
590 }
591
592 /*
593  *  Menu definition tables
594  */
595
596 MenuItem fileMenu[] = {
597   {N_("New Game"),             "<Ctrl>n",          "NewGame",              ResetGameEvent},
598   {N_("New Shuffle Game..."),   NULL,              "NewShuffleGame",       ShuffleMenuProc},
599   {N_("New Variant..."),       "<Alt><Shift>v",    "NewVariant",           NewVariantProc},// [HGM] variant: not functional yet
600   {"----",                      NULL,               NULL,                  NothingProc},
601   {N_("Load Game"),            "<Ctrl>o",          "LoadGame",             LoadGameProc,           CHECK},
602   {N_("Load Position"),        "<Ctrl><Shift>o",   "LoadPosition",         LoadPositionProc},
603   {N_("Next Position"),        "<Shift>Page_Down", "LoadNextPosition",     LoadNextPositionProc},
604   {N_("Prev Position"),        "<Shift>Page_Up",   "LoadPreviousPosition", LoadPrevPositionProc},
605   {"----",                      NULL,               NULL,                  NothingProc},
606   {N_("Save Game"),            "<Ctrl>s",          "SaveGame",             SaveGameProc},
607   {N_("Save Position"),        "<Ctrl><Shift>s",   "SavePosition",         SavePositionProc},
608   {N_("Save Selected Games"),   NULL,              "SaveSelected",         SaveSelectedProc},
609   {N_("Save Games as Book"),    NULL,              "CreateBook",           CreateBookDelayed},
610   {"----",                      NULL,               NULL,                  NothingProc},
611   {N_("Mail Move"),             NULL,              "MailMove",             MailMoveEvent},
612   {N_("Reload CMail Message"),  NULL,              "ReloadCMailMessage",   ReloadCmailMsgProc},
613   {"----",                      NULL,               NULL,                  NothingProc},
614   {N_("Quit "),                "<Ctrl>q",          "Quit",                 QuitProc},
615   {NULL,                        NULL,               NULL,                  NULL}
616 };
617
618 MenuItem editMenu[] = {
619   {N_("Copy Game"),      "<Ctrl>c",        "CopyGame",      CopyGameProc},
620   {N_("Copy Position"),  "<Ctrl><Shift>c", "CopyPosition",  CopyPositionProc},
621   {N_("Copy Game List"),  NULL,            "CopyGameList",  CopyGameListProc},
622   {"----",                NULL,             NULL,           NothingProc},
623   {N_("Paste Game"),     "<Ctrl>v",        "PasteGame",     PasteGameProc},
624   {N_("Paste Position"), "<Ctrl><Shift>v", "PastePosition", PastePositionProc},
625   {"----",                NULL,             NULL,           NothingProc},
626   {N_("Edit Game"),      "<Ctrl>e",        "EditGame",      EditGameEvent},
627   {N_("Edit Position"),  "<Ctrl><Shift>e", "EditPosition",  EditPositionEvent},
628   {N_("Edit Tags"),       NULL,            "EditTags",      EditTagsProc},
629   {N_("Edit Comment"),    NULL,            "EditComment",   EditCommentProc},
630   {N_("Edit Book"),       NULL,            "EditBook",      EditBookEvent},
631   {"----",                NULL,             NULL,           NothingProc},
632   {N_("Revert"),         "Home",           "Revert",        RevertProc},
633   {N_("Annotate"),        NULL,            "Annotate",      AnnotateProc},
634   {N_("Truncate Game"),  "End",            "TruncateGame",  TruncateGameEvent},
635   {"----",                NULL,             NULL,           NothingProc},
636   {N_("Backward"),       "<Alt>Left",      "Backward",      BackwardEvent},
637   {N_("Forward"),        "<Alt>Right",     "Forward",       ForwardEvent},
638   {N_("Back to Start"),  "<Alt>Home",      "BacktoStart",   ToStartEvent},
639   {N_("Forward to End"), "<Alt>End",       "ForwardtoEnd",  ToEndEvent},
640   {NULL,                  NULL,             NULL,           NULL}
641 };
642
643 MenuItem viewMenu[] = {
644   {N_("Flip View"),         "F2",            "FlipView",        FlipViewProc,           CHECK},
645   {"----",                   NULL,            NULL,             NothingProc},
646   {N_("Engine Output"),     "<Alt><Shift>o", "EngineOutput",    EngineOutputProc,       CHECK},
647   {N_("Move History"),      "<Alt><Shift>h", "MoveHistory",     HistoryShowProc,        CHECK}, // [HGM] hist: activate 4.2.7 code
648   {N_("Evaluation Graph"),  "<Alt><Shift>e", "EvaluationGraph", EvalGraphProc,          CHECK},
649   {N_("Game List"),         "<Alt><Shift>g", "GameList",        ShowGameListProc,       CHECK},
650   {N_("ICS text menu"),      NULL,           "ICStextmenu",     IcsTextProc,            CHECK},
651   {"----",                   NULL,            NULL,             NothingProc},
652   {N_("Tags"),               NULL,           "Tags",            EditTagsProc,           CHECK},
653   {N_("Comments"),           NULL,           "Comments",        EditCommentProc,        CHECK},
654   {N_("ICS Input Box"),      NULL,           "ICSInputBox",     IcsInputBoxProc,        CHECK},
655   {N_("ICS/Chat Console"),   NULL,           "OpenChatWindow",  ChatProc,               CHECK},
656   {"----",                   NULL,            NULL,             NothingProc},
657   {N_("Board..."),           NULL,           "Board",           BoardOptionsProc},
658   {N_("Game List Tags..."),  NULL,           "GameListTags",    GameListOptionsProc},
659   {NULL,                     NULL,            NULL,             NULL}
660 };
661
662 MenuItem modeMenu[] = {
663   {N_("Machine White"),  "<Ctrl>w",        "MachineWhite",  MachineWhiteEvent,              RADIO },
664   {N_("Machine Black"),  "<Ctrl>b",        "MachineBlack",  MachineBlackEvent,              RADIO },
665   {N_("Two Machines"),   "<Ctrl>t",        "TwoMachines",   TwoMachinesEvent,               RADIO },
666   {N_("Analysis Mode"),  "<Ctrl>a",        "AnalysisMode",  (MenuProc*) AnalyzeModeEvent,   RADIO },
667   {N_("Analyze Game"),   "<Ctrl>g",        "AnalyzeFile",   AnalyzeFileEvent,               RADIO },
668   {N_("Edit Game"),      "<Ctrl>e",        "EditGame",      EditGameEvent,                  RADIO },
669   {N_("Edit Position"),  "<Ctrl><Shift>e", "EditPosition",  EditPositionEvent,              RADIO },
670   {N_("Training"),        NULL,            "Training",      TrainingEvent,                  RADIO },
671   {N_("ICS Client"),      NULL,            "ICSClient",     IcsClientEvent,                 RADIO },
672   {"----",                NULL,             NULL,           NothingProc},
673   {N_("Machine Match"),   NULL,            "MachineMatch",  MatchProc,                      CHECK },
674   {N_("Pause"),          "Pause",          "Pause",         PauseEvent,                     CHECK },
675   {NULL,                  NULL,             NULL,           NULL}
676 };
677
678 MenuItem actionMenu[] = {
679   {N_("Accept"),             "F3",   "Accept",             AcceptEvent},
680   {N_("Decline"),            "F4",   "Decline",            DeclineEvent},
681   {N_("Rematch"),            "F12",  "Rematch",            RematchEvent},
682   {"----",                    NULL,   NULL,                NothingProc},
683   {N_("Call Flag"),          "F5",   "CallFlag",           CallFlagEvent},
684   {N_("Draw"),               "F6",   "Draw",               DrawEvent},
685   {N_("Adjourn"),            "F7",   "Adjourn",            AdjournEvent},
686   {N_("Abort"),              "F8",   "Abort",              AbortEvent},
687   {N_("Resign"),             "F9",   "Resign",             ResignEvent},
688   {"----",                    NULL,   NULL,                NothingProc},
689   {N_("Stop Observing"),     "F10",  "StopObserving",      StopObservingEvent},
690   {N_("Stop Examining"),     "F11",  "StopExamining",      StopExaminingEvent},
691   {N_("Upload to Examine"),   NULL,  "UploadtoExamine",    UploadGameEvent},
692   {"----",                    NULL,   NULL,                NothingProc},
693   {N_("Adjudicate to White"), NULL,  "AdjudicatetoWhite",  AdjuWhiteProc},
694   {N_("Adjudicate to Black"), NULL,  "AdjudicatetoBlack",  AdjuBlackProc},
695   {N_("Adjudicate Draw"),     NULL,  "AdjudicateDraw",     AdjuDrawProc},
696   {NULL,                      NULL,   NULL,                NULL}
697 };
698
699 MenuItem engineMenu[100] = {
700   {N_("Edit Engine List..."),      NULL,     "EditEngList",      EditEngineProc},
701   {"----",                         NULL,      NULL,              NothingProc},
702   {N_("Load New 1st Engine..."),   NULL,     "LoadNew1stEngine", LoadEngine1Proc},
703   {N_("Load New 2nd Engine..."),   NULL,     "LoadNew2ndEngine", LoadEngine2Proc},
704   {"----",                         NULL,      NULL,              NothingProc},
705   {N_("Engine #1 Settings..."),    NULL,     "Engine#1Settings", FirstSettingsProc},
706   {N_("Engine #2 Settings..."),    NULL,     "Engine#2Settings", SecondSettingsProc},
707   {"----",                         NULL,      NULL,              NothingProc},
708   {N_("Hint"),                     NULL,     "Hint",             HintEvent},
709   {N_("Book"),                     NULL,     "Book",             BookEvent},
710   {"----",                         NULL,      NULL,              NothingProc},
711   {N_("Move Now"),                "<Ctrl>m", "MoveNow",          MoveNowEvent},
712   {N_("Retract Move"),            "<Ctrl>x", "RetractMove",      RetractMoveEvent},
713   {NULL,                           NULL,      NULL,              NULL}
714 };
715
716 MenuItem optionsMenu[] = {
717 #ifdef OPTIONSDIALOG
718   {N_("General..."),              NULL,             "General",             OptionsProc},
719 #endif
720   {N_("Time Control..."),        "<Alt><Shift>t",   "TimeControl",         TimeControlProc},
721   {N_("Common Engine..."),       "<Alt><Shift>u",   "CommonEngine",        UciMenuProc},
722   {N_("Adjudications..."),       "<Alt><Shift>j",   "Adjudications",       EngineMenuProc},
723   {N_("ICS..."),                  NULL,             "ICS",                 IcsOptionsProc},
724   {N_("Tournament..."),           NULL,             "Match",               MatchOptionsProc},
725   {N_("Load Game..."),            NULL,             "LoadGame",            LoadOptionsProc},
726   {N_("Save Game..."),            NULL,             "SaveGame",            SaveOptionsProc},
727   {N_("Game List..."),            NULL,             "GameList",            GameListOptionsProc},
728   {N_("Sounds..."),               NULL,             "Sounds",              SoundOptionsProc},
729   {"----",                        NULL,              NULL,                 NothingProc},
730 #ifndef OPTIONSDIALOG
731   {N_("Always Queen"),           "<Ctrl><Shift>q",  "AlwaysQueen",         AlwaysQueenProc},
732   {N_("Animate Dragging"),        NULL,             "AnimateDragging",     AnimateDraggingProc},
733   {N_("Animate Moving"),         "<Ctrl><Shift>a",  "AnimateMoving",       AnimateMovingProc},
734   {N_("Auto Flag"),              "<Ctrl><Shift>f",  "AutoFlag",            AutoflagProc},
735   {N_("Auto Flip View"),          NULL,             "AutoFlipView",        AutoflipProc},
736   {N_("Blindfold"),               NULL,             "Blindfold",           BlindfoldProc},
737   {N_("Flash Moves"),             NULL,             "FlashMoves",          FlashMovesProc},
738 #if HIGHDRAG
739   {N_("Highlight Dragging"),      NULL,             "HighlightDragging",   HighlightDraggingProc},
740 #endif
741   {N_("Highlight Last Move"),     NULL,             "HighlightLastMove",   HighlightLastMoveProc},
742   {N_("Highlight With Arrow"),    NULL,             "HighlightWithArrow",  HighlightArrowProc},
743   {N_("Move Sound"),              NULL,             "MoveSound",           MoveSoundProc},
744   {N_("One-Click Moving"),        NULL,             "OneClickMoving",      OneClickProc},
745   {N_("Periodic Updates"),        NULL,             "PeriodicUpdates",     PeriodicUpdatesProc},
746   {N_("Ponder Next Move"),       "<Ctrl><Shift>p",  "PonderNextMove",      PonderNextMoveProc},
747   {N_("Popup Exit Message"),      NULL,             "PopupExitMessage",    PopupExitMessageProc},
748   {N_("Popup Move Errors"),       NULL,             "PopupMoveErrors",     PopupMoveErrorsProc},
749   {N_("Show Coords"),             NULL,             "ShowCoords",          ShowCoordsProc},
750   {N_("Hide Thinking"),          "<Ctrl><Shift>h",  "HideThinking",        HideThinkingProc},
751   {N_("Test Legality"),          "<Ctrl><Shift>l",  "TestLegality",        TestLegalityProc},
752   {"----",                        NULL,              NULL,                 NothingProc},
753 #endif
754   {N_("Save Settings Now"),       NULL,             "SaveSettingsNow",     SaveSettingsProc},
755   {N_("Save Settings on Exit"),   NULL,             "SaveSettingsonExit",  SaveOnExitProc,         CHECK },
756   {NULL,                          NULL,              NULL,                 NULL}
757 };
758
759 MenuItem helpMenu[] = {
760   {N_("Info XBoard"),            NULL,   "InfoXBoard",           InfoProc},
761   {N_("Man XBoard"),            "F1",    "ManXBoard",            ManProc},
762   {"----",                       NULL,    NULL,                  NothingProc},
763   {N_("XBoard Home Page"),       NULL,   "XBoardHomePage",       HomePageProc},
764   {N_("On-line User Guide"),     NULL,   "On-lineUserGuide",     GuideProc},
765   {N_("Development News"),       NULL,   "DevelopmentNews",      NewsPageProc},
766   {N_("e-Mail Bug Report"),      NULL,   "e-MailBugReport",      BugReportProc},
767   {"----",                       NULL,    NULL,                  NothingProc},
768   {N_("About XBoard"),           NULL,   "AboutXBoard",          AboutProc},
769   {NULL,                         NULL,    NULL,                  NULL}
770 };
771
772 MenuItem noMenu[] = {
773   { "", "<Alt>Next" ,"LoadNextGame", LoadNextGameProc },
774   { "", "<Alt>Prior" ,"LoadPrevGame", LoadPrevGameProc },
775   { "", NULL,"ReloadGame", ReloadGameProc },
776   { "", NULL,"ReloadPosition", ReloadPositionProc },
777 #ifndef OPTIONSDIALOG
778   { "", NULL,"AlwaysQueen", AlwaysQueenProc },
779   { "", NULL,"AnimateDragging", AnimateDraggingProc },
780   { "", NULL,"AnimateMoving", AnimateMovingProc },
781   { "", NULL,"Autoflag", AutoflagProc },
782   { "", NULL,"Autoflip", AutoflipProc },
783   { "", NULL,"Blindfold", BlindfoldProc },
784   { "", NULL,"FlashMoves", FlashMovesProc },
785 #if HIGHDRAG
786   { "", NULL,"HighlightDragging", HighlightDraggingProc },
787 #endif
788   { "", NULL,"HighlightLastMove", HighlightLastMoveProc },
789   { "", NULL,"MoveSound", MoveSoundProc },
790   { "", NULL,"PeriodicUpdates", PeriodicUpdatesProc },
791   { "", NULL,"PopupExitMessage", PopupExitMessageProc },
792   { "", NULL,"PopupMoveErrors", PopupMoveErrorsProc },
793   { "", NULL,"ShowCoords", ShowCoordsProc },
794   { "", NULL,"ShowThinking", ShowThinkingProc },
795   { "", NULL,"HideThinking", HideThinkingProc },
796   { "", NULL,"TestLegality", TestLegalityProc },
797 #endif
798   { "", NULL,"AboutGame", AboutGameEvent },
799   { "", "<Ctrl>d" ,"DebugProc", DebugProc },
800   { "", NULL,"Nothing", NothingProc },
801   {NULL, NULL, NULL, NULL}
802 };
803
804 Menu menuBar[] = {
805     {N_("File"),    "File", fileMenu},
806     {N_("Edit"),    "Edit", editMenu},
807     {N_("View"),    "View", viewMenu},
808     {N_("Mode"),    "Mode", modeMenu},
809     {N_("Action"),  "Action", actionMenu},
810     {N_("Engine"),  "Engine", engineMenu},
811     {N_("Options"), "Options", optionsMenu},
812     {N_("Help"),    "Help", helpMenu},
813     {NULL, NULL, NULL}
814 };
815
816 MenuItem *
817 MenuNameToItem (char *menuName)
818 {
819     int i=0;
820     char buf[MSG_SIZ], *p;
821     MenuItem *menuTab;
822     static MenuItem a = { NULL, NULL, NULL, NothingProc };
823     extern Option mainOptions[];
824     safeStrCpy(buf, menuName, MSG_SIZ);
825     p = strchr(buf, '.');
826     if(!p) menuTab = noMenu, p = menuName; else {
827         *p++ = NULLCHAR;
828         for(i=0; menuBar[i].name; i++)
829             if(!strcmp(buf, menuBar[i].name)) break;
830         if(!menuBar[i].name) return NULL; // main menu not found
831         menuTab = menuBar[i].mi;
832     }
833     if(*p == NULLCHAR) { a.handle = mainOptions[i+1].handle; return &a; } // main menu bar
834     for(i=0; menuTab[i].string; i++)
835         if(menuTab[i].ref && !strcmp(p, menuTab[i].ref)) return menuTab + i;
836     return NULL; // item not found
837 }
838
839 int firstEngineItem;
840
841 void
842 AppendEnginesToMenu (char *list)
843 {
844     int i=0;
845     char *p;
846     if(appData.icsActive || appData.recentEngines <= 0) return;
847     for(firstEngineItem=0; engineMenu[firstEngineItem].string; firstEngineItem++);
848     recentEngines = strdup(list);
849     while (*list) {
850         p = strchr(list, '\n'); if(p == NULL) break;
851         if(i == 0) engineMenu[firstEngineItem++].string = "----"; // at least one valid item to add
852         *p = 0;
853         if(firstEngineItem + i < 99)
854             engineMenu[firstEngineItem+i].string = strdup(list); // just set name; MenuProc stays NULL
855         i++; *p = '\n'; list = p + 1;
856     }
857 }
858
859 Enables icsEnables[] = {
860     { "File.MailMove", False },
861     { "File.ReloadCMailMessage", False },
862     { "Mode.MachineBlack", False },
863     { "Mode.MachineWhite", False },
864     { "Mode.AnalysisMode", False },
865     { "Mode.AnalyzeFile", False },
866     { "Mode.TwoMachines", False },
867     { "Mode.MachineMatch", False },
868 #if !ZIPPY
869     { "Engine.Hint", False },
870     { "Engine.Book", False },
871     { "Engine.MoveNow", False },
872 #ifndef OPTIONSDIALOG
873     { "PeriodicUpdates", False },
874     { "HideThinking", False },
875     { "PonderNextMove", False },
876 #endif
877 #endif
878     { "Engine.Engine#1Settings", False },
879     { "Engine.Engine#2Settings", False },
880     { "Engine.Load1stEngine", False },
881     { "Engine.Load2ndEngine", False },
882     { "Edit.Annotate", False },
883     { "Options.Match", False },
884     { NULL, False }
885 };
886
887 Enables ncpEnables[] = {
888     { "File.MailMove", False },
889     { "File.ReloadCMailMessage", False },
890     { "Mode.MachineWhite", False },
891     { "Mode.MachineBlack", False },
892     { "Mode.AnalysisMode", False },
893     { "Mode.AnalyzeFile", False },
894     { "Mode.TwoMachines", False },
895     { "Mode.MachineMatch", False },
896     { "Mode.ICSClient", False },
897     { "View.ICStextmenu", False },
898     { "View.ICSInputBox", False },
899     { "View.OpenChatWindow", False },
900     { "Action.", False },
901     { "Edit.Revert", False },
902     { "Edit.Annotate", False },
903     { "Engine.Engine#1Settings", False },
904     { "Engine.Engine#2Settings", False },
905     { "Engine.MoveNow", False },
906     { "Engine.RetractMove", False },
907     { "Options.ICS", False },
908 #ifndef OPTIONSDIALOG
909     { "Options.AutoFlag", False },
910     { "Options.AutoFlip View", False },
911 //    { "Options.ICSAlarm", False },
912     { "Options.MoveSound", False },
913     { "Options.HideThinking", False },
914     { "Options.PeriodicUpdates", False },
915     { "Options.PonderNextMove", False },
916 #endif
917     { "Engine.Hint", False },
918     { "Engine.Book", False },
919     { NULL, False }
920 };
921
922 Enables gnuEnables[] = {
923     { "Mode.ICSClient", False },
924     { "View.ICStextmenu", False },
925     { "View.ICSInputBox", False },
926     { "View.OpenChatWindow", False },
927     { "Action.Accept", False },
928     { "Action.Decline", False },
929     { "Action.Rematch", False },
930     { "Action.Adjourn", False },
931     { "Action.StopExamining", False },
932     { "Action.StopObserving", False },
933     { "Action.UploadtoExamine", False },
934     { "Edit.Revert", False },
935     { "Edit.Annotate", False },
936     { "Options.ICS", False },
937
938     /* The next two options rely on SetCmailMode being called *after*    */
939     /* SetGNUMode so that when GNU is being used to give hints these     */
940     /* menu options are still available                                  */
941
942     { "File.MailMove", False },
943     { "File.ReloadCMailMessage", False },
944     // [HGM] The following have been added to make a switch from ncp to GNU mode possible
945     { "Mode.MachineWhite", True },
946     { "Mode.MachineBlack", True },
947     { "Mode.AnalysisMode", True },
948     { "Mode.AnalyzeFile", True },
949     { "Mode.TwoMachines", True },
950     { "Mode.MachineMatch", True },
951     { "Engine.Engine#1Settings", True },
952     { "Engine.Engine#2Settings", True },
953     { "Engine.Hint", True },
954     { "Engine.Book", True },
955     { "Engine.MoveNow", True },
956     { "Engine.RetractMove", True },
957     { "Action.", True },
958     { NULL, False }
959 };
960
961 Enables cmailEnables[] = {
962     { "Action.", True },
963     { "Action.CallFlag", False },
964     { "Action.Draw", True },
965     { "Action.Adjourn", False },
966     { "Action.Abort", False },
967     { "Action.StopObserving", False },
968     { "Action.StopExamining", False },
969     { "File.MailMove", True },
970     { "File.ReloadCMailMessage", True },
971     { NULL, False }
972 };
973
974 Enables trainingOnEnables[] = {
975   { "Edit.EditComment", False },
976   { "Mode.Pause", False },
977   { "Edit.Forward", False },
978   { "Edit.Backward", False },
979   { "Edit.ForwardtoEnd", False },
980   { "Edit.BacktoStart", False },
981   { "Engine.MoveNow", False },
982   { "Edit.TruncateGame", False },
983   { NULL, False }
984 };
985
986 Enables trainingOffEnables[] = {
987   { "Edit.EditComment", True },
988   { "Mode.Pause", True },
989   { "Edit.Forward", True },
990   { "Edit.Backward", True },
991   { "Edit.ForwardtoEnd", True },
992   { "Edit.BacktoStart", True },
993   { "Engine.MoveNow", True },
994   { "Engine.TruncateGame", True },
995   { NULL, False }
996 };
997
998 Enables machineThinkingEnables[] = {
999   { "File.LoadGame", False },
1000 //  { "LoadNextGame", False },
1001 //  { "LoadPreviousGame", False },
1002 //  { "ReloadSameGame", False },
1003   { "Edit.PasteGame", False },
1004   { "File.LoadPosition", False },
1005 //  { "LoadNextPosition", False },
1006 //  { "LoadPreviousPosition", False },
1007 //  { "ReloadSamePosition", False },
1008   { "Edit.PastePosition", False },
1009   { "Mode.MachineWhite", False },
1010   { "Mode.MachineBlack", False },
1011   { "Mode.TwoMachines", False },
1012 //  { "MachineMatch", False },
1013   { "Engine.RetractMove", False },
1014   { NULL, False }
1015 };
1016
1017 Enables userThinkingEnables[] = {
1018   { "File.LoadGame", True },
1019 //  { "LoadNextGame", True },
1020 //  { "LoadPreviousGame", True },
1021 //  { "ReloadSameGame", True },
1022   { "Edit.PasteGame", True },
1023   { "File.LoadPosition", True },
1024 //  { "LoadNextPosition", True },
1025 //  { "LoadPreviousPosition", True },
1026 //  { "ReloadSamePosition", True },
1027   { "Edit.PastePosition", True },
1028   { "Mode.MachineWhite", True },
1029   { "Mode.MachineBlack", True },
1030   { "Mode.TwoMachines", True },
1031 //  { "MachineMatch", True },
1032   { "Engine.RetractMove", True },
1033   { NULL, False }
1034 };
1035
1036 void
1037 SetICSMode ()
1038 {
1039   SetMenuEnables(icsEnables);
1040
1041 #if ZIPPY
1042   if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
1043      EnableNamedMenuItem("Mode.AnalysisMode", True);
1044      EnableNamedMenuItem("Engine.Engine#1Settings", True);
1045   }
1046 #endif
1047 }
1048
1049 void
1050 SetNCPMode ()
1051 {
1052   SetMenuEnables(ncpEnables);
1053 }
1054
1055 void
1056 SetGNUMode ()
1057 {
1058   SetMenuEnables(gnuEnables);
1059 }
1060
1061 void
1062 SetCmailMode ()
1063 {
1064   SetMenuEnables(cmailEnables);
1065 }
1066
1067 void
1068 SetTrainingModeOn ()
1069 {
1070   SetMenuEnables(trainingOnEnables);
1071   if (appData.showButtonBar) {
1072     EnableButtonBar(False);
1073   }
1074   CommentPopDown();
1075 }
1076
1077 void
1078 SetTrainingModeOff ()
1079 {
1080   SetMenuEnables(trainingOffEnables);
1081   if (appData.showButtonBar) {
1082     EnableButtonBar(True);
1083   }
1084 }
1085
1086 void
1087 SetUserThinkingEnables ()
1088 {
1089   if (appData.noChessProgram) return;
1090   SetMenuEnables(userThinkingEnables);
1091 }
1092
1093 void
1094 SetMachineThinkingEnables ()
1095 {
1096   if (appData.noChessProgram) return;
1097   SetMenuEnables(machineThinkingEnables);
1098   switch (gameMode) {
1099   case MachinePlaysBlack:
1100   case MachinePlaysWhite:
1101   case TwoMachinesPlay:
1102     EnableNamedMenuItem(ModeToWidgetName(gameMode), True);
1103     break;
1104   default:
1105     break;
1106   }
1107 }
1108
1109 void
1110 GreyRevert (Boolean grey)
1111 {
1112     EnableNamedMenuItem("Edit.Revert", !grey);
1113     EnableNamedMenuItem("Edit.Annotate", !grey);
1114 }
1115
1116 char *
1117 ModeToWidgetName (GameMode mode)
1118 {
1119     switch (mode) {
1120       case BeginningOfGame:
1121         if (appData.icsActive)
1122           return "Mode.ICSClient";
1123         else if (appData.noChessProgram ||
1124                  *appData.cmailGameName != NULLCHAR)
1125           return "Mode.EditGame";
1126         else
1127           return "Mode.MachineBlack";
1128       case MachinePlaysBlack:
1129         return "Mode.MachineBlack";
1130       case MachinePlaysWhite:
1131         return "Mode.MachineWhite";
1132       case AnalyzeMode:
1133         return "Mode.AnalysisMode";
1134       case AnalyzeFile:
1135         return "Mode.AnalyzeFile";
1136       case TwoMachinesPlay:
1137         return "Mode.TwoMachines";
1138       case EditGame:
1139         return "Mode.EditGame";
1140       case PlayFromGameFile:
1141         return "File.LoadGame";
1142       case EditPosition:
1143         return "Mode.EditPosition";
1144       case Training:
1145         return "Mode.Training";
1146       case IcsPlayingWhite:
1147       case IcsPlayingBlack:
1148       case IcsObserving:
1149       case IcsIdle:
1150       case IcsExamining:
1151         return "Mode.ICSClient";
1152       default:
1153       case EndOfGame:
1154         return NULL;
1155     }
1156 }
1157
1158 void
1159 InitMenuMarkers()
1160 {
1161 #ifndef OPTIONSDIALOG
1162     if (appData.alwaysPromoteToQueen) {
1163         MarkMenuItem("Options.Always Queen", True);
1164     }
1165     if (appData.animateDragging) {
1166         MarkMenuItem("Options.Animate Dragging", True);
1167     }
1168     if (appData.animate) {
1169         MarkMenuItem("Options.Animate Moving", True);
1170     }
1171     if (appData.autoCallFlag) {
1172         MarkMenuItem("Options.Auto Flag", True);
1173     }
1174     if (appData.autoFlipView) {
1175         XtSetValues(XtNameToWidget(menuBarWidget,"Options.Auto Flip View", True);
1176     }
1177     if (appData.blindfold) {
1178         MarkMenuItem("Options.Blindfold", True);
1179     }
1180     if (appData.flashCount > 0) {
1181         MarkMenuItem("Options.Flash Moves", True);
1182     }
1183 #if HIGHDRAG
1184     if (appData.highlightDragging) {
1185         MarkMenuItem("Options.Highlight Dragging", True);
1186     }
1187 #endif
1188     if (appData.highlightLastMove) {
1189         MarkMenuItem("Options.Highlight Last Move", True);
1190     }
1191     if (appData.highlightMoveWithArrow) {
1192         MarkMenuItem("Options.Arrow", True);
1193     }
1194 //    if (appData.icsAlarm) {
1195 //      MarkMenuItem("Options.ICS Alarm", True);
1196 //    }
1197     if (appData.ringBellAfterMoves) {
1198         MarkMenuItem("Options.Move Sound", True);
1199     }
1200     if (appData.oneClick) {
1201         MarkMenuItem("Options.OneClick", True);
1202     }
1203     if (appData.periodicUpdates) {
1204         MarkMenuItem("Options.Periodic Updates", True);
1205     }
1206     if (appData.ponderNextMove) {
1207         MarkMenuItem("Options.Ponder Next Move", True);
1208     }
1209     if (appData.popupExitMessage) {
1210         MarkMenuItem("Options.Popup Exit Message", True);
1211     }
1212     if (appData.popupMoveErrors) {
1213         MarkMenuItem("Options.Popup Move Errors", True);
1214     }
1215 //    if (appData.premove) {
1216 //      MarkMenuItem("Options.Premove", True);
1217 //    }
1218     if (appData.showCoords) {
1219         MarkMenuItem("Options.Show Coords", True);
1220     }
1221     if (appData.hideThinkingFromHuman) {
1222         MarkMenuItem("Options.Hide Thinking", True);
1223     }
1224     if (appData.testLegality) {
1225         MarkMenuItem("Options.Test Legality", True);
1226     }
1227 #endif
1228     if (saveSettingsOnExit) {
1229         MarkMenuItem("Options.SaveSettingsonExit", True);
1230     }
1231     EnableNamedMenuItem("File.SaveSelected", False);
1232 }