allowe parsing / disambiguation of SAN moves like Xe4 in certain situations
[xboard.git] / xhistory.c
1 /*
2  * xhistory.c -- Move list window, part of X front end for XBoard
3  *
4  * Copyright 2000,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 <stdio.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <sys/types.h>
29
30 #if STDC_HEADERS
31 # include <stdlib.h>
32 # include <string.h>
33 #else /* not STDC_HEADERS */
34 extern char *getenv();
35 # if HAVE_STRING_H
36 #  include <string.h>
37 # else /* not HAVE_STRING_H */
38 #  include <strings.h>
39 # endif /* not HAVE_STRING_H */
40 #endif /* not STDC_HEADERS */
41
42 #if HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45
46 #include <X11/Intrinsic.h>
47 #include <X11/StringDefs.h>
48 #include <X11/Shell.h>
49 #include <X11/Xaw/Dialog.h>
50 #include <X11/Xaw/Form.h>
51 #include <X11/Xaw/List.h>
52 #include <X11/Xaw/Label.h>
53 #include <X11/Xaw/SimpleMenu.h>
54 #include <X11/Xaw/SmeBSB.h>
55 #include <X11/Xaw/SmeLine.h>
56 #include <X11/Xaw/Box.h>
57 #include <X11/Xaw/Paned.h>
58 #include <X11/Xaw/MenuButton.h>
59 #include <X11/cursorfont.h>
60 #include <X11/Xaw/Text.h>
61 #include <X11/Xaw/AsciiText.h>
62 #include <X11/Xaw/Viewport.h>
63
64 #include "common.h"
65 #include "frontend.h"
66 #include "backend.h"
67 #include "xboard.h"
68 #include "xhistory.h"
69 #include "gettext.h"
70
71 #ifdef ENABLE_NLS
72 # define  _(s) gettext (s)
73 # define N_(s) gettext_noop (s)
74 #else
75 # define  _(s) (s)
76 # define N_(s)  s
77 #endif
78
79 #define _LL_ 100
80
81 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
82 extern Display *xDisplay;
83 extern int squareSize;
84 extern Pixmap xMarkPixmap;
85 extern char *layoutName;
86
87 struct History{
88   String *Nr,*white,*black;
89   int     aNr;  /* space actually alocated */
90   Widget mvn,mvw,mvb,vbox,viewport,sh;
91   char Up;
92 };
93
94 struct History *hist=0;
95 String dots=" ... ";
96 Position gameHistoryX, gameHistoryY;
97
98 void
99 HistoryPopDown(w, client_data, call_data)
100      Widget w;
101      XtPointer client_data, call_data;
102 {
103   Arg args[16];
104   int j;
105   if(hist) {
106     // [HGM] remember old position
107     j = 0;
108     XtSetArg(args[j], XtNx, &gameHistoryX);  j++;
109     XtSetArg(args[j], XtNy, &gameHistoryY);  j++;
110     XtGetValues(hist->sh, args, j);
111
112     XtPopdown(hist->sh);
113     hist->Up=False;
114   }
115   j=0;
116   XtSetArg(args[j], XtNleftBitmap, None); j++;
117   XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Move History"),
118                 args, j);
119 }
120
121 void HistoryMoveProc(Widget w, XtPointer closure, XtPointer call_data)
122 {
123     int to;
124     XawListReturnStruct *R = (XawListReturnStruct *) call_data;
125     if (w == hist->mvn || w == hist->mvw) {
126       to=2*R->list_index-1;
127       ToNrEvent(to);
128     }
129     else if (w == hist->mvb) {
130       to=2*R->list_index;
131       ToNrEvent(to);
132     }
133 }
134
135 void HistoryAlloc(int len){
136   int i;
137   if(hist){
138     free(hist->Nr[0]);free(hist->white[0]);free(hist->black[0]);
139     free(hist->Nr);free(hist->white);free(hist->black);
140   }
141   else{
142     hist=(struct History*)malloc(sizeof(struct History));
143   }
144     hist->aNr=len;
145     hist->Nr=(String*)malloc(hist->aNr*sizeof(String*));
146     hist->white=(String*)malloc(hist->aNr*sizeof(String*));
147     hist->black=(String*)malloc(hist->aNr*sizeof(String*));
148
149     hist->Nr[0]=(String)malloc(hist->aNr*6);
150     hist->white[0]=(String)malloc(hist->aNr*MOVE_LEN);
151     hist->black[0]=(String)malloc(hist->aNr*MOVE_LEN);
152
153       sprintf(hist->Nr[0],"    ");
154       sprintf(hist->white[0],_("White "));
155       sprintf(hist->black[0],_("Black "));
156     for(i=1;i<hist->aNr;i++){
157       hist->Nr[i]= hist->Nr[i-1]+6;
158       hist->white[i]= hist->white[i-1]+MOVE_LEN;
159       hist->black[i]= hist->black[i-1]+MOVE_LEN;
160       sprintf(hist->Nr[i],"%i.",i);
161       sprintf(hist->white[i],"-----");
162       sprintf(hist->black[i],"-----");
163      }
164 }
165
166
167 /* Find empty space inside vbox form widget and redistribute it amongst
168    the list widgets inside it. */
169 /* This version sort of works */
170 void
171 HistoryFill()
172 {
173   Dimension w, bw;
174   long extra;
175   Position x, x1, x2;
176   int j, dd;
177   Arg args[16];
178
179   j = 0;
180   XtSetArg(args[j], XtNx, &x);  j++;
181   XtSetArg(args[j], XtNwidth, &w);  j++;
182   XtSetArg(args[j], XtNborderWidth, &bw);  j++;
183   XtGetValues(hist->mvb, args, j);
184   x1 = x + w + 2*bw;
185
186   j = 0;
187   XtSetArg(args[j], XtNwidth, &w);  j++;
188   XtSetArg(args[j], XtNdefaultDistance, &dd);  j++;
189   XtGetValues(hist->vbox, args, j);
190   x2 = w - dd;
191
192   extra = x2 - x1;
193   if (extra < 0) {
194     extra = -((-extra)/2);
195   } else {
196     extra = extra/2;
197   }
198
199   j = 0;
200   XtSetArg(args[j], XtNwidth, &w);  j++;
201   XtGetValues(hist->mvw, args, j);
202   w += extra;
203   j = 0;
204   XtSetArg(args[j], XtNwidth, w);  j++;
205   XtSetValues(hist->mvw, args, j);
206
207   j = 0;
208   XtSetArg(args[j], XtNwidth, &w);  j++;
209   XtGetValues(hist->mvb, args, j);
210   w += extra;
211   j = 0;
212   XtSetArg(args[j], XtNwidth, w);  j++;
213   XtSetValues(hist->mvb, args, j);
214 }
215
216 void HistorySet(char movelist[][2*MOVE_LEN],int first,int last,int current){
217   int i,b,m;
218   if(hist){
219     if(last >= hist->aNr) HistoryAlloc(last+_LL_);
220     for(i=0;i<last;i++) {
221       if((i%2)==0) {
222         if(movelist[i][0]) {
223           char* p = strchr(movelist[i], ' ');
224           if (p) {
225             strncpy(hist->white[i/2+1], movelist[i], p-movelist[i]);
226             hist->white[i/2+1][p-movelist[i]] = NULLCHAR;
227           } else {
228             strcpy(hist->white[i/2+1],movelist[i]);
229           }
230         } else {
231           strcpy(hist->white[i/2+1],dots);
232         }
233       } else {
234         if(movelist[i][0]) {
235           char* p = strchr(movelist[i], ' ');
236           if (p) {
237             strncpy(hist->black[i/2+1], movelist[i], p-movelist[i]);
238             hist->black[i/2+1][p-movelist[i]] = NULLCHAR;
239           } else {
240             strcpy(hist->black[i/2+1],movelist[i]);
241           }
242         } else {
243           strcpy(hist->black[i/2+1],"");
244         }
245       }
246     }
247     strcpy(hist->black[last/2+1],"");
248     b=first/2;
249     m=(last+3)/2-b;
250     XawFormDoLayout(hist->vbox, False);
251     XawListChange(hist->mvn,hist->Nr+b,m,0,True);
252     XawListChange(hist->mvw,hist->white+b,m,0,True);
253     XawListChange(hist->mvb,hist->black+b,m,0,True);
254     HistoryFill();
255     XawFormDoLayout(hist->vbox, True);
256     if(current<0){
257       XawListUnhighlight(hist->mvw);
258       XawListUnhighlight(hist->mvb);
259     }
260     else if((current%2)==0){
261       XawListHighlight(hist->mvw, current/2+1);
262       XawListUnhighlight(hist->mvb);
263     }
264     else{
265       XawListUnhighlight(hist->mvw);
266       if(current) XawListHighlight(hist->mvb, current/2+1);
267       else XawListUnhighlight(hist->mvb);
268     }
269   }
270 }
271
272 Widget HistoryCreate()
273 {
274     Arg args[16];
275     int i,j;
276
277     Widget layout,form,b_close;
278     String trstr=
279              "<Key>Up: BackwardProc() \n \
280              <Key>Left: BackwardProc() \n \
281              <Key>Down: ForwardProc() \n \
282              <Key>Right: ForwardProc() \n";
283     /*--- allocate memory for move-strings ---*/
284     HistoryAlloc(_LL_);
285
286     /*-------- create the widgets ---------------*/
287     j = 0;
288     XtSetArg(args[j], XtNresizable, True);  j++;
289     XtSetArg(args[j], XtNallowShellResize, True);  j++;
290 #if TOPLEVEL
291     hist->sh =
292       XtCreatePopupShell(_("Move list"), topLevelShellWidgetClass,
293                          shellWidget, args, j);
294 #else
295     hist->sh =
296       XtCreatePopupShell(_("Move list"), transientShellWidgetClass,
297                          shellWidget, args, j);
298 #endif
299     j = 0;
300     XtSetArg(args[j], XtNborderWidth, 0); j++;
301     XtSetArg(args[j], XtNdefaultDistance, 0);  j++;
302       layout =
303       XtCreateManagedWidget(layoutName, formWidgetClass, hist->sh,
304                             args, j);
305
306     j = 0;
307     XtSetArg(args[j], XtNborderWidth, 0); j++;
308     XtSetArg(args[j], XtNresizable, True);  j++;
309
310     form =
311       XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
312      j=0;
313
314     j = 0;
315
316     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
317     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
318     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
319     XtSetArg(args[j], XtNright, XtChainRight);  j++;
320
321     XtSetArg(args[j], XtNborderWidth, 1); j++;
322     XtSetArg(args[j], XtNresizable, False);  j++;
323     XtSetArg(args[j], XtNallowVert, True); j++;
324     XtSetArg(args[j], XtNallowHoriz, True);  j++;
325     XtSetArg(args[j], XtNforceBars, False); j++;
326     XtSetArg(args[j], XtNheight, 280); j++;
327     hist->viewport =
328       XtCreateManagedWidget("viewport", viewportWidgetClass,
329                             form, args, j);
330     j=0;
331     XtSetArg(args[j], XtNborderWidth, 0); j++;
332     XtSetArg(args[j], XtNorientation,XtorientHorizontal);j++;
333     hist->vbox =
334       XtCreateManagedWidget("vbox", formWidgetClass, hist->viewport, args, j);
335
336     j=0;
337     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
338     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
339     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
340     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
341
342     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
343     XtSetArg(args[j], XtNforceColumns, True);  j++;
344     XtSetArg(args[j], XtNverticalList, True);  j++;
345     XtSetArg(args[j], XtNborderWidth, 0); j++;
346     XtSetArg(args[j], XtNresizable,True);j++;
347     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
348     hist->mvn = XtCreateManagedWidget("movesn", listWidgetClass,
349                                       hist->vbox, args, j);
350     XtAddCallback(hist->mvn, XtNcallback, HistoryMoveProc, (XtPointer) hist);
351
352     j=0;
353     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
354     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
355     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
356     XtSetArg(args[j], XtNright, XtRubber);  j++;
357
358     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
359     XtSetArg(args[j], XtNforceColumns, True);  j++;
360     XtSetArg(args[j], XtNverticalList, True);  j++;
361     XtSetArg(args[j], XtNborderWidth, 0); j++;
362     XtSetArg(args[j], XtNresizable,True);j++;
363     XtSetArg(args[j], XtNfromHoriz, hist->mvn);  j++;
364     hist->mvw = XtCreateManagedWidget("movesw", listWidgetClass,
365                                       hist->vbox, args, j);
366     XtAddCallback(hist->mvw, XtNcallback, HistoryMoveProc, (XtPointer) hist);
367
368     j=0;
369     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
370     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
371     XtSetArg(args[j], XtNleft, XtRubber);  j++;
372     XtSetArg(args[j], XtNright,  XtRubber);  j++;
373
374     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
375     XtSetArg(args[j], XtNforceColumns, True);  j++;
376     XtSetArg(args[j], XtNverticalList, True);  j++;
377     XtSetArg(args[j], XtNborderWidth, 0); j++;
378     XtSetArg(args[j], XtNresizable,True);j++;
379     XtSetArg(args[j], XtNfromHoriz, hist->mvw);  j++;
380     hist->mvb = XtCreateManagedWidget("movesb", listWidgetClass,
381                                       hist->vbox, args, j);
382     XtAddCallback(hist->mvb, XtNcallback, HistoryMoveProc, (XtPointer) hist);
383
384     j=0;
385     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
386     XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
387     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
388     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
389     XtSetArg(args[j], XtNfromVert, hist->viewport);  j++;
390     b_close= XtCreateManagedWidget(_("Close"), commandWidgetClass,
391                                    form, args, j);
392     XtAddCallback(b_close, XtNcallback, HistoryPopDown, (XtPointer) 0);
393
394     XtAugmentTranslations(hist->sh,XtParseTranslationTable (trstr));
395
396     XtRealizeWidget(hist->sh);
397     CatchDeleteWindow(hist->sh, "HistoryPopDown");
398
399     for(i=1;i<hist->aNr;i++){
400       strcpy(hist->white[i],dots);
401       strcpy(hist->black[i],"");
402      }
403
404     return hist->sh;
405 }
406
407 void
408 HistoryPopUp()
409 {
410   Arg args[16];
411   int j;
412
413   if(!hist) HistoryCreate();
414
415   XtPopup(hist->sh, XtGrabNone);
416
417   // [HGM] restore old position
418   j = 0;
419   XtSetArg(args[j], XtNx, gameHistoryX);  j++;
420   XtSetArg(args[j], XtNy, gameHistoryY);  j++;
421   XtSetValues(hist->sh, args, j);
422
423   j=0;
424   XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
425   XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Move History"),
426                 args, j);
427   hist->Up=True;
428 }
429
430
431 void
432 HistoryShowProc(w, event, prms, nprms)
433      Widget w;
434      XEvent *event;
435      String *prms;
436      Cardinal *nprms;
437 {
438   if (!hist) {
439     HistoryCreate();
440     HistoryPopUp();
441   } else if (hist->Up) {
442     HistoryPopDown(0,0,0);
443   } else {
444     HistoryPopUp();
445   }
446   ToNrEvent(currentMove);
447 }
448