Refactoring of move-history code
authorH.G. Muller <h.g.muller@hccnet.nl>
Thu, 21 Jan 2010 13:32:46 +0000 (14:32 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 30 Jan 2010 08:41:43 +0000 (09:41 +0100)
The WinBoard code in whistory.c was split in a front-end part (remaining
in whistory.c) and a back-end part (now in history.c in the xboard
directory). This to allow easy porting to other platforms.

history.c [new file with mode: 0644]
winboard/makefile.gcc
winboard/makefile.ms
winboard/whistory.c

diff --git a/history.c b/history.c
new file mode 100644 (file)
index 0000000..4598799
--- /dev/null
+++ b/history.c
@@ -0,0 +1,246 @@
+/*
+ * Move history for WinBoard
+ *
+ * Author: Alessandro Scotti (Dec 2005)
+ * back-end part split off by HGM
+ *
+ * Copyright 2005 Alessandro Scotti
+ *
+ * ------------------------------------------------------------------------
+ *
+ * GNU XBoard is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU XBoard is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/. 
+ *
+ * ------------------------------------------------------------------------
+ ** See the file ChangeLog for a revision history.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "common.h"
+#include "frontend.h"
+#include "backend.h"
+
+/* templates for low-level front-end tasks (requiring platform-dependent implementation) */
+void ClearHistoryMemo P((void));                                   // essential
+int AppendToHistoryMemo P(( char * text, int bold, int colorNr )); // essential (coloring / styling optional)
+void HighlightMove P(( int from, int to, Boolean highlight ));     // optional (can be dummy)
+void ScrollToCurrent P((int caretPos));                            // optional (can be dummy)
+
+/* templates for front-end entry point to allow inquiring about front-end state */
+Boolean MoveHistoryDialogExists P((void));
+Boolean MoveHistoryIsUp P((void));
+
+/* Module globals */
+typedef char MoveHistoryString[ MOVE_LEN*2 ];
+
+static int lastFirst = 0;
+static int lastLast = 0;
+static int lastCurrent = -1;
+
+static char lastLastMove[ MOVE_LEN ];
+
+static MoveHistoryString * currMovelist;
+static ChessProgramStats_Move * currPvInfo;
+static int currFirst = 0;
+static int currLast = 0;
+static int currCurrent = -1;
+
+typedef struct {
+    int memoOffset;
+    int memoLength;
+} HistoryMove;
+
+static HistoryMove histMoves[ MAX_MOVES ];
+
+/* Note: in the following code a "Memo" is a Rich Edit control (it's Delphi lingo) */
+
+// back-end after replacing Windows data-types by equivalents
+static Boolean OnlyCurrentPositionChanged()
+{
+    Boolean result = FALSE;
+
+    if( lastFirst >= 0 &&
+        lastLast >= lastFirst &&
+        lastCurrent >= lastFirst && 
+        currFirst == lastFirst &&
+        currLast == lastLast &&
+        currCurrent >= 0 &&
+        TRUE )
+    {
+        result = TRUE;
+
+        /* Special case: last move changed */
+        if( currCurrent == currLast-1 ) {
+            if( strcmp( currMovelist[currCurrent], lastLastMove ) != 0 ) {
+                result = FALSE;
+            }
+        }
+    }
+
+    return result;
+}
+
+// back-end, after replacing Windows data types
+static Boolean OneMoveAppended()
+{
+    Boolean result = FALSE;
+
+    if( lastCurrent >= 0 && lastCurrent >= lastFirst && lastLast >= lastFirst &&
+        currCurrent >= 0 && currCurrent >= currFirst && currLast >= currFirst &&
+        lastFirst == currFirst &&
+        lastLast == (currLast-1) &&
+        lastCurrent == (currCurrent-1) &&
+        currCurrent == (currLast-1) &&
+        TRUE )
+    {
+        result = TRUE;
+    }
+
+    return result;
+}
+
+// back-end, now that color and font-style are passed as numbers
+static void AppendMoveToMemo( int index )
+{
+    char buf[64];
+
+    if( index < 0 || index >= MAX_MOVES ) {
+        return;
+    }
+
+    buf[0] = '\0';
+
+    /* Move number */
+    if( (index % 2) == 0 ) {
+        sprintf( buf, "%d.%s ", (index / 2)+1, index & 1 ? ".." : "" );
+        AppendToHistoryMemo( buf, 1, 0 ); // [HGM] 1 means bold, 0 default color
+    }
+
+    /* Move text */
+    strcpy( buf, SavePart( currMovelist[index] ) );
+    strcat( buf, " " );
+
+    histMoves[index].memoOffset = AppendToHistoryMemo( buf, 0, 0 );
+    histMoves[index].memoLength = strlen(buf)-1;
+
+    /* PV info (if any) */
+    if( appData.showEvalInMoveHistory && currPvInfo[index].depth > 0 ) {
+        sprintf( buf, "{%s%.2f/%d} ", 
+            currPvInfo[index].score >= 0 ? "+" : "",
+            currPvInfo[index].score / 100.0,
+            currPvInfo[index].depth );
+
+        AppendToHistoryMemo( buf, 0, 1); // [HGM] 1 means gray
+    }
+}
+
+// back-end
+void RefreshMemoContent()
+{
+    int i;
+
+    ClearHistoryMemo();
+
+    for( i=currFirst; i<currLast; i++ ) {
+        AppendMoveToMemo( i );
+    }
+}
+
+// back-end part taken out of HighlightMove to determine character positions
+static void DoHighlight(int index, int onoff)
+{
+    if( index >= 0 && index < MAX_MOVES ) {
+        HighlightMove( histMoves[index].memoOffset, 
+            histMoves[index].memoOffset + histMoves[index].memoLength, onoff );
+    }
+}
+
+// back-end, now that a wrapper is provided for the front-end code to do the actual scrolling
+void MemoContentUpdated()
+{
+    int caretPos;
+
+    DoHighlight( lastCurrent, FALSE );
+    DoHighlight( currCurrent, TRUE );
+
+    lastFirst = currFirst;
+    lastLast = currLast;
+    lastCurrent = currCurrent;
+    lastLastMove[0] = '\0';
+
+    if( lastLast > 0 ) {
+        strcpy( lastLastMove, SavePart( currMovelist[lastLast-1] ) );
+    }
+
+    /* Deselect any text, move caret to end of memo */
+    if( currCurrent >= 0 ) {
+        caretPos = histMoves[currCurrent].memoOffset + histMoves[currCurrent].memoLength;
+    }
+    else {
+        caretPos = -1;
+    }
+
+    ScrollToCurrent(caretPos);
+}
+
+// back-end. Must be called as double-click call-back on move-history text edit
+void FindMoveByCharIndex( int char_index )
+{
+    int index;
+
+    for( index=currFirst; index<currLast; index++ ) {
+        if( char_index >= histMoves[index].memoOffset &&
+            char_index <  (histMoves[index].memoOffset + histMoves[index].memoLength) )
+        {
+            ToNrEvent( index + 1 ); // moved here from call-back
+        }
+    }
+}
+
+// back-end. In WinBoard called by call-back, but could be called directly by SetIfExists?
+void UpdateMoveHistory()
+{
+        /* Update the GUI */
+        if( OnlyCurrentPositionChanged() ) {
+            /* Only "cursor" changed, no need to update memo content */
+        }
+        else if( OneMoveAppended() ) {
+            AppendMoveToMemo( currCurrent );
+        }
+        else {
+            RefreshMemoContent();
+        }
+
+        MemoContentUpdated();
+}
+
+// back-end
+void MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo )
+{
+    /* [AS] Danger! For now we rely on the movelist parameter being a static variable! */
+
+    currMovelist = movelist;
+    currFirst = first;
+    currLast = last;
+    currCurrent = current;
+    currPvInfo = pvInfo;
+
+    if(MoveHistoryDialogExists())
+        UpdateMoveHistory(); // [HGM] call this directly, in stead of through call-back
+}
+
index 6bb84c8..778883e 100644 (file)
@@ -6,7 +6,7 @@ PROJ=winboard
 \r
 OBJS=backend.o book.o gamelist.o lists.o moves.o pgntags.o uci.o zippy.o\\r
  parser.o wbres.o wclipbrd.o wedittags.o wengineoutput.o wevalgraph.o\\r
- wgamelist.o whistory.o winboard.o wlayout.o woptions.o wsnap.o\\r
+ wgamelist.o whistory.o history.o winboard.o wlayout.o woptions.o wsnap.o\\r
  wsockerr.o help.o wsettings.o wchat.o engineoutput.o evalgraph.o\r
 \r
 \r
@@ -137,6 +137,10 @@ whistory.o: whistory.c config.h ../common.h ../frontend.h ../backend.h \
        ../lists.h winboard.h resource.h wsnap.h\r
        $(call compile, $<)\r
 \r
+history.o: ../history.c config.h ../common.h ../frontend.h ../backend.h \\r
+       ../lists.h\r
+       $(call compile, $<)\r
+\r
 wevalgraph.o: wevalgraph.c ../evalgraph.h config.h ../common.h ../frontend.h \\r
        ../backend.h ../lists.h winboard.h resource.h wsnap.h\r
        $(call compile, $<)\r
index ca127b5..759139e 100644 (file)
@@ -14,7 +14,7 @@ PROJ = winboard
 \r
 OBJS=backend.obj book.obj gamelist.obj lists.obj moves.obj pgntags.obj uci.obj\\r
  zippy.obj parser.obj wclipbrd.obj wedittags.obj wengineoutput.obj wevalgraph.obj\\r
- wgamelist.obj whistory.obj winboard.obj wlayout.obj woptions.obj wsnap.obj\\r
+ wgamelist.obj whistory.obj history.obj winboard.obj wlayout.obj woptions.obj wsnap.obj\\r
  wsockerr.obj help.obj wsettings.obj wchat.obj engineoutput.obj evalgraph.obj\r
 \r
 \r
@@ -145,6 +145,10 @@ whistory.obj: whistory.c config.h ../common.h ../frontend.h ../backend.h \
        ../lists.h winboard.h resource.h wsnap.h\r
         $(CC) $(CFLAGS) whistory.c\r
 \r
+history.obj: ../history.c config.h ../common.h ../frontend.h ../backend.h \\r
+       ../lists.h\r
+        $(CC) $(CFLAGS) whistory.c\r
+\r
 wevalgraph.obj: wevalgraph.c config.h ../common.h ../frontend.h ../backend.h \\r
        ../lists.h winboard.h resource.h wsnap.h\r
         $(CC) $(CFLAGS) wevalgraph.c\r
index 0a42f18..854557a 100644 (file)
@@ -2,6 +2,7 @@
  * 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
 \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
-static VOID HighlightMove( int index, BOOL highlight )\r
+// ------------- low-level front-end actions called by MoveHistory back-end -----------------\r
+\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
@@ -99,60 +79,24 @@ static VOID HighlightMove( int index, BOOL highlight )
         }\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
@@ -184,98 +128,21 @@ static int AppendToMemo( char * text, DWORD flags, DWORD color )
     return cbTextLen;\r
 }\r
 \r
-static VOID AppendMoveToMemo( int index )\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
+// low-level front-end; wrapper for the code to scroll the mentioned character in view (-1 = end)\r
+void ScrollToCurrent(int caretPos)\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
@@ -333,11 +200,7 @@ LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPAR
 \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
@@ -347,22 +210,6 @@ LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPAR
         }\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
@@ -401,6 +248,9 @@ LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPAR
     return FALSE;\r
 }\r
 \r
+// ------------ standard entry points into MoveHistory code -----------\r
+\r
+// front-end\r
 VOID MoveHistoryPopUp()\r
 {\r
   FARPROC lpProc;\r
@@ -424,8 +274,13 @@ VOID MoveHistoryPopUp()
   }\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
@@ -437,22 +292,14 @@ VOID MoveHistoryPopDown()
   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
-Boolean MoveHistoryIsUp()\r
+// front-end\r
+Boolean MoveHistoryDialogExists()\r
 {\r
-    return moveHistoryDialogUp;\r
+    return moveHistoryDialog != NULL;\r
 }\r