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