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, 2012 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)
121 DrawSegment (int x, int y, int *lastX, int *lastY, int penType)
123 static int curX, curY;
125 if(penType != PEN_NONE)
126 XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
127 if(lastX != NULL) { *lastX = curX; *lastY = curY; }
131 // front-end wrapper for drawing functions to do rectangles
133 DrawRectangle (int left, int top, int right, int bottom, int side, int style)
135 XFillRectangle(yDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top);
137 XDrawRectangle(yDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
140 // front-end wrapper for putting text in graph
142 DrawEvalText (char *buf, int cbBuf, int y)
144 // the magic constants 7 and 5 should really be derived from the font size somehow
145 XDrawString(yDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
150 MakeColor (char *color)
154 vFrom.addr = (caddr_t) color;
155 vFrom.size = strlen(color);
156 XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo);
159 return *(Pixel *) vTo.addr;
163 CreateGC (int width, char *fg, char *bg, int style)
165 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
166 | GCBackground | GCFunction | GCPlaneMask;
169 gc_values.plane_mask = AllPlanes;
170 gc_values.line_width = width;
171 gc_values.line_style = style;
172 gc_values.function = GXcopy;
174 gc_values.foreground = MakeColor(fg);
175 gc_values.background = MakeColor(bg);
177 return XtGetGC(evalGraphShell, value_mask, &gc_values);
180 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display
181 // The back-end part n the middle has been taken out and moed to PainEvalGraph()
191 /* Get client area */
193 XtSetArg(args[j], XtNwidth, &w); j++;
194 XtSetArg(args[j], XtNheight, &h); j++;
195 XtGetValues(evalGraphShell, args, j);
199 /* Create or recreate paint box if needed */
200 if( width != nWidthPB || height != nHeightPB ) {
206 // back-end painting; calls back front-end primitives for lines, rectangles and text
208 XtSetArg(args[0], XtNtitle, MakeEvalTitle(_(title))); j++;
209 XtSetValues(evalGraphShell, args, 1);
211 XSync(yDisplay, False);
215 InitializeEvalGraph ()
217 pens[PEN_BLACK] = CreateGC(1, "black", "black", LineSolid);
218 pens[PEN_DOTTED] = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
219 pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
220 pens[PEN_BOLD] = CreateGC(3, crWhite, crWhite, LineSolid);
221 pens[PEN_BOLD+1] = CreateGC(3, crBlack, crBlack, LineSolid);
222 hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid);
223 hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid);
224 hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve)
228 EvalClick (Widget widget, caddr_t unused, XEvent *event)
230 if( widget && event->type == ButtonPress ) {
231 int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y );
233 if( index >= 0 && index < currLast ) {
234 ToNrEvent( index + 1 );
239 // This (cloned from EventProc in xboard.c) is needed as event handler, to prevent
240 // the graph being wiped out after covering / uncovering by other windows.
242 EvalEventProc (Widget widget, caddr_t unused, XEvent *event)
244 if (!XtIsRealized(widget))
247 switch (event->type) {
249 if (event->xexpose.count > 0) return; /* no clipping is done */
256 // The following routines are mutated clones of the commentPopUp routines
259 EvalGraphCreate (char *name)
262 Widget shell, layout, form;
263 Dimension bw_width, bw_height;
268 XtSetArg(args[j], XtNwidth, &bw_width); j++;
269 XtSetArg(args[j], XtNheight, &bw_height); j++;
270 XtGetValues(boardWidget, args, j);
272 // define form within layout within shell.
274 XtSetArg(args[j], XtNresizable, True); j++;
277 XtCreatePopupShell(name, topLevelShellWidgetClass,
279 XtCreatePopupShell(name, transientShellWidgetClass,
281 shellWidget, args, j);
283 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
284 layoutArgs, XtNumber(layoutArgs));
285 // divide window vertically into two equal parts, by creating two forms
287 XtCreateManagedWidget("form", formWidgetClass, layout,
288 formArgs, XtNumber(formArgs));
289 // make sure width is known in advance, for better placement of child widgets
291 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
292 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/4); j++;
293 XtSetValues(shell, args, j);
295 XtRealizeWidget(shell);
297 if(wpEvalGraph.width > 0) {
298 evalGraphW = wpEvalGraph.width;
299 evalGraphH = wpEvalGraph.height;
300 evalGraphX = wpEvalGraph.x;
301 evalGraphY = wpEvalGraph.y;
304 if (evalGraphX == -1) {
307 evalGraphH = bw_height/4;
308 evalGraphW = bw_width-16;
310 XSync(xDisplay, False);
312 /* This code seems to tickle an X bug if it is executed too soon
313 after xboard starts up. The coordinates get transformed as if
314 the main window was positioned at (0, 0).
316 XtTranslateCoords(shellWidget,
317 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
318 &evalGraphX, &evalGraphY);
320 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
321 RootWindowOfScreen(XtScreen(shellWidget)),
322 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
327 if (evalGraphY < 0) evalGraphY = 0; /*avoid positioning top offscreen*/
330 XtSetArg(args[j], XtNheight, evalGraphH); j++;
331 XtSetArg(args[j], XtNwidth, evalGraphW); j++;
332 XtSetArg(args[j], XtNx, evalGraphX); j++;
333 XtSetArg(args[j], XtNy, evalGraphY); j++;
334 XtSetValues(shell, args, j);
336 yDisplay = XtDisplay(shell);
337 eGraphWindow = XtWindow(form);
338 XtAddEventHandler(form, ExposureMask, False,
339 (XtEventHandler) EvalEventProc, NULL);
340 XtAddEventHandler(form, ButtonPressMask, False,
341 (XtEventHandler) EvalClick, NULL);
351 static int needInit = TRUE;
353 if (evalGraphShell == NULL) {
356 EvalGraphCreate(_(title));
357 XtRealizeWidget(evalGraphShell);
358 CatchDeleteWindow(evalGraphShell, "EvalGraphPopDown");
360 InitializeEvalGraph();
365 XtSetArg(args[j], XtNiconName, (XtArgVal) _(title)); j++;
366 XtSetArg(args[j], XtNtitle, (XtArgVal) _(title)); j++;
367 XtSetValues(evalGraphShell, args, j);
370 XtPopup(evalGraphShell, XtGrabNone);
371 XSync(yDisplay, False);
374 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
375 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"),
378 evalGraphDialogUp = True;
379 // ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
388 if (!evalGraphDialogUp) return;
390 XtSetArg(args[j], XtNx, &evalGraphX); j++;
391 XtSetArg(args[j], XtNy, &evalGraphY); j++;
392 XtSetArg(args[j], XtNwidth, &evalGraphW); j++;
393 XtSetArg(args[j], XtNheight, &evalGraphH); j++;
394 XtGetValues(evalGraphShell, args, j);
395 wpEvalGraph.x = evalGraphX - 4;
396 wpEvalGraph.y = evalGraphY - 23;
397 wpEvalGraph.width = evalGraphW;
398 wpEvalGraph.height = evalGraphH;
399 XtPopdown(evalGraphShell);
400 XSync(xDisplay, False);
402 XtSetArg(args[j], XtNleftBitmap, None); j++;
403 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"),
406 evalGraphDialogUp = False;
407 // ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
413 return evalGraphDialogUp;
417 EvalGraphDialogExists ()
419 return evalGraphShell != NULL;
423 EvalGraphProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
425 if (evalGraphDialogUp) {
431 // This function is the interface to the back-end. It is currently called through the front-end,
432 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends
433 // support the eval graph, it would be more logical to call it directly from the back-end.
435 EvalGraphSet (int first, int last, int current, ChessProgramStats_Move * pvInfo)
437 /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
441 currCurrent = current;
444 if( evalGraphShell ) {