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