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