X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=winboard%2Fwhistory.c;fp=winboard%2Fwhistory.c;h=ba69a63c7873a5f1937b41f81f637ad8ce8cf1b4;hb=2380bd9a886c088ba6040d99932c20cdf080fbbb;hp=0000000000000000000000000000000000000000;hpb=3076655d51195e09429c2abde2763e917d3a67a9;p=xboard.git diff --git a/winboard/whistory.c b/winboard/whistory.c new file mode 100644 index 0000000..ba69a63 --- /dev/null +++ b/winboard/whistory.c @@ -0,0 +1,453 @@ +/* + * Move history for WinBoard + * + * Author: Alessandro Scotti + * + * ------------------------------------------------------------------------ + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------ + */ +#include "config.h" + +#include /* required for all Windows applications */ +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "winboard.h" +#include "frontend.h" +#include "backend.h" + +#include "wsnap.h" + +VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo ); +VOID MoveHistoryPopUp(); +VOID MoveHistoryPopDown(); +BOOL MoveHistoryIsUp(); + +/* Imports from backend.c */ +char * SavePart(char *str); + +/* Imports from winboard.c */ +extern HWND moveHistoryDialog; +extern BOOLEAN moveHistoryDialogUp; + +extern HINSTANCE hInst; +extern HWND hwndMain; + +extern WindowPlacement wpMoveHistory; + +/* Module globals */ +typedef char MoveHistoryString[ MOVE_LEN*2 ]; + +static int lastFirst = 0; +static int lastLast = 0; +static int lastCurrent = -1; + +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 ]; + +#define WM_REFRESH_HISTORY (WM_USER+4657) + +#define DEFAULT_COLOR 0xFFFFFFFF + +#define H_MARGIN 2 +#define V_MARGIN 2 + +/* Note: in the following code a "Memo" is a Rich Edit control (it's Delphi lingo) */ + +static VOID HighlightMove( int index, BOOL highlight ) +{ + if( index >= 0 && index < MAX_MOVES ) { + CHARFORMAT cf; + HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory ); + + SendMessage( hMemo, + EM_SETSEL, + histMoves[index].memoOffset, + histMoves[index].memoOffset + histMoves[index].memoLength ); + + + /* Set style */ + ZeroMemory( &cf, sizeof(cf) ); + + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_BOLD | CFM_COLOR; + + if( highlight ) { + cf.dwEffects |= CFE_BOLD; + cf.crTextColor = RGB( 0x00, 0x00, 0xFF ); + } + else { + cf.dwEffects |= CFE_AUTOCOLOR; + } + + SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf ); + } +} + +static BOOL OnlyCurrentPositionChanged() +{ + BOOL result = FALSE; + + if( lastFirst >= 0 && + lastLast >= lastFirst && + lastCurrent >= lastFirst && + currFirst == lastFirst && + currLast == lastLast && + currCurrent >= 0 && + TRUE ) + { + result = TRUE; + } + + return result; +} + +static BOOL OneMoveAppended() +{ + BOOL 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; +} + +static VOID ClearMemo() +{ + SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_SETTEXT, 0, (LPARAM) "" ); +} + +static int AppendToMemo( char * text, DWORD flags, DWORD color ) +{ + CHARFORMAT cf; + + HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory ); + + /* Select end of text */ + int cbTextLen = (int) SendMessage( hMemo, WM_GETTEXTLENGTH, 0, 0 ); + + SendMessage( hMemo, EM_SETSEL, cbTextLen, cbTextLen ); + + /* Set style */ + ZeroMemory( &cf, sizeof(cf) ); + + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_COLOR | CFM_UNDERLINE; + cf.dwEffects = flags; + + if( color != DEFAULT_COLOR ) { + cf.crTextColor = color; + } + else { + cf.dwEffects |= CFE_AUTOCOLOR; + } + + SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf ); + + /* Append text */ + SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text ); + + /* Return offset of appended text */ + return cbTextLen; +} + +static VOID AppendMoveToMemo( int index ) +{ + char buf[64]; + DWORD flags = 0; + DWORD color = DEFAULT_COLOR; + + 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 ? ".." : "" ); + AppendToMemo( buf, CFE_BOLD, DEFAULT_COLOR ); + } + + /* Move text */ + strcpy( buf, SavePart( currMovelist[index] ) ); + strcat( buf, " " ); + + histMoves[index].memoOffset = AppendToMemo( buf, flags, color ); + 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 ); + + AppendToMemo( buf, flags, + color == DEFAULT_COLOR ? GetSysColor(COLOR_GRAYTEXT) : color ); + } +} + +static void RefreshMemoContent() +{ + int i; + + ClearMemo(); + + for( i=currFirst; i= 0 ) { + caretPos = histMoves[currCurrent].memoOffset + histMoves[currCurrent].memoLength; + } + else { + caretPos = (int) SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_GETTEXTLENGTH, 0, 0 ); + } + + SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETSEL, caretPos, caretPos ); + + SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SCROLLCARET, 0, 0 ); +} + +int FindMoveByCharIndex( int char_index ) +{ + int index; + + for( index=currFirst; index= histMoves[index].memoOffset && + char_index < (histMoves[index].memoOffset + histMoves[index].memoLength) ) + { + return index; + } + } + + return -1; +} + +LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) +{ + static SnapData sd; + + switch (message) { + case WM_INITDIALOG: + if( moveHistoryDialog == NULL ) { + moveHistoryDialog = hDlg; + + /* Enable word wrapping and notifications */ + SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETTARGETDEVICE, 0, 0 ); + + SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS ); + + /* Restore window placement */ + RestoreWindowPlacement( hDlg, &wpMoveHistory ); + } + + /* Update memo */ + RefreshMemoContent(); + + MemoContentUpdated(); + + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + EndDialog(hDlg, TRUE); + return TRUE; + + case IDCANCEL: + EndDialog(hDlg, FALSE); + return TRUE; + + default: + break; + } + + break; + + case WM_NOTIFY: + if( wParam == IDC_MoveHistory ) { + MSGFILTER * lpMF = (MSGFILTER *) lParam; + + if( lpMF->msg == WM_LBUTTONDBLCLK && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ) { + POINTL pt; + LRESULT index; + + pt.x = LOWORD( lpMF->lParam ); + pt.y = HIWORD( lpMF->lParam ); + + index = SendDlgItemMessage( hDlg, IDC_MoveHistory, EM_CHARFROMPOS, 0, (LPARAM) &pt ); + + index = FindMoveByCharIndex( index ); + + if( index >= 0 ) { + ToNrEvent( index + 1 ); + } + + /* Zap the message for good: apparently, returning non-zero is not enough */ + lpMF->msg = WM_USER; + + return TRUE; + } + } + break; + + case WM_REFRESH_HISTORY: + /* Update the GUI */ + if( OnlyCurrentPositionChanged() ) { + /* Only "cursor" changed, no need to update memo content */ + } + else if( OneMoveAppended() ) { + AppendMoveToMemo( currCurrent ); + } + else { + RefreshMemoContent(); + } + + MemoContentUpdated(); + + break; + + case WM_SIZE: + SetWindowPos( GetDlgItem( moveHistoryDialog, IDC_MoveHistory ), + HWND_TOP, + H_MARGIN, V_MARGIN, + LOWORD(lParam) - 2*H_MARGIN, + HIWORD(lParam) - 2*V_MARGIN, + SWP_NOZORDER ); + break; + + case WM_GETMINMAXINFO: + { + MINMAXINFO * mmi = (MINMAXINFO *) lParam; + + mmi->ptMinTrackSize.x = 100; + mmi->ptMinTrackSize.y = 100; + } + break; + + case WM_CLOSE: + MoveHistoryPopDown(); + break; + + case WM_ENTERSIZEMOVE: + return OnEnterSizeMove( &sd, hDlg, wParam, lParam ); + + case WM_SIZING: + return OnSizing( &sd, hDlg, wParam, lParam ); + + case WM_MOVING: + return OnMoving( &sd, hDlg, wParam, lParam ); + + case WM_EXITSIZEMOVE: + return OnExitSizeMove( &sd, hDlg, wParam, lParam ); + } + + return FALSE; +} + +VOID MoveHistoryPopUp() +{ + FARPROC lpProc; + + CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_CHECKED); + + if( moveHistoryDialog ) { + SendMessage( moveHistoryDialog, WM_INITDIALOG, 0, 0 ); + + if( ! moveHistoryDialogUp ) { + ShowWindow(moveHistoryDialog, SW_SHOW); + } + } + else { + lpProc = MakeProcInstance( (FARPROC) HistoryDialogProc, hInst ); + + /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */ + CreateDialog( hInst, MAKEINTRESOURCE(DLG_MoveHistory), hwndMain, (DLGPROC)lpProc ); + + FreeProcInstance(lpProc); + } + + moveHistoryDialogUp = TRUE; +} + +VOID MoveHistoryPopDown() +{ + CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_UNCHECKED); + + if( moveHistoryDialog ) { + ShowWindow(moveHistoryDialog, SW_HIDE); + } + + moveHistoryDialogUp = FALSE; +} + +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( moveHistoryDialog ) { + SendMessage( moveHistoryDialog, WM_REFRESH_HISTORY, 0, 0 ); + } +} + +BOOL MoveHistoryIsUp() +{ + return moveHistoryDialogUp; +}