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