changes from H.G. Muller; version 4.3.15
[xboard.git] / xhistory.c
1 /*
2  * xhistory.c -- Move list window, part of X front end for XBoard
3  * $Id: xhistory.c,v 2.1 2003/10/27 19:21:00 mann Exp $
4  *
5  * Copyright 2000 Free Software Foundation, Inc.
6  *
7  * The following terms apply to the enhanced version of XBoard distributed
8  * by the Free Software Foundation:
9  * ------------------------------------------------------------------------
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  * ------------------------------------------------------------------------
24  *
25  * See the file ChangeLog for a revision history.
26  */
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <sys/types.h>
34
35 #if STDC_HEADERS
36 # include <stdlib.h>
37 # include <string.h>
38 #else /* not STDC_HEADERS */
39 extern char *getenv();
40 # if HAVE_STRING_H
41 #  include <string.h>
42 # else /* not HAVE_STRING_H */
43 #  include <strings.h>
44 # endif /* not HAVE_STRING_H */
45 #endif /* not STDC_HEADERS */
46
47 #if HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50
51 #include <X11/Intrinsic.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Shell.h>
54 #include <X11/Xaw/Dialog.h>
55 #include <X11/Xaw/Form.h>
56 #include <X11/Xaw/List.h>
57 #include <X11/Xaw/Label.h>
58 #include <X11/Xaw/SimpleMenu.h>
59 #include <X11/Xaw/SmeBSB.h>
60 #include <X11/Xaw/SmeLine.h>
61 #include <X11/Xaw/Box.h>
62 #include <X11/Xaw/Paned.h>
63 #include <X11/Xaw/MenuButton.h>
64 #include <X11/cursorfont.h>
65 #include <X11/Xaw/Text.h>
66 #include <X11/Xaw/AsciiText.h>
67 #include <X11/Xaw/Viewport.h>
68
69 #include "common.h"
70 #include "frontend.h"
71 #include "backend.h"
72 #include "xboard.h"
73 #include "xhistory.h"
74
75
76 #define _LL_ 100
77
78 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
79 extern Display *xDisplay;
80 extern int squareSize;
81 extern Pixmap xMarkPixmap;
82 extern char *layoutName;
83
84 struct History{
85   String *Nr,*white,*black;
86   int     aNr;  /* space actually alocated */  
87   Widget mvn,mvw,mvb,vbox,viewport,sh;
88   char Up;
89 };
90
91 struct History *hist=0;
92 String dots=" ... ";
93 Position gameHistoryX, gameHistoryY;
94 void
95 HistoryPopDown(w, client_data, call_data)
96      Widget w;
97      XtPointer client_data, call_data;
98 {
99   Arg args[16];
100   int j;
101   if(hist) {
102     // [HGM] remember old position
103     j = 0;
104     XtSetArg(args[j], XtNx, &gameHistoryX);  j++;\r
105     XtSetArg(args[j], XtNy, &gameHistoryY);  j++;\r
106     XtGetValues(hist->sh, args, j);\r
107
108     XtPopdown(hist->sh);
109     hist->Up=False;
110   }
111   j=0;
112   XtSetArg(args[j], XtNleftBitmap, None); j++;
113   XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Move History"),
114                 args, j);
115 }
116
117 void HistoryMoveProc(Widget w, XtPointer closure, XtPointer call_data)
118 {
119     int to;
120
121     XawListReturnStruct *R = (XawListReturnStruct *) call_data;
122     if (w == hist->mvn || w == hist->mvw) {
123       to=2*R->list_index-1;
124       ToNrEvent(to);
125     }
126     else if (w == hist->mvb) {
127       to=2*R->list_index;
128       ToNrEvent(to);
129     }
130 }
131
132 void HistoryAlloc(int len){
133   int i;
134   if(hist){
135     free(hist->Nr[0]);free(hist->white[0]);free(hist->black[0]);
136     free(hist->Nr);free(hist->white);free(hist->black);
137   }
138   else{
139     hist=(struct History*)malloc(sizeof(struct History)); 
140   }
141     hist->aNr=len;
142     hist->Nr=(String*)malloc(hist->aNr*sizeof(String*));
143     hist->white=(String*)malloc(hist->aNr*sizeof(String*));
144     hist->black=(String*)malloc(hist->aNr*sizeof(String*));
145     
146     hist->Nr[0]=(String)malloc(hist->aNr*6);
147     hist->white[0]=(String)malloc(hist->aNr*MOVE_LEN);
148     hist->black[0]=(String)malloc(hist->aNr*MOVE_LEN);
149
150       sprintf(hist->Nr[0],"    ");
151       sprintf(hist->white[0],"White ");
152       sprintf(hist->black[0],"Black ");
153     for(i=1;i<hist->aNr;i++){
154       hist->Nr[i]= hist->Nr[i-1]+6;
155       hist->white[i]= hist->white[i-1]+MOVE_LEN;
156       hist->black[i]= hist->black[i-1]+MOVE_LEN;
157       sprintf(hist->Nr[i],"%i.",i);
158       sprintf(hist->white[i],"-----");
159       sprintf(hist->black[i],"-----");
160      }
161 }
162
163
164 #if 1
165 /* Find empty space inside vbox form widget and redistribute it amongst
166    the list widgets inside it. */
167 /* This version sort of works */
168 void
169 HistoryFill()
170 {
171   Dimension w, bw;
172   long extra;
173   Position x, x1, x2;
174   int j, dd;
175   Arg args[16];
176
177   j = 0;
178   XtSetArg(args[j], XtNx, &x);  j++;
179   XtSetArg(args[j], XtNwidth, &w);  j++;
180   XtSetArg(args[j], XtNborderWidth, &bw);  j++;
181   XtGetValues(hist->mvb, args, j);
182   x1 = x + w + 2*bw;
183
184   j = 0;
185   XtSetArg(args[j], XtNwidth, &w);  j++;
186   XtSetArg(args[j], XtNdefaultDistance, &dd);  j++;
187   XtGetValues(hist->vbox, args, j);
188   x2 = w - dd;
189
190   extra = x2 - x1;
191   if (extra < 0) {
192     extra = -((-extra)/2);
193   } else {
194     extra = extra/2;
195   }
196  
197   j = 0;
198   XtSetArg(args[j], XtNwidth, &w);  j++;
199   XtGetValues(hist->mvw, args, j);
200   w += extra;
201   j = 0;
202   XtSetArg(args[j], XtNwidth, w);  j++;
203   XtSetValues(hist->mvw, args, j);
204
205   j = 0;
206   XtSetArg(args[j], XtNwidth, &w);  j++;
207   XtGetValues(hist->mvb, args, j);
208   w += extra;
209   j = 0;
210   XtSetArg(args[j], XtNwidth, w);  j++;
211   XtSetValues(hist->mvb, args, j);
212 }
213 #else
214 /* Find empty space inside vbox form widget and redistribute it amongst
215    the list widgets inside it. */
216 /* This version doesn't work */
217 void
218 HistoryFill()
219 {
220   Arg args[16];
221   Dimension fw, niw, wiw, biw, nbw, wbw, bbw;
222   int j, nl, wl, bl, fdd;
223   long extra;
224
225   j = 0;
226   XtSetArg(args[j], XtNwidth, &fw);  j++;
227   XtSetArg(args[j], XtNdefaultDistance, &fdd);  j++;
228   XtGetValues(hist->vbox, args, j);
229
230   j = 0;
231   XtSetArg(args[j], XtNlongest, &nl);  j++;
232   XtSetArg(args[j], XtNinternalWidth, &niw);  j++;
233   XtSetArg(args[j], XtNborderWidth, &nbw);  j++;
234   XtGetValues(hist->mvn, args, j);
235
236   j = 0;
237   XtSetArg(args[j], XtNlongest, &wl);  j++;
238   XtSetArg(args[j], XtNinternalWidth, &wiw);  j++;
239   XtSetArg(args[j], XtNborderWidth, &wbw);  j++;
240   XtGetValues(hist->mvw, args, j);
241
242   j = 0;
243   XtSetArg(args[j], XtNlongest, &bl);  j++;
244   XtSetArg(args[j], XtNinternalWidth, &biw);  j++;
245   XtSetArg(args[j], XtNborderWidth, &bbw);  j++;
246   XtGetValues(hist->mvb, args, j);
247
248   extra = fw - 4*fdd -
249     nl - 1 - 2*niw - 2*nbw - wl - 2*wiw - 2*wbw - bl - 2*biw - 2*bbw;
250   if (extra < 0) extra = 0;
251
252   j = 0;
253   XtSetArg(args[j], XtNwidth, nl + 1 + 2*niw);  j++;
254   XtSetValues(hist->mvn, args, j);
255
256   j = 0;
257   XtSetArg(args[j], XtNwidth, wl + 2*wiw + extra/2);  j++;
258   XtSetValues(hist->mvw, args, j);
259
260   j = 0;
261   XtSetArg(args[j], XtNwidth, bl + 2*biw + extra/2);  j++;
262   XtSetValues(hist->mvb, args, j);
263 }
264 #endif
265
266 void HistorySet(char movelist[][2*MOVE_LEN],int first,int last,int current){
267   int i,b,m;
268   if(hist){
269     if(last >= hist->aNr) HistoryAlloc(last+_LL_);
270     for(i=0;i<last;i++) {
271       if((i%2)==0) { 
272         if(movelist[i][0]) {
273           char* p = strchr(movelist[i], ' ');
274           if (p) {
275             strncpy(hist->white[i/2+1], movelist[i], p-movelist[i]);
276             hist->white[i/2+1][p-movelist[i]] = NULLCHAR;
277           } else {
278             strcpy(hist->white[i/2+1],movelist[i]);
279           }         
280         } else {
281           strcpy(hist->white[i/2+1],dots);
282         }
283       } else {
284         if(movelist[i][0]) {
285           char* p = strchr(movelist[i], ' ');
286           if (p) {
287             strncpy(hist->black[i/2+1], movelist[i], p-movelist[i]);
288             hist->black[i/2+1][p-movelist[i]] = NULLCHAR;
289           } else {
290             strcpy(hist->black[i/2+1],movelist[i]);
291           }         
292         } else {
293           strcpy(hist->black[i/2+1],"");
294         }
295       }
296     }
297     strcpy(hist->black[last/2+1],"");
298     b=first/2;
299     m=(last+3)/2-b;
300     XawFormDoLayout(hist->vbox, False);
301     XawListChange(hist->mvn,hist->Nr+b,m,0,True);
302     XawListChange(hist->mvw,hist->white+b,m,0,True);
303     XawListChange(hist->mvb,hist->black+b,m,0,True);
304     HistoryFill();
305     XawFormDoLayout(hist->vbox, True);
306     if(current<0){
307       XawListUnhighlight(hist->mvw);
308       XawListUnhighlight(hist->mvb);
309     }
310     else if((current%2)==0){
311       XawListHighlight(hist->mvw, current/2+1);
312       XawListUnhighlight(hist->mvb);
313     }
314     else{
315       XawListUnhighlight(hist->mvw);
316       if(current) XawListHighlight(hist->mvb, current/2+1);
317       else XawListUnhighlight(hist->mvb);
318     }
319   }
320 }
321
322 Widget HistoryCreate()
323 {
324     Arg args[16];
325     int i,j;
326
327     Widget layout,form,b_close;
328     String trstr=
329              "<Key>Up: BackwardProc() \n \
330              <Key>Left: BackwardProc() \n \
331              <Key>Down: ForwardProc() \n \
332              <Key>Right: ForwardProc() \n";
333     /*--- allocate memory for move-strings ---*/
334     HistoryAlloc(_LL_);
335    
336     /*-------- create the widgets ---------------*/
337     j = 0;
338     XtSetArg(args[j], XtNresizable, True);  j++;
339     XtSetArg(args[j], XtNallowShellResize, True);  j++;   
340 #if TOPLEVEL
341     hist->sh =
342       XtCreatePopupShell("Move list", topLevelShellWidgetClass,
343                          shellWidget, args, j);
344 #else
345     hist->sh =
346       XtCreatePopupShell("Move list", transientShellWidgetClass,
347                          shellWidget, args, j);
348 #endif        
349     j = 0;
350     XtSetArg(args[j], XtNborderWidth, 0); j++;
351     XtSetArg(args[j], XtNdefaultDistance, 0);  j++;
352       layout =
353       XtCreateManagedWidget(layoutName, formWidgetClass, hist->sh,
354                             args, j);
355     
356     j = 0;
357     XtSetArg(args[j], XtNborderWidth, 0); j++;
358     XtSetArg(args[j], XtNresizable, True);  j++;
359   
360     form =
361       XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
362      j=0;
363
364     j = 0;
365
366     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
367     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
368     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
369     XtSetArg(args[j], XtNright, XtChainRight);  j++;
370
371     XtSetArg(args[j], XtNborderWidth, 1); j++;
372     XtSetArg(args[j], XtNresizable, False);  j++;
373     XtSetArg(args[j], XtNallowVert, True); j++;
374     XtSetArg(args[j], XtNallowHoriz, True);  j++;
375     XtSetArg(args[j], XtNforceBars, False); j++;
376     XtSetArg(args[j], XtNheight, 280); j++;
377     hist->viewport =
378       XtCreateManagedWidget("viewport", viewportWidgetClass,
379                             form, args, j);
380     j=0;
381     XtSetArg(args[j], XtNborderWidth, 0); j++;
382     XtSetArg(args[j], XtNorientation,XtorientHorizontal);j++;
383     hist->vbox =
384       XtCreateManagedWidget("vbox", formWidgetClass, hist->viewport, args, j);
385     
386     j=0;
387     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
388     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
389     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
390     XtSetArg(args[j], XtNright, XtChainLeft);  j++;    
391      
392     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
393     XtSetArg(args[j], XtNforceColumns, True);  j++;
394     XtSetArg(args[j], XtNverticalList, True);  j++;
395     XtSetArg(args[j], XtNborderWidth, 0); j++;
396     XtSetArg(args[j], XtNresizable,True);j++;
397     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
398     hist->mvn = XtCreateManagedWidget("movesn", listWidgetClass,
399                                       hist->vbox, args, j);
400     XtAddCallback(hist->mvn, XtNcallback, HistoryMoveProc, (XtPointer) hist);
401
402     j=0;
403     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
404     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
405     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
406     XtSetArg(args[j], XtNright, XtRubber);  j++;    
407     
408     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
409     XtSetArg(args[j], XtNforceColumns, True);  j++;
410     XtSetArg(args[j], XtNverticalList, True);  j++;
411     XtSetArg(args[j], XtNborderWidth, 0); j++;
412     XtSetArg(args[j], XtNresizable,True);j++;
413     XtSetArg(args[j], XtNfromHoriz, hist->mvn);  j++;
414     hist->mvw = XtCreateManagedWidget("movesw", listWidgetClass,
415                                       hist->vbox, args, j);
416     XtAddCallback(hist->mvw, XtNcallback, HistoryMoveProc, (XtPointer) hist);
417
418     j=0;
419     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
420     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
421     XtSetArg(args[j], XtNleft, XtRubber);  j++;
422     XtSetArg(args[j], XtNright,  XtRubber);  j++;
423     
424     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
425     XtSetArg(args[j], XtNforceColumns, True);  j++;
426     XtSetArg(args[j], XtNverticalList, True);  j++;
427     XtSetArg(args[j], XtNborderWidth, 0); j++;
428     XtSetArg(args[j], XtNresizable,True);j++;
429     XtSetArg(args[j], XtNfromHoriz, hist->mvw);  j++;
430     hist->mvb = XtCreateManagedWidget("movesb", listWidgetClass,
431                                       hist->vbox, args, j);
432     XtAddCallback(hist->mvb, XtNcallback, HistoryMoveProc, (XtPointer) hist);
433
434     j=0;
435     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
436     XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
437     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
438     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
439     XtSetArg(args[j], XtNfromVert, hist->viewport);  j++;
440     b_close= XtCreateManagedWidget("Close", commandWidgetClass,
441                                    form, args, j);   
442     XtAddCallback(b_close, XtNcallback, HistoryPopDown, (XtPointer) 0);
443
444     XtAugmentTranslations(hist->sh,XtParseTranslationTable (trstr)); 
445
446     XtRealizeWidget(hist->sh);
447     CatchDeleteWindow(hist->sh, "HistoryPopDown");
448
449     for(i=1;i<hist->aNr;i++){
450       strcpy(hist->white[i],dots);
451       strcpy(hist->black[i],"");
452      }
453    
454   // [HGM] remember old position
455   j = 0;
456   XtSetArg(args[j], XtNx, &gameHistoryX);  j++;\r
457   XtSetArg(args[j], XtNy, &gameHistoryY);  j++;\r
458   XtGetValues(hist->sh, args, j);\r
459
460     return hist->sh;
461 }
462
463 void
464 HistoryPopUp()
465 {
466   Arg args[16];
467   int j;
468
469   if(!hist) HistoryCreate();
470   XtPopup(hist->sh, XtGrabNone);
471
472   // [HGM] restore old position
473   j = 0;
474   XtSetArg(args[j], XtNx, gameHistoryX);  j++;\r
475   XtSetArg(args[j], XtNy, gameHistoryY);  j++;\r
476   XtSetValues(hist->sh, args, j);\r
477
478   j=0;
479   XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
480   XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Move History"),
481                 args, j);
482   hist->Up=True;
483 }
484
485  
486 void
487 HistoryShowProc(w, event, prms, nprms)
488      Widget w;
489      XEvent *event;
490      String *prms;
491      Cardinal *nprms;
492 {
493   if (!hist) {
494     HistoryCreate();
495     HistoryPopUp();
496   } else if (hist->Up) {
497     HistoryPopDown(0,0,0);
498   } else {
499     HistoryPopUp();
500   }
501   ToNrEvent(currentMove);
502 }
503