4 * Author: Alessandro Scotti (Dec 2005)
5 * Translated to X by H.G.Muller (Nov 2009)
7 * Copyright 2005 Alessandro Scotti
9 * Enhancements Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
11 * ------------------------------------------------------------------------
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.
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.
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/.
26 * ------------------------------------------------------------------------
27 ** See the file ChangeLog for a revision history. */
34 #include <sys/types.h>
39 #else /* not STDC_HEADERS */
40 extern char *getenv();
43 # else /* not HAVE_STRING_H */
45 # endif /* not HAVE_STRING_H */
46 #endif /* not STDC_HEADERS */
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>
74 #include "evalgraph.h"
78 # define _(s) gettext (s)
79 # define N_(s) gettext_noop (s)
93 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
94 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
95 static char *title = N_("Evaluation graph");
97 //extern WindowPlacement wpEvalGraph;
99 Position evalGraphX = -1, evalGraphY = -1;
100 Dimension evalGraphW, evalGraphH;
101 Widget evalGraphShell;
102 static int evalGraphDialogUp;
104 /* Module variables */
106 char *crWhite = "#FFFFB0";
107 char *crBlack = "#AD5D3D";
108 static Display *yDisplay;
109 static Window eGraphWindow;
111 static GC pens[6]; // [HGM] put all pens in one array
112 static GC hbrHist[3];
115 static HDC hdcPB = NULL;
116 static HBITMAP hbmPB = NULL;
119 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end)
120 void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )
122 static int curX, curY;
124 if(penType != PEN_NONE)
125 XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
126 if(lastX != NULL) { *lastX = curX; *lastY = curY; }
130 // front-end wrapper for drawing functions to do rectangles
131 void DrawRectangle( int left, int top, int right, int bottom, int side, int style )
133 XFillRectangle(yDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top);
135 XDrawRectangle(yDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
138 // front-end wrapper for putting text in graph
139 void DrawEvalText(char *buf, int cbBuf, int y)
141 // the magic constants 7 and 5 should really be derived from the font size somehow
142 XDrawString(yDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
146 static Pixel MakeColor(char *color )
150 vFrom.addr = (caddr_t) color;
151 vFrom.size = strlen(color);
152 XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo);
155 return *(Pixel *) vTo.addr;
158 static GC CreateGC(int width, char *fg, char *bg, int style)
160 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
161 | GCBackground | GCFunction | GCPlaneMask;
164 gc_values.plane_mask = AllPlanes;
165 gc_values.line_width = width;
166 gc_values.line_style = style;
167 gc_values.function = GXcopy;
169 gc_values.foreground = MakeColor(fg);
170 gc_values.background = MakeColor(bg);
172 return XtGetGC(evalGraphShell, value_mask, &gc_values);
175 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display
176 // The back-end part n the middle has been taken out and moed to PainEvalGraph()
177 static void DisplayEvalGraph()
185 /* Get client area */
187 XtSetArg(args[j], XtNwidth, &w); j++;
188 XtSetArg(args[j], XtNheight, &h); j++;
189 XtGetValues(evalGraphShell, args, j);
193 /* Create or recreate paint box if needed */
194 if( width != nWidthPB || height != nHeightPB ) {
200 // back-end painting; calls back front-end primitives for lines, rectangles and text
202 XtSetArg(args[0], XtNtitle, MakeEvalTitle(_(title))); j++;
203 XtSetValues(evalGraphShell, args, 1);
205 XSync(yDisplay, False);
208 static void InitializeEvalGraph()
210 pens[PEN_BLACK] = CreateGC(1, "black", "black", LineSolid);
211 pens[PEN_DOTTED] = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
212 pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
213 pens[PEN_BOLD] = CreateGC(3, crWhite, crWhite, LineSolid);
214 pens[PEN_BOLD+1] = CreateGC(3, crBlack, crBlack, LineSolid);
215 hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid);
216 hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid);
217 hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve)
220 void EvalClick(widget, unused, event)
225 if( widget && event->type == ButtonPress ) {
226 int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y );
228 if( index >= 0 && index < currLast ) {
229 ToNrEvent( index + 1 );
234 // This (cloned from EventProc in xboard.c) is needed as event handler, to prevent
235 // the graph being wiped out after covering / uncovering by other windows.
236 void EvalEventProc(widget, unused, event)
241 if (!XtIsRealized(widget))
244 switch (event->type) {
246 if (event->xexpose.count > 0) return; /* no clipping is done */
253 // The following routines are mutated clones of the commentPopUp routines
255 Widget EvalGraphCreate(name)
259 Widget shell, layout, form;
260 Dimension bw_width, bw_height;
265 XtSetArg(args[j], XtNwidth, &bw_width); j++;
266 XtSetArg(args[j], XtNheight, &bw_height); j++;
267 XtGetValues(boardWidget, args, j);
269 // define form within layout within shell.
271 XtSetArg(args[j], XtNresizable, True); j++;
274 XtCreatePopupShell(name, topLevelShellWidgetClass,
276 XtCreatePopupShell(name, transientShellWidgetClass,
278 shellWidget, args, j);
280 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
281 layoutArgs, XtNumber(layoutArgs));
282 // divide window vertically into two equal parts, by creating two forms
284 XtCreateManagedWidget("form", formWidgetClass, layout,
285 formArgs, XtNumber(formArgs));
286 // make sure width is known in advance, for better placement of child widgets
288 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
289 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/4); j++;
290 XtSetValues(shell, args, j);
292 XtRealizeWidget(shell);
294 if(wpEvalGraph.width > 0) {
295 evalGraphW = wpEvalGraph.width;
296 evalGraphH = wpEvalGraph.height;
297 evalGraphX = wpEvalGraph.x;
298 evalGraphY = wpEvalGraph.y;
301 if (evalGraphX == -1) {
304 evalGraphH = bw_height/4;
305 evalGraphW = bw_width-16;
307 XSync(xDisplay, False);
309 /* This code seems to tickle an X bug if it is executed too soon
310 after xboard starts up. The coordinates get transformed as if
311 the main window was positioned at (0, 0).
313 XtTranslateCoords(shellWidget,
314 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
315 &evalGraphX, &evalGraphY);
317 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
318 RootWindowOfScreen(XtScreen(shellWidget)),
319 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
324 if (evalGraphY < 0) evalGraphY = 0; /*avoid positioning top offscreen*/
327 XtSetArg(args[j], XtNheight, evalGraphH); j++;
328 XtSetArg(args[j], XtNwidth, evalGraphW); j++;
329 XtSetArg(args[j], XtNx, evalGraphX); j++;
330 XtSetArg(args[j], XtNy, evalGraphY); j++;
331 XtSetValues(shell, args, j);
333 yDisplay = XtDisplay(shell);
334 eGraphWindow = XtWindow(form);
335 XtAddEventHandler(form, ExposureMask, False,
336 (XtEventHandler) EvalEventProc, NULL);
337 XtAddEventHandler(form, ButtonPressMask, False,
338 (XtEventHandler) EvalClick, NULL);
348 static int needInit = TRUE;
350 if (evalGraphShell == NULL) {
353 EvalGraphCreate(_(title));
354 XtRealizeWidget(evalGraphShell);
355 CatchDeleteWindow(evalGraphShell, "EvalGraphPopDown");
357 InitializeEvalGraph();
362 XtSetArg(args[j], XtNiconName, (XtArgVal) _(title)); j++;
363 XtSetArg(args[j], XtNtitle, (XtArgVal) _(title)); j++;
364 XtSetValues(evalGraphShell, args, j);
367 XtPopup(evalGraphShell, XtGrabNone);
368 XSync(yDisplay, False);
371 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
372 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"),
375 evalGraphDialogUp = True;
376 // ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
379 void EvalGraphPopDown()
384 if (!evalGraphDialogUp) return;
386 XtSetArg(args[j], XtNx, &evalGraphX); j++;
387 XtSetArg(args[j], XtNy, &evalGraphY); j++;
388 XtSetArg(args[j], XtNwidth, &evalGraphW); j++;
389 XtSetArg(args[j], XtNheight, &evalGraphH); j++;
390 XtGetValues(evalGraphShell, args, j);
391 wpEvalGraph.x = evalGraphX - 4;
392 wpEvalGraph.y = evalGraphY - 23;
393 wpEvalGraph.width = evalGraphW;
394 wpEvalGraph.height = evalGraphH;
395 XtPopdown(evalGraphShell);
396 XSync(xDisplay, False);
398 XtSetArg(args[j], XtNleftBitmap, None); j++;
399 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"),
402 evalGraphDialogUp = False;
403 // ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
406 Boolean EvalGraphIsUp()
408 return evalGraphDialogUp;
411 int EvalGraphDialogExists()
413 return evalGraphShell != NULL;
417 EvalGraphProc(w, event, prms, nprms)
423 if (evalGraphDialogUp) {
429 // This function is the interface to the back-end. It is currently called through the front-end,
430 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends
431 // support the eval graph, it would be more logical to call it directly from the back-end.
432 void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )
434 /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
438 currCurrent = current;
441 if( evalGraphShell ) {