2 * Move history for WinBoard
4 * Author: Alessandro Scotti
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 MoveHistoryString * currMovelist;
64 static ChessProgramStats_Move * currPvInfo;
65 static int currFirst = 0;
66 static int currLast = 0;
67 static int currCurrent = -1;
74 static HistoryMove histMoves[ MAX_MOVES ];
76 #define WM_REFRESH_HISTORY (WM_USER+4657)
78 #define DEFAULT_COLOR 0xFFFFFFFF
83 /* Note: in the following code a "Memo" is a Rich Edit control (it's Delphi lingo) */
85 static VOID HighlightMove( int index, BOOL highlight )
87 if( index >= 0 && index < MAX_MOVES ) {
89 HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );
93 histMoves[index].memoOffset,
94 histMoves[index].memoOffset + histMoves[index].memoLength );
98 ZeroMemory( &cf, sizeof(cf) );
100 cf.cbSize = sizeof(cf);
101 cf.dwMask = CFM_BOLD | CFM_COLOR;
104 cf.dwEffects |= CFE_BOLD;
105 cf.crTextColor = RGB( 0x00, 0x00, 0xFF );
108 cf.dwEffects |= CFE_AUTOCOLOR;
111 SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf );
115 static BOOL OnlyCurrentPositionChanged()
119 if( lastFirst >= 0 &&
120 lastLast >= lastFirst &&
121 lastCurrent >= lastFirst &&
122 currFirst == lastFirst &&
123 currLast == lastLast &&
133 static BOOL OneMoveAppended()
137 if( lastCurrent >= 0 && lastCurrent >= lastFirst && lastLast >= lastFirst &&
138 currCurrent >= 0 && currCurrent >= currFirst && currLast >= currFirst &&
139 lastFirst == currFirst &&
140 lastLast == (currLast-1) &&
141 lastCurrent == (currCurrent-1) &&
142 currCurrent == (currLast-1) &&
151 static VOID ClearMemo()
153 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_SETTEXT, 0, (LPARAM) "" );
156 static int AppendToMemo( char * text, DWORD flags, DWORD color )
160 HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );
162 /* Select end of text */
163 int cbTextLen = (int) SendMessage( hMemo, WM_GETTEXTLENGTH, 0, 0 );
165 SendMessage( hMemo, EM_SETSEL, cbTextLen, cbTextLen );
168 ZeroMemory( &cf, sizeof(cf) );
170 cf.cbSize = sizeof(cf);
171 cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_COLOR | CFM_UNDERLINE;
172 cf.dwEffects = flags;
174 if( color != DEFAULT_COLOR ) {
175 cf.crTextColor = color;
178 cf.dwEffects |= CFE_AUTOCOLOR;
181 SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf );
184 SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
186 /* Return offset of appended text */
190 static VOID AppendMoveToMemo( int index )
194 DWORD color = DEFAULT_COLOR;
196 if( index < 0 || index >= MAX_MOVES ) {
203 if( (index % 2) == 0 ) {
204 sprintf( buf, "%d.%s ", (index / 2)+1, index & 1 ? ".." : "" );
205 AppendToMemo( buf, CFE_BOLD, DEFAULT_COLOR );
209 strcpy( buf, SavePart( currMovelist[index] ) );
212 histMoves[index].memoOffset = AppendToMemo( buf, flags, color );
213 histMoves[index].memoLength = strlen(buf)-1;
215 /* PV info (if any) */
216 if( appData.showEvalInMoveHistory && currPvInfo[index].depth > 0 ) {
217 sprintf( buf, "%{%s%.2f/%d} ",
218 currPvInfo[index].score >= 0 ? "+" : "",
219 currPvInfo[index].score / 100.0,
220 currPvInfo[index].depth );
222 AppendToMemo( buf, flags,
223 color == DEFAULT_COLOR ? GetSysColor(COLOR_GRAYTEXT) : color );
227 static void RefreshMemoContent()
233 for( i=currFirst; i<currLast; i++ ) {
234 AppendMoveToMemo( i );
238 static void MemoContentUpdated()
242 HighlightMove( lastCurrent, FALSE );
243 HighlightMove( currCurrent, TRUE );
245 lastFirst = currFirst;
247 lastCurrent = currCurrent;
249 /* Deselect any text, move caret to end of memo */
250 if( currCurrent >= 0 ) {
251 caretPos = histMoves[currCurrent].memoOffset + histMoves[currCurrent].memoLength;
254 caretPos = (int) SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_GETTEXTLENGTH, 0, 0 );
257 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETSEL, caretPos, caretPos );
259 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SCROLLCARET, 0, 0 );
262 int FindMoveByCharIndex( int char_index )
266 for( index=currFirst; index<currLast; index++ ) {
267 if( char_index >= histMoves[index].memoOffset &&
268 char_index < (histMoves[index].memoOffset + histMoves[index].memoLength) )
277 LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
283 if( moveHistoryDialog == NULL ) {
284 moveHistoryDialog = hDlg;
286 /* Enable word wrapping and notifications */
287 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETTARGETDEVICE, 0, 0 );
289 SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS );
291 /* Restore window placement */
292 RestoreWindowPlacement( hDlg, &wpMoveHistory );
296 RefreshMemoContent();
298 MemoContentUpdated();
303 switch (LOWORD(wParam)) {
305 EndDialog(hDlg, TRUE);
309 EndDialog(hDlg, FALSE);
319 if( wParam == IDC_MoveHistory ) {
320 MSGFILTER * lpMF = (MSGFILTER *) lParam;
322 if( lpMF->msg == WM_LBUTTONDBLCLK && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ) {
326 pt.x = LOWORD( lpMF->lParam );
327 pt.y = HIWORD( lpMF->lParam );
329 index = SendDlgItemMessage( hDlg, IDC_MoveHistory, EM_CHARFROMPOS, 0, (LPARAM) &pt );
331 index = FindMoveByCharIndex( index );
334 ToNrEvent( index + 1 );
337 /* Zap the message for good: apparently, returning non-zero is not enough */
345 case WM_REFRESH_HISTORY:
347 if( OnlyCurrentPositionChanged() ) {
348 /* Only "cursor" changed, no need to update memo content */
350 else if( OneMoveAppended() ) {
351 AppendMoveToMemo( currCurrent );
354 RefreshMemoContent();
357 MemoContentUpdated();
362 SetWindowPos( GetDlgItem( moveHistoryDialog, IDC_MoveHistory ),
365 LOWORD(lParam) - 2*H_MARGIN,
366 HIWORD(lParam) - 2*V_MARGIN,
370 case WM_GETMINMAXINFO:
372 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
374 mmi->ptMinTrackSize.x = 100;
375 mmi->ptMinTrackSize.y = 100;
380 MoveHistoryPopDown();
383 case WM_ENTERSIZEMOVE:
384 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
387 return OnSizing( &sd, hDlg, wParam, lParam );
390 return OnMoving( &sd, hDlg, wParam, lParam );
392 case WM_EXITSIZEMOVE:
393 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
399 VOID MoveHistoryPopUp()
403 CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_CHECKED);
405 if( moveHistoryDialog ) {
406 SendMessage( moveHistoryDialog, WM_INITDIALOG, 0, 0 );
408 if( ! moveHistoryDialogUp ) {
409 ShowWindow(moveHistoryDialog, SW_SHOW);
413 lpProc = MakeProcInstance( (FARPROC) HistoryDialogProc, hInst );
415 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
416 CreateDialog( hInst, MAKEINTRESOURCE(DLG_MoveHistory), hwndMain, (DLGPROC)lpProc );
418 FreeProcInstance(lpProc);
421 moveHistoryDialogUp = TRUE;
424 VOID MoveHistoryPopDown()
426 CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_UNCHECKED);
428 if( moveHistoryDialog ) {
429 ShowWindow(moveHistoryDialog, SW_HIDE);
432 moveHistoryDialogUp = FALSE;
435 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo )
437 /* [AS] Danger! For now we rely on the movelist parameter being a static variable! */
439 currMovelist = movelist;
442 currCurrent = current;
445 if( moveHistoryDialog ) {
446 SendMessage( moveHistoryDialog, WM_REFRESH_HISTORY, 0, 0 );
450 BOOL MoveHistoryIsUp()
452 return moveHistoryDialogUp;