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 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 // imports from xboard.c
94 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
95 extern Display *xDisplay;
96 extern Window xBoardWindow;
97 extern int squareSize;
98 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
99 extern char *layoutName;
101 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
102 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
104 /* Imports from backend.c */
106 /* Imports from xboard.c */
107 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
110 //extern WindowPlacement wpEvalGraph;
112 Position evalGraphX = -1, evalGraphY = -1;
113 Dimension evalGraphW, evalGraphH;
114 Widget evalGraphShell;
115 static int evalGraphDialogUp;
117 /* Module variables */
119 char *crWhite = "#FFFFB0";
120 char *crBlack = "#AD5D3D";
121 static Display *yDisplay;
122 static Window eGraphWindow;
124 static GC pens[6]; // [HGM] put all pens in one array
125 static GC hbrHist[3];
128 static HDC hdcPB = NULL;
129 static HBITMAP hbmPB = NULL;
132 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end)
133 void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )
135 static int curX, curY;
137 if(penType != PEN_NONE)
138 XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
139 if(lastX != NULL) { *lastX = curX; *lastY = curY; }
143 // front-end wrapper for drawing functions to do rectangles
144 void DrawRectangle( int left, int top, int right, int bottom, int side, int style )
146 XFillRectangle(yDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top);
148 XDrawRectangle(yDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
151 // front-end wrapper for putting text in graph
152 void DrawEvalText(char *buf, int cbBuf, int y)
154 // the magic constants 7 and 5 should really be derived from the font size somehow
155 XDrawString(yDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
159 static Pixel MakeColor(char *color )
163 vFrom.addr = (caddr_t) color;
164 vFrom.size = strlen(color);
165 XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo);
168 return *(Pixel *) vTo.addr;
171 static GC CreateGC(int width, char *fg, char *bg, int style)
173 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
174 | GCBackground | GCFunction | GCPlaneMask;
177 gc_values.plane_mask = AllPlanes;
178 gc_values.line_width = width;
179 gc_values.line_style = style;
180 gc_values.function = GXcopy;
182 gc_values.foreground = MakeColor(fg);
183 gc_values.background = MakeColor(bg);
185 return XtGetGC(evalGraphShell, value_mask, &gc_values);
188 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display
189 // The back-end part n the middle has been taken out and moed to PainEvalGraph()
190 static void DisplayEvalGraph()
198 /* Get client area */
200 XtSetArg(args[j], XtNwidth, &w); j++;
201 XtSetArg(args[j], XtNheight, &h); j++;
202 XtGetValues(evalGraphShell, args, j);
206 /* Create or recreate paint box if needed */
207 if( width != nWidthPB || height != nHeightPB ) {
213 // back-end painting; calls back front-end primitives for lines, rectangles and text
216 XSync(yDisplay, False);
219 static void InitializeEvalGraph()
221 pens[PEN_BLACK] = CreateGC(1, "black", "black", LineSolid);
222 pens[PEN_DOTTED] = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
223 pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
224 pens[PEN_BOLD] = CreateGC(3, crWhite, crWhite, LineSolid);
225 pens[PEN_BOLD+1] = CreateGC(3, crBlack, crBlack, LineSolid);
226 hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid);
227 hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid);
228 hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve)
231 void EvalClick(widget, unused, event)
236 if( widget && event->type == ButtonPress ) {
237 int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y );
239 if( index >= 0 && index < currLast ) {
240 ToNrEvent( index + 1 );
245 // This (cloned from EventProc in xboard.c) is needed as event handler, to prevent
246 // the graph being wiped out after covering / uncovering by other windows.
247 void EvalEventProc(widget, unused, event)
252 if (!XtIsRealized(widget))
255 switch (event->type) {
257 if (event->xexpose.count > 0) return; /* no clipping is done */
264 // The following routines are mutated clones of the commentPopUp routines
266 Widget EvalGraphCreate(name)
270 Widget shell, layout, form;
271 Dimension bw_width, bw_height;
276 XtSetArg(args[j], XtNwidth, &bw_width); j++;
277 XtSetArg(args[j], XtNheight, &bw_height); j++;
278 XtGetValues(boardWidget, args, j);
280 // define form within layout within shell.
282 XtSetArg(args[j], XtNresizable, True); j++;
285 XtCreatePopupShell(name, topLevelShellWidgetClass,
287 XtCreatePopupShell(name, transientShellWidgetClass,
289 shellWidget, args, j);
291 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
292 layoutArgs, XtNumber(layoutArgs));
293 // divide window vertically into two equal parts, by creating two forms
295 XtCreateManagedWidget("form", formWidgetClass, layout,
296 formArgs, XtNumber(formArgs));
297 // make sure width is known in advance, for better placement of child widgets
299 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
300 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/4); j++;
301 XtSetValues(shell, args, j);
303 XtRealizeWidget(shell);
305 if(wpEvalGraph.width > 0) {
306 evalGraphW = wpEvalGraph.width;
307 evalGraphH = wpEvalGraph.height;
308 evalGraphX = wpEvalGraph.x;
309 evalGraphY = wpEvalGraph.y;
312 if (evalGraphX == -1) {
315 evalGraphH = bw_height/4;
316 evalGraphW = bw_width-16;
318 XSync(xDisplay, False);
320 /* This code seems to tickle an X bug if it is executed too soon
321 after xboard starts up. The coordinates get transformed as if
322 the main window was positioned at (0, 0).
324 XtTranslateCoords(shellWidget,
325 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
326 &evalGraphX, &evalGraphY);
328 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
329 RootWindowOfScreen(XtScreen(shellWidget)),
330 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
335 if (evalGraphY < 0) evalGraphY = 0; /*avoid positioning top offscreen*/
338 XtSetArg(args[j], XtNheight, evalGraphH); j++;
339 XtSetArg(args[j], XtNwidth, evalGraphW); j++;
340 XtSetArg(args[j], XtNx, evalGraphX); j++;
341 XtSetArg(args[j], XtNy, evalGraphY); j++;
342 XtSetValues(shell, args, j);
344 yDisplay = XtDisplay(shell);
345 eGraphWindow = XtWindow(form);
346 XtAddEventHandler(form, ExposureMask, False,
347 (XtEventHandler) EvalEventProc, NULL);
348 XtAddEventHandler(form, ButtonPressMask, False,
349 (XtEventHandler) EvalClick, NULL);
359 static int needInit = TRUE;
360 static char *title = _("Evaluation graph");
362 if (evalGraphShell == NULL) {
365 EvalGraphCreate(title);
366 XtRealizeWidget(evalGraphShell);
367 CatchDeleteWindow(evalGraphShell, "EvalGraphPopDown");
369 InitializeEvalGraph();
374 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
375 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
376 XtSetValues(evalGraphShell, args, j);
379 XtPopup(evalGraphShell, XtGrabNone);
380 XSync(yDisplay, False);
383 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
384 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Evaluation Graph"),
387 evalGraphDialogUp = True;
388 // ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
391 void EvalGraphPopDown()
396 if (!evalGraphDialogUp) return;
398 XtSetArg(args[j], XtNx, &evalGraphX); j++;
399 XtSetArg(args[j], XtNy, &evalGraphY); j++;
400 XtSetArg(args[j], XtNwidth, &evalGraphW); j++;
401 XtSetArg(args[j], XtNheight, &evalGraphH); j++;
402 XtGetValues(evalGraphShell, args, j);
403 wpEvalGraph.x = evalGraphX - 4;
404 wpEvalGraph.y = evalGraphY - 23;
405 wpEvalGraph.width = evalGraphW;
406 wpEvalGraph.height = evalGraphH;
407 XtPopdown(evalGraphShell);
408 XSync(xDisplay, False);
410 XtSetArg(args[j], XtNleftBitmap, None); j++;
411 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Evaluation Graph"),
414 evalGraphDialogUp = False;
415 // ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
418 Boolean EvalGraphIsUp()
420 return evalGraphDialogUp;
423 int EvalGraphDialogExists()
425 return evalGraphShell != NULL;
429 EvalGraphProc(w, event, prms, nprms)
435 if (evalGraphDialogUp) {
441 // This function is the interface to the back-end. It is currently called through the front-end,
442 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends
443 // support the eval graph, it would be more logical to call it directly from the back-end.
444 void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )
446 /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
450 currCurrent = current;
453 if( evalGraphShell ) {