Fix some warnings and header-file improvement
[xboard.git] / xhistory.c
1 /*
2  * xhistory.c -- Move list window, part of X front end for XBoard
3  *
4  * Copyright 2000, 2009, 2010, 2011 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 #include "xevalgraph.h"
71
72 #ifdef ENABLE_NLS
73 # define  _(s) gettext (s)
74 # define N_(s) gettext_noop (s)
75 #else
76 # define  _(s) (s)
77 # define N_(s)  s
78 #endif
79
80 #define _LL_ 100
81
82 struct History{
83   String *Nr,*white,*black;
84   int     aNr;  /* space actually alocated */
85   Widget mvn,mvw,mvb,vbox,viewport,sh;
86   char Up;
87 };
88
89 struct History *hist=0;
90 String dots=" ... ";
91 Position gameHistoryX, gameHistoryY;
92 Dimension gameHistoryW, gameHistoryH;
93
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
103     // [HGM] remember old position
104     j = 0;
105     XtSetArg(args[j], XtNx, &gameHistoryX);  j++;
106     XtSetArg(args[j], XtNy, &gameHistoryY);  j++;
107     XtSetArg(args[j], XtNwidth, &gameHistoryW);  j++;
108     XtSetArg(args[j], XtNheight, &gameHistoryH);  j++;
109     XtGetValues(hist->sh, args, j);
110     wpMoveHistory.x = gameHistoryX - 4;
111     wpMoveHistory.y = gameHistoryY - 23;
112     wpMoveHistory.width  = gameHistoryW;
113     wpMoveHistory.height = gameHistoryH;
114
115     XtPopdown(hist->sh);
116     hist->Up=False;
117   }
118   j=0;
119   XtSetArg(args[j], XtNleftBitmap, None); j++;
120   XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Move History"),
121                 args, j);
122 }
123
124 void HistoryMoveProc(Widget w, XtPointer closure, XtPointer call_data)
125 {
126     int to;
127     XawListReturnStruct *R = (XawListReturnStruct *) call_data;
128     if (w == hist->mvn || w == hist->mvw) {
129       to=2*R->list_index-1;
130       ToNrEvent(to);
131     }
132     else if (w == hist->mvb) {
133       to=2*R->list_index;
134       ToNrEvent(to);
135     }
136 }
137
138 void HistoryAlloc(int len){
139   int i;
140   if(hist){
141     free(hist->Nr[0]);free(hist->white[0]);free(hist->black[0]);
142     free(hist->Nr);free(hist->white);free(hist->black);
143   }
144   else{
145     hist=(struct History*)malloc(sizeof(struct History));
146   }
147     hist->aNr=len;
148     hist->Nr=(String*)malloc(hist->aNr*sizeof(String*));
149     hist->white=(String*)malloc(hist->aNr*sizeof(String*));
150     hist->black=(String*)malloc(hist->aNr*sizeof(String*));
151
152     hist->Nr[0]=(String)malloc(hist->aNr*6);
153     hist->white[0]=(String)malloc(hist->aNr*MOVE_LEN);
154     hist->black[0]=(String)malloc(hist->aNr*MOVE_LEN);
155
156       sprintf(hist->Nr[0],"    ");
157       sprintf(hist->white[0],_("White "));
158       sprintf(hist->black[0],_("Black "));
159     for(i=1;i<hist->aNr;i++){
160       hist->Nr[i]= hist->Nr[i-1]+6;
161       hist->white[i]= hist->white[i-1]+MOVE_LEN;
162       hist->black[i]= hist->black[i-1]+MOVE_LEN;
163       sprintf(hist->Nr[i],"%i.",i);
164       sprintf(hist->white[i],"-----");
165       sprintf(hist->black[i],"-----");
166      }
167 }
168
169
170 /* Find empty space inside vbox form widget and redistribute it amongst
171    the list widgets inside it. */
172 /* This version sort of works */
173 void
174 HistoryFill()
175 {
176   Dimension w, bw;
177   long extra;
178   Position x, x1, x2;
179   int j, dd;
180   Arg args[16];
181
182   j = 0;
183   XtSetArg(args[j], XtNx, &x);  j++;
184   XtSetArg(args[j], XtNwidth, &w);  j++;
185   XtSetArg(args[j], XtNborderWidth, &bw);  j++;
186   XtGetValues(hist->mvb, args, j);
187   x1 = x + w + 2*bw;
188
189   j = 0;
190   XtSetArg(args[j], XtNwidth, &w);  j++;
191   XtSetArg(args[j], XtNdefaultDistance, &dd);  j++;
192   XtGetValues(hist->vbox, args, j);
193   x2 = w - dd;
194
195   extra = x2 - x1;
196   if (extra < 0) {
197     extra = -((-extra)/2);
198   } else {
199     extra = extra/2;
200   }
201
202   j = 0;
203   XtSetArg(args[j], XtNwidth, &w);  j++;
204   XtGetValues(hist->mvw, args, j);
205   w += extra;
206   j = 0;
207   XtSetArg(args[j], XtNwidth, w);  j++;
208   XtSetValues(hist->mvw, args, j);
209
210   j = 0;
211   XtSetArg(args[j], XtNwidth, &w);  j++;
212   XtGetValues(hist->mvb, args, j);
213   w += extra;
214   j = 0;
215   XtSetArg(args[j], XtNwidth, w);  j++;
216   XtSetValues(hist->mvb, args, j);
217 }
218
219 void HistorySet(char movelist[][2*MOVE_LEN],int first,int last,int current){
220   int i,b,m;
221   Widget scroll;
222   if(hist){
223     if(last >= hist->aNr) HistoryAlloc(last+_LL_);
224     for(i=0;i<last;i++) {
225       if((i%2)==0) {
226         if(movelist[i][0]) {
227           char* p = strchr(movelist[i], ' ');
228           if (p) {
229             strncpy(hist->white[i/2+1], movelist[i], p-movelist[i]);
230             hist->white[i/2+1][p-movelist[i]] = NULLCHAR;
231           } else {
232             safeStrCpy(hist->white[i/2+1],movelist[i], MOVE_LEN);
233           }
234         } else {
235           safeStrCpy(hist->white[i/2+1],dots, MOVE_LEN);
236         }
237       } else {
238         if(movelist[i][0]) {
239           char* p = strchr(movelist[i], ' ');
240           if (p) {
241             strncpy(hist->black[i/2+1], movelist[i], p-movelist[i]);
242             hist->black[i/2+1][p-movelist[i]] = NULLCHAR;
243           } else {
244             safeStrCpy(hist->black[i/2+1],movelist[i], MOVE_LEN);
245           }
246         } else {
247           safeStrCpy(hist->black[i/2+1],"", MOVE_LEN);
248         }
249       }
250     }
251     safeStrCpy(hist->black[last/2+1],"", MOVE_LEN);
252     b=first/2;
253     m=(last+3)/2-b;
254     XawFormDoLayout(hist->vbox, False);
255     XawListChange(hist->mvn,hist->Nr+b,m,0,True);
256     XawListChange(hist->mvw,hist->white+b,m,0,True);
257     XawListChange(hist->mvb,hist->black+b,m,0,True);
258     HistoryFill();
259     XawFormDoLayout(hist->vbox, True);
260     if(current<0){
261       XawListUnhighlight(hist->mvw);
262       XawListUnhighlight(hist->mvb);
263     }
264     else if((current%2)==0){
265       XawListHighlight(hist->mvw, current/2+1);
266       XawListUnhighlight(hist->mvb);
267     }
268     else{
269       XawListUnhighlight(hist->mvw);
270       if(current) XawListHighlight(hist->mvb, current/2+1);
271       else XawListUnhighlight(hist->mvb);
272     }
273     if(scroll = XtNameToWidget(hist->sh, "*form.viewport.vertical")) { // [HGM] always scroll to bottom
274       static char *params[3] = { "", "Forward", "FullLength" };
275       static XEvent event;
276       XtCallActionProc(scroll, "StartScroll", &event, params+1, 1);
277       XtCallActionProc(scroll, "NotifyScroll", &event, params+2, 1);
278       XtCallActionProc(scroll, "EndScroll", &event, params, 0);
279     }
280   }
281   EvalGraphSet( first, last, current, pvInfoList ); // piggy-backed
282 }
283
284 Widget HistoryCreate()
285 {
286     Arg args[16];
287     int i,j;
288
289     Widget layout,form,b_close;
290     String trstr=
291              "<Key>Up: BackwardProc() \n \
292              <Key>Left: BackwardProc() \n \
293              <Key>Down: ForwardProc() \n \
294              <Key>Right: ForwardProc() \n";
295     /*--- allocate memory for move-strings ---*/
296     HistoryAlloc(_LL_);
297
298     /*-------- create the widgets ---------------*/
299     j = 0;
300     XtSetArg(args[j], XtNresizable, True);  j++;
301     XtSetArg(args[j], XtNallowShellResize, True);  j++;
302 #if TOPLEVEL
303     hist->sh = historyShell =
304       XtCreatePopupShell(_("Move list"), topLevelShellWidgetClass,
305                          shellWidget, args, j);
306 #else
307     hist->sh = historyShell =
308       XtCreatePopupShell(_("Move list"), transientShellWidgetClass,
309                          shellWidget, args, j);
310 #endif
311     j = 0;
312     XtSetArg(args[j], XtNborderWidth, 0); j++;
313     XtSetArg(args[j], XtNdefaultDistance, 0);  j++;
314       layout =
315       XtCreateManagedWidget(layoutName, formWidgetClass, hist->sh,
316                             args, j);
317
318     j = 0;
319     XtSetArg(args[j], XtNborderWidth, 0); j++;
320     XtSetArg(args[j], XtNresizable, True);  j++;
321
322     form =
323       XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
324
325     j = 0;
326     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
327     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
328     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
329     XtSetArg(args[j], XtNright, XtChainRight);  j++;
330
331     XtSetArg(args[j], XtNborderWidth, 1); j++;
332     XtSetArg(args[j], XtNresizable, False);  j++;
333     XtSetArg(args[j], XtNallowVert, True); j++;
334     XtSetArg(args[j], XtNallowHoriz, True);  j++;
335     XtSetArg(args[j], XtNforceBars, False); j++;
336     XtSetArg(args[j], XtNheight, 280); j++;
337     hist->viewport =
338       XtCreateManagedWidget("viewport", viewportWidgetClass,
339                             form, args, j);
340     j=0;
341     XtSetArg(args[j], XtNborderWidth, 0); j++;
342     XtSetArg(args[j], XtNorientation,XtorientHorizontal);j++;
343     hist->vbox =
344       XtCreateManagedWidget("vbox", formWidgetClass, hist->viewport, args, j);
345
346     j=0;
347     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
348     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
349     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
350     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
351
352     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
353     XtSetArg(args[j], XtNforceColumns, True);  j++;
354     XtSetArg(args[j], XtNverticalList, True);  j++;
355     XtSetArg(args[j], XtNborderWidth, 0); j++;
356     XtSetArg(args[j], XtNresizable,True);j++;
357     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
358     hist->mvn = XtCreateManagedWidget("movesn", listWidgetClass,
359                                       hist->vbox, args, j);
360     XtAddCallback(hist->mvn, XtNcallback, HistoryMoveProc, (XtPointer) hist);
361
362     j=0;
363     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
364     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
365     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
366     XtSetArg(args[j], XtNright, XtRubber);  j++;
367
368     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
369     XtSetArg(args[j], XtNforceColumns, True);  j++;
370     XtSetArg(args[j], XtNverticalList, True);  j++;
371     XtSetArg(args[j], XtNborderWidth, 0); j++;
372     XtSetArg(args[j], XtNresizable,True);j++;
373     XtSetArg(args[j], XtNfromHoriz, hist->mvn);  j++;
374     hist->mvw = XtCreateManagedWidget("movesw", listWidgetClass,
375                                       hist->vbox, args, j);
376     XtAddCallback(hist->mvw, XtNcallback, HistoryMoveProc, (XtPointer) hist);
377
378     j=0;
379     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
380     XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
381     XtSetArg(args[j], XtNleft, XtRubber);  j++;
382     XtSetArg(args[j], XtNright,  XtRubber);  j++;
383
384     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
385     XtSetArg(args[j], XtNforceColumns, True);  j++;
386     XtSetArg(args[j], XtNverticalList, True);  j++;
387     XtSetArg(args[j], XtNborderWidth, 0); j++;
388     XtSetArg(args[j], XtNresizable,True);j++;
389     XtSetArg(args[j], XtNfromHoriz, hist->mvw);  j++;
390     hist->mvb = XtCreateManagedWidget("movesb", listWidgetClass,
391                                       hist->vbox, args, j);
392     XtAddCallback(hist->mvb, XtNcallback, HistoryMoveProc, (XtPointer) hist);
393
394     j=0;
395     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
396     XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
397     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
398     XtSetArg(args[j], XtNright, XtChainLeft);  j++;
399     XtSetArg(args[j], XtNfromVert, hist->viewport);  j++;
400     b_close= XtCreateManagedWidget(_("Close"), commandWidgetClass,
401                                    form, args, j);
402     XtAddCallback(b_close, XtNcallback, HistoryPopDown, (XtPointer) 0);
403
404     XtAugmentTranslations(hist->sh,XtParseTranslationTable (trstr));
405
406     XtRealizeWidget(hist->sh);
407     CatchDeleteWindow(hist->sh, "HistoryPopDown");
408
409     for(i=1;i<hist->aNr;i++){
410       safeStrCpy(hist->white[i],dots, MOVE_LEN);
411       safeStrCpy(hist->black[i],"", MOVE_LEN);
412      }
413
414     if(wpMoveHistory.width > 0) {
415       gameHistoryW = wpMoveHistory.width;
416       gameHistoryH = wpMoveHistory.height;
417       gameHistoryX = wpMoveHistory.x;
418       gameHistoryY = wpMoveHistory.y;
419     }
420
421   // [HGM] restore old position
422   if(gameHistoryW > 0) {
423   j = 0;
424     XtSetArg(args[j], XtNx, gameHistoryX);  j++;
425   XtSetArg(args[j], XtNy, gameHistoryY);  j++;
426     XtSetArg(args[j], XtNwidth, gameHistoryW);  j++;
427     XtSetArg(args[j], XtNheight, gameHistoryH);  j++;
428   XtSetValues(hist->sh, args, j);
429   }
430     XtRealizeWidget(hist->sh);
431
432     return hist->sh;
433 }
434
435 void
436 HistoryPopUp()
437 {
438   Arg args[16];
439   int j;
440
441   if(!hist) HistoryCreate();
442
443   XtPopup(hist->sh, XtGrabNone);
444
445   j=0;
446   XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
447   XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Move History"),
448                 args, j);
449   hist->Up=True;
450 }
451
452
453 void
454 HistoryShowProc(w, event, prms, nprms)
455      Widget w;
456      XEvent *event;
457      String *prms;
458      Cardinal *nprms;
459 {
460   if (!hist) {
461     HistoryCreate();
462     HistoryPopUp();
463   } else if (hist->Up) {
464     HistoryPopDown(0,0,0);
465   } else {
466     HistoryPopUp();
467   }
468   ToNrEvent(currentMove);
469 }
470
471 Boolean
472 MoveHistoryIsUp()
473 {
474   return hist && hist->Up;
475 }