neglected this for the auto-width updating in xboard
[xboard.git] / winboard / wevalgraph.c
1 /*\r
2  * Evaluation graph\r
3  *\r
4  * Author: Alessandro Scotti (Dec 2005)\r
5  *\r
6  * Copyright 2005 Alessandro Scotti\r
7  *\r
8  * ------------------------------------------------------------------------\r
9  *\r
10  * GNU XBoard is free software: you can redistribute it and/or modify\r
11  * it under the terms of the GNU General Public License as published by\r
12  * the Free Software Foundation, either version 3 of the License, or (at\r
13  * your option) any later version.\r
14  *\r
15  * GNU XBoard is distributed in the hope that it will be useful, but\r
16  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
18  * General Public License for more details.\r
19  *\r
20  * You should have received a copy of the GNU General Public License\r
21  * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
22  *\r
23  *------------------------------------------------------------------------\r
24  ** See the file ChangeLog for a revision history.  */\r
25 \r
26 // code refactored by HGM to obtain front-end / back-end separation\r
27 \r
28 #include "config.h"\r
29 \r
30 #include <windows.h> /* required for all Windows applications */\r
31 //include <richedit.h>\r
32 #include <stdio.h>\r
33 //include <stdlib.h>\r
34 //include <malloc.h>\r
35 \r
36 #include "common.h"\r
37 #include "frontend.h"\r
38 #include "backend.h"\r
39 \r
40 /* Imports from winboard.c */\r
41 extern BOOLEAN evalGraphDialogUp; // should be back-end variable, and defined here\r
42 \r
43 /* Module globals */ // used to communicate between back-end and front-end part\r
44 static ChessProgramStats_Move * currPvInfo;\r
45 static int currFirst = 0;\r
46 static int currLast = 0;\r
47 static int currCurrent = -1;\r
48 \r
49 static int nWidthPB = 0;\r
50 static int nHeightPB = 0;\r
51 \r
52 static int MarginX = 18;\r
53 static int MarginW = 4;\r
54 static int MarginH = 4;\r
55 \r
56 #define MIN_HIST_WIDTH  4\r
57 #define MAX_HIST_WIDTH  10\r
58 \r
59 #define PEN_NONE        0\r
60 #define PEN_BLACK       1\r
61 #define PEN_DOTTED      2\r
62 #define PEN_BLUEDOTTED  3\r
63 #define PEN_BOLD        4 /* or 5 for black */\r
64 \r
65 #define FILLED 1\r
66 #define OPEN   0\r
67 \r
68 // calls from back-end part into front-end\r
69 static void DrawSegment( int x, int y, int *lastX, int *lastY, int penType );\r
70 void DrawRectangle( int left, int top, int right, int bottom, int side, int style );\r
71 void DrawEvalText(char *buf, int cbBuf, int y);\r
72 \r
73 \r
74 // back-end\r
75 static void DrawLine( int x1, int y1, int x2, int y2, int penType )\r
76 {\r
77     DrawSegment( x1, y1, NULL, NULL, PEN_NONE );\r
78     DrawSegment( x2, y2, NULL, NULL, penType );\r
79 }\r
80 \r
81 // back-end\r
82 static void DrawLineEx( int x1, int y1, int x2, int y2, int penType )\r
83 {\r
84     int savX, savY;\r
85     DrawSegment( x1, y1, &savX, &savY, PEN_NONE );\r
86     DrawSegment( x2, y2, NULL, NULL, penType );\r
87     DrawSegment( savX, savY, NULL, NULL, PEN_NONE );\r
88 }\r
89 \r
90 // back-end\r
91 static int GetPvScore( int index )\r
92 {\r
93     int score = currPvInfo[ index ].score;\r
94 \r
95     if( index & 1 ) score = -score; /* Flip score for black */\r
96 \r
97     return score;\r
98 }\r
99 \r
100 // back-end\r
101 /*\r
102     For a centipawn value, this function returns the height of the corresponding\r
103     histogram, centered on the reference axis.\r
104 \r
105     Note: height can be negative!\r
106 */\r
107 static int GetValueY( int value )\r
108 {\r
109     if( value < -700 ) value = -700;\r
110     if( value > +700 ) value = +700;\r
111 \r
112     return (nHeightPB / 2) - (int)(value * (nHeightPB - 2*MarginH) / 1400.0);\r
113 }\r
114 \r
115 // the brush selection is made part of the DrawLine, by passing a style argument\r
116 // the wrapper for doing the text output makes this back-end\r
117 static void DrawAxisSegmentHoriz( int value, BOOL drawValue )\r
118 {\r
119     int y = GetValueY( value*100 );\r
120 \r
121     if( drawValue ) {\r
122         char buf[MSG_SIZ], *b = buf;\r
123 \r
124         if( value > 0 ) *b++ = '+';\r
125         sprintf(b, "%d", value);\r
126 \r
127         DrawEvalText(buf, strlen(buf), y);\r
128     }\r
129     // [HGM] counts on DrawEvalText to have select transparent background for dotted line!\r
130     DrawLine( MarginX, y, MarginX + MarginW, y, PEN_BLACK ); // Y-axis tick marks\r
131     DrawLine( MarginX + MarginW, y, nWidthPB - MarginW, y, PEN_DOTTED ); // hor grid\r
132 }\r
133 \r
134 // The DrawLines again must select their own brush.\r
135 // the initial brush selection is useless? BkMode needed for dotted line and text\r
136 static void DrawAxis()\r
137 {\r
138     int cy = nHeightPB / 2;\r
139     \r
140 //    SelectObject( hdcPB, GetStockObject(NULL_BRUSH) );\r
141 \r
142 //    SetBkMode( hdcPB, TRANSPARENT );\r
143 \r
144     DrawAxisSegmentHoriz( +5, TRUE );\r
145     DrawAxisSegmentHoriz( +3, FALSE );\r
146     DrawAxisSegmentHoriz( +1, FALSE );\r
147     DrawAxisSegmentHoriz(  0, TRUE );\r
148     DrawAxisSegmentHoriz( -1, FALSE );\r
149     DrawAxisSegmentHoriz( -3, FALSE );\r
150     DrawAxisSegmentHoriz( -5, TRUE );\r
151 \r
152     DrawLine( MarginX + MarginW, cy, nWidthPB - MarginW, cy, PEN_BLACK ); // x-axis\r
153     DrawLine( MarginX + MarginW, MarginH, MarginX + MarginW, nHeightPB - MarginH, PEN_BLACK ); // y-axis\r
154 }\r
155 \r
156 // back-end\r
157 static void DrawHistogram( int x, int y, int width, int value, int side )\r
158 {\r
159     int left, top, right, bottom;\r
160 \r
161     if( value > -25 && value < +25 ) return;\r
162 \r
163     left = x;\r
164     right = left + width + 1;\r
165 \r
166     if( value > 0 ) {\r
167         top = GetValueY( value );\r
168         bottom = y+1;\r
169     }\r
170     else {\r
171         top = y;\r
172         bottom = GetValueY( value ) + 1;\r
173     }\r
174 \r
175 \r
176     if( width == MIN_HIST_WIDTH ) {\r
177         right--;\r
178         DrawRectangle( left, top, right, bottom, side, FILLED );\r
179     }\r
180     else {\r
181         DrawRectangle( left, top, right, bottom, side, OPEN );\r
182     }\r
183 }\r
184 \r
185 // back-end\r
186 static void DrawSeparator( int index, int x )\r
187 {\r
188     if( index > 0 ) {\r
189         if( index == currCurrent ) {\r
190             DrawLineEx( x, MarginH, x, nHeightPB - MarginH, PEN_BLUEDOTTED );\r
191         }\r
192         else if( (index % 20) == 0 ) {\r
193             DrawLineEx( x, MarginH, x, nHeightPB - MarginH, PEN_DOTTED );\r
194         }\r
195     }\r
196 }\r
197 \r
198 // made back-end by replacing MoveToEx and LineTo by DrawSegment\r
199 /* Actually draw histogram as a diagram, cause there's too much data */\r
200 static void DrawHistogramAsDiagram( int cy, int paint_width, int hist_count )\r
201 {\r
202     double step;\r
203     int i;\r
204 \r
205     /* Rescale the graph every few moves (as opposed to every move) */\r
206     hist_count -= hist_count % 8;\r
207     hist_count += 8;\r
208     hist_count /= 2;\r
209 \r
210     step = (double) paint_width / (hist_count + 1);\r
211 \r
212     for( i=0; i<2; i++ ) {\r
213         int index = currFirst;\r
214         int side = (currCurrent + i + 1) & 1; /* Draw current side last */\r
215         double x = MarginX + MarginW;\r
216 \r
217         if( (index & 1) != side ) {\r
218             x += step / 2;\r
219             index++;\r
220         }\r
221 \r
222         DrawSegment( (int) x, cy, NULL, NULL, PEN_NONE );\r
223 \r
224         index += 2;\r
225 \r
226         while( index < currLast ) {\r
227             x += step;\r
228 \r
229             DrawSeparator( index, (int) x );\r
230 \r
231             /* Extend line up to current point */\r
232             if( currPvInfo[index].depth > 0 ) {\r
233                 DrawSegment((int) x, GetValueY( GetPvScore(index) ), NULL, NULL, PEN_BOLD + side );\r
234             }\r
235 \r
236             index += 2;\r
237         }\r
238     }\r
239 }\r
240 \r
241 // back-end, delete pen selection\r
242 static void DrawHistogramFull( int cy, int hist_width, int hist_count )\r
243 {\r
244     int i;\r
245 \r
246 //    SelectObject( hdcPB, GetStockObject(BLACK_PEN) );\r
247 \r
248     for( i=0; i<hist_count; i++ ) {\r
249         int index = currFirst + i;\r
250         int x = MarginX + MarginW + index * hist_width;\r
251 \r
252         /* Draw a separator every 10 moves */\r
253         DrawSeparator( index, x );\r
254 \r
255         /* Draw histogram */\r
256         if( currPvInfo[i].depth > 0 ) {\r
257             DrawHistogram( x, cy, hist_width, GetPvScore(index), index & 1 );\r
258         }\r
259     }\r
260 }\r
261 \r
262 typedef struct {\r
263     int cy;\r
264     int hist_width;\r
265     int hist_count;\r
266     int paint_width;\r
267 } VisualizationData;\r
268 \r
269 // back-end\r
270 static Boolean InitVisualization( VisualizationData * vd )\r
271 {\r
272     BOOL result = FALSE;\r
273 \r
274     vd->cy = nHeightPB / 2;\r
275     vd->hist_width = MIN_HIST_WIDTH;\r
276     vd->hist_count = currLast - currFirst;\r
277     vd->paint_width = nWidthPB - MarginX - 2*MarginW;\r
278 \r
279     if( vd->hist_count > 0 ) {\r
280         result = TRUE;\r
281 \r
282         /* Compute width */\r
283         vd->hist_width = vd->paint_width / vd->hist_count;\r
284 \r
285         if( vd->hist_width > MAX_HIST_WIDTH ) vd->hist_width = MAX_HIST_WIDTH;\r
286 \r
287         vd->hist_width -= vd->hist_width % 2;\r
288     }\r
289 \r
290     return result;\r
291 }\r
292 \r
293 // back-end\r
294 static void DrawHistograms()\r
295 {\r
296     VisualizationData vd;\r
297 \r
298     if( InitVisualization( &vd ) ) {\r
299         if( vd.hist_width < MIN_HIST_WIDTH ) {\r
300             DrawHistogramAsDiagram( vd.cy, vd.paint_width, vd.hist_count );\r
301         }\r
302         else {\r
303             DrawHistogramFull( vd.cy, vd.hist_width, vd.hist_count );\r
304         }\r
305     }\r
306 }\r
307 \r
308 // back-end\r
309 int GetMoveIndexFromPoint( int x, int y )\r
310 {\r
311     int result = -1;\r
312     int start_x = MarginX + MarginW;\r
313     VisualizationData vd;\r
314 \r
315     if( x >= start_x && InitVisualization( &vd ) ) {\r
316         /* Almost an hack here... we duplicate some of the paint logic */\r
317         if( vd.hist_width < MIN_HIST_WIDTH ) {\r
318             double step;\r
319 \r
320             vd.hist_count -= vd.hist_count % 8;\r
321             vd.hist_count += 8;\r
322             vd.hist_count /= 2;\r
323 \r
324             step = (double) vd.paint_width / (vd.hist_count + 1);\r
325             step /= 2;\r
326 \r
327             result = (int) (0.5 + (double) (x - start_x) / step);\r
328         }\r
329         else {\r
330             result = (x - start_x) / vd.hist_width;\r
331         }\r
332     }\r
333 \r
334     if( result >= currLast ) {\r
335         result = -1;\r
336     }\r
337 \r
338     return result;\r
339 }\r
340 \r
341 // init and display part split of so they can be moved to front end\r
342 void PaintEvalGraph( void )\r
343 {\r
344     /* Draw */\r
345     DrawRectangle(0, 0, nWidthPB, nHeightPB, 2, FILLED);\r
346     DrawAxis();\r
347     DrawHistograms();\r
348 }\r
349 \r
350 Boolean EvalGraphIsUp()\r
351 {\r
352     return evalGraphDialogUp;\r
353 }\r
354 \r
355 // ------------------------------------------ front-end starts here ----------------------------------------------\r
356 \r
357 #include <commdlg.h>\r
358 #include <dlgs.h>\r
359 \r
360 #include "winboard.h"\r
361 #include "wsnap.h"\r
362 \r
363 #define WM_REFRESH_GRAPH    (WM_USER + 1)\r
364 \r
365 void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
366 void EvalGraphPopUp();\r
367 void EvalGraphPopDown();\r
368 Boolean EvalGraphIsUp();\r
369 \r
370 // calls of front-end part into back-end part\r
371 extern int GetMoveIndexFromPoint( int x, int y );\r
372 extern void PaintEvalGraph( void );\r
373 \r
374 /* Imports from winboard.c */\r
375 extern HWND evalGraphDialog;\r
376 extern BOOLEAN evalGraphDialogUp; // should be back-end, really\r
377 \r
378 extern HINSTANCE hInst;\r
379 extern HWND hwndMain;\r
380 \r
381 extern WindowPlacement wpEvalGraph;\r
382 \r
383 static COLORREF crWhite = RGB( 0xFF, 0xFF, 0xB0 );\r
384 static COLORREF crBlack = RGB( 0xAD, 0x5D, 0x3D );\r
385 \r
386 static HDC hdcPB = NULL;\r
387 static HBITMAP hbmPB = NULL;\r
388 static HPEN pens[6]; // [HGM] put all pens in one array\r
389 static HBRUSH hbrHist[3] = { NULL, NULL, NULL };\r
390 \r
391 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end) \r
392 static void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )\r
393 {\r
394     POINT stPt;\r
395     if(penType == PEN_NONE) MoveToEx( hdcPB, x, y, &stPt ); else {\r
396         HPEN hp = SelectObject( hdcPB, pens[penType] );\r
397         LineTo( hdcPB, x, y );\r
398         SelectObject( hdcPB, hp );\r
399     }\r
400     if(lastX != NULL) { *lastX = stPt.x; *lastY = stPt.y; }\r
401 }\r
402 \r
403 // front-end wrapper for drawing functions to do rectangles\r
404 void DrawRectangle( int left, int top, int right, int bottom, int side, int style )\r
405 {\r
406     HPEN hp = SelectObject( hdcPB, pens[PEN_BLACK] );\r
407     RECT rc;\r
408 \r
409     rc.top = top; rc.left = left; rc.bottom = bottom; rc.right = right;\r
410     if(style == FILLED)\r
411         FillRect( hdcPB, &rc, hbrHist[side] );\r
412     else {\r
413         SelectObject( hdcPB, hbrHist[side] );\r
414         Rectangle( hdcPB, left, top, right, bottom );\r
415     }\r
416     SelectObject( hdcPB, hp );\r
417 }\r
418 \r
419 // front-end wrapper for putting text in graph\r
420 void DrawEvalText(char *buf, int cbBuf, int y)\r
421 {\r
422         SIZE stSize;\r
423         SetBkMode( hdcPB, TRANSPARENT );\r
424         GetTextExtentPoint32( hdcPB, buf, cbBuf, &stSize );\r
425         TextOut( hdcPB, MarginX - stSize.cx - 2, y - stSize.cy / 2, buf, cbBuf );\r
426 }\r
427 \r
428 // front-end\r
429 static HBRUSH CreateBrush( UINT style, COLORREF color )\r
430 {\r
431     LOGBRUSH stLB;\r
432 \r
433     stLB.lbStyle = style;\r
434     stLB.lbColor = color;\r
435     stLB.lbHatch = 0;\r
436 \r
437     return CreateBrushIndirect( &stLB );\r
438 }\r
439 \r
440 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display\r
441 // The back-end part n the middle has been taken out and moed to PainEvalGraph()\r
442 static VOID DisplayEvalGraph( HWND hWnd, HDC hDC )\r
443 {\r
444     RECT rcClient;\r
445     int width;\r
446     int height;\r
447 \r
448     /* Get client area */\r
449     GetClientRect( hWnd, &rcClient );\r
450 \r
451     width = rcClient.right - rcClient.left;\r
452     height = rcClient.bottom - rcClient.top;\r
453 \r
454     /* Create or recreate paint box if needed */\r
455     if( hbmPB == NULL || width != nWidthPB || height != nHeightPB ) {\r
456         if( pens[PEN_DOTTED] == NULL ) {\r
457             pens[PEN_BLACK]     = GetStockObject(BLACK_PEN);\r
458             pens[PEN_DOTTED]    = CreatePen( PS_DOT, 0, RGB(0xA0,0xA0,0xA0) );\r
459             pens[PEN_BLUEDOTTED] = CreatePen( PS_DOT, 0, RGB(0x00,0x00,0xFF) );\r
460             pens[PEN_BOLD]      = CreatePen( PS_SOLID, 2, crWhite );\r
461             pens[PEN_BOLD+1]    = CreatePen( PS_SOLID, 2, crBlack );\r
462             hbrHist[0] = CreateBrush( BS_SOLID, crWhite );\r
463             hbrHist[1] = CreateBrush( BS_SOLID, crBlack );\r
464             hbrHist[2] = CreateBrush( BS_SOLID, GetSysColor( COLOR_3DFACE ) ); // background\r
465         }\r
466 \r
467         if( hdcPB != NULL ) {\r
468             DeleteDC( hdcPB );\r
469             hdcPB = NULL;\r
470         }\r
471 \r
472         if( hbmPB != NULL ) {\r
473             DeleteObject( hbmPB );\r
474             hbmPB = NULL;\r
475         }\r
476 \r
477         hdcPB = CreateCompatibleDC( hDC );\r
478 \r
479         nWidthPB = width;\r
480         nHeightPB = height;\r
481         hbmPB = CreateCompatibleBitmap( hDC, nWidthPB, nHeightPB );\r
482 \r
483         SelectObject( hdcPB, hbmPB );\r
484     }\r
485 \r
486     // back-end painting; calls back front-end primitives for lines, rectangles and text\r
487     PaintEvalGraph();\r
488 \r
489     /* Copy bitmap into destination DC */\r
490     BitBlt( hDC, 0, 0, nWidthPB, nHeightPB, hdcPB, 0, 0, SRCCOPY );\r
491 }\r
492 \r
493 // Note: Once the eval graph is opened, this window-proc lives forever; een closing the\r
494 // eval-graph window merely hides it. On opening we re-initialize it, though, so it could\r
495 // as well hae been destroyed. While it is open it processes the REFRESH_GRAPH commands.\r
496 LRESULT CALLBACK EvalGraphProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
497 {\r
498     static SnapData sd;\r
499 \r
500     PAINTSTRUCT stPS;\r
501     HDC hDC;\r
502 \r
503     switch (message) {\r
504     case WM_INITDIALOG:\r
505         if( evalGraphDialog == NULL ) {\r
506             evalGraphDialog = hDlg;\r
507 \r
508             RestoreWindowPlacement( hDlg, &wpEvalGraph ); /* Restore window placement */\r
509         }\r
510 \r
511         return FALSE;\r
512 \r
513     case WM_COMMAND:\r
514         switch (LOWORD(wParam)) {\r
515         case IDOK:\r
516           EndDialog(hDlg, TRUE);\r
517           return TRUE;\r
518 \r
519         case IDCANCEL:\r
520           EndDialog(hDlg, FALSE);\r
521           return TRUE;\r
522 \r
523         default:\r
524           break;\r
525         }\r
526 \r
527         break;\r
528 \r
529     case WM_ERASEBKGND:\r
530         return TRUE;\r
531 \r
532     case WM_PAINT:\r
533         hDC = BeginPaint( hDlg, &stPS );\r
534         DisplayEvalGraph( hDlg, hDC );\r
535         EndPaint( hDlg, &stPS );\r
536         break;\r
537 \r
538     case WM_REFRESH_GRAPH:\r
539         hDC = GetDC( hDlg );\r
540         DisplayEvalGraph( hDlg, hDC );\r
541         ReleaseDC( hDlg, hDC );\r
542         break;\r
543 \r
544     case WM_LBUTTONDBLCLK:\r
545         if( wParam == 0 || wParam == MK_LBUTTON ) {\r
546             int index = GetMoveIndexFromPoint( LOWORD(lParam), HIWORD(lParam) );\r
547 \r
548             if( index >= 0 && index < currLast ) {\r
549                 ToNrEvent( index + 1 );\r
550             }\r
551         }\r
552         return TRUE;\r
553 \r
554     case WM_SIZE:\r
555         InvalidateRect( hDlg, NULL, FALSE );\r
556         break;\r
557 \r
558     case WM_GETMINMAXINFO:\r
559         {\r
560             MINMAXINFO * mmi = (MINMAXINFO *) lParam;\r
561         \r
562             mmi->ptMinTrackSize.x = 100;\r
563             mmi->ptMinTrackSize.y = 100;\r
564         }\r
565         break;\r
566 \r
567     /* Support for captionless window */\r
568     case WM_CLOSE:\r
569         EvalGraphPopDown();\r
570         break;\r
571 \r
572     case WM_ENTERSIZEMOVE:\r
573         return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
574 \r
575     case WM_SIZING:\r
576         return OnSizing( &sd, hDlg, wParam, lParam );\r
577 \r
578     case WM_MOVING:\r
579         return OnMoving( &sd, hDlg, wParam, lParam );\r
580 \r
581     case WM_EXITSIZEMOVE:\r
582         return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
583     }\r
584 \r
585     return FALSE;\r
586 }\r
587 \r
588 // creates the eval graph, or unhides it.\r
589 VOID EvalGraphPopUp()\r
590 {\r
591   FARPROC lpProc;\r
592   \r
593   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEvalGraph, MF_CHECKED);\r
594 \r
595   if( evalGraphDialog ) {\r
596     SendMessage( evalGraphDialog, WM_INITDIALOG, 0, 0 );\r
597 \r
598     if( ! evalGraphDialogUp ) {\r
599         ShowWindow(evalGraphDialog, SW_SHOW);\r
600     }\r
601   }\r
602   else {\r
603     crWhite = appData.evalHistColorWhite;\r
604     crBlack = appData.evalHistColorBlack;\r
605 \r
606     lpProc = MakeProcInstance( (FARPROC) EvalGraphProc, hInst );\r
607 \r
608     /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */\r
609     CreateDialog( hInst, MAKEINTRESOURCE(DLG_EvalGraph), hwndMain, (DLGPROC)lpProc );\r
610 \r
611     FreeProcInstance(lpProc);\r
612   }\r
613 \r
614   evalGraphDialogUp = TRUE;\r
615 }\r
616 \r
617 // Note that this hides the window. It could as well have destroyed it.\r
618 VOID EvalGraphPopDown()\r
619 {\r
620   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEvalGraph, MF_UNCHECKED);\r
621 \r
622   if( evalGraphDialog ) {\r
623       ShowWindow(evalGraphDialog, SW_HIDE);\r
624   }\r
625 \r
626   evalGraphDialogUp = FALSE;\r
627 }\r
628 \r
629 // This function is the interface to the back-end. It is currently called through the front-end,\r
630 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends\r
631 // support the eval graph, it would be more logical to call it directly from the back-end.\r
632 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )\r
633 {\r
634     /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */\r
635 \r
636     currFirst = first;\r
637     currLast = last;\r
638     currCurrent = current;\r
639     currPvInfo = pvInfo;\r
640 \r
641     if( evalGraphDialog ) {\r
642         SendMessage( evalGraphDialog, WM_REFRESH_GRAPH, 0, 0 );\r
643     }\r
644 }\r
645 \r