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
96 //extern WindowPlacement wpEvalGraph;
98 Position evalGraphX = -1, evalGraphY = -1;
99 Dimension evalGraphW, evalGraphH;
100 Widget evalGraphShell;
101 static int evalGraphDialogUp;
103 /* Module variables */
105 char *crWhite = "#FFFFB0";
106 char *crBlack = "#AD5D3D";
107 static Display *yDisplay;
108 static Window eGraphWindow;
110 static GC pens[6]; // [HGM] put all pens in one array
111 static GC hbrHist[3];
114 static HDC hdcPB = NULL;
115 static HBITMAP hbmPB = NULL;
118 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end)
119 void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )
121 static int curX, curY;
123 if(penType != PEN_NONE)
124 XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
125 if(lastX != NULL) { *lastX = curX; *lastY = curY; }
129 // front-end wrapper for drawing functions to do rectangles
130 void DrawRectangle( int left, int top, int right, int bottom, int side, int style )
132 XFillRectangle(yDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top);
134 XDrawRectangle(yDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
137 // front-end wrapper for putting text in graph
138 void DrawEvalText(char *buf, int cbBuf, int y)
140 // the magic constants 7 and 5 should really be derived from the font size somehow
141 XDrawString(yDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
145 static Pixel MakeColor(char *color )
149 vFrom.addr = (caddr_t) color;
150 vFrom.size = strlen(color);
151 XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo);
154 return *(Pixel *) vTo.addr;
157 static GC CreateGC(int width, char *fg, char *bg, int style)
159 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
160 | GCBackground | GCFunction | GCPlaneMask;
163 gc_values.plane_mask = AllPlanes;
164 gc_values.line_width = width;
165 gc_values.line_style = style;
166 gc_values.function = GXcopy;
168 gc_values.foreground = MakeColor(fg);
169 gc_values.background = MakeColor(bg);
171 return XtGetGC(evalGraphShell, value_mask, &gc_values);
174 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display
175 // The back-end part n the middle has been taken out and moed to PainEvalGraph()
176 static void DisplayEvalGraph()
184 /* Get client area */
186 XtSetArg(args[j], XtNwidth, &w); j++;
187 XtSetArg(args[j], XtNheight, &h); j++;
188 XtGetValues(evalGraphShell, args, j);
192 /* Create or recreate paint box if needed */
193 if( width != nWidthPB || height != nHeightPB ) {
199 // back-end painting; calls back front-end primitives for lines, rectangles and text
202 XSync(yDisplay, False);
205 static void InitializeEvalGraph()
207 pens[PEN_BLACK] = CreateGC(1, "black", "black", LineSolid);
208 pens[PEN_DOTTED] = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
209 pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
210 pens[PEN_BOLD] = CreateGC(3, crWhite, crWhite, LineSolid);
211 pens[PEN_BOLD+1] = CreateGC(3, crBlack, crBlack, LineSolid);
212 hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid);
213 hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid);
214 hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve)
217 void EvalClick(widget, unused, event)
222 if( widget && event->type == ButtonPress ) {
223 int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y );
225 if( index >= 0 && index < currLast ) {
226 ToNrEvent( index + 1 );
231 // This (cloned from EventProc in xboard.c) is needed as event handler, to prevent
232 // the graph being wiped out after covering / uncovering by other windows.
233 void EvalEventProc(widget, unused, event)
238 if (!XtIsRealized(widget))
241 switch (event->type) {
243 if (event->xexpose.count > 0) return; /* no clipping is done */
250 // The following routines are mutated clones of the commentPopUp routines
252 Widget EvalGraphCreate(name)
256 Widget shell, layout, form;
257 Dimension bw_width, bw_height;
262 XtSetArg(args[j], XtNwidth, &bw_width); j++;
263 XtSetArg(args[j], XtNheight, &bw_height); j++;
264 XtGetValues(boardWidget, args, j);
266 // define form within layout within shell.
268 XtSetArg(args[j], XtNresizable, True); j++;
271 XtCreatePopupShell(name, topLevelShellWidgetClass,
273 XtCreatePopupShell(name, transientShellWidgetClass,
275 shellWidget, args, j);
277 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
278 layoutArgs, XtNumber(layoutArgs));
279 // divide window vertically into two equal parts, by creating two forms
281 XtCreateManagedWidget("form", formWidgetClass, layout,
282 formArgs, XtNumber(formArgs));
283 // make sure width is known in advance, for better placement of child widgets
285 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
286 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/4); j++;
287 XtSetValues(shell, args, j);
289 XtRealizeWidget(shell);
291 if(wpEvalGraph.width > 0) {
292 evalGraphW = wpEvalGraph.width;
293 evalGraphH = wpEvalGraph.height;
294 evalGraphX = wpEvalGraph.x;
295 evalGraphY = wpEvalGraph.y;
298 if (evalGraphX == -1) {
301 evalGraphH = bw_height/4;
302 evalGraphW = bw_width-16;
304 XSync(xDisplay, False);
306 /* This code seems to tickle an X bug if it is executed too soon
307 after xboard starts up. The coordinates get transformed as if
308 the main window was positioned at (0, 0).
310 XtTranslateCoords(shellWidget,
311 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
312 &evalGraphX, &evalGraphY);
314 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
315 RootWindowOfScreen(XtScreen(shellWidget)),
316 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
321 if (evalGraphY < 0) evalGraphY = 0; /*avoid positioning top offscreen*/
324 XtSetArg(args[j], XtNheight, evalGraphH); j++;
325 XtSetArg(args[j], XtNwidth, evalGraphW); j++;
326 XtSetArg(args[j], XtNx, evalGraphX); j++;
327 XtSetArg(args[j], XtNy, evalGraphY); j++;
328 XtSetValues(shell, args, j);
330 yDisplay = XtDisplay(shell);
331 eGraphWindow = XtWindow(form);
332 XtAddEventHandler(form, ExposureMask, False,
333 (XtEventHandler) EvalEventProc, NULL);
334 XtAddEventHandler(form, ButtonPressMask, False,
335 (XtEventHandler) EvalClick, NULL);
345 static int needInit = TRUE;
346 static char *title = N_("Evaluation graph");
348 if (evalGraphShell == NULL) {
351 EvalGraphCreate(_(title));
352 XtRealizeWidget(evalGraphShell);
353 CatchDeleteWindow(evalGraphShell, "EvalGraphPopDown");
355 InitializeEvalGraph();
360 XtSetArg(args[j], XtNiconName, (XtArgVal) _(title)); j++;
361 XtSetArg(args[j], XtNtitle, (XtArgVal) _(title)); j++;
362 XtSetValues(evalGraphShell, args, j);
365 XtPopup(evalGraphShell, XtGrabNone);
366 XSync(yDisplay, False);
369 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
370 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"),
373 evalGraphDialogUp = True;
374 // ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
377 void EvalGraphPopDown()
382 if (!evalGraphDialogUp) return;
384 XtSetArg(args[j], XtNx, &evalGraphX); j++;
385 XtSetArg(args[j], XtNy, &evalGraphY); j++;
386 XtSetArg(args[j], XtNwidth, &evalGraphW); j++;
387 XtSetArg(args[j], XtNheight, &evalGraphH); j++;
388 XtGetValues(evalGraphShell, args, j);
389 wpEvalGraph.x = evalGraphX - 4;
390 wpEvalGraph.y = evalGraphY - 23;
391 wpEvalGraph.width = evalGraphW;
392 wpEvalGraph.height = evalGraphH;
393 XtPopdown(evalGraphShell);
394 XSync(xDisplay, False);
396 XtSetArg(args[j], XtNleftBitmap, None); j++;
397 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"),
400 evalGraphDialogUp = False;
401 // ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
404 Boolean EvalGraphIsUp()
406 return evalGraphDialogUp;
409 int EvalGraphDialogExists()
411 return evalGraphShell != NULL;
415 EvalGraphProc(w, event, prms, nprms)
421 if (evalGraphDialogUp) {
427 // This function is the interface to the back-end. It is currently called through the front-end,
428 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends
429 // support the eval graph, it would be more logical to call it directly from the back-end.
430 void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )
432 /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
436 currCurrent = current;
439 if( evalGraphShell ) {