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