Get rid of promotion popup
[xboard.git] / xgamelist.c
1 /*
2  * xgamelist.c -- Game list window, part of X front end for XBoard
3  *
4  * Copyright 1995,2009 Free Software Foundation, Inc.
5  * ------------------------------------------------------------------------
6  *
7  * GNU XBoard is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or (at
10  * your option) any later version.
11  *
12  * GNU XBoard is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see http://www.gnu.org/licenses/.  *
19  *
20  *------------------------------------------------------------------------
21  ** See the file ChangeLog for a revision history.  */
22
23 #include "config.h"
24
25 #include <gtk/gtk.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <sys/types.h>
30
31 #if STDC_HEADERS
32 # include <stdlib.h>
33 # include <string.h>
34 #else /* not STDC_HEADERS */
35 extern char *getenv();
36 # if HAVE_STRING_H
37 #  include <string.h>
38 # else /* not HAVE_STRING_H */
39 #  include <strings.h>
40 # endif /* not HAVE_STRING_H */
41 #endif /* not STDC_HEADERS */
42
43 #if HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46
47 #include <X11/Intrinsic.h>
48 #include <X11/StringDefs.h>
49 #include <X11/Shell.h>
50 #include <X11/cursorfont.h>
51 #if USE_XAW3D
52 #include <X11/Xaw3d/Dialog.h>
53 #include <X11/Xaw3d/Form.h>
54 #include <X11/Xaw3d/List.h>
55 #include <X11/Xaw3d/Label.h>
56 #include <X11/Xaw3d/SimpleMenu.h>
57 #include <X11/Xaw3d/SmeBSB.h>
58 #include <X11/Xaw3d/SmeLine.h>
59 #include <X11/Xaw3d/Box.h>
60 #include <X11/Xaw3d/MenuButton.h>
61 #include <X11/Xaw3d/Text.h>
62 #include <X11/Xaw3d/AsciiText.h>
63 #include <X11/Xaw3d/Viewport.h>
64 #else
65 #include <X11/Xaw/Dialog.h>
66 #include <X11/Xaw/Form.h>
67 #include <X11/Xaw/List.h>
68 #include <X11/Xaw/Label.h>
69 #include <X11/Xaw/SimpleMenu.h>
70 #include <X11/Xaw/SmeBSB.h>
71 #include <X11/Xaw/SmeLine.h>
72 #include <X11/Xaw/Box.h>
73 #include <X11/Xaw/MenuButton.h>
74 #include <X11/Xaw/Text.h>
75 #include <X11/Xaw/AsciiText.h>
76 #include <X11/Xaw/Viewport.h>
77 #endif
78
79 #include "common.h"
80 #include "frontend.h"
81 #include "backend.h"
82 #include "xboard.h"
83 #include "xgamelist.h"
84 #include "gettext.h"
85
86 #ifdef ENABLE_NLS
87 # define  _(s) gettext (s)
88 # define N_(s) gettext_noop (s)
89 #else
90 # define  _(s) (s)
91 # define N_(s)  s
92 #endif
93
94 extern GtkWidget               *GUI_GameList;
95 extern GtkListStore            *LIST_GameList;
96
97 void SetFocus P((Widget w, XtPointer data, XEvent *event, Boolean *b));
98
99 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget, gameListShell;
100
101 extern int squareSize;
102 extern Pixmap xMarkPixmap;
103 extern char *layoutName;
104
105 static Widget filterText;
106 static char filterString[MSG_SIZ];
107 static int listLength;
108
109 char gameListTranslations[] =
110   "<Btn1Up>(2): LoadSelectedProc(0) \n \
111    <Key>Home: LoadSelectedProc(-2) \n \
112    <Key>End: LoadSelectedProc(2) \n \
113    <Key>Up: LoadSelectedProc(-1) \n \
114    <Key>Down: LoadSelectedProc(1) \n \
115    <Key>Left: LoadSelectedProc(-1) \n \
116    <Key>Right: LoadSelectedProc(1) \n \
117    <Key>Return: LoadSelectedProc(0) \n";
118 char filterTranslations[] =
119   "<Key>Return: SetFilterProc() \n";
120
121 typedef struct {
122     Widget shell;
123     Position x, y;
124     Dimension w, h;
125     Boolean up;
126     FILE *fp;
127     char *filename;
128     char **strings;
129 } GameListClosure;
130 static GameListClosure *glc = NULL;
131
132 static Arg layoutArgs[] = {
133     { XtNborderWidth, 0 },
134     { XtNdefaultDistance, 0 }
135 };
136
137 Widget
138 GameListCreate(name, callback, client_data)
139      char *name;
140      XtCallbackProc callback;
141      XtPointer client_data;
142 {
143   return;
144 }
145
146 static int
147 GameListPrepare()
148 {   // [HGM] filter: put in separate routine, to make callable from call-back
149     int nstrings;
150     ListGame *lg;
151     char **st, *line;
152
153     nstrings = ((ListGame *) gameList.tailPred)->number;
154     glc->strings = (char **) malloc((nstrings + 1) * sizeof(char *));
155     st = glc->strings;
156     lg = (ListGame *) gameList.head;
157     listLength = 0;
158     while (nstrings--) {
159         line = GameListLine(lg->number, &lg->gameInfo);
160         if(filterString[0] == NULLCHAR || SearchPattern( line, filterString ) ) {
161             *st++ = line; // [HGM] filter: make adding line conditional
162             listLength++;
163         }
164         lg = (ListGame *) lg->node.succ;
165      }
166     *st = NULL;
167     return listLength;
168 }
169
170 static void
171 GameListReplace()
172 {   // [HGM] filter: put in separate routine, to make callable from call-back
173     Arg args[16];
174     int j;
175     Widget listwidg;
176
177         listwidg = XtNameToWidget(glc->shell, "*form.viewport.list");
178         XawListChange(listwidg, glc->strings, 0, 0, True);
179         XawListHighlight(listwidg, 0);
180 }
181
182 void
183 GameListCallback(w, client_data, call_data)
184      Widget w;
185      XtPointer client_data, call_data;
186 {
187     String name;
188     Arg args[16];
189     int j;
190     Widget listwidg;
191     GameListClosure *glc = (GameListClosure *) client_data;
192     XawListReturnStruct *rs;
193     int index;
194
195     j = 0;
196     XtSetArg(args[j], XtNlabel, &name);  j++;
197     XtGetValues(w, args, j);
198
199     if (strcmp(name, _("close")) == 0) {
200         GameListPopDown();
201         return;
202     }
203     listwidg = XtNameToWidget(glc->shell, "*form.viewport.list");
204     rs = XawListShowCurrent(listwidg);
205     if (strcmp(name, _("load")) == 0) {
206         index = rs->list_index;
207         if (index < 0) {
208             DisplayError(_("No game selected"), 0);
209             return;
210         }
211     } else if (strcmp(name, _("next")) == 0) {
212         index = rs->list_index + 1;
213         if (index >= listLength) {
214             DisplayError(_("Can't go forward any further"), 0);
215             return;
216         }
217         XawListHighlight(listwidg, index);
218     } else if (strcmp(name, _("prev")) == 0) {
219         index = rs->list_index - 1;
220         if (index < 0) {
221             DisplayError(_("Can't back up any further"), 0);
222             return;
223         }
224         XawListHighlight(listwidg, index);
225     } else if (strcmp(name, _("apply")) == 0) {
226         String name;
227         j = 0;
228         XtSetArg(args[j], XtNstring, &name);  j++;
229         XtGetValues(filterText, args, j);
230         strcpy(filterString, name);
231         XawListHighlight(listwidg, 0);
232         if(GameListPrepare()) GameListReplace(); // crashes on empty list...
233         return;
234     }
235     index = atoi(glc->strings[index])-1; // [HGM] filter: read true index from sequence nr of line
236     if (cmailMsgLoaded) {
237         CmailLoadGame(glc->fp, index + 1, glc->filename, True);
238     } else {
239         LoadGame(glc->fp, index + 1, glc->filename, True);
240     }
241 }
242
243 void
244 GameListPopUp(fp, filename)
245      FILE *fp;
246      char *filename;
247 {
248   GtkTreeIter iter;
249   int  i=0,nstrings;
250   ListGame *lg;
251   
252   /* first clear everything, do we need this? */
253   gtk_list_store_clear(LIST_GameList);
254
255   /* fill list with information */
256   lg = (ListGame *) gameList.head;
257   nstrings = ((ListGame *) gameList.tailPred)->number;
258   while (nstrings--) 
259     {
260       gtk_list_store_append (LIST_GameList, &iter);
261       gtk_list_store_set (LIST_GameList, &iter,
262                           0, StrSave(filename),
263                           1, GameListLine(lg->number, &lg->gameInfo),
264                           2, fp,
265                           -1);
266       lg = (ListGame *) lg->node.succ;
267     }
268
269   /* show widget */
270   gtk_widget_show (GUI_GameList);
271
272 //    XtPopup(glc->shell, XtGrabNone);
273 //    glc->up = True;
274 //    j = 0;
275 //    XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
276 //    XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"),
277 //              args, j);
278
279   return;
280 }
281
282 void
283 GameListDestroy()
284 {
285   GameListPopDown();
286
287   gtk_list_store_clear(LIST_GameList);
288   return;
289 }
290
291 void
292 ShowGameListProc(w, event, prms, nprms)
293      Widget w;
294      XEvent *event;
295      String *prms;
296      Cardinal *nprms;
297 {
298     Arg args[16];
299     int j;
300
301     if (glc == NULL) {
302         DisplayError(_("There is no game list"), 0);
303         return;
304     }
305     if (glc->up) {
306         GameListPopDown();
307         return;
308     }
309     XtPopup(glc->shell, XtGrabNone);
310     glc->up = True;
311     j = 0;
312     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
313     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"),
314                 args, j);
315 }
316
317 void
318 LoadSelectedProc(w, event, prms, nprms)
319      Widget w;
320      XEvent *event;
321      String *prms;
322      Cardinal *nprms;
323 {
324     Widget listwidg;
325     XawListReturnStruct *rs;
326     int index, direction = atoi(prms[0]);
327
328     if (glc == NULL) return;
329     listwidg = XtNameToWidget(glc->shell, "*form.viewport.list");
330     rs = XawListShowCurrent(listwidg);
331     index = rs->list_index;
332     if (index < 0) return;
333     if(direction != 0) {
334         index += direction; 
335         if(direction == -2) index = 0;
336         if(direction == 2) index = listLength-1;
337         if(index < 0 || index >= listLength) return;
338         XawListHighlight(listwidg, index);
339         return;
340     }
341     index = atoi(glc->strings[index])-1; // [HGM] filter: read true index from sequence nr of line
342     if (cmailMsgLoaded) {
343         CmailLoadGame(glc->fp, index + 1, glc->filename, True);
344     } else {
345         LoadGame(glc->fp, index + 1, glc->filename, True);
346     }
347 }
348
349 void
350 SetFilterProc(w, event, prms, nprms)
351      Widget w;
352      XEvent *event;
353      String *prms;
354      Cardinal *nprms;
355 {
356         Arg args[16];
357         String name;
358         Widget list;
359         int j = 0;
360         XtSetArg(args[j], XtNstring, &name);  j++;
361         XtGetValues(filterText, args, j);
362         strcpy(filterString, name);
363         if(GameListPrepare()) GameListReplace(); // crashes on empty list...
364         list = XtNameToWidget(glc->shell, "*form.viewport.list");
365         XawListHighlight(list, 0);
366         j = 0;
367         XtSetArg(args[j], XtNdisplayCaret, False); j++;
368         XtSetValues(filterText, args, j);
369         XtSetKeyboardFocus(glc->shell, list);
370 }
371
372 void
373 GameListPopDown()
374 {
375   /* hides the history window */
376
377   gtk_widget_hide (GUI_GameList);
378   return;
379 }
380
381 void
382 GameListHighlight(index)
383      int index;
384 {
385     Widget listwidg;
386     int i=0; char **st;
387     if (glc == NULL || !glc->up) return;
388     listwidg = XtNameToWidget(glc->shell, "*form.viewport.list");
389     st = glc->strings;
390     while(*st && atoi(*st)<index) st++,i++;
391     XawListHighlight(listwidg, i);
392 }
393
394 Boolean
395 GameListIsUp()
396 {
397   /* return status of history window */
398   
399   return gtk_widget_get_visible (GUI_GameList);
400 }
401
402 //--------------------------------- Game-List options dialog ------------------------------------------
403
404 Widget gameListOptShell, listwidg;
405
406 char *strings[20];
407 int stringPtr;
408
409 void GLT_ClearList()
410 {
411     strings[0] = NULL;
412     stringPtr = 0;
413 }
414
415 void GLT_AddToList(char *name)
416 {
417     strings[stringPtr++] = name;
418     strings[stringPtr] = NULL;
419 }
420
421 Boolean GLT_GetFromList(int index, char *name)
422 {
423     strcpy(name, strings[index]);
424 }
425
426 void GLT_DeSelectList()
427 {
428     XawListChange(listwidg, strings, 0, 0, True);
429     XawListHighlight(listwidg, 0);
430 }
431
432 void
433 GameListOptionsPopDown()
434 {
435     Arg args[16];
436     int j;
437
438     if (gameListOptShell == NULL) return;
439     XtPopdown(gameListOptShell);
440     XtDestroyWidget(gameListOptShell);
441     gameListOptShell = 0;
442     //    XtSetKeyboardFocus(shellWidget, formWidget);
443 }
444
445 void
446 GameListOptionsCallback(w, client_data, call_data)
447      Widget w;
448      XtPointer client_data, call_data;
449 {
450     String name;
451     Arg args[16];
452     int j;
453     Widget listwidg;
454     XawListReturnStruct *rs;
455     int index;
456     char *p;
457
458     j = 0;
459     XtSetArg(args[j], XtNlabel, &name);  j++;
460     XtGetValues(w, args, j);
461
462     if (strcmp(name, _("OK")) == 0) {
463         GLT_ParseList();
464         appData.gameListTags = strdup(lpUserGLT);
465         GameListOptionsPopDown();
466         return;
467     } else
468     if (strcmp(name, _("cancel")) == 0) {
469         GameListOptionsPopDown();
470         return;
471     }
472     listwidg = XtNameToWidget(gameListOptShell, "*form.list");
473     rs = XawListShowCurrent(listwidg);
474     index = rs->list_index;
475     if (index < 0) {
476         DisplayError(_("No tag selected"), 0);
477         return;
478     }
479     p = strings[index];
480     if (strcmp(name, _("down")) == 0) {
481         if(index >= strlen(GLT_ALL_TAGS)) return;
482         strings[index] = strings[index+1];
483         strings[++index] = p;
484     } else
485     if (strcmp(name, _("up")) == 0) {
486         if(index == 0) return;
487         strings[index] = strings[index-1];
488         strings[--index] = p;
489     } else
490     if (strcmp(name, _("factory")) == 0) {
491         strcpy(lpUserGLT, GLT_DEFAULT_TAGS);
492         GLT_TagsToList(lpUserGLT);
493         index = 0;
494     }
495     XawListHighlight(listwidg, index);
496 }
497
498 Widget
499 GameListOptionsCreate()
500 {
501     Arg args[16];
502     Widget shell, form, viewport, layout;
503     Widget b_load, b_loadprev, b_loadnext, b_close, b_cancel;
504     Dimension fw_width;
505     XtPointer client_data = NULL;
506     int j;
507
508     j = 0;
509     XtSetArg(args[j], XtNwidth, &fw_width);  j++;
510     XtGetValues(formWidget, args, j);
511
512     j = 0;
513     XtSetArg(args[j], XtNresizable, True);  j++;
514     XtSetArg(args[j], XtNallowShellResize, True);  j++;
515     //    shell = gameListOptShell =
516       //      XtCreatePopupShell("Game-list options", transientShellWidgetClass,
517       //                         shellWidget, args, j);
518     layout =
519       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
520                             layoutArgs, XtNumber(layoutArgs));
521     j = 0;
522     XtSetArg(args[j], XtNborderWidth, 0); j++;
523     form =
524       XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
525
526     j = 0;
527     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
528     XtSetArg(args[j], XtNforceColumns, True);  j++;
529     XtSetArg(args[j], XtNverticalList, True);  j++;
530     listwidg = viewport =
531       XtCreateManagedWidget("list", listWidgetClass, form, args, j);
532     XawListHighlight(listwidg, 0);
533 //    XtAugmentTranslations(listwidg,
534 //                        XtParseTranslationTable(gameListOptTranslations));
535
536     j = 0;
537     XtSetArg(args[j], XtNfromVert, viewport);  j++;
538     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
539     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
540     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
541     XtSetArg(args[j], XtNright, XtChainLeft); j++;
542     b_load =
543       XtCreateManagedWidget(_("factory"), commandWidgetClass, form, args, j);
544     XtAddCallback(b_load, XtNcallback, GameListOptionsCallback, client_data);
545
546     j = 0;
547     XtSetArg(args[j], XtNfromVert, viewport);  j++;
548     XtSetArg(args[j], XtNfromHoriz, b_load);  j++;
549     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
550     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
551     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
552     XtSetArg(args[j], XtNright, XtChainLeft); j++;
553     b_loadprev =
554       XtCreateManagedWidget(_("up"), commandWidgetClass, form, args, j);
555     XtAddCallback(b_loadprev, XtNcallback, GameListOptionsCallback, client_data);
556
557     j = 0;
558     XtSetArg(args[j], XtNfromVert, viewport);  j++;
559     XtSetArg(args[j], XtNfromHoriz, b_loadprev);  j++;
560     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
561     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
562     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
563     XtSetArg(args[j], XtNright, XtChainLeft); j++;
564     b_loadnext =
565       XtCreateManagedWidget(_("down"), commandWidgetClass, form, args, j);
566     XtAddCallback(b_loadnext, XtNcallback, GameListOptionsCallback, client_data);
567
568     j = 0;
569     XtSetArg(args[j], XtNfromVert, viewport);  j++;
570     XtSetArg(args[j], XtNfromHoriz, b_loadnext);  j++;
571     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
572     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
573     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
574     XtSetArg(args[j], XtNright, XtChainLeft); j++;
575     b_cancel =
576       XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
577     XtAddCallback(b_cancel, XtNcallback, GameListOptionsCallback, client_data);
578
579     j = 0;
580     XtSetArg(args[j], XtNfromVert, viewport);  j++;
581     XtSetArg(args[j], XtNfromHoriz, b_cancel);  j++;
582     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
583     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
584     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
585     XtSetArg(args[j], XtNright, XtChainLeft); j++;
586     b_close =
587       XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
588     XtAddCallback(b_close, XtNcallback, GameListOptionsCallback, client_data);
589
590     strcpy(lpUserGLT, appData.gameListTags);
591     GLT_TagsToList(lpUserGLT);
592
593     XtRealizeWidget(shell);
594     //    CatchDeleteWindow(shell, "GameListOptionsPopDown");
595
596     return shell;
597 }
598
599 void
600 GameListOptionsPopUp(Widget w, XEvent *event, String *prms, Cardinal *nprms)
601 {
602     Arg args[16];
603     int j, nstrings;
604     Widget listwidg;
605
606     if (gameListOptShell == NULL) {
607         gameListOptShell = GameListOptionsCreate(); 
608     }
609
610     XtPopup(gameListOptShell, XtGrabNone);
611 }
612
613