*------------------------------------------------------------------------\r
** See the file ChangeLog for a revision history. */\r
\r
+// code refactored by HGM to obtain front-end / back-end separation\r
+\r
#include "config.h"\r
\r
#include <windows.h> /* required for all Windows applications */\r
-#include <richedit.h>\r
+//include <richedit.h>\r
#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <malloc.h>\r
-#include <commdlg.h>\r
-#include <dlgs.h>\r
+//include <stdlib.h>\r
+//include <malloc.h>\r
\r
#include "common.h"\r
-#include "winboard.h"\r
#include "frontend.h"\r
#include "backend.h"\r
\r
-#include "wsnap.h"\r
-\r
-VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
-VOID EvalGraphPopUp();\r
-VOID EvalGraphPopDown();\r
-BOOL EvalGraphIsUp();\r
-\r
-#define WM_REFRESH_GRAPH (WM_USER + 1)\r
-\r
-/* Imports from backend.c */\r
-char * SavePart(char *str);\r
-\r
/* Imports from winboard.c */\r
-extern HWND evalGraphDialog;\r
-extern BOOLEAN evalGraphDialogUp;\r
+extern BOOLEAN evalGraphDialogUp; // should be back-end variable, and defined here\r
\r
-extern HINSTANCE hInst;\r
-extern HWND hwndMain;\r
-\r
-extern WindowPlacement wpEvalGraph;\r
-\r
-/* Module globals */\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 COLORREF crWhite = RGB( 0xFF, 0xFF, 0xB0 );\r
-static COLORREF crBlack = RGB( 0xAD, 0x5D, 0x3D );\r
-\r
-static HDC hdcPB = NULL;\r
-static HBITMAP hbmPB = NULL;\r
static int nWidthPB = 0;\r
static int nHeightPB = 0;\r
-static HPEN hpenDotted = NULL;\r
-static HPEN hpenBlueDotted = NULL;\r
-static HPEN hpenBold[2] = { NULL, NULL };\r
-static HBRUSH hbrHist[2] = { NULL, NULL };\r
\r
static int MarginX = 18;\r
static int MarginW = 4;\r
#define MIN_HIST_WIDTH 4\r
#define MAX_HIST_WIDTH 10\r
\r
-static int GetPvScore( int index )\r
-{\r
- int score = currPvInfo[ index ].score;\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
- if( index & 1 ) score = -score; /* Flip score for black */\r
+#define FILLED 1\r
+#define OPEN 0\r
\r
- return score;\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
-static VOID DrawLine( int x1, int y1, int x2, int y2 )\r
-{\r
- MoveToEx( hdcPB, x1, y1, NULL );\r
\r
- LineTo( hdcPB, x2, y2 );\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
-static VOID DrawLineEx( int x1, int y1, int x2, int y2 )\r
+// back-end\r
+static void DrawLineEx( int x1, int y1, int x2, int y2, int penType )\r
{\r
- POINT stPT;\r
-\r
- MoveToEx( hdcPB, x1, y1, &stPT );\r
-\r
- LineTo( hdcPB, x2, y2 );\r
-\r
- MoveToEx( hdcPB, stPT.x, stPT.y, NULL );\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
-static HBRUSH CreateBrush( UINT style, COLORREF color )\r
+// back-end\r
+static int GetPvScore( int index )\r
{\r
- LOGBRUSH stLB;\r
+ int score = currPvInfo[ index ].score;\r
\r
- stLB.lbStyle = style;\r
- stLB.lbColor = color;\r
- stLB.lbHatch = 0;\r
+ if( index & 1 ) score = -score; /* Flip score for black */\r
\r
- return CreateBrushIndirect( &stLB );\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
return (nHeightPB / 2) - (int)(value * (nHeightPB - 2*MarginH) / 1400.0);\r
}\r
\r
-static VOID DrawAxisSegmentHoriz( int value, BOOL drawValue )\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
- SelectObject( hdcPB, GetStockObject(BLACK_PEN) );\r
- DrawLine( MarginX, y, MarginX + MarginW, y );\r
- SelectObject( hdcPB, hpenDotted );\r
- DrawLine( MarginX + MarginW, y, nWidthPB - MarginW, y );\r
-\r
if( drawValue ) {\r
- SIZE stSize;\r
char buf[MSG_SIZ], *b = buf;\r
- int cbBuf;\r
\r
if( value > 0 ) *b++ = '+';\r
sprintf(b, "%d", value);\r
\r
- cbBuf = strlen( buf );\r
- GetTextExtentPoint32( hdcPB, buf, cbBuf, &stSize );\r
- TextOut( hdcPB, MarginX - stSize.cx - 2, y - stSize.cy / 2, buf, cbBuf );\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
-static VOID DrawAxis()\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
+// SelectObject( hdcPB, GetStockObject(NULL_BRUSH) );\r
\r
- SetBkMode( hdcPB, TRANSPARENT );\r
+// SetBkMode( hdcPB, TRANSPARENT );\r
\r
DrawAxisSegmentHoriz( +5, TRUE );\r
DrawAxisSegmentHoriz( +3, FALSE );\r
DrawAxisSegmentHoriz( -3, FALSE );\r
DrawAxisSegmentHoriz( -5, TRUE );\r
\r
- SelectObject( hdcPB, GetStockObject(BLACK_PEN) );\r
-\r
- DrawLine( MarginX + MarginW, cy, nWidthPB - MarginW, cy );\r
- DrawLine( MarginX + MarginW, MarginH, MarginX + MarginW, nHeightPB - MarginH );\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
-static VOID DrawHistogram( int x, int y, int width, int value, int side )\r
+// back-end\r
+static void DrawHistogram( int x, int y, int width, int value, int side )\r
{\r
- RECT rc;\r
+ int left, top, right, bottom;\r
\r
if( value > -25 && value < +25 ) return;\r
\r
- rc.left = x;\r
- rc.right = rc.left + width + 1;\r
+ left = x;\r
+ right = left + width + 1;\r
\r
if( value > 0 ) {\r
- rc.top = GetValueY( value );\r
- rc.bottom = y+1;\r
+ top = GetValueY( value );\r
+ bottom = y+1;\r
}\r
else {\r
- rc.top = y;\r
- rc.bottom = GetValueY( value ) + 1;\r
+ top = y;\r
+ bottom = GetValueY( value ) + 1;\r
}\r
\r
\r
if( width == MIN_HIST_WIDTH ) {\r
- rc.right--;\r
- FillRect( hdcPB, &rc, hbrHist[side] );\r
+ right--;\r
+ DrawRectangle( left, top, right, bottom, side, FILLED );\r
}\r
else {\r
- SelectObject( hdcPB, hbrHist[side] );\r
- Rectangle( hdcPB, rc.left, rc.top, rc.right, rc.bottom );\r
+ DrawRectangle( left, top, right, bottom, side, OPEN );\r
}\r
}\r
\r
-static VOID DrawSeparator( int index, int x )\r
+// back-end\r
+static void DrawSeparator( int index, int x )\r
{\r
if( index > 0 ) {\r
if( index == currCurrent ) {\r
- HPEN hp = SelectObject( hdcPB, hpenBlueDotted );\r
- DrawLineEx( x, MarginH, x, nHeightPB - MarginH );\r
- SelectObject( hdcPB, hp );\r
+ DrawLineEx( x, MarginH, x, nHeightPB - MarginH, PEN_BLUEDOTTED );\r
}\r
else if( (index % 20) == 0 ) {\r
- HPEN hp = SelectObject( hdcPB, hpenDotted );\r
- DrawLineEx( x, MarginH, x, nHeightPB - MarginH );\r
- SelectObject( hdcPB, hp );\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
+static void DrawHistogramAsDiagram( int cy, int paint_width, int hist_count )\r
{\r
double step;\r
int i;\r
index++;\r
}\r
\r
- SelectObject( hdcPB, hpenBold[side] );\r
-\r
- MoveToEx( hdcPB, (int) x, cy, NULL );\r
+ DrawSegment( (int) x, cy, NULL, NULL, PEN_NONE );\r
\r
index += 2;\r
\r
\r
/* Extend line up to current point */\r
if( currPvInfo[index].depth > 0 ) {\r
- LineTo( hdcPB, (int) x, GetValueY( GetPvScore(index) ) );\r
+ DrawSegment((int) x, GetValueY( GetPvScore(index) ), NULL, NULL, PEN_BOLD + side );\r
}\r
\r
index += 2;\r
}\r
}\r
\r
-static VOID DrawHistogramFull( int cy, int hist_width, int hist_count )\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
+// SelectObject( hdcPB, GetStockObject(BLACK_PEN) );\r
\r
for( i=0; i<hist_count; i++ ) {\r
int index = currFirst + i;\r
int paint_width;\r
} VisualizationData;\r
\r
-static BOOL InitVisualization( VisualizationData * vd )\r
+// back-end\r
+static Boolean InitVisualization( VisualizationData * vd )\r
{\r
BOOL result = FALSE;\r
\r
return result;\r
}\r
\r
-static VOID DrawHistograms()\r
+// back-end\r
+static void DrawHistograms()\r
{\r
VisualizationData vd;\r
\r
}\r
}\r
\r
-static int GetMoveIndexFromPoint( int x, int y )\r
+// back-end\r
+int GetMoveIndexFromPoint( int x, int y )\r
{\r
int result = -1;\r
int start_x = MarginX + MarginW;\r
return result;\r
}\r
\r
-static VOID DrawBackground()\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
+Boolean EvalGraphIsUp()\r
{\r
- HBRUSH hbr;\r
+ return evalGraphDialogUp;\r
+}\r
+\r
+// ------------------------------------------ front-end starts here ----------------------------------------------\r
+\r
+#include <commdlg.h>\r
+#include <dlgs.h>\r
+\r
+#include "winboard.h"\r
+#include "wsnap.h"\r
+\r
+#define WM_REFRESH_GRAPH (WM_USER + 1)\r
+\r
+void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
+void EvalGraphPopUp();\r
+void EvalGraphPopDown();\r
+Boolean EvalGraphIsUp();\r
+\r
+// calls of front-end part into back-end part\r
+extern int GetMoveIndexFromPoint( int x, int y );\r
+extern void PaintEvalGraph( void );\r
+\r
+/* Imports from winboard.c */\r
+extern HWND evalGraphDialog;\r
+extern BOOLEAN evalGraphDialogUp; // should be back-end, really\r
+\r
+extern HINSTANCE hInst;\r
+extern HWND hwndMain;\r
+\r
+extern WindowPlacement wpEvalGraph;\r
+\r
+static COLORREF crWhite = RGB( 0xFF, 0xFF, 0xB0 );\r
+static COLORREF crBlack = RGB( 0xAD, 0x5D, 0x3D );\r
+\r
+static HDC hdcPB = NULL;\r
+static HBITMAP hbmPB = NULL;\r
+static HPEN pens[6]; // [HGM] put all pens in one array\r
+static HBRUSH hbrHist[3] = { NULL, NULL, NULL };\r
+\r
+// [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end) \r
+static void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )\r
+{\r
+ POINT stPt;\r
+ if(penType == PEN_NONE) MoveToEx( hdcPB, x, y, &stPt ); else {\r
+ HPEN hp = SelectObject( hdcPB, pens[penType] );\r
+ LineTo( hdcPB, x, y );\r
+ SelectObject( hdcPB, hp );\r
+ }\r
+ if(lastX != NULL) { *lastX = stPt.x; *lastY = stPt.y; }\r
+}\r
+\r
+// front-end wrapper for drawing functions to do rectangles\r
+void DrawRectangle( int left, int top, int right, int bottom, int side, int style )\r
+{\r
+ HPEN hp = SelectObject( hdcPB, pens[PEN_BLACK] );\r
RECT rc;\r
\r
- hbr = CreateBrush( BS_SOLID, GetSysColor( COLOR_3DFACE ) );\r
+ rc.top = top; rc.left = left; rc.bottom = bottom; rc.right = right;\r
+ if(style == FILLED)\r
+ FillRect( hdcPB, &rc, hbrHist[side] );\r
+ else {\r
+ SelectObject( hdcPB, hbrHist[side] );\r
+ Rectangle( hdcPB, left, top, right, bottom );\r
+ }\r
+ SelectObject( hdcPB, hp );\r
+}\r
+\r
+// front-end wrapper for putting text in graph\r
+void DrawEvalText(char *buf, int cbBuf, int y)\r
+{\r
+ SIZE stSize;\r
+ SetBkMode( hdcPB, TRANSPARENT );\r
+ GetTextExtentPoint32( hdcPB, buf, cbBuf, &stSize );\r
+ TextOut( hdcPB, MarginX - stSize.cx - 2, y - stSize.cy / 2, buf, cbBuf );\r
+}\r
\r
- rc.left = 0;\r
- rc.top = 0;\r
- rc.right = nWidthPB;\r
- rc.bottom = nHeightPB;\r
+// front-end\r
+static HBRUSH CreateBrush( UINT style, COLORREF color )\r
+{\r
+ LOGBRUSH stLB;\r
\r
- FillRect( hdcPB, &rc, hbr );\r
+ stLB.lbStyle = style;\r
+ stLB.lbColor = color;\r
+ stLB.lbHatch = 0;\r
\r
- DeleteObject( hbr );\r
+ return CreateBrushIndirect( &stLB );\r
}\r
\r
-static VOID PaintEvalGraph( HWND hWnd, HDC hDC )\r
+// front-end. Create pens, device context and buffer bitmap for global use, copy result to display\r
+// The back-end part n the middle has been taken out and moed to PainEvalGraph()\r
+static VOID DisplayEvalGraph( HWND hWnd, HDC hDC )\r
{\r
RECT rcClient;\r
int width;\r
\r
/* Create or recreate paint box if needed */\r
if( hbmPB == NULL || width != nWidthPB || height != nHeightPB ) {\r
- if( hpenDotted == NULL ) {\r
- hpenDotted = CreatePen( PS_DOT, 0, RGB(0xA0,0xA0,0xA0) );\r
- hpenBlueDotted = CreatePen( PS_DOT, 0, RGB(0x00,0x00,0xFF) );\r
- hpenBold[0] = CreatePen( PS_SOLID, 2, crWhite );\r
- hpenBold[1] = CreatePen( PS_SOLID, 2, crBlack );\r
+ if( pens[PEN_DOTTED] == NULL ) {\r
+ pens[PEN_BLACK] = GetStockObject(BLACK_PEN);\r
+ pens[PEN_DOTTED] = CreatePen( PS_DOT, 0, RGB(0xA0,0xA0,0xA0) );\r
+ pens[PEN_BLUEDOTTED] = CreatePen( PS_DOT, 0, RGB(0x00,0x00,0xFF) );\r
+ pens[PEN_BOLD] = CreatePen( PS_SOLID, 2, crWhite );\r
+ pens[PEN_BOLD+1] = CreatePen( PS_SOLID, 2, crBlack );\r
hbrHist[0] = CreateBrush( BS_SOLID, crWhite );\r
hbrHist[1] = CreateBrush( BS_SOLID, crBlack );\r
+ hbrHist[2] = CreateBrush( BS_SOLID, GetSysColor( COLOR_3DFACE ) ); // background\r
}\r
\r
if( hdcPB != NULL ) {\r
SelectObject( hdcPB, hbmPB );\r
}\r
\r
- /* Draw */\r
- DrawBackground();\r
- DrawAxis();\r
- DrawHistograms();\r
+ // back-end painting; calls back front-end primitives for lines, rectangles and text\r
+ PaintEvalGraph();\r
\r
/* Copy bitmap into destination DC */\r
- BitBlt( hDC, 0, 0, width, height, hdcPB, 0, 0, SRCCOPY );\r
+ BitBlt( hDC, 0, 0, nWidthPB, nHeightPB, hdcPB, 0, 0, SRCCOPY );\r
}\r
\r
+// Note: Once the eval graph is opened, this window-proc lives forever; een closing the\r
+// eval-graph window merely hides it. On opening we re-initialize it, though, so it could\r
+// as well hae been destroyed. While it is open it processes the REFRESH_GRAPH commands.\r
LRESULT CALLBACK EvalGraphProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
{\r
static SnapData sd;\r
\r
case WM_PAINT:\r
hDC = BeginPaint( hDlg, &stPS );\r
- PaintEvalGraph( hDlg, hDC );\r
+ DisplayEvalGraph( hDlg, hDC );\r
EndPaint( hDlg, &stPS );\r
break;\r
\r
case WM_REFRESH_GRAPH:\r
hDC = GetDC( hDlg );\r
- PaintEvalGraph( hDlg, hDC );\r
+ DisplayEvalGraph( hDlg, hDC );\r
ReleaseDC( hDlg, hDC );\r
break;\r
\r
return FALSE;\r
}\r
\r
+// creates the eval graph, or unhides it.\r
VOID EvalGraphPopUp()\r
{\r
FARPROC lpProc;\r
evalGraphDialogUp = TRUE;\r
}\r
\r
+// Note that this hides the window. It could as well have destroyed it.\r
VOID EvalGraphPopDown()\r
{\r
CheckMenuItem(GetMenu(hwndMain), IDM_ShowEvalGraph, MF_UNCHECKED);\r
evalGraphDialogUp = FALSE;\r
}\r
\r
+// This function is the interface to the back-end. It is currently called through the front-end,\r
+// though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends\r
+// support the eval graph, it would be more logical to call it directly from the back-end.\r
VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )\r
{\r
/* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */\r
}\r
}\r
\r
-BOOL EvalGraphIsUp()\r
-{\r
- return evalGraphDialogUp;\r
-}\r