Bugfix ICS interaction console
[xboard.git] / xhistory.c
1 /*
2  * xhistory.c -- Move list window, part of X front end for XBoard
3  * $Id$
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 #include "gettext.h"
75
76 #ifdef ENABLE_NLS
77 # define  _(s) gettext (s)
78 # define N_(s) gettext_noop (s)
79 #else
80 # define  _(s) (s)
81 # define N_(s)  s
82 #endif
83
84 #define _LL_ 100
85
86 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
87 extern Display *xDisplay;
88 extern int squareSize;
89 extern Pixmap xMarkPixmap;
90 extern char *layoutName;
91
92 struct History{
93   String *Nr,*white,*black;
94   int     aNr;  /* space actually alocated */  
95   Widget mvn,mvw,mvb,vbox,viewport,sh;
96   char Up;
97 };
98
99 struct History *hist=0;
100 String dots=" ... ";
101
102 void
103 HistoryPopDown(w, client_data, call_data)
104      Widget w;
105      XtPointer client_data, call_data;
106 {
107   Arg args[16];
108   int j;
109   if(hist)
110
111   XtPopdown(hist->sh);
112   hist->Up=False;
113
114   j=0;
115   XtSetArg(args[j], XtNleftBitmap, None); j++;
116   XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Move List"),
117                 args, j);
118 }
119
120 void HistoryMoveProc(Widget w, XtPointer closure, XtPointer call_data)
121 {
122     int to;
123     XawListReturnStruct *R = (XawListReturnStruct *) call_data;
124     if (w == hist->mvn || w == hist->mvw) {
125       to=2*R->list_index-1;
126       ToNrEvent(to);
127     }
128     else if (w == hist->mvb) {
129       to=2*R->list_index;
130       ToNrEvent(to);
131     }
132 }
133
134 void HistoryAlloc(int len){
135   int i;
136   if(hist){
137     free(hist->Nr[0]);free(hist->white[0]);free(hist->black[0]);
138     free(hist->Nr);free(hist->white);free(hist->black);
139   }
140   else{
141     hist=(struct History*)malloc(sizeof(struct History)); 
142   }
143     hist->aNr=len;
144     hist->Nr=(String*)malloc(hist->aNr*sizeof(String*));
145     hist->white=(String*)malloc(hist->aNr*sizeof(String*));
146     hist->black=(String*)malloc(hist->aNr*sizeof(String*));
147     
148     hist->Nr[0]=(String)malloc(hist->aNr*6);
149     hist->white[0]=(String)malloc(hist->aNr*MOVE_LEN);
150     hist->black[0]=(String)malloc(hist->aNr*MOVE_LEN);
151
152       sprintf(hist->Nr[0],"    ");
153       sprintf(hist->white[0],_("White "));
154       sprintf(hist->black[0],_("Black "));
155     for(i=1;i<hist->aNr;i++){
156       hist->Nr[i]= hist->Nr[i-1]+6;
157       hist->white[i]= hist->white[i-1]+MOVE_LEN;
158       hist->black[i]= hist->black[i-1]+MOVE_LEN;
159       sprintf(hist->Nr[i],"%i.",i);
160       sprintf(hist->white[i],"-----");
161       sprintf(hist->black[i],"-----");
162      }
163 }
164
165
166 #if 1
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 #else
216 /* Find empty space inside vbox form widget and redistribute it amongst
217    the list widgets inside it. */
218 /* This version doesn't work */
219 void
220 HistoryFill()
221 {
222   Arg args[16];
223   Dimension fw, niw, wiw, biw, nbw, wbw, bbw;
224   int j, nl, wl, bl, fdd;
225   long extra;
226
227   j = 0;
228   XtSetArg(args[j], XtNwidth, &fw);  j++;
229   XtSetArg(args[j], XtNdefaultDistance, &fdd);  j++;
230   XtGetValues(hist->vbox, args, j);
231
232   j = 0;
233   XtSetArg(args[j], XtNlongest, &nl);  j++;
234   XtSetArg(args[j], XtNinternalWidth, &niw);  j++;
235   XtSetArg(args[j], XtNborderWidth, &nbw);  j++;
236   XtGetValues(hist->mvn, args, j);
237
238   j = 0;
239   XtSetArg(args[j], XtNlongest, &wl);  j++;
240   XtSetArg(args[j], XtNinternalWidth, &wiw);  j++;
241   XtSetArg(args[j], XtNborderWidth, &wbw);  j++;
242   XtGetValues(hist->mvw, args, j);
243
244   j = 0;
245   XtSetArg(args[j], XtNlongest, &bl);  j++;
246   XtSetArg(args[j], XtNinternalWidth, &biw);  j++;
247   XtSetArg(args[j], XtNborderWidth, &bbw);  j++;
248   XtGetValues(hist->mvb, args, j);
249
250   extra = fw - 4*fdd -
251     nl - 1 - 2*niw - 2*nbw - wl - 2*wiw - 2*wbw - bl - 2*biw - 2*bbw;
252   if (extra < 0) extra = 0;
253
254   j = 0;
255   XtSetArg(args[j], XtNwidth, nl + 1 + 2*niw);  j++;
256   XtSetValues(hist->mvn, args, j);
257
258   j = 0;
259   XtSetArg(args[j], XtNwidth, wl + 2*wiw + extra/2);  j++;
260   XtSetValues(hist->mvw, args, j);
261
262   j = 0;
263   XtSetArg(args[j], XtNwidth, bl + 2*biw + extra/2);  j++;
264   XtSetValues(hist->mvb, args, j);
265 }
266 #endif
267
268 void HistorySet(char movelist[][2*MOVE_LEN],int first,int last,int current){
269   int i,b,m;
270   if(hist){
271     if(last >= hist->aNr) HistoryAlloc(last+_LL_);
272     for(i=0;i<last;i++) {
273       if((i%2)==0) { 
274         if(movelist[i][0]) {
275           char* p = strchr(movelist[i], ' ');
276           if (p) {
277             strncpy(hist->white[i/2+1], movelist[i], p-movelist[i]);
278             hist->white[i/2+1][p-movelist[i]] = NULLCHAR;
279           } else {
280             strcpy(hist->white[i/2+1],movelist[i]);
281           }         
282         } else {
283           strcpy(hist->white[i/2+1],dots);
284         }
285       } else {
286         if(movelist[i][0]) {
287           char* p = strchr(movelist[i], ' ');
288           if (p) {
289             strncpy(hist->black[i/2+1], movelist[i], p-movelist[i]);
290             hist->black[i/2+1][p-movelist[i]] = NULLCHAR;
291           } else {
292             strcpy(hist->black[i/2+1],movelist[i]);
293           }         
294         } else {
295           strcpy(hist->black[i/2+1],"");
296         }
297       }
298     }
299     strcpy(hist->black[last/2+1],"");
300     b=first/2;
301     m=(last+3)/2-b;
302     XawFormDoLayout(hist->vbox, False);
303     XawListChange(hist->mvn,hist->Nr+b,m,0,True);
304     XawListChange(hist->mvw,hist->white+b,m,0,True);
305     XawListChange(hist->mvb,hist->black+b,m,0,True);
306     HistoryFill();
307     XawFormDoLayout(hist->vbox, True);
308     if(current<0){
309       XawListUnhighlight(hist->mvw);
310       XawListUnhighlight(hist->mvb);
311     }
312     else if((current%2)==0){
313       XawListHighlight(hist->mvw, current/2+1);
314       XawListUnhighlight(hist->mvb);
315     }
316     else{
317       XawListUnhighlight(hist->mvw);
318       if(current) XawListHighlight(hist->mvb, current/2+1);
319       else XawListUnhighlight(hist->mvb);
320     }
321   }
322 }
323
324 Widget HistoryCreate()
325 {
326     Arg args[16];
327     int i,j;
328
329     Widget layout,form,b_close;
330     String trstr=
331              "<Key>Up: BackwardProc() \n \
332              <Key>Left: BackwardProc() \n \
333              <Key>Down: ForwardProc() \n \
334              <Key>Right: ForwardProc() \n";
335     /*--- allocate memory for move-strings ---*/
336     HistoryAlloc(_LL_);
337    
338     /*-------- create the widgets ---------------*/
339     j = 0;
340     XtSetArg(args[j], XtNresizable, True);  j++;
341     XtSetArg(args[j], XtNallowShellResize, True);  j++;   
342 #if TOPLEVEL
343     hist->sh =
344       XtCreatePopupShell(_("Move list"), topLevelShellWidgetClass,
345                          shellWidget, args, j);
346 #else
347     hist->sh =
348       XtCreatePopupShell(_("Move list"), transientShellWidgetClass,
349                          shellWidget, args, j);
350 #endif        
351     j = 0;
352     XtSetArg(args[j], XtNborderWidth, 0); j++;
353     XtSetArg(args[j], XtNdefaultDistance, 0);  j++;
354       layout =
355       XtCreateManagedWidget(layoutName, formWidgetClass, hist->sh,
356                             args, j);
357     
358     j = 0;
359     XtSetArg(args[j], XtNborderWidth, 0); j++;
360     XtSetArg(args[j], XtNresizable, True);  j++;
361   
362     form =
363       XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
364      j=0;
365
366     j = 0;
367
368     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
369     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
370     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
371     XtSetArg(args[j], XtNright, XtChainRight);  j++;
372
373     XtSetArg(args[j], XtNborderWidth, 1); j++;
374     XtSetArg(args[j], XtNresizable, False);  j++;
375     XtSetArg(args[j], XtNallowVert, True); j++;
376     XtSetArg(args[j], XtNallowHoriz, True);  j++;
377     XtSetArg(args[j], XtNforceBars, False); j++;
378     XtSetArg(args[j], XtNheight, 280); j++;
379     hist->viewport =
380       XtCreateManagedWidget("viewport", viewportWidgetClass,
381                             form, args, j);
382     j=0;
383     XtSetArg(args[j], XtNborderWidth, 0); j++;
384     XtSetArg(args[j], XtNorientation,XtorientHorizontal);j++;
385     hist->vbox =
386       XtCreateManagedWidget("vbox", formWidgetClass, hist->viewport, args, j);
387     
388     j=0;
389     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
390     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
391     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
392     XtSetArg(args[j], XtNright, XtChainLeft);  j++;    
393      
394     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
395     XtSetArg(args[j], XtNforceColumns, True);  j++;
396     XtSetArg(args[j], XtNverticalList, True);  j++;
397     XtSetArg(args[j], XtNborderWidth, 0); j++;
398     XtSetArg(args[j], XtNresizable,True);j++;
399     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
400     hist->mvn = XtCreateManagedWidget("movesn", listWidgetClass,
401                                       hist->vbox, args, j);
402     XtAddCallback(hist->mvn, XtNcallback, HistoryMoveProc, (XtPointer) hist);
403
404     j=0;
405     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
406     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
407     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
408     XtSetArg(args[j], XtNright, XtRubber);  j++;    
409     
410     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
411     XtSetArg(args[j], XtNforceColumns, True);  j++;
412     XtSetArg(args[j], XtNverticalList, True);  j++;
413     XtSetArg(args[j], XtNborderWidth, 0); j++;
414     XtSetArg(args[j], XtNresizable,True);j++;
415     XtSetArg(args[j], XtNfromHoriz, hist->mvn);  j++;
416     hist->mvw = XtCreateManagedWidget("movesw", listWidgetClass,
417                                       hist->vbox, args, j);
418     XtAddCallback(hist->mvw, XtNcallback, HistoryMoveProc, (XtPointer) hist);
419
420     j=0;
421     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
422     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
423     XtSetArg(args[j], XtNleft, XtRubber);  j++;
424     XtSetArg(args[j], XtNright,  XtRubber);  j++;
425     
426     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
427     XtSetArg(args[j], XtNforceColumns, True);  j++;
428     XtSetArg(args[j], XtNverticalList, True);  j++;
429     XtSetArg(args[j], XtNborderWidth, 0); j++;
430     XtSetArg(args[j], XtNresizable,True);j++;
431     XtSetArg(args[j], XtNfromHoriz, hist->mvw);  j++;
432     hist->mvb = XtCreateManagedWidget("movesb", listWidgetClass,
433                                       hist->vbox, args, j);
434     XtAddCallback(hist->mvb, XtNcallback, HistoryMoveProc, (XtPointer) hist);
435
436     j=0;
437     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
438     XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
439     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
440     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
441     XtSetArg(args[j], XtNfromVert, hist->viewport);  j++;
442     b_close= XtCreateManagedWidget(_("Close"), commandWidgetClass,
443                                    form, args, j);   
444     XtAddCallback(b_close, XtNcallback, HistoryPopDown, (XtPointer) 0);
445
446     XtAugmentTranslations(hist->sh,XtParseTranslationTable (trstr)); 
447
448     XtRealizeWidget(hist->sh);
449     CatchDeleteWindow(hist->sh, "HistoryPopDown");
450
451     for(i=1;i<hist->aNr;i++){
452       strcpy(hist->white[i],dots);
453       strcpy(hist->black[i],"");
454      }
455    
456     return hist->sh;
457 }
458
459 void
460 HistoryPopUp()
461 {
462   Arg args[16];
463   int j;
464
465   if(!hist) HistoryCreate();
466   XtPopup(hist->sh, XtGrabNone);
467   j=0;
468   XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
469   XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Move List"),
470                 args, j);
471   hist->Up=True;
472 }
473
474  
475 void
476 HistoryShowProc(w, event, prms, nprms)
477      Widget w;
478      XEvent *event;
479      String *prms;
480      Cardinal *nprms;
481 {
482   if (!hist) {
483     HistoryCreate();
484     HistoryPopUp();
485   } else if (hist->Up) {
486     HistoryPopDown(0,0,0);
487   } else {
488     HistoryPopUp();
489   }
490   ToNrEvent(currentMove);
491 }
492