* Move history for WinBoard\r
*\r
* Author: Alessandro Scotti (Dec 2005)\r
+ * front-end code split off by HGM\r
*\r
* Copyright 2005 Alessandro Scotti\r
*\r
+ * Enhancements Copyright 2009, 2010, 2014, 2015, 2016 Free Software\r
+ * Foundation, Inc.\r
+ *\r
* ------------------------------------------------------------------------\r
*\r
* GNU XBoard is free software: you can redistribute it and/or modify\r
* General Public License for more details.\r
*\r
* You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see http://www.gnu.org/licenses/. \r
+ * along with this program. If not, see http://www.gnu.org/licenses/.\r
*\r
* ------------------------------------------------------------------------\r
** See the file ChangeLog for a revision history. */\r
\r
#include "config.h"\r
\r
-#include <windows.h> /* required for all Windows applications */\r
-#include <richedit.h>\r
#include <stdio.h>\r
#include <stdlib.h>\r
#include <malloc.h>\r
+#include <windows.h> /* required for all Windows applications */\r
+#include <richedit.h>\r
#include <commdlg.h>\r
#include <dlgs.h>\r
\r
#include "frontend.h"\r
#include "backend.h"\r
#include "winboard.h"\r
-\r
#include "wsnap.h"\r
\r
-/* Module globals */\r
-typedef char MoveHistoryString[ MOVE_LEN*2 ];\r
-static BOOLEAN moveHistoryDialogUp = FALSE;\r
-\r
-static int lastFirst = 0;\r
-static int lastLast = 0;\r
-static int lastCurrent = -1;\r
-\r
-static char lastLastMove[ MOVE_LEN ];\r
-\r
-static MoveHistoryString * currMovelist;\r
-static ChessProgramStats_Move * currPvInfo;\r
-static int currFirst = 0;\r
-static int currLast = 0;\r
-static int currCurrent = -1;\r
-\r
-typedef struct {\r
- int memoOffset;\r
- int memoLength;\r
-} HistoryMove;\r
-\r
-static HistoryMove histMoves[ MAX_MOVES ];\r
-\r
-#define WM_REFRESH_HISTORY (WM_USER+4657)\r
+// templates for calls into back-end\r
+void RefreshMemoContent P((void));\r
+void MemoContentUpdated P((void));\r
+void FindMoveByCharIndex P(( int char_index ));\r
\r
#define DEFAULT_COLOR 0xFFFFFFFF\r
\r
#define H_MARGIN 2\r
#define V_MARGIN 2\r
\r
-/* Note: in the following code a "Memo" is a Rich Edit control (it's Delphi lingo) */\r
+static BOOLEAN moveHistoryDialogUp = FALSE;\r
+\r
+// ------------- low-level front-end actions called by MoveHistory back-end -----------------\r
\r
-static VOID HighlightMove( int index, BOOL highlight )\r
+// low-level front-end, after calculating from & to is left to caller\r
+// it task is to highlight the indicated characters. (In WinBoard it makes them bold and blue.)\r
+void HighlightMove( int from, int to, Boolean highlight )\r
{\r
- if( index >= 0 && index < MAX_MOVES ) {\r
CHARFORMAT cf;\r
HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );\r
\r
- SendMessage( hMemo, \r
- EM_SETSEL, \r
- histMoves[index].memoOffset, \r
- histMoves[index].memoOffset + histMoves[index].memoLength );\r
+ SendMessage( hMemo, EM_SETSEL, from, to);\r
\r
\r
/* Set style */\r
}\r
\r
SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf );\r
- }\r
-}\r
-\r
-static BOOL OnlyCurrentPositionChanged()\r
-{\r
- BOOL result = FALSE;\r
-\r
- if( lastFirst >= 0 &&\r
- lastLast >= lastFirst &&\r
- lastCurrent >= lastFirst && \r
- currFirst == lastFirst &&\r
- currLast == lastLast &&\r
- currCurrent >= 0 &&\r
- TRUE )\r
- {\r
- result = TRUE;\r
-\r
- /* Special case: last move changed */\r
- if( currCurrent == currLast-1 ) {\r
- if( strcmp( currMovelist[currCurrent], lastLastMove ) != 0 ) {\r
- result = FALSE;\r
- }\r
- }\r
- }\r
-\r
- return result;\r
-}\r
-\r
-static BOOL OneMoveAppended()\r
-{\r
- BOOL result = FALSE;\r
-\r
- if( lastCurrent >= 0 && lastCurrent >= lastFirst && lastLast >= lastFirst &&\r
- currCurrent >= 0 && currCurrent >= currFirst && currLast >= currFirst &&\r
- lastFirst == currFirst &&\r
- lastLast == (currLast-1) &&\r
- lastCurrent == (currCurrent-1) &&\r
- currCurrent == (currLast-1) &&\r
- TRUE )\r
- {\r
- result = TRUE;\r
- }\r
-\r
- return result;\r
}\r
\r
-static VOID ClearMemo()\r
+// low-level front-end, but replace Windows data types to make it callable from back-end\r
+// its task is to clear the contents of the move-history text edit\r
+void ClearHistoryMemo()\r
{\r
SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_SETTEXT, 0, (LPARAM) "" );\r
}\r
\r
-static int AppendToMemo( char * text, DWORD flags, DWORD color )\r
+// low-level front-end, made callable from back-end by passing flags and color numbers\r
+// its task is to append the given text to the text edit\r
+// the bold argument says 0 = normal, 1 = bold typeface\r
+// the colorNr argument says 0 = font-default, 1 = gray\r
+int AppendToHistoryMemo( char * text, int bold, int colorNr )\r
{\r
CHARFORMAT cf;\r
+ DWORD flags = bold ? CFE_BOLD :0;\r
+ DWORD color = colorNr ? GetSysColor(COLOR_GRAYTEXT) : DEFAULT_COLOR;\r
\r
HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );\r
\r
return cbTextLen;\r
}\r
\r
-static VOID AppendMoveToMemo( int index )\r
+// low-level front-end; wrapper for the code to scroll the mentioned character in view (-1 = end)\r
+void ScrollToCurrent(int caretPos)\r
{\r
- char buf[64];\r
- DWORD flags = 0;\r
- DWORD color = DEFAULT_COLOR;\r
-\r
- if( index < 0 || index >= MAX_MOVES ) {\r
- return;\r
- }\r
-\r
- buf[0] = '\0';\r
-\r
- /* Move number */\r
- if( (index % 2) == 0 ) {\r
- sprintf( buf, "%d.%s ", (index / 2)+1, index & 1 ? ".." : "" );\r
- AppendToMemo( buf, CFE_BOLD, DEFAULT_COLOR );\r
- }\r
-\r
- /* Move text */\r
- strcpy( buf, SavePart( currMovelist[index] ) );\r
- strcat( buf, " " );\r
-\r
- histMoves[index].memoOffset = AppendToMemo( buf, flags, color );\r
- histMoves[index].memoLength = strlen(buf)-1;\r
-\r
- /* PV info (if any) */\r
- if( appData.showEvalInMoveHistory && currPvInfo[index].depth > 0 ) {\r
- sprintf( buf, "{%s%.2f/%d} ", \r
- currPvInfo[index].score >= 0 ? "+" : "",\r
- currPvInfo[index].score / 100.0,\r
- currPvInfo[index].depth );\r
-\r
- AppendToMemo( buf, flags, \r
- color == DEFAULT_COLOR ? GetSysColor(COLOR_GRAYTEXT) : color );\r
- }\r
-}\r
-\r
-static void RefreshMemoContent()\r
-{\r
- int i;\r
-\r
- ClearMemo();\r
-\r
- for( i=currFirst; i<currLast; i++ ) {\r
- AppendMoveToMemo( i );\r
- }\r
-}\r
-\r
-static void MemoContentUpdated()\r
-{\r
- int caretPos;\r
-\r
- HighlightMove( lastCurrent, FALSE );\r
- HighlightMove( currCurrent, TRUE );\r
-\r
- lastFirst = currFirst;\r
- lastLast = currLast;\r
- lastCurrent = currCurrent;\r
- lastLastMove[0] = '\0';\r
-\r
- if( lastLast > 0 ) {\r
- strcpy( lastLastMove, SavePart( currMovelist[lastLast-1] ) );\r
- }\r
-\r
- /* Deselect any text, move caret to end of memo */\r
- if( currCurrent >= 0 ) {\r
- caretPos = histMoves[currCurrent].memoOffset + histMoves[currCurrent].memoLength;\r
- }\r
- else {\r
+ if(caretPos < 0)\r
caretPos = (int) SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_GETTEXTLENGTH, 0, 0 );\r
- }\r
-\r
SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETSEL, caretPos, caretPos );\r
\r
SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SCROLLCARET, 0, 0 );\r
}\r
\r
-int FindMoveByCharIndex( int char_index )\r
-{\r
- int index;\r
\r
- for( index=currFirst; index<currLast; index++ ) {\r
- if( char_index >= histMoves[index].memoOffset &&\r
- char_index < (histMoves[index].memoOffset + histMoves[index].memoLength) )\r
- {\r
- return index;\r
- }\r
- }\r
-\r
- return -1;\r
-}\r
+// ------------------------------ call backs --------------------------\r
\r
+// front-end. Universal call-back for any event. Recognized vents are dialog creation, OK and cancel button-press\r
+// (dead code, as these buttons do not exist?), mouse clicks on the text edit, and moving / sizing\r
LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
{\r
static SnapData sd;\r
case WM_INITDIALOG:\r
if( moveHistoryDialog == NULL ) {\r
moveHistoryDialog = hDlg;\r
+ Translate(hDlg, DLG_MoveHistory);\r
\r
/* Enable word wrapping and notifications */\r
SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETTARGETDEVICE, 0, 0 );\r
\r
index = SendDlgItemMessage( hDlg, IDC_MoveHistory, EM_CHARFROMPOS, 0, (LPARAM) &pt );\r
\r
- index = FindMoveByCharIndex( index );\r
-\r
- if( index >= 0 ) {\r
- ToNrEvent( index + 1 );\r
- }\r
+ FindMoveByCharIndex( index ); // [HGM] also does the actual moving to it, now\r
\r
/* Zap the message for good: apparently, returning non-zero is not enough */\r
lpMF->msg = WM_USER;\r
}\r
break;\r
\r
- case WM_REFRESH_HISTORY:\r
- /* Update the GUI */\r
- if( OnlyCurrentPositionChanged() ) {\r
- /* Only "cursor" changed, no need to update memo content */\r
- }\r
- else if( OneMoveAppended() ) {\r
- AppendMoveToMemo( currCurrent );\r
- }\r
- else {\r
- RefreshMemoContent();\r
- }\r
-\r
- MemoContentUpdated();\r
-\r
- break;\r
-\r
case WM_SIZE:\r
SetWindowPos( GetDlgItem( moveHistoryDialog, IDC_MoveHistory ),\r
HWND_TOP,\r
return FALSE;\r
}\r
\r
+// ------------ standard entry points into MoveHistory code -----------\r
+\r
+// front-end\r
VOID MoveHistoryPopUp()\r
{\r
FARPROC lpProc;\r
}\r
\r
moveHistoryDialogUp = TRUE;\r
+\r
+// Note that in WIndows creating the dialog causes its call-back to perform\r
+// RefreshMemoContent() and MemoContentUpdated() immediately after it is realized.\r
+// To port this to X we might have to do that from here.\r
}\r
\r
+// front-end\r
VOID MoveHistoryPopDown()\r
{\r
CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_UNCHECKED);\r
moveHistoryDialogUp = FALSE;\r
}\r
\r
-VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo )\r
+// front-end\r
+Boolean MoveHistoryIsUp()\r
{\r
- /* [AS] Danger! For now we rely on the movelist parameter being a static variable! */\r
-\r
- currMovelist = movelist;\r
- currFirst = first;\r
- currLast = last;\r
- currCurrent = current;\r
- currPvInfo = pvInfo;\r
-\r
- if( moveHistoryDialog ) {\r
- SendMessage( moveHistoryDialog, WM_REFRESH_HISTORY, 0, 0 );\r
- }\r
+ return moveHistoryDialogUp;\r
}\r
\r
-BOOL MoveHistoryIsUp()\r
+// front-end\r
+Boolean MoveHistoryDialogExists()\r
{\r
- return moveHistoryDialogUp;\r
+ return moveHistoryDialog != NULL;\r
}\r