2 * wevalgraph.c - Evaluation graph front-end part
\r
4 * Author: Alessandro Scotti (Dec 2005)
\r
6 * Copyright 2005 Alessandro Scotti
\r
8 * Enhancements Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015,
\r
9 * 2016 Free Software Foundation, Inc.
\r
11 * ------------------------------------------------------------------------
\r
13 * GNU XBoard is free software: you can redistribute it and/or modify
\r
14 * it under the terms of the GNU General Public License as published by
\r
15 * the Free Software Foundation, either version 3 of the License, or (at
\r
16 * your option) any later version.
\r
18 * GNU XBoard is distributed in the hope that it will be useful, but
\r
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
21 * General Public License for more details.
\r
23 * You should have received a copy of the GNU General Public License
\r
24 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
26 *------------------------------------------------------------------------
\r
27 ** See the file ChangeLog for a revision history. */
\r
29 // code refactored by HGM to obtain front-end / back-end separation
\r
33 #include <windows.h>
\r
34 #include <commdlg.h>
\r
39 #include "frontend.h"
\r
40 #include "backend.h"
\r
41 #include "winboard.h"
\r
42 #include "evalgraph.h"
\r
45 #define WM_REFRESH_GRAPH (WM_USER + 1)
\r
47 /* Module globals */
\r
48 static BOOLEAN evalGraphDialogUp;
\r
50 static COLORREF crWhite = RGB( 0xFF, 0xFF, 0xB0 );
\r
51 static COLORREF crBlack = RGB( 0xAD, 0x5D, 0x3D );
\r
53 static HDC hdcPB = NULL;
\r
54 static HBITMAP hbmPB = NULL;
\r
55 static HPEN pens[PEN_ANY+1]; // [HGM] put all pens in one array
\r
56 static HBRUSH hbrHist[3] = { NULL, NULL, NULL };
\r
58 Boolean EvalGraphIsUp()
\r
60 return evalGraphDialogUp;
\r
63 // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end)
\r
64 void DrawSegment( int x, int y, int *lastX, int *lastY, int penType )
\r
67 if(penType == PEN_NONE) MoveToEx( hdcPB, x, y, &stPt ); else {
\r
68 HPEN hp = SelectObject( hdcPB, pens[penType] );
\r
69 LineTo( hdcPB, x, y );
\r
70 SelectObject( hdcPB, hp );
\r
72 if(lastX != NULL) { *lastX = stPt.x; *lastY = stPt.y; }
\r
75 // front-end wrapper for drawing functions to do rectangles
\r
76 void DrawRectangle( int left, int top, int right, int bottom, int side, int style )
\r
78 HPEN hp = SelectObject( hdcPB, pens[PEN_BLACK] );
\r
81 rc.top = top; rc.left = left; rc.bottom = bottom; rc.right = right;
\r
83 FillRect( hdcPB, &rc, hbrHist[side] );
\r
85 SelectObject( hdcPB, hbrHist[side] );
\r
86 Rectangle( hdcPB, left, top, right, bottom );
\r
88 SelectObject( hdcPB, hp );
\r
91 // front-end wrapper for putting text in graph
\r
92 void DrawEvalText(char *buf, int cbBuf, int y)
\r
95 SetBkMode( hdcPB, TRANSPARENT );
\r
96 GetTextExtentPoint32( hdcPB, buf, cbBuf, &stSize );
\r
97 TextOut( hdcPB, MarginX - stSize.cx - 2, y - stSize.cy / 2, buf, cbBuf );
\r
101 static HBRUSH CreateBrush( UINT style, COLORREF color )
\r
105 stLB.lbStyle = style;
\r
106 stLB.lbColor = color;
\r
109 return CreateBrushIndirect( &stLB );
\r
112 // front-end. Create pens, device context and buffer bitmap for global use, copy result to display
\r
113 // The back-end part n the middle has been taken out and moed to PainEvalGraph()
\r
114 static VOID DisplayEvalGraph( HWND hWnd, HDC hDC )
\r
120 /* Get client area */
\r
121 GetClientRect( hWnd, &rcClient );
\r
123 width = rcClient.right - rcClient.left;
\r
124 height = rcClient.bottom - rcClient.top;
\r
126 /* Create or recreate paint box if needed */
\r
127 if( hbmPB == NULL || width != nWidthPB || height != nHeightPB ) {
\r
128 if( pens[PEN_DOTTED] == NULL ) {
\r
129 pens[PEN_BLACK] = GetStockObject(BLACK_PEN);
\r
130 pens[PEN_DOTTED] = CreatePen( PS_DOT, 0, RGB(0xA0,0xA0,0xA0) );
\r
131 pens[PEN_BLUEDOTTED] = CreatePen( PS_DOT, 0, RGB(0x00,0x00,0xFF) );
\r
132 pens[PEN_BOLDWHITE] = CreatePen( PS_SOLID, 2, crWhite );
\r
133 pens[PEN_BOLDBLACK] = CreatePen( PS_SOLID, 2, crBlack );
\r
134 hbrHist[0] = CreateBrush( BS_SOLID, crWhite );
\r
135 hbrHist[1] = CreateBrush( BS_SOLID, crBlack );
\r
136 hbrHist[2] = CreateBrush( BS_SOLID, GetSysColor( COLOR_3DFACE ) ); // background
\r
139 if( hdcPB != NULL ) {
\r
144 if( hbmPB != NULL ) {
\r
145 DeleteObject( hbmPB );
\r
149 hdcPB = CreateCompatibleDC( hDC );
\r
152 nHeightPB = height;
\r
153 hbmPB = CreateCompatibleBitmap( hDC, nWidthPB, nHeightPB );
\r
155 SelectObject( hdcPB, hbmPB );
\r
158 // back-end painting; calls back front-end primitives for lines, rectangles and text
\r
160 SetWindowText(hWnd, MakeEvalTitle(differentialView ? T_("Blunder Graph") : T_("Evaluation Graph")));
\r
162 /* Copy bitmap into destination DC */
\r
163 BitBlt( hDC, 0, 0, nWidthPB, nHeightPB, hdcPB, 0, 0, SRCCOPY );
\r
166 // Note: Once the eval graph is opened, this window-proc lives forever; een closing the
\r
167 // eval-graph window merely hides it. On opening we re-initialize it, though, so it could
\r
168 // as well hae been destroyed. While it is open it processes the REFRESH_GRAPH commands.
\r
169 LRESULT CALLBACK EvalGraphProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
\r
171 static SnapData sd;
\r
177 case WM_INITDIALOG:
\r
178 Translate(hDlg, DLG_EvalGraph);
\r
179 if( evalGraphDialog == NULL ) {
\r
180 evalGraphDialog = hDlg;
\r
182 RestoreWindowPlacement( hDlg, &wpEvalGraph ); /* Restore window placement */
\r
188 switch (LOWORD(wParam)) {
\r
190 EndDialog(hDlg, TRUE);
\r
194 EndDialog(hDlg, FALSE);
\r
203 case WM_ERASEBKGND:
\r
207 hDC = BeginPaint( hDlg, &stPS );
\r
208 DisplayEvalGraph( hDlg, hDC );
\r
209 EndPaint( hDlg, &stPS );
\r
212 case WM_MOUSEWHEEL:
\r
213 if((short)HIWORD(wParam) < 0) appData.zoom++;
\r
214 if((short)HIWORD(wParam) > 0 && appData.zoom > 1) appData.zoom--;
\r
216 case WM_RBUTTONDOWN:
\r
217 differentialView = !differentialView;
\r
218 case WM_REFRESH_GRAPH:
\r
220 hDC = GetDC( hDlg );
\r
221 DisplayEvalGraph( hDlg, hDC );
\r
222 ReleaseDC( hDlg, hDC );
\r
225 case WM_LBUTTONDOWN:
\r
226 if( wParam == 0 || wParam == MK_LBUTTON ) {
\r
227 int index = GetMoveIndexFromPoint( LOWORD(lParam), HIWORD(lParam) );
\r
229 if( index >= 0 && index < currLast ) {
\r
230 ToNrEvent( index + 1 );
\r
236 InvalidateRect( hDlg, NULL, FALSE );
\r
239 case WM_GETMINMAXINFO:
\r
241 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
\r
243 mmi->ptMinTrackSize.x = 100;
\r
244 mmi->ptMinTrackSize.y = 100;
\r
248 /* Support for captionless window */
\r
250 EvalGraphPopDown();
\r
253 case WM_ENTERSIZEMOVE:
\r
254 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
257 return OnSizing( &sd, hDlg, wParam, lParam );
\r
260 return OnMoving( &sd, hDlg, wParam, lParam );
\r
262 case WM_EXITSIZEMOVE:
\r
263 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
269 // creates the eval graph, or unhides it.
\r
270 VOID EvalGraphPopUp()
\r
274 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEvalGraph, MF_CHECKED);
\r
276 if( evalGraphDialog ) {
\r
277 SendMessage( evalGraphDialog, WM_INITDIALOG, 0, 0 );
\r
279 if( ! evalGraphDialogUp ) {
\r
280 ShowWindow(evalGraphDialog, SW_SHOW);
\r
284 crWhite = appData.evalHistColorWhite;
\r
285 crBlack = appData.evalHistColorBlack;
\r
287 lpProc = MakeProcInstance( (FARPROC) EvalGraphProc, hInst );
\r
289 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
\r
290 CreateDialog( hInst, MAKEINTRESOURCE(DLG_EvalGraph), hwndMain, (DLGPROC)lpProc );
\r
292 FreeProcInstance(lpProc);
\r
295 evalGraphDialogUp = TRUE;
\r
298 // Note that this hides the window. It could as well have destroyed it.
\r
299 VOID EvalGraphPopDown()
\r
301 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEvalGraph, MF_UNCHECKED);
\r
303 if( evalGraphDialog ) {
\r
304 ShowWindow(evalGraphDialog, SW_HIDE);
\r
307 evalGraphDialogUp = FALSE;
\r
310 // This function is the interface to the back-end. It is currently called through the front-end,
\r
311 // though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends
\r
312 // support the eval graph, it would be more logical to call it directly from the back-end.
\r
313 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo )
\r
315 /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */
\r
319 currCurrent = current;
\r
320 currPvInfo = pvInfo;
\r
322 if( evalGraphDialog ) {
\r
323 SendMessage( evalGraphDialog, WM_REFRESH_GRAPH, 0, 0 );
\r