worked on premove bug
[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 #if 1
168 /* Find empty space inside vbox form widget and redistribute it amongst
169    the list widgets inside it. */
170 /* This version sort of works */
171 void
172 HistoryFill()
173 {
174   Dimension w, bw;
175   long extra;
176   Position x, x1, x2;
177   int j, dd;
178   Arg args[16];
179
180   j = 0;
181   XtSetArg(args[j], XtNx, &x);  j++;
182   XtSetArg(args[j], XtNwidth, &w);  j++;
183   XtSetArg(args[j], XtNborderWidth, &bw);  j++;
184   XtGetValues(hist->mvb, args, j);
185   x1 = x + w + 2*bw;
186
187   j = 0;
188   XtSetArg(args[j], XtNwidth, &w);  j++;
189   XtSetArg(args[j], XtNdefaultDistance, &dd);  j++;
190   XtGetValues(hist->vbox, args, j);
191   x2 = w - dd;
192
193   extra = x2 - x1;
194   if (extra < 0) {
195     extra = -((-extra)/2);
196   } else {
197     extra = extra/2;
198   }
199
200   j = 0;
201   XtSetArg(args[j], XtNwidth, &w);  j++;
202   XtGetValues(hist->mvw, args, j);
203   w += extra;
204   j = 0;
205   XtSetArg(args[j], XtNwidth, w);  j++;
206   XtSetValues(hist->mvw, args, j);
207
208   j = 0;
209   XtSetArg(args[j], XtNwidth, &w);  j++;
210   XtGetValues(hist->mvb, args, j);
211   w += extra;
212   j = 0;
213   XtSetArg(args[j], XtNwidth, w);  j++;
214   XtSetValues(hist->mvb, args, j);
215 }
216 #else
217 /* Find empty space inside vbox form widget and redistribute it amongst
218    the list widgets inside it. */
219 /* This version doesn't work */
220 void
221 HistoryFill()
222 {
223   Arg args[16];
224   Dimension fw, niw, wiw, biw, nbw, wbw, bbw;
225   int j, nl, wl, bl, fdd;
226   long extra;
227
228   j = 0;
229   XtSetArg(args[j], XtNwidth, &fw);  j++;
230   XtSetArg(args[j], XtNdefaultDistance, &fdd);  j++;
231   XtGetValues(hist->vbox, args, j);
232
233   j = 0;
234   XtSetArg(args[j], XtNlongest, &nl);  j++;
235   XtSetArg(args[j], XtNinternalWidth, &niw);  j++;
236   XtSetArg(args[j], XtNborderWidth, &nbw);  j++;
237   XtGetValues(hist->mvn, args, j);
238
239   j = 0;
240   XtSetArg(args[j], XtNlongest, &wl);  j++;
241   XtSetArg(args[j], XtNinternalWidth, &wiw);  j++;
242   XtSetArg(args[j], XtNborderWidth, &wbw);  j++;
243   XtGetValues(hist->mvw, args, j);
244
245   j = 0;
246   XtSetArg(args[j], XtNlongest, &bl);  j++;
247   XtSetArg(args[j], XtNinternalWidth, &biw);  j++;
248   XtSetArg(args[j], XtNborderWidth, &bbw);  j++;
249   XtGetValues(hist->mvb, args, j);
250
251   extra = fw - 4*fdd -
252     nl - 1 - 2*niw - 2*nbw - wl - 2*wiw - 2*wbw - bl - 2*biw - 2*bbw;
253   if (extra < 0) extra = 0;
254
255   j = 0;
256   XtSetArg(args[j], XtNwidth, nl + 1 + 2*niw);  j++;
257   XtSetValues(hist->mvn, args, j);
258
259   j = 0;
260   XtSetArg(args[j], XtNwidth, wl + 2*wiw + extra/2);  j++;
261   XtSetValues(hist->mvw, args, j);
262
263   j = 0;
264   XtSetArg(args[j], XtNwidth, bl + 2*biw + extra/2);  j++;
265   XtSetValues(hist->mvb, args, j);
266 }
267 #endif
268
269 void HistorySet(char movelist[][2*MOVE_LEN],int first,int last,int current){
270   int i,b,m;
271   if(hist){
272     if(last >= hist->aNr) HistoryAlloc(last+_LL_);
273     for(i=0;i<last;i++) {
274       if((i%2)==0) {
275         if(movelist[i][0]) {
276           char* p = strchr(movelist[i], ' ');
277           if (p) {
278             strncpy(hist->white[i/2+1], movelist[i], p-movelist[i]);
279             hist->white[i/2+1][p-movelist[i]] = NULLCHAR;
280           } else {
281             strcpy(hist->white[i/2+1],movelist[i]);
282           }
283         } else {
284           strcpy(hist->white[i/2+1],dots);
285         }
286       } else {
287         if(movelist[i][0]) {
288           char* p = strchr(movelist[i], ' ');
289           if (p) {
290             strncpy(hist->black[i/2+1], movelist[i], p-movelist[i]);
291             hist->black[i/2+1][p-movelist[i]] = NULLCHAR;
292           } else {
293             strcpy(hist->black[i/2+1],movelist[i]);
294           }
295         } else {
296           strcpy(hist->black[i/2+1],"");
297         }
298       }
299     }
300     strcpy(hist->black[last/2+1],"");
301     b=first/2;
302     m=(last+3)/2-b;
303     XawFormDoLayout(hist->vbox, False);
304     XawListChange(hist->mvn,hist->Nr+b,m,0,True);
305     XawListChange(hist->mvw,hist->white+b,m,0,True);
306     XawListChange(hist->mvb,hist->black+b,m,0,True);
307     HistoryFill();
308     XawFormDoLayout(hist->vbox, True);
309     if(current<0){
310       XawListUnhighlight(hist->mvw);
311       XawListUnhighlight(hist->mvb);
312     }
313     else if((current%2)==0){
314       XawListHighlight(hist->mvw, current/2+1);
315       XawListUnhighlight(hist->mvb);
316     }
317     else{
318       XawListUnhighlight(hist->mvw);
319       if(current) XawListHighlight(hist->mvb, current/2+1);
320       else XawListUnhighlight(hist->mvb);
321     }
322   }
323 }
324
325 Widget HistoryCreate()
326 {
327     Arg args[16];
328     int i,j;
329
330     Widget layout,form,b_close;
331     String trstr=
332              "<Key>Up: BackwardProc() \n \
333              <Key>Left: BackwardProc() \n \
334              <Key>Down: ForwardProc() \n \
335              <Key>Right: ForwardProc() \n";
336     /*--- allocate memory for move-strings ---*/
337     HistoryAlloc(_LL_);
338
339     /*-------- create the widgets ---------------*/
340     j = 0;
341     XtSetArg(args[j], XtNresizable, True);  j++;
342     XtSetArg(args[j], XtNallowShellResize, True);  j++;
343 #if TOPLEVEL
344     hist->sh =
345       XtCreatePopupShell(_("Move list"), topLevelShellWidgetClass,
346                          shellWidget, args, j);
347 #else
348     hist->sh =
349       XtCreatePopupShell(_("Move list"), transientShellWidgetClass,
350                          shellWidget, args, j);
351 #endif
352     j = 0;
353     XtSetArg(args[j], XtNborderWidth, 0); j++;
354     XtSetArg(args[j], XtNdefaultDistance, 0);  j++;
355       layout =
356       XtCreateManagedWidget(layoutName, formWidgetClass, hist->sh,
357                             args, j);
358
359     j = 0;
360     XtSetArg(args[j], XtNborderWidth, 0); j++;
361     XtSetArg(args[j], XtNresizable, True);  j++;
362
363     form =
364       XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
365      j=0;
366
367     j = 0;
368
369     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
370     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
371     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
372     XtSetArg(args[j], XtNright, XtChainRight);  j++;
373
374     XtSetArg(args[j], XtNborderWidth, 1); j++;
375     XtSetArg(args[j], XtNresizable, False);  j++;
376     XtSetArg(args[j], XtNallowVert, True); j++;
377     XtSetArg(args[j], XtNallowHoriz, True);  j++;
378     XtSetArg(args[j], XtNforceBars, False); j++;
379     XtSetArg(args[j], XtNheight, 280); j++;
380     hist->viewport =
381       XtCreateManagedWidget("viewport", viewportWidgetClass,
382                             form, args, j);
383     j=0;
384     XtSetArg(args[j], XtNborderWidth, 0); j++;
385     XtSetArg(args[j], XtNorientation,XtorientHorizontal);j++;
386     hist->vbox =
387       XtCreateManagedWidget("vbox", formWidgetClass, hist->viewport, args, j);
388
389     j=0;
390     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
391     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
392     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
393     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
394
395     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
396     XtSetArg(args[j], XtNforceColumns, True);  j++;
397     XtSetArg(args[j], XtNverticalList, True);  j++;
398     XtSetArg(args[j], XtNborderWidth, 0); j++;
399     XtSetArg(args[j], XtNresizable,True);j++;
400     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
401     hist->mvn = XtCreateManagedWidget("movesn", listWidgetClass,
402                                       hist->vbox, args, j);
403     XtAddCallback(hist->mvn, XtNcallback, HistoryMoveProc, (XtPointer) hist);
404
405     j=0;
406     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
407     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
408     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
409     XtSetArg(args[j], XtNright, XtRubber);  j++;
410
411     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
412     XtSetArg(args[j], XtNforceColumns, True);  j++;
413     XtSetArg(args[j], XtNverticalList, True);  j++;
414     XtSetArg(args[j], XtNborderWidth, 0); j++;
415     XtSetArg(args[j], XtNresizable,True);j++;
416     XtSetArg(args[j], XtNfromHoriz, hist->mvn);  j++;
417     hist->mvw = XtCreateManagedWidget("movesw", listWidgetClass,
418                                       hist->vbox, args, j);
419     XtAddCallback(hist->mvw, XtNcallback, HistoryMoveProc, (XtPointer) hist);
420
421     j=0;
422     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
423     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
424     XtSetArg(args[j], XtNleft, XtRubber);  j++;
425     XtSetArg(args[j], XtNright,  XtRubber);  j++;
426
427     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
428     XtSetArg(args[j], XtNforceColumns, True);  j++;
429     XtSetArg(args[j], XtNverticalList, True);  j++;
430     XtSetArg(args[j], XtNborderWidth, 0); j++;
431     XtSetArg(args[j], XtNresizable,True);j++;
432     XtSetArg(args[j], XtNfromHoriz, hist->mvw);  j++;
433     hist->mvb = XtCreateManagedWidget("movesb", listWidgetClass,
434                                       hist->vbox, args, j);
435     XtAddCallback(hist->mvb, XtNcallback, HistoryMoveProc, (XtPointer) hist);
436
437     j=0;
438     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
439     XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
440     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
441     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
442     XtSetArg(args[j], XtNfromVert, hist->viewport);  j++;
443     b_close= XtCreateManagedWidget(_("Close"), commandWidgetClass,
444                                    form, args, j);
445     XtAddCallback(b_close, XtNcallback, HistoryPopDown, (XtPointer) 0);
446
447     XtAugmentTranslations(hist->sh,XtParseTranslationTable (trstr));
448
449     XtRealizeWidget(hist->sh);
450     CatchDeleteWindow(hist->sh, "HistoryPopDown");
451
452     for(i=1;i<hist->aNr;i++){
453       strcpy(hist->white[i],dots);
454       strcpy(hist->black[i],"");
455      }
456
457     return hist->sh;
458 }
459
460 void
461 HistoryPopUp()
462 {
463   Arg args[16];
464   int j;
465
466   if(!hist) HistoryCreate();
467
468   XtPopup(hist->sh, XtGrabNone);
469
470   // [HGM] restore old position
471   j = 0;
472   XtSetArg(args[j], XtNx, gameHistoryX);  j++;
473   XtSetArg(args[j], XtNy, gameHistoryY);  j++;
474   XtSetValues(hist->sh, args, j);
475
476   j=0;
477   XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
478   XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Move History"),
479                 args, j);
480   hist->Up=True;
481 }
482
483
484 void
485 HistoryShowProc(w, event, prms, nprms)
486      Widget w;
487      XEvent *event;
488      String *prms;
489      Cardinal *nprms;
490 {
491   if (!hist) {
492     HistoryCreate();
493     HistoryPopUp();
494   } else if (hist->Up) {
495     HistoryPopDown(0,0,0);
496   } else {
497     HistoryPopUp();
498   }
499   ToNrEvent(currentMove);
500 }
501