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