-\r
-/* Module globals */ // used to communicate between back-end and front-end part\r
-static ChessProgramStats_Move * currPvInfo;\r
-static int currFirst = 0;\r
-static int currLast = 0;\r
-static int currCurrent = -1;\r
-\r
-static int nWidthPB = 0;\r
-static int nHeightPB = 0;\r
-\r
-static int MarginX = 18;\r
-static int MarginW = 4;\r
-static int MarginH = 4;\r
-\r
-#define MIN_HIST_WIDTH 4\r
-#define MAX_HIST_WIDTH 10\r
-\r
-#define PEN_NONE 0\r
-#define PEN_BLACK 1\r
-#define PEN_DOTTED 2\r
-#define PEN_BLUEDOTTED 3\r
-#define PEN_BOLD 4 /* or 5 for black */\r
-\r
-#define FILLED 1\r
-#define OPEN 0\r
-\r
-// calls from back-end part into front-end\r
-static void DrawSegment( int x, int y, int *lastX, int *lastY, int penType );\r
-void DrawRectangle( int left, int top, int right, int bottom, int side, int style );\r
-void DrawEvalText(char *buf, int cbBuf, int y);\r
-\r
-\r
-// back-end\r
-static void DrawLine( int x1, int y1, int x2, int y2, int penType )\r
-{\r
- DrawSegment( x1, y1, NULL, NULL, PEN_NONE );\r
- DrawSegment( x2, y2, NULL, NULL, penType );\r
-}\r
-\r
-// back-end\r
-static void DrawLineEx( int x1, int y1, int x2, int y2, int penType )\r
-{\r
- int savX, savY;\r
- DrawSegment( x1, y1, &savX, &savY, PEN_NONE );\r
- DrawSegment( x2, y2, NULL, NULL, penType );\r
- DrawSegment( savX, savY, NULL, NULL, PEN_NONE );\r
-}\r
-\r
-// back-end\r
-static int GetPvScore( int index )\r
-{\r
- int score = currPvInfo[ index ].score;\r
-\r
- if( index & 1 ) score = -score; /* Flip score for black */\r
-\r
- return score;\r
-}\r
-\r
-// back-end\r
-/*\r
- For a centipawn value, this function returns the height of the corresponding\r
- histogram, centered on the reference axis.\r
-\r
- Note: height can be negative!\r
-*/\r
-static int GetValueY( int value )\r
-{\r
- if( value < -700 ) value = -700;\r
- if( value > +700 ) value = +700;\r
-\r
- return (nHeightPB / 2) - (int)(value * (nHeightPB - 2*MarginH) / 1400.0);\r
-}\r
-\r
-// the brush selection is made part of the DrawLine, by passing a style argument\r
-// the wrapper for doing the text output makes this back-end\r
-static void DrawAxisSegmentHoriz( int value, BOOL drawValue )\r
-{\r
- int y = GetValueY( value*100 );\r
-\r
- if( drawValue ) {\r
- char buf[MSG_SIZ], *b = buf;\r
-\r
- if( value > 0 ) *b++ = '+';\r
- sprintf(b, "%d", value);\r
-\r
- DrawEvalText(buf, strlen(buf), y);\r
- }\r
- // [HGM] counts on DrawEvalText to have select transparent background for dotted line!\r
- DrawLine( MarginX, y, MarginX + MarginW, y, PEN_BLACK ); // Y-axis tick marks\r
- DrawLine( MarginX + MarginW, y, nWidthPB - MarginW, y, PEN_DOTTED ); // hor grid\r
-}\r
-\r
-// The DrawLines again must select their own brush.\r
-// the initial brush selection is useless? BkMode needed for dotted line and text\r
-static void DrawAxis()\r
-{\r
- int cy = nHeightPB / 2;\r
- \r
-// SelectObject( hdcPB, GetStockObject(NULL_BRUSH) );\r
-\r
-// SetBkMode( hdcPB, TRANSPARENT );\r
-\r
- DrawAxisSegmentHoriz( +5, TRUE );\r
- DrawAxisSegmentHoriz( +3, FALSE );\r
- DrawAxisSegmentHoriz( +1, FALSE );\r
- DrawAxisSegmentHoriz( 0, TRUE );\r
- DrawAxisSegmentHoriz( -1, FALSE );\r
- DrawAxisSegmentHoriz( -3, FALSE );\r
- DrawAxisSegmentHoriz( -5, TRUE );\r
-\r
- DrawLine( MarginX + MarginW, cy, nWidthPB - MarginW, cy, PEN_BLACK ); // x-axis\r
- DrawLine( MarginX + MarginW, MarginH, MarginX + MarginW, nHeightPB - MarginH, PEN_BLACK ); // y-axis\r
-}\r
-\r
-// back-end\r
-static void DrawHistogram( int x, int y, int width, int value, int side )\r
-{\r
- int left, top, right, bottom;\r
-\r
- if( value > -25 && value < +25 ) return;\r
-\r
- left = x;\r
- right = left + width + 1;\r
-\r
- if( value > 0 ) {\r
- top = GetValueY( value );\r
- bottom = y+1;\r
- }\r
- else {\r
- top = y;\r
- bottom = GetValueY( value ) + 1;\r
- }\r
-\r
-\r
- if( width == MIN_HIST_WIDTH ) {\r
- right--;\r
- DrawRectangle( left, top, right, bottom, side, FILLED );\r
- }\r
- else {\r
- DrawRectangle( left, top, right, bottom, side, OPEN );\r
- }\r
-}\r
-\r
-// back-end\r
-static void DrawSeparator( int index, int x )\r
-{\r
- if( index > 0 ) {\r
- if( index == currCurrent ) {\r
- DrawLineEx( x, MarginH, x, nHeightPB - MarginH, PEN_BLUEDOTTED );\r
- }\r
- else if( (index % 20) == 0 ) {\r
- DrawLineEx( x, MarginH, x, nHeightPB - MarginH, PEN_DOTTED );\r
- }\r
- }\r
-}\r
-\r
-// made back-end by replacing MoveToEx and LineTo by DrawSegment\r
-/* Actually draw histogram as a diagram, cause there's too much data */\r
-static void DrawHistogramAsDiagram( int cy, int paint_width, int hist_count )\r
-{\r
- double step;\r
- int i;\r
-\r
- /* Rescale the graph every few moves (as opposed to every move) */\r
- hist_count -= hist_count % 8;\r
- hist_count += 8;\r
- hist_count /= 2;\r
-\r
- step = (double) paint_width / (hist_count + 1);\r
-\r
- for( i=0; i<2; i++ ) {\r
- int index = currFirst;\r
- int side = (currCurrent + i + 1) & 1; /* Draw current side last */\r
- double x = MarginX + MarginW;\r
-\r
- if( (index & 1) != side ) {\r
- x += step / 2;\r
- index++;\r
- }\r
-\r
- DrawSegment( (int) x, cy, NULL, NULL, PEN_NONE );\r
-\r
- index += 2;\r
-\r
- while( index < currLast ) {\r
- x += step;\r
-\r
- DrawSeparator( index, (int) x );\r
-\r
- /* Extend line up to current point */\r
- if( currPvInfo[index].depth > 0 ) {\r
- DrawSegment((int) x, GetValueY( GetPvScore(index) ), NULL, NULL, PEN_BOLD + side );\r
- }\r
-\r
- index += 2;\r
- }\r
- }\r
-}\r
-\r
-// back-end, delete pen selection\r
-static void DrawHistogramFull( int cy, int hist_width, int hist_count )\r
-{\r
- int i;\r
-\r
-// SelectObject( hdcPB, GetStockObject(BLACK_PEN) );\r
-\r
- for( i=0; i<hist_count; i++ ) {\r
- int index = currFirst + i;\r
- int x = MarginX + MarginW + index * hist_width;\r
-\r
- /* Draw a separator every 10 moves */\r
- DrawSeparator( index, x );\r
-\r
- /* Draw histogram */\r
- if( currPvInfo[i].depth > 0 ) {\r
- DrawHistogram( x, cy, hist_width, GetPvScore(index), index & 1 );\r
- }\r
- }\r
-}\r
-\r
-typedef struct {\r
- int cy;\r
- int hist_width;\r
- int hist_count;\r
- int paint_width;\r
-} VisualizationData;\r
-\r
-// back-end\r
-static Boolean InitVisualization( VisualizationData * vd )\r
-{\r
- BOOL result = FALSE;\r
-\r
- vd->cy = nHeightPB / 2;\r
- vd->hist_width = MIN_HIST_WIDTH;\r
- vd->hist_count = currLast - currFirst;\r
- vd->paint_width = nWidthPB - MarginX - 2*MarginW;\r
-\r
- if( vd->hist_count > 0 ) {\r
- result = TRUE;\r
-\r
- /* Compute width */\r
- vd->hist_width = vd->paint_width / vd->hist_count;\r
-\r
- if( vd->hist_width > MAX_HIST_WIDTH ) vd->hist_width = MAX_HIST_WIDTH;\r
-\r
- vd->hist_width -= vd->hist_width % 2;\r
- }\r
-\r
- return result;\r
-}\r
-\r
-// back-end\r
-static void DrawHistograms()\r
-{\r
- VisualizationData vd;\r
-\r
- if( InitVisualization( &vd ) ) {\r
- if( vd.hist_width < MIN_HIST_WIDTH ) {\r
- DrawHistogramAsDiagram( vd.cy, vd.paint_width, vd.hist_count );\r
- }\r
- else {\r
- DrawHistogramFull( vd.cy, vd.hist_width, vd.hist_count );\r
- }\r
- }\r
-}\r
-\r
-// back-end\r
-int GetMoveIndexFromPoint( int x, int y )\r
-{\r
- int result = -1;\r
- int start_x = MarginX + MarginW;\r
- VisualizationData vd;\r
-\r
- if( x >= start_x && InitVisualization( &vd ) ) {\r
- /* Almost an hack here... we duplicate some of the paint logic */\r
- if( vd.hist_width < MIN_HIST_WIDTH ) {\r
- double step;\r
-\r
- vd.hist_count -= vd.hist_count % 8;\r
- vd.hist_count += 8;\r
- vd.hist_count /= 2;\r
-\r
- step = (double) vd.paint_width / (vd.hist_count + 1);\r
- step /= 2;\r
-\r
- result = (int) (0.5 + (double) (x - start_x) / step);\r
- }\r
- else {\r
- result = (x - start_x) / vd.hist_width;\r
- }\r
- }\r
-\r
- if( result >= currLast ) {\r
- result = -1;\r
- }\r
-\r
- return result;\r
-}\r
-\r
-// init and display part split of so they can be moved to front end\r
-void PaintEvalGraph( void )\r
-{\r
- /* Draw */\r
- DrawRectangle(0, 0, nWidthPB, nHeightPB, 2, FILLED);\r
- DrawAxis();\r
- DrawHistograms();\r
-}\r
-\r
-// ------------------------------------------ front-end starts here ----------------------------------------------\r
-\r
-#include <commdlg.h>\r
-#include <dlgs.h>\r
-\r