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