Fix recent-engines menu
[xboard.git] / xevalgraph.c
1 /*
2  * Evaluation graph
3  *
4  * Author: Alessandro Scotti (Dec 2005)
5  * Translated to X by H.G.Muller (Nov 2009)
6  *
7  * Copyright 2005 Alessandro Scotti
8  *
9  * Enhancements Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
10  *
11  * ------------------------------------------------------------------------
12  *
13  * GNU XBoard is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or (at
16  * your option) any later version.
17  *
18  * GNU XBoard is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see http://www.gnu.org/licenses/.
25  *
26  * ------------------------------------------------------------------------
27  ** See the file ChangeLog for a revision history.  */
28
29 #include "config.h"
30
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <sys/types.h>
35
36 #if STDC_HEADERS
37 # include <stdlib.h>
38 # include <string.h>
39 #else /* not STDC_HEADERS */
40 extern char *getenv();
41 # if HAVE_STRING_H
42 #  include <string.h>
43 # else /* not HAVE_STRING_H */
44 #  include <strings.h>
45 # endif /* not HAVE_STRING_H */
46 #endif /* not STDC_HEADERS */
47
48 #if HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51
52 #include <X11/Intrinsic.h>
53 #include <X11/StringDefs.h>
54 #include <X11/Shell.h>
55 #include <X11/Xaw/Dialog.h>
56 #include <X11/Xaw/Form.h>
57 #include <X11/Xaw/List.h>
58 #include <X11/Xaw/Label.h>
59 #include <X11/Xaw/SimpleMenu.h>
60 #include <X11/Xaw/SmeBSB.h>
61 #include <X11/Xaw/SmeLine.h>
62 #include <X11/Xaw/Box.h>
63 #include <X11/Xaw/Paned.h>
64 #include <X11/Xaw/MenuButton.h>
65 #include <X11/cursorfont.h>
66 #include <X11/Xaw/Text.h>
67 #include <X11/Xaw/AsciiText.h>
68 #include <X11/Xaw/Viewport.h>
69
70 #include "common.h"
71 #include "frontend.h"
72 #include "backend.h"
73 #include "dialogs.h"
74 #include "menus.h"
75 #include "xboard.h"
76 #include "evalgraph.h"
77 #include "gettext.h"
78
79 #ifdef ENABLE_NLS
80 # define  _(s) gettext (s)
81 # define N_(s) gettext_noop (s)
82 #else
83 # define  _(s) (s)
84 # define N_(s)  s
85 #endif
86
87 #include <X11/xpm.h>
88
89 #ifdef SNAP
90 #include "wsnap.h"
91 #endif
92
93 #define _LL_ 100
94
95 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
96 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
97 static char *title = N_("Evaluation graph");
98
99 //extern WindowPlacement wpEvalGraph;
100
101 Position evalGraphX = -1, evalGraphY = -1;
102 Dimension evalGraphW, evalGraphH;
103
104 /* Module variables */
105
106 char *crWhite = "#FFFFB0";
107 char *crBlack = "#AD5D3D";
108 static Window eGraphWindow;
109
110 static GC pens[6]; // [HGM] put all pens in one array
111 static GC hbrHist[3];
112
113 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end)
114 void
115 DrawSegment (int x, int y, int *lastX, int *lastY, int penType)
116 {
117   static int curX, curY;
118
119   if(penType != PEN_NONE)
120     XDrawLine(xDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
121   if(lastX != NULL) { *lastX = curX; *lastY = curY; }
122   curX = x; curY = y;
123 }
124
125 // front-end wrapper for drawing functions to do rectangles
126 void
127 DrawRectangle (int left, int top, int right, int bottom, int side, int style)
128 {
129     XFillRectangle(xDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top);
130     if(style != FILLED)
131       XDrawRectangle(xDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
132 }
133
134 // front-end wrapper for putting text in graph
135 void
136 DrawEvalText (char *buf, int cbBuf, int y)
137 {
138     // the magic constants 7 and 5 should really be derived from the font size somehow
139     XDrawString(xDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
140 }
141
142 // front-end
143 static Pixel
144 MakeColor (char *color)
145 {
146     XrmValue vFrom, vTo;
147
148     vFrom.addr = (caddr_t) color;
149     vFrom.size = strlen(color);
150     XtConvert(shells[EvalGraphDlg], XtRString, &vFrom, XtRPixel, &vTo);
151     // test for NULL?
152
153     return *(Pixel *) vTo.addr;
154 }
155
156 static GC
157 CreateGC (int width, char *fg, char *bg, int style)
158 {
159     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
160       | GCBackground | GCFunction | GCPlaneMask;
161     XGCValues gc_values;
162
163     gc_values.plane_mask = AllPlanes;
164     gc_values.line_width = width;
165     gc_values.line_style = style;
166     gc_values.function = GXcopy;
167
168     gc_values.foreground = MakeColor(fg);
169     gc_values.background = MakeColor(bg);
170
171     return XtGetGC(shells[EvalGraphDlg], value_mask, &gc_values);
172 }
173
174 static int initDone = FALSE;
175
176 static void
177 InitializeEvalGraph (Option *opt)
178 {
179   eGraphWindow = XtWindow(opt->handle);
180
181   pens[PEN_BLACK]      = CreateGC(1, "black", "black", LineSolid);
182   pens[PEN_DOTTED]     = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
183   pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
184   pens[PEN_BOLD]       = CreateGC(3, crWhite, crWhite, LineSolid);
185   pens[PEN_BOLD+1]     = CreateGC(3, crBlack, crBlack, LineSolid);
186   hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid);
187   hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid);
188   hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve)
189
190   initDone = TRUE;
191 }
192
193 // The following stuff is really back-end (but too little to bother with a separate file)
194
195 static void
196 DisplayEvalGraph ()
197 {   // back-end painting; calls back front-end primitives for lines, rectangles and text
198     char *t = MakeEvalTitle(_(title));
199     if(t != title && nWidthPB < 340) t = MakeEvalTitle(nWidthPB < 240 ? "" : _("Eval"));
200     PaintEvalGraph();
201     SetDialogTitle(EvalGraphDlg, t);
202 }
203
204 static void
205 EvalClick (int x, int y)
206 {
207     int index = GetMoveIndexFromPoint( x, y );
208
209     if( index >= 0 && index < currLast ) ToNrEvent( index + 1 );
210 }
211
212 static Option *
213 EvalCallback (int button, int x, int y)
214 {
215     if(!initDone) return NULL;
216
217     switch(button) {
218         case 10: // expose event
219             /* Create or recreate paint box if needed */
220             nWidthPB = x;
221             nHeightPB = y;
222             DisplayEvalGraph();
223             break;
224         case 1: EvalClick(x, y); // left button
225         default: break; // other buttons ignored
226     }
227     return NULL; // no context menu!
228 }
229
230 static Option graphOptions[] = {
231 { 150, 0x9C, 300, NULL, (void*) &EvalCallback, NULL, NULL, Graph , "" },
232 { 0, 2, 0, NULL, NULL, "", NULL, EndMark , "" }
233 };
234
235 void
236 EvalGraphPopUp ()
237 {
238     Arg args[16];
239     int j;
240
241     if (GenericPopUp(graphOptions, _(title), EvalGraphDlg, BoardWindow, NONMODAL, 1)) {
242         InitializeEvalGraph(&graphOptions[0]); // first time: add callbacks and initialize pens
243     } else {
244         SetDialogTitle(EvalGraphDlg, _(title));
245         SetIconName(EvalGraphDlg, _(title));
246     }
247
248     MarkMenu("View.EvaluationGraph", EvalGraphDlg);
249
250 //    ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
251 }
252
253 void
254 EvalGraphPopDown ()
255 {
256     PopDown(EvalGraphDlg);
257
258 //    ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
259 }
260
261 Boolean
262 EvalGraphIsUp ()
263 {
264     return shellUp[EvalGraphDlg];
265 }
266
267 int
268 EvalGraphDialogExists ()
269 {
270     return DialogExists(EvalGraphDlg);
271 }
272
273 void
274 EvalGraphProc ()
275 {
276   if (!PopDown(EvalGraphDlg)) EvalGraphPopUp();
277 }
278
279 // This function is the interface to the back-end.
280
281 void
282 EvalGraphSet (int first, int last, int current, ChessProgramStats_Move * pvInfo)
283 {
284     /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
285
286     currFirst = first;
287     currLast = last;
288     currCurrent = current;
289     currPvInfo = pvInfo;
290
291     if( DialogExists(EvalGraphDlg) ) {
292         DisplayEvalGraph();
293     }
294 }
295