2 * Move history for WinBoard
4 * Author: Alessandro Scotti (Dec 2005)
6 * ------------------------------------------------------------------------
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * ------------------------------------------------------------------------
24 #include <windows.h> /* required for all Windows applications */
39 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
40 VOID MoveHistoryPopUp();
41 VOID MoveHistoryPopDown();
42 BOOL MoveHistoryIsUp();
44 /* Imports from backend.c */
45 char * SavePart(char *str);
47 /* Imports from winboard.c */
48 extern HWND moveHistoryDialog;
49 extern BOOLEAN moveHistoryDialogUp;
51 extern HINSTANCE hInst;
54 extern WindowPlacement wpMoveHistory;
57 typedef char MoveHistoryString[ MOVE_LEN*2 ];
59 static int lastFirst = 0;
60 static int lastLast = 0;
61 static int lastCurrent = -1;
63 static char lastLastMove[ MOVE_LEN ];
65 static MoveHistoryString * currMovelist;
66 static ChessProgramStats_Move * currPvInfo;
67 static int currFirst = 0;
68 static int currLast = 0;
69 static int currCurrent = -1;
76 static HistoryMove histMoves[ MAX_MOVES ];
78 #define WM_REFRESH_HISTORY (WM_USER+4657)
80 #define DEFAULT_COLOR 0xFFFFFFFF
85 /* Note: in the following code a "Memo" is a Rich Edit control (it's Delphi lingo) */
87 static VOID HighlightMove( int index, BOOL highlight )
89 if( index >= 0 && index < MAX_MOVES ) {
91 HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );
95 histMoves[index].memoOffset,
96 histMoves[index].memoOffset + histMoves[index].memoLength );
100 ZeroMemory( &cf, sizeof(cf) );
102 cf.cbSize = sizeof(cf);
103 cf.dwMask = CFM_BOLD | CFM_COLOR;
106 cf.dwEffects |= CFE_BOLD;
107 cf.crTextColor = RGB( 0x00, 0x00, 0xFF );
110 cf.dwEffects |= CFE_AUTOCOLOR;
113 SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf );
117 static BOOL OnlyCurrentPositionChanged()
121 if( lastFirst >= 0 &&
122 lastLast >= lastFirst &&
123 lastCurrent >= lastFirst &&
124 currFirst == lastFirst &&
125 currLast == lastLast &&
131 /* Special case: last move changed */
132 if( currCurrent == currLast-1 ) {
133 if( strcmp( currMovelist[currCurrent], lastLastMove ) != 0 ) {
142 static BOOL OneMoveAppended()
146 if( lastCurrent >= 0 && lastCurrent >= lastFirst && lastLast >= lastFirst &&
147 currCurrent >= 0 && currCurrent >= currFirst && currLast >= currFirst &&
148 lastFirst == currFirst &&
149 lastLast == (currLast-1) &&
150 lastCurrent == (currCurrent-1) &&
151 currCurrent == (currLast-1) &&
160 static VOID ClearMemo()
162 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_SETTEXT, 0, (LPARAM) "" );
165 static int AppendToMemo( char * text, DWORD flags, DWORD color )
169 HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );
171 /* Select end of text */
172 int cbTextLen = (int) SendMessage( hMemo, WM_GETTEXTLENGTH, 0, 0 );
174 SendMessage( hMemo, EM_SETSEL, cbTextLen, cbTextLen );
177 ZeroMemory( &cf, sizeof(cf) );
179 cf.cbSize = sizeof(cf);
180 cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_COLOR | CFM_UNDERLINE;
181 cf.dwEffects = flags;
183 if( color != DEFAULT_COLOR ) {
184 cf.crTextColor = color;
187 cf.dwEffects |= CFE_AUTOCOLOR;
190 SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf );
193 SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
195 /* Return offset of appended text */
199 static VOID AppendMoveToMemo( int index )
203 DWORD color = DEFAULT_COLOR;
205 if( index < 0 || index >= MAX_MOVES ) {
212 if( (index % 2) == 0 ) {
213 sprintf( buf, "%d.%s ", (index / 2)+1, index & 1 ? ".." : "" );
214 AppendToMemo( buf, CFE_BOLD, DEFAULT_COLOR );
218 strcpy( buf, SavePart( currMovelist[index] ) );
221 histMoves[index].memoOffset = AppendToMemo( buf, flags, color );
222 histMoves[index].memoLength = strlen(buf)-1;
224 /* PV info (if any) */
225 if( appData.showEvalInMoveHistory && currPvInfo[index].depth > 0 ) {
226 sprintf( buf, "{%s%.2f/%d} ",
227 currPvInfo[index].score >= 0 ? "+" : "",
228 currPvInfo[index].score / 100.0,
229 currPvInfo[index].depth );
231 AppendToMemo( buf, flags,
232 color == DEFAULT_COLOR ? GetSysColor(COLOR_GRAYTEXT) : color );
236 static void RefreshMemoContent()
242 for( i=currFirst; i<currLast; i++ ) {
243 AppendMoveToMemo( i );
247 static void MemoContentUpdated()
251 HighlightMove( lastCurrent, FALSE );
252 HighlightMove( currCurrent, TRUE );
254 lastFirst = currFirst;
256 lastCurrent = currCurrent;
257 lastLastMove[0] = '\0';
260 strcpy( lastLastMove, SavePart( currMovelist[lastLast-1] ) );
263 /* Deselect any text, move caret to end of memo */
264 if( currCurrent >= 0 ) {
265 caretPos = histMoves[currCurrent].memoOffset + histMoves[currCurrent].memoLength;
268 caretPos = (int) SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_GETTEXTLENGTH, 0, 0 );
271 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETSEL, caretPos, caretPos );
273 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SCROLLCARET, 0, 0 );
276 int FindMoveByCharIndex( int char_index )
280 for( index=currFirst; index<currLast; index++ ) {
281 if( char_index >= histMoves[index].memoOffset &&
282 char_index < (histMoves[index].memoOffset + histMoves[index].memoLength) )
291 LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
297 if( moveHistoryDialog == NULL ) {
298 moveHistoryDialog = hDlg;
300 /* Enable word wrapping and notifications */
301 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETTARGETDEVICE, 0, 0 );
303 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS );
305 /* Restore window placement */
306 RestoreWindowPlacement( hDlg, &wpMoveHistory );
310 RefreshMemoContent();
312 MemoContentUpdated();
317 switch (LOWORD(wParam)) {
319 EndDialog(hDlg, TRUE);
323 EndDialog(hDlg, FALSE);
333 if( wParam == IDC_MoveHistory ) {
334 MSGFILTER * lpMF = (MSGFILTER *) lParam;
336 if( lpMF->msg == WM_LBUTTONDBLCLK && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ) {
340 pt.x = LOWORD( lpMF->lParam );
341 pt.y = HIWORD( lpMF->lParam );
343 index = SendDlgItemMessage( hDlg, IDC_MoveHistory, EM_CHARFROMPOS, 0, (LPARAM) &pt );
345 index = FindMoveByCharIndex( index );
348 ToNrEvent( index + 1 );
351 /* Zap the message for good: apparently, returning non-zero is not enough */
359 case WM_REFRESH_HISTORY:
361 if( OnlyCurrentPositionChanged() ) {
362 /* Only "cursor" changed, no need to update memo content */
364 else if( OneMoveAppended() ) {
365 AppendMoveToMemo( currCurrent );
368 RefreshMemoContent();
371 MemoContentUpdated();
376 SetWindowPos( GetDlgItem( moveHistoryDialog, IDC_MoveHistory ),
379 LOWORD(lParam) - 2*H_MARGIN,
380 HIWORD(lParam) - 2*V_MARGIN,
384 case WM_GETMINMAXINFO:
386 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
388 mmi->ptMinTrackSize.x = 100;
389 mmi->ptMinTrackSize.y = 100;
394 MoveHistoryPopDown();
397 case WM_ENTERSIZEMOVE:
398 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
401 return OnSizing( &sd, hDlg, wParam, lParam );
404 return OnMoving( &sd, hDlg, wParam, lParam );
406 case WM_EXITSIZEMOVE:
407 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
413 VOID MoveHistoryPopUp()
417 CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_CHECKED);
419 if( moveHistoryDialog ) {
420 SendMessage( moveHistoryDialog, WM_INITDIALOG, 0, 0 );
422 if( ! moveHistoryDialogUp ) {
423 ShowWindow(moveHistoryDialog, SW_SHOW);
427 lpProc = MakeProcInstance( (FARPROC) HistoryDialogProc, hInst );
429 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
430 CreateDialog( hInst, MAKEINTRESOURCE(DLG_MoveHistory), hwndMain, (DLGPROC)lpProc );
432 FreeProcInstance(lpProc);
435 moveHistoryDialogUp = TRUE;
438 VOID MoveHistoryPopDown()
440 CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_UNCHECKED);
442 if( moveHistoryDialog ) {
443 ShowWindow(moveHistoryDialog, SW_HIDE);
446 moveHistoryDialogUp = FALSE;
449 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo )
451 /* [AS] Danger! For now we rely on the movelist parameter being a static variable! */
453 currMovelist = movelist;
456 currCurrent = current;
459 if( moveHistoryDialog ) {
460 SendMessage( moveHistoryDialog, WM_REFRESH_HISTORY, 0, 0 );
464 BOOL MoveHistoryIsUp()
466 return moveHistoryDialogUp;