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, boardWidget, menuBarWidget;
104 extern Window xBoardWindow;
105 extern int squareSize;
106 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
107 extern char *layoutName;
109 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
110 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
112 /* Imports from backend.c */
114 /* Imports from xboard.c */
115 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
118 //extern WindowPlacement wpEvalGraph;
120 Position evalGraphX = -1, evalGraphY = -1;
121 Dimension evalGraphW, evalGraphH;
122 Widget evalGraphShell;
123 static int evalGraphDialogUp;
125 /* Module variables */
127 char *crWhite = "#FFFFB0";
128 char *crBlack = "#AD5D3D";
129 static Display *yDisplay;
130 static Window eGraphWindow;
132 static GC pens[6]; // [HGM] put all pens in one array
133 static GC hbrHist[3];
136 static HDC hdcPB = NULL;
137 static HBITMAP hbmPB = NULL;
140 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end)
141 void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )
144 if(penType != PEN_NONE)
145 XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
146 if(lastX != NULL) { *lastX = curX; *lastY = curY; }
150 // front-end wrapper for drawing functions to do rectangles
151 void DrawRectangle( int left, int top, int right, int bottom, int side, int style )
153 XFillRectangle(yDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top);
155 XDrawRectangle(yDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
158 // front-end wrapper for putting text in graph
159 void DrawEvalText(char *buf, int cbBuf, int y)
161 // the magic constants 7 and 5 should really be derived from the font size somehow
162 XDrawString(yDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
166 static Pixel MakeColor(char *color )
170 vFrom.addr = (caddr_t) color;
171 vFrom.size = strlen(color);
172 XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo);
175 return *(Pixel *) vTo.addr;
178 static GC CreateGC(int width, char *fg, char *bg, int style)
180 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
181 | GCBackground | GCFunction | GCPlaneMask;
184 gc_values.plane_mask = AllPlanes;
185 gc_values.line_width = width;
186 gc_values.line_style = style;
187 gc_values.function = GXcopy;
189 gc_values.foreground = MakeColor(fg);
190 gc_values.background = MakeColor(bg);
192 return XtGetGC(evalGraphShell, value_mask, &gc_values);
195 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display
196 // The back-end part n the middle has been taken out and moed to PainEvalGraph()
197 static void DisplayEvalGraph()
205 /* Get client area */
207 XtSetArg(args[j], XtNwidth, &w); j++;
208 XtSetArg(args[j], XtNheight, &h); j++;
209 XtGetValues(evalGraphShell, args, j);
213 /* Create or recreate paint box if needed */
214 if( width != nWidthPB || height != nHeightPB ) {
220 // back-end painting; calls back front-end primitives for lines, rectangles and text
223 XSync(yDisplay, False);
226 static void InitializeEvalGraph()
227 { int i; XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
228 | GCBackground | GCFunction | GCPlaneMask;
230 // GC copyInvertedGC;
232 pens[PEN_BLACK] = CreateGC(1, "black", "black", LineSolid);
233 pens[PEN_DOTTED] = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
234 pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
235 pens[PEN_BOLD] = CreateGC(3, crWhite, crWhite, LineSolid);
236 pens[PEN_BOLD+1] = CreateGC(3, crBlack, crBlack, LineSolid);
237 hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid);
238 hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid);
239 hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve)
242 void EvalClick(widget, unused, event)
247 if( widget && event->type == ButtonPress ) {
248 int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y );
250 if( index >= 0 && index < currLast ) {
251 ToNrEvent( index + 1 );
256 // This (cloned from EventProc in xboard.c) is needed as event handler, to prevent
257 // the graph being wiped out after covering / uncovering by other windows.
258 void EvalEventProc(widget, unused, event)
263 if (!XtIsRealized(widget))
266 switch (event->type) {
268 if (event->xexpose.count > 0) return; /* no clipping is done */
275 // The following routines are mutated clones of the commentPopUp routines
277 Widget EvalGraphCreate(name)
281 Widget shell, layout, form, form2, edit;
282 Dimension bw_width, bw_height;
287 XtSetArg(args[j], XtNwidth, &bw_width); j++;
288 XtSetArg(args[j], XtNheight, &bw_height); j++;
289 XtGetValues(boardWidget, args, j);
291 // define form within layout within shell.
293 XtSetArg(args[j], XtNresizable, True); j++;
296 // XtCreatePopupShell(name, topLevelShellWidgetClass,
298 // XtCreatePopupShell(name, transientShellWidgetClass,
300 // shellWidget, args, j);
302 // XtCreateManagedWidget(layoutName, formWidgetClass, shell,
303 // layoutArgs, XtNumber(layoutArgs));
304 // divide window vertically into two equal parts, by creating two forms
306 XtCreateManagedWidget("form", formWidgetClass, layout,
307 formArgs, XtNumber(formArgs));
308 // make sure width is known in advance, for better placement of child widgets
310 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
311 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/4); j++;
312 XtSetValues(shell, args, j);
314 XtRealizeWidget(shell);
316 if(wpEvalGraph.width > 0) {
317 evalGraphW = wpEvalGraph.width;
318 evalGraphH = wpEvalGraph.height;
319 evalGraphX = wpEvalGraph.x;
320 evalGraphY = wpEvalGraph.y;
323 if (evalGraphX == -1) {
328 evalGraphH = bw_height/4;
329 evalGraphW = bw_width-16;
331 // XSync(xDisplay, False);
333 /* This code seems to tickle an X bug if it is executed too soon
334 after xboard starts up. The coordinates get transformed as if
335 the main window was positioned at (0, 0).
337 // XtTranslateCoords(shellWidget,
338 // (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
339 // &evalGraphX, &evalGraphY);
341 // XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
342 // RootWindowOfScreen(XtScreen(shellWidget)),
343 // (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2,
348 if (evalGraphY < 0) evalGraphY = 0; /*avoid positioning top offscreen*/
351 XtSetArg(args[j], XtNheight, evalGraphH); j++;
352 XtSetArg(args[j], XtNwidth, evalGraphW); j++;
353 XtSetArg(args[j], XtNx, evalGraphX); j++;
354 XtSetArg(args[j], XtNy, evalGraphY); j++;
355 XtSetValues(shell, args, j);
356 // XtSetKeyboardFocus(shell, edit);
358 yDisplay = XtDisplay(shell);
359 eGraphWindow = XtWindow(form);
360 XtAddEventHandler(form, ExposureMask, False,
361 (XtEventHandler) EvalEventProc, NULL);
362 XtAddEventHandler(form, ButtonPressMask, False,
363 (XtEventHandler) EvalClick, NULL);
374 static int needInit = TRUE;
375 static char *title = _("Evaluation graph");
377 if (evalGraphShell == NULL) {
380 EvalGraphCreate(title);
381 XtRealizeWidget(evalGraphShell);
382 // CatchDeleteWindow(evalGraphShell, "EvalGraphPopDown");
384 InitializeEvalGraph();
389 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
390 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
391 XtSetValues(evalGraphShell, args, j);
394 XtPopup(evalGraphShell, XtGrabNone);
395 XSync(yDisplay, False);
398 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
399 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Evaluation Graph"),
402 evalGraphDialogUp = True;
403 // ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
406 void EvalGraphPopDown()
411 if (!evalGraphDialogUp) return;
413 XtSetArg(args[j], XtNx, &evalGraphX); j++;
414 XtSetArg(args[j], XtNy, &evalGraphY); j++;
415 XtSetArg(args[j], XtNwidth, &evalGraphW); j++;
416 XtSetArg(args[j], XtNheight, &evalGraphH); j++;
417 XtGetValues(evalGraphShell, args, j);
418 wpEvalGraph.x = evalGraphX - 4;
419 wpEvalGraph.y = evalGraphY - 23;
420 wpEvalGraph.width = evalGraphW;
421 wpEvalGraph.height = evalGraphH;
422 XtPopdown(evalGraphShell);
423 // XSync(xDisplay, False);
425 XtSetArg(args[j], XtNleftBitmap, None); j++;
426 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Evaluation Graph"),
429 evalGraphDialogUp = False;
430 // ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
433 Boolean EvalGraphIsUp()
435 return evalGraphDialogUp;
438 int EvalGraphDialogExists()
440 return evalGraphShell != NULL;
444 EvalGraphProc(w, event, prms, nprms)
450 if (evalGraphDialogUp) {
456 // This function is the interface to the back-end. It is currently called through the front-end,
457 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends
458 // support the eval graph, it would be more logical to call it directly from the back-end.
459 void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )
461 /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
465 currCurrent = current;
468 if( evalGraphShell ) {