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 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)
87 // [HGM] pixmaps of some ICONS used in the engine-outut window
88 #include "pixmaps/WHITE_14.xpm"
89 #include "pixmaps/BLACK_14.xpm"
90 #include "pixmaps/CLEAR_14.xpm"
91 #include "pixmaps/UNKNOWN_14.xpm"
92 #include "pixmaps/THINKING_14.xpm"
93 #include "pixmaps/PONDER_14.xpm"
94 #include "pixmaps/ANALYZING_14.xpm"
102 // imports from xboard.c
103 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
104 extern Display *xDisplay;
105 extern Window xBoardWindow;
106 extern int squareSize;
107 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
108 extern char *layoutName;
110 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
111 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
113 /* Imports from backend.c */
115 /* Imports from xboard.c */
116 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
119 //extern WindowPlacement wpEvalGraph;
121 Position evalGraphX = -1, evalGraphY = -1;
122 Dimension evalGraphW, evalGraphH;
123 Widget evalGraphShell;
124 static int evalGraphDialogUp;
126 /* Module variables */
128 char *crWhite = "#FFFFB0";
129 char *crBlack = "#AD5D3D";
130 static Display *yDisplay;
131 static Window eGraphWindow;
133 static GC pens[6]; // [HGM] put all pens in one array
134 static GC hbrHist[3];
137 static HDC hdcPB = NULL;
138 static HBITMAP hbmPB = NULL;
141 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end)
142 void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )
145 if(penType != PEN_NONE)
146 XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
147 if(lastX != NULL) { *lastX = curX; *lastY = curY; }
151 // front-end wrapper for drawing functions to do rectangles
152 void DrawRectangle( int left, int top, int right, int bottom, int side, int style )
154 XFillRectangle(yDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top);
156 XDrawRectangle(yDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
159 // front-end wrapper for putting text in graph
160 void DrawEvalText(char *buf, int cbBuf, int y)
162 // the magic constants 7 and 5 should really be derived from the font size somehow
163 XDrawString(yDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
167 static Pixel MakeColor(char *color )
171 vFrom.addr = (caddr_t) color;
172 vFrom.size = strlen(color);
173 XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo);
176 return *(Pixel *) vTo.addr;
179 static GC CreateGC(int width, char *fg, char *bg, int style)
181 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
182 | GCBackground | GCFunction | GCPlaneMask;
185 gc_values.plane_mask = AllPlanes;
186 gc_values.line_width = width;
187 gc_values.line_style = style;
188 gc_values.function = GXcopy;
190 gc_values.foreground = MakeColor(fg);
191 gc_values.background = MakeColor(bg);
193 return XtGetGC(evalGraphShell, value_mask, &gc_values);
196 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display
197 // The back-end part n the middle has been taken out and moed to PainEvalGraph()
198 static void DisplayEvalGraph()
206 /* Get client area */
208 XtSetArg(args[j], XtNwidth, &w); j++;
209 XtSetArg(args[j], XtNheight, &h); j++;
210 XtGetValues(evalGraphShell, args, j);
214 /* Create or recreate paint box if needed */
215 if( width != nWidthPB || height != nHeightPB ) {
221 // back-end painting; calls back front-end primitives for lines, rectangles and text
224 XSync(yDisplay, False);
227 static void InitializeEvalGraph()
228 { int i; XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
229 | GCBackground | GCFunction | GCPlaneMask;
231 // GC copyInvertedGC;
233 pens[PEN_BLACK] = CreateGC(1, "black", "black", LineSolid);
234 pens[PEN_DOTTED] = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
235 pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
236 pens[PEN_BOLD] = CreateGC(3, crWhite, crWhite, LineSolid);
237 pens[PEN_BOLD+1] = CreateGC(3, crBlack, crBlack, LineSolid);
238 hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid);
239 hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid);
240 hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve)
243 void EvalClick(widget, unused, event)
248 if( widget && event->type == ButtonPress ) {
249 int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y );
251 if( index >= 0 && index < currLast ) {
252 ToNrEvent( index + 1 );
257 // This (cloned from EventProc in xboard.c) is needed as event handler, to prevent
258 // the graph being wiped out after covering / uncovering by other windows.
259 void EvalEventProc(widget, unused, event)
264 if (!XtIsRealized(widget))
267 switch (event->type) {
269 if (event->xexpose.count > 0) return; /* no clipping is done */
276 // The following routines are mutated clones of the commentPopUp routines
278 Widget EvalGraphCreate(name)
282 Widget shell, layout, form, form2, edit;
283 Dimension bw_width, bw_height;
288 XtSetArg(args[j], XtNwidth, &bw_width); j++;
289 XtSetArg(args[j], XtNheight, &bw_height); j++;
290 XtGetValues(boardWidget, args, j);
292 // define form within layout within shell.
294 XtSetArg(args[j], XtNresizable, True); j++;
297 XtCreatePopupShell(name, topLevelShellWidgetClass,
299 XtCreatePopupShell(name, transientShellWidgetClass,
301 shellWidget, args, j);
303 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
304 layoutArgs, XtNumber(layoutArgs));
305 // divide window vertically into two equal parts, by creating two forms
307 XtCreateManagedWidget("form", formWidgetClass, layout,
308 formArgs, XtNumber(formArgs));
309 // make sure width is known in advance, for better placement of child widgets
311 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
312 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/4); j++;
313 XtSetValues(shell, args, j);
315 XtRealizeWidget(shell);
317 if(wpEvalGraph.width > 0) {
318 evalGraphW = wpEvalGraph.width;
319 evalGraphH = wpEvalGraph.height;
320 evalGraphX = wpEvalGraph.x;
321 evalGraphY = wpEvalGraph.y;
324 if (evalGraphX == -1) {
329 evalGraphH = bw_height/4;
330 evalGraphW = bw_width-16;
332 XSync(xDisplay, False);
334 /* This code seems to tickle an X bug if it is executed too soon
335 after xboard starts up. The coordinates get transformed as if
336 the main window was positioned at (0, 0).
338 XtTranslateCoords(shellWidget,
339 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
340 &evalGraphX, &evalGraphY);
342 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
343 RootWindowOfScreen(XtScreen(shellWidget)),
344 (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
349 if (evalGraphY < 0) evalGraphY = 0; /*avoid positioning top offscreen*/
352 XtSetArg(args[j], XtNheight, evalGraphH); j++;
353 XtSetArg(args[j], XtNwidth, evalGraphW); j++;
354 XtSetArg(args[j], XtNx, evalGraphX); j++;
355 XtSetArg(args[j], XtNy, evalGraphY); j++;
356 XtSetValues(shell, args, j);
357 // XtSetKeyboardFocus(shell, edit);
359 yDisplay = XtDisplay(shell);
360 eGraphWindow = XtWindow(form);
361 XtAddEventHandler(form, ExposureMask, False,
362 (XtEventHandler) EvalEventProc, NULL);
363 XtAddEventHandler(form, ButtonPressMask, False,
364 (XtEventHandler) EvalClick, NULL);
375 static int needInit = TRUE;
376 static char *title = _("Evaluation graph");
378 if (evalGraphShell == NULL) {
381 EvalGraphCreate(title);
382 XtRealizeWidget(evalGraphShell);
383 CatchDeleteWindow(evalGraphShell, "EvalGraphPopDown");
385 InitializeEvalGraph();
390 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
391 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
392 XtSetValues(evalGraphShell, args, j);
395 XtPopup(evalGraphShell, XtGrabNone);
396 XSync(yDisplay, False);
399 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
400 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Evaluation Graph"),
403 evalGraphDialogUp = True;
404 // ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
407 void EvalGraphPopDown()
412 if (!evalGraphDialogUp) return;
414 XtSetArg(args[j], XtNx, &evalGraphX); j++;
415 XtSetArg(args[j], XtNy, &evalGraphY); j++;
416 XtSetArg(args[j], XtNwidth, &evalGraphW); j++;
417 XtSetArg(args[j], XtNheight, &evalGraphH); j++;
418 XtGetValues(evalGraphShell, args, j);
419 wpEvalGraph.x = evalGraphX - 4;
420 wpEvalGraph.y = evalGraphY - 23;
421 wpEvalGraph.width = evalGraphW;
422 wpEvalGraph.height = evalGraphH;
423 XtPopdown(evalGraphShell);
424 XSync(xDisplay, False);
426 XtSetArg(args[j], XtNleftBitmap, None); j++;
427 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Evaluation Graph"),
430 evalGraphDialogUp = False;
431 // ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
434 Boolean EvalGraphIsUp()
436 return evalGraphDialogUp;
439 int EvalGraphDialogExists()
441 return evalGraphShell != NULL;
445 EvalGraphProc(w, event, prms, nprms)
451 if (evalGraphDialogUp) {
457 // This function is the interface to the back-end. It is currently called through the front-end,
458 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends
459 // support the eval graph, it would be more logical to call it directly from the back-end.
460 void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )
462 /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
466 currCurrent = current;
469 if( evalGraphShell ) {