From: A. Scotti Date: Thu, 16 Apr 2009 21:04:02 +0000 (-0700) Subject: changes from Alessandro Scotti from 20051231 X-Git-Tag: v4.3.2~4 X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=commitdiff_plain;h=2380bd9a886c088ba6040d99932c20cdf080fbbb changes from Alessandro Scotti from 20051231 --- diff --git a/backend.c b/backend.c index b347a3e..d545851 100644 --- a/backend.c +++ b/backend.c @@ -47,7 +47,7 @@ * * See the file ChangeLog for a revision history. */ -/* [AS] For debugging purposes */ +/* [AS] Also useful here for debugging */ #ifdef WIN32 #include @@ -144,12 +144,6 @@ typedef struct { int seen_stat; /* 1 if we've seen the stat01: line */ } ChessProgramStats; -/* [AS] Search stats from chessprogram, for the played move */ -typedef struct { - int score; - int depth; -} ChessProgramStats_Move; - int establish P((void)); void read_from_player P((InputSourceRef isr, VOIDSTAR closure, char *buf, int count, int error)); @@ -222,6 +216,8 @@ void InitBackEnd3 P((void)); void FeatureDone P((ChessProgramState* cps, int val)); void InitChessProgram P((ChessProgramState *cps)); +void GetInfoFromComment( int, char * ); + extern int tinyLayout, smallLayout; static ChessProgramStats programStats; @@ -2905,6 +2901,7 @@ ParseBoard12(string) movesPerSession = 0; gameInfo.timeControl = TimeControlTagValue(); gameInfo.variant = StringToVariant(gameInfo.event); + gameInfo.outOfBook = NULL; /* Do we have the ratings? */ if (strcmp(player1Name, white) == 0 && @@ -3573,7 +3570,7 @@ InitPosition(redraw) } if (redraw) - DrawPosition(FALSE, boards[currentMove]); + DrawPosition(TRUE, boards[currentMove]); } void @@ -4037,6 +4034,16 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar) } } +void SendProgramStatsToFrontend( ChessProgramState * cps ) +{ + SetProgramStats( cps == &first ? 0 : 1, + programStats.depth, + programStats.nodes, + programStats.score, + programStats.time, + programStats.movelist ); +} + void HandleMachineMove(message, cps) char *message; @@ -4080,11 +4087,9 @@ HandleMachineMove(message, cps) /* * Look for machine move. */ - if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && - strcmp(buf2, "...") == 0) || - (sscanf(message, "%s %s", buf1, machineMove) == 2 && - strcmp(buf1, "move") == 0)) { - + if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && strcmp(buf2, "...") == 0) || + (sscanf(message, "%s %s", buf1, machineMove) == 2 && strcmp(buf1, "move") == 0)) + { /* This method is only useful on engines that support ping */ if (cps->lastPing != cps->lastPong) { if (gameMode == BeginningOfGame) { @@ -4184,6 +4189,7 @@ HandleMachineMove(message, cps) /* [AS] Save move info and clear stats for next move */ pvInfoList[ forwardMostMove ].score = programStats.score; pvInfoList[ forwardMostMove ].depth = programStats.depth; + pvInfoList[ forwardMostMove ].time = -1; ClearProgramStats(); thinkOutput[0] = NULLCHAR; hiddenThinkOutputState = 0; @@ -4219,6 +4225,14 @@ HandleMachineMove(message, cps) } } + if( appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) { + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + + GameEnds( GameIsDrawn, "Xboard adjudication: long game", GE_XBOARD ); + + return; + } + if (gameMode == TwoMachinesPlay) { if (cps->other->sendTime) { SendTimeRemaining(cps->other, @@ -4702,19 +4716,21 @@ HandleMachineMove(message, cps) if (plyext != ' ' && plyext != '\t') { time *= 100; } - programStats.depth = plylev; - programStats.nodes = nodes; - programStats.time = time; - programStats.score = curscore; - programStats.got_only_move = 0; - /* [AS] Negate score if machine is playing black and it's reporting absolute scores */ + /* [AS] Negate score if machine is playing black and reporting absolute scores */ if( cps->scoreIsAbsolute && ((gameMode == MachinePlaysBlack) || (gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b')) ) { - programStats.score = -curscore; + curscore = -curscore; } + + programStats.depth = plylev; + programStats.nodes = nodes; + programStats.time = time; + programStats.score = curscore; + programStats.got_only_move = 0; + /* Buffer overflow protection */ if (buf1[0] != NULLCHAR) { if (strlen(buf1) >= sizeof(programStats.movelist) @@ -4741,6 +4757,8 @@ HandleMachineMove(message, cps) programStats.line_is_book = 0; } + SendProgramStatsToFrontend( cps ); + /* [AS] Protect the thinkOutput buffer from overflow... this is only useful if buf1 hasn't overflowed first! @@ -4791,6 +4809,8 @@ HandleMachineMove(message, cps) isn't searching, so stats won't change) */ programStats.line_is_book = 1; + SendProgramStatsToFrontend( cps ); + if (currentMove == forwardMostMove || gameMode==AnalyzeMode || gameMode == AnalyzeFile) { DisplayMove(currentMove - 1); DisplayAnalysis(); @@ -4814,6 +4834,9 @@ HandleMachineMove(message, cps) programStats.nr_moves = mvtot; strcpy(programStats.move_name, mvname); programStats.ok_to_send = 1; + + SendProgramStatsToFrontend( cps ); + DisplayAnalysis(); return; @@ -5262,6 +5285,7 @@ ShowMove(fromX, fromY, toX, toY) } if (instant) return; + DisplayMove(currentMove - 1); DrawPosition(FALSE, boards[currentMove]); DisplayBothClocks(); @@ -5812,6 +5836,10 @@ AutoPlayOneMove() if (currentMove >= forwardMostMove) { gameMode = EditGame; ModeHighlight(); + + /* [AS] Clear current move marker at the end of a game */ + /* HistorySet(parseList, backwardMostMove, forwardMostMove, -1); */ + return FALSE; } @@ -5825,6 +5853,9 @@ AutoPlayOneMove() } else { fromX = moveList[currentMove][0] - 'a'; fromY = moveList[currentMove][1] - '1'; + + HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove); /* [AS] */ + AnimateMove(boards[currentMove], fromX, fromY, toX, toY); if (appData.highlightLastMove) { @@ -6546,10 +6577,12 @@ LoadGame(f, gameNumber, title, useList) gameInfo.variant = StringToVariant(gameInfo.event); } if (!matchMode) { + if( appData.autoDisplayTags ) { tags = PGNTags(&gameInfo); TagsPopUp(tags, CmailMsg()); free(tags); } + } } else { /* Make something up, but don't display it now */ SetGameInfo(); @@ -6951,6 +6984,80 @@ SavePart(str) #define PGN_MAX_LINE 75 +#define PGN_SIDE_WHITE 0 +#define PGN_SIDE_BLACK 1 + +static int FindFirstMoveOutOfBook( int side ) +{ + int result = -1; + + if( backwardMostMove == 0 && ! startedFromSetupPosition) { + int index = backwardMostMove; + int has_book_hit = 0; + + if( (index % 2) != side ) { + index++; + } + + while( index < forwardMostMove ) { + /* Check to see if engine is in book */ + int depth = pvInfoList[index].depth; + int score = pvInfoList[index].score; + int in_book = 0; + + if( depth == 0 ) { + in_book = 1; /* Yace */ + } + if( score == 0 ) { + if( depth <= 1 || depth == 63 /* Zappa */ ) { + in_book = 1; + } + } + + has_book_hit += in_book; + + if( ! in_book ) { + result = index; + + break; + } + + index += 2; + } + } + + return result; +} + +void GetOutOfBookInfo( char * buf ) +{ + int oob[2]; + int i; + int offset = backwardMostMove & (~1L); /* output move numbers start at 1 */ + + oob[0] = FindFirstMoveOutOfBook( PGN_SIDE_WHITE ); + oob[1] = FindFirstMoveOutOfBook( PGN_SIDE_BLACK ); + + *buf = '\0'; + + if( oob[0] >= 0 || oob[1] >= 0 ) { + for( i=0; i<2; i++ ) { + int idx = oob[i]; + + if( idx >= 0 ) { + if( i > 0 && oob[0] >= 0 ) { + strcat( buf, " " ); + } + + sprintf( buf+strlen(buf), "%d%s. ", (idx - offset)/2 + 1, idx & 1 ? ".." : "" ); + sprintf( buf+strlen(buf), "%s%.2f", + pvInfoList[idx].score >= 0 ? "+" : "", + pvInfoList[idx].score / 100.0 ); + } + } + } +} + /* Save game in PGN style and close the file */ int SaveGamePGN(f) @@ -6963,6 +7070,8 @@ SaveGamePGN(f) int movelen, numlen, blank; char move_buffer[100]; /* [AS] Buffer for move+PV info */ + offset = backwardMostMove & (~1L); /* output move numbers start at 1 */ + tm = time((time_t *) NULL); PrintPGNTags(f, &gameInfo); @@ -6974,12 +7083,23 @@ SaveGamePGN(f) PrintPosition(f, backwardMostMove); fprintf(f, "--------------}\n"); free(fen); - } else { + } + else { + /* [AS] Out of book annotation */ + if( appData.saveOutOfBookInfo ) { + char buf[64]; + + GetOutOfBookInfo( buf ); + + if( buf[0] != '\0' ) { + fprintf( f, "[%s \"%s\"]\n", PGN_OUT_OF_BOOK, buf ); + } + } + fprintf(f, "\n"); } i = backwardMostMove; - offset = backwardMostMove & (~1L); /* output move numbers start at 1 */ linelen = 0; newblock = TRUE; @@ -8204,6 +8324,7 @@ EditPositionDone() gameMode = EditGame; ModeHighlight(); HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1); + ClearHighlights(); /* [AS] */ } /* Pause for `ms' milliseconds */ @@ -8711,6 +8832,8 @@ void BackwardInner(target) int target; { + int full_redraw = TRUE; /* [AS] Was FALSE, had to change it! */ + if (appData.debugMode) fprintf(debugFP, "BackwardInner(%d), current %d, forward %d\n", target, currentMove, forwardMostMove); @@ -8718,7 +8841,7 @@ BackwardInner(target) if (gameMode == EditPosition) return; if (currentMove <= backwardMostMove) { ClearHighlights(); - DrawPosition(FALSE, boards[currentMove]); + DrawPosition(full_redraw, boards[currentMove]); return; } if (gameMode == PlayFromGameFile && !pausing) @@ -8759,7 +8882,7 @@ BackwardInner(target) } DisplayBothClocks(); DisplayMove(currentMove - 1); - DrawPosition(FALSE, boards[currentMove]); + DrawPosition(full_redraw, boards[currentMove]); HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); if (commentList[currentMove] != NULL) { DisplayComment(currentMove - 1, commentList[currentMove]); @@ -8851,7 +8974,7 @@ RetractMoveEvent() DisplayBothClocks(); DisplayMove(currentMove - 1); ClearHighlights();/*!! could figure this out*/ - DrawPosition(FALSE, boards[currentMove]); + DrawPosition(TRUE, boards[currentMove]); /* [AS] Changed to full redraw! */ SendToProgram("remove\n", &first); /*first.maybeThinking = TRUE;*/ /* GNU Chess does not ponder here */ break; @@ -9210,6 +9333,8 @@ AppendComment(index, text) int oldlen, len; char *old; + GetInfoFromComment( index, text ); + CrushCRs(text); while (*text == '\n') text++; len = strlen(text); @@ -9234,6 +9359,78 @@ AppendComment(index, text) } } +static char * FindStr( char * text, char * sub_text ) +{ + char * result = strstr( text, sub_text ); + + if( result != NULL ) { + result += strlen( sub_text ); + } + + return result; +} + +/* [AS] Try to extract PV info from PGN comment */ +void GetInfoFromComment( int index, char * text ) +{ + if( text != NULL && index > 0 ) { + int score = 0; + int depth = 0; + int time = -1; + char * s_eval = FindStr( text, "[%eval " ); + char * s_emt = FindStr( text, "[%emt " ); + + if( s_eval != NULL || s_emt != NULL ) { + /* New style */ + char delim; + + if( s_eval != NULL ) { + if( sscanf( s_eval, "%d,%d%c", &score, &depth, &delim ) != 3 ) { + return; + } + + if( delim != ']' ) { + return; + } + } + + if( s_emt != NULL ) { + } + } + else { + /* We expect something like: [+|-]nnn.nn/dd */ + char * sep = strchr( text, '/' ); + int score_lo = 0; + + if( sep == NULL || sep < (text+4) ) { + return; + } + + if( sscanf( text, "%d.%d/%d", &score, &score_lo, &depth ) != 3 ) { + return; + } + + if( score_lo < 0 || score_lo >= 100 ) { + return; + } + + score = score >= 0 ? score*100 + score_lo : score*100 - score_lo; + } + + if( depth <= 0 ) { + return; + } + + if( time < 0 ) { + time = -1; + } + + pvInfoList[index-1].depth = depth; + pvInfoList[index-1].score = score; + pvInfoList[index-1].time = time; + } +} + void SendToProgram(message, cps) char *message; @@ -9763,6 +9960,7 @@ DisplayComment(moveNumber, text) { char title[MSG_SIZ]; + if( appData.autoDisplayComment ) { if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) { strcpy(title, "Comment"); } else { @@ -9772,6 +9970,7 @@ DisplayComment(moveNumber, text) } CommentPopUp(title, text); + } } /* This routine sends a ^C interrupt to gnuchess, to awaken it if it diff --git a/backend.h b/backend.h index 9d74c57..b08a092 100644 --- a/backend.h +++ b/backend.h @@ -196,11 +196,11 @@ void ClearGameInfo P((GameInfo *)); int GameListBuild P((FILE *)); void GameListInitGameInfo P((GameInfo *)); char *GameListLine P((int, GameInfo *)); +char * GameListLineFull P(( int, GameInfo *)); extern char* StripHighlight P((char *)); /* returns static data */ extern char* StripHighlightAndTitle P((char *)); /* returns static data */ - typedef struct _CPS { char *which; int maybeThinking; @@ -241,12 +241,21 @@ typedef struct _CPS { /* Added by Tord: */ int useFEN960; /* 0=use "KQkq" style FENs, 1=use "HAha" style FENs */ - int useOOCastle; /* 0="O-O" notation for castling, 1="king capture rook" - * notation */ + int useOOCastle; /* 0="O-O" notation for castling, 1="king capture rook" notation */ /* End of additions by Tord */ + int scoreIsAbsolute; /* [AS] 0=don't know (standard), 1=score is always from white side */ } ChessProgramState; extern ChessProgramState first, second; +/* [AS] Search stats from chessprogram, for the played move */ +typedef struct { + int score; /* Centipawns */ + int depth; /* Plies */ + int time; /* Milliseconds */ +} ChessProgramStats_Move; + +extern ChessProgramStats_Move pvInfoList[MAX_MOVES]; + #endif /* _BACKEND */ diff --git a/common.h b/common.h index 2cca437..140f94f 100644 --- a/common.h +++ b/common.h @@ -407,7 +407,7 @@ typedef struct { int firstProtocolVersion; int secondProtocolVersion; Boolean showButtonBar; - /* [AS] New properties */ + /* [AS] New properties (down to the "ZIPPY" part) */ Boolean firstScoreIsAbsolute; /* If true, engine score is always from white side */ Boolean secondScoreIsAbsolute; /* If true, engine score is always from white side */ Boolean saveExtendedInfoInPGN; /* If true, saved PGN games contain extended info */ @@ -430,6 +430,17 @@ typedef struct { char * nameOfDebugFile; char * pgnEventHeader; int defaultFrcPosition; + char * gameListTags; + Boolean saveOutOfBookInfo; + Boolean showEvalInMoveHistory; + int evalHistColorWhite; + int evalHistColorBlack; + Boolean highlightMoveWithArrow; + int highlightArrowColor; + Boolean useStickyWindows; + int adjudicateDrawMoves; + Boolean autoDisplayComment; + Boolean autoDisplayTags; #if ZIPPY char *zippyLines; char *zippyPinhead; @@ -450,6 +461,25 @@ typedef struct { #endif } AppData, *AppDataPtr; +/* [AS] PGN tags (for showing in the game list) */ +#define GLT_EVENT 'e' +#define GLT_SITE 's' +#define GLT_DATE 'd' +#define GLT_ROUND 'o' +#define GLT_PLAYERS 'p' /* I.e. white "-" black */ +#define GLT_RESULT 'r' +#define GLT_WHITE_ELO 'w' +#define GLT_BLACK_ELO 'b' +#define GLT_TIME_CONTROL 't' +#define GLT_VARIANT 'v' +#define GLT_OUT_OF_BOOK 'a' + +#define GLT_DEFAULT_TAGS "eprd" /* Event, players, result, date */ + +#define GLT_ALL_TAGS "esdoprwbtva" + +#define PGN_OUT_OF_BOOK "Annotator" + extern AppData appData; typedef struct { @@ -469,6 +499,7 @@ typedef struct { int whiteRating; /* -1 if unknown */ int blackRating; /* -1 if unknown */ VariantClass variant; + char *outOfBook; /* [AS] Move and score when engine went out of book */ } GameInfo; diff --git a/frontend.h b/frontend.h index 732b316..ef79f23 100644 --- a/frontend.h +++ b/frontend.h @@ -164,10 +164,11 @@ void ClearPremoveHighlights P((void)); void ShutDownFrontEnd P((void)); void BoardToTop P((void)); void AnimateMove P((Board board, int fromX, int fromY, int toX, int toY)); -void HistorySet P((char movelist[][2*MOVE_LEN], - int first, int last, int current)); +void HistorySet P((char movelist[][2*MOVE_LEN], int first, int last, int current)); void FreezeUI P((void)); void ThawUI P((void)); extern char *programName; +void SetProgramStats P(( int which, int depth, unsigned long nodes, int score, int time, char * pv )); /* [AS] */ + #endif diff --git a/gamelist.c b/gamelist.c index e8d4132..2be1fe8 100644 --- a/gamelist.c +++ b/gamelist.c @@ -70,6 +70,7 @@ static void GameListDeleteGame(listGame) if (listGame->gameInfo.resultDetails) free(listGame->gameInfo.resultDetails); if (listGame->gameInfo.timeControl) free(listGame->gameInfo.timeControl); if (listGame->gameInfo.extraTags) free(listGame->gameInfo.extraTags); + if (listGame->gameInfo.outOfBook) free(listGame->gameInfo.outOfBook); ListNodeFree((ListNode *) listGame); } } @@ -107,6 +108,7 @@ void GameListInitGameInfo(gameInfo) gameInfo->whiteRating = -1; /* unknown */ gameInfo->blackRating = -1; /* unknown */ gameInfo->variant = VariantNormal; + gameInfo->outOfBook = NULL; } @@ -295,12 +297,16 @@ void ClearGameInfo(gameInfo) if (gameInfo->extraTags != NULL) { free(gameInfo->extraTags); } + if (gameInfo->outOfBook != NULL) { + free(gameInfo->outOfBook); + } GameListInitGameInfo(gameInfo); } +/* [AS] Replaced by "dynamic" tag selection below */ char * -GameListLine(number, gameInfo) +GameListLineOld(number, gameInfo) int number; GameInfo *gameInfo; { @@ -317,3 +323,97 @@ GameListLine(number, gameInfo) return ret; } +#define MAX_FIELD_LEN 64 /* To avoid overflowing the buffer */ + +char * GameListLine( int number, GameInfo * gameInfo ) +{ + char buffer[1024]; + char * buf = buffer; + char * glt = appData.gameListTags; + + buf += sprintf( buffer, "%d.", number ); + + while( *glt != '\0' ) { + *buf++ = ' '; + + switch( *glt ) { + case GLT_EVENT: + strncpy( buf, gameInfo->event ? gameInfo->event : "?", MAX_FIELD_LEN ); + break; + case GLT_SITE: + strncpy( buf, gameInfo->site ? gameInfo->site : "?", MAX_FIELD_LEN ); + break; + case GLT_DATE: + strncpy( buf, gameInfo->date ? gameInfo->date : "?", MAX_FIELD_LEN ); + break; + case GLT_ROUND: + strncpy( buf, gameInfo->round ? gameInfo->round : "?", MAX_FIELD_LEN ); + break; + case GLT_PLAYERS: + strncpy( buf, gameInfo->white ? gameInfo->white : "?", MAX_FIELD_LEN ); + buf[ MAX_FIELD_LEN-1 ] = '\0'; + buf += strlen( buf ); + *buf++ = '-'; + strncpy( buf, gameInfo->black ? gameInfo->black : "?", MAX_FIELD_LEN ); + break; + case GLT_RESULT: + strcpy( buf, PGNResult(gameInfo->result) ); + break; + case GLT_WHITE_ELO: + if( gameInfo->whiteRating > 0 ) + sprintf( buf, "%d", gameInfo->whiteRating ); + else + strcpy( buf, "?" ); + break; + case GLT_BLACK_ELO: + if( gameInfo->blackRating > 0 ) + sprintf( buf, "%d", gameInfo->blackRating ); + else + strcpy( buf, "?" ); + break; + case GLT_TIME_CONTROL: + strncpy( buf, gameInfo->timeControl ? gameInfo->timeControl : "?", MAX_FIELD_LEN ); + break; + case GLT_VARIANT: + break; + case GLT_OUT_OF_BOOK: + strncpy( buf, gameInfo->outOfBook ? gameInfo->outOfBook : "?", MAX_FIELD_LEN ); + break; + default: + break; + } + + buf[MAX_FIELD_LEN-1] = '\0'; + + buf += strlen( buf ); + + glt++; + + if( *glt != '\0' ) { + *buf++ = ','; + } + } + + *buf = '\0'; + + return strdup( buffer ); +} + +char * GameListLineFull( int number, GameInfo * gameInfo ) +{ + char * event = gameInfo->event ? gameInfo->event : "?"; + char * site = gameInfo->site ? gameInfo->site : "?"; + char * white = gameInfo->white ? gameInfo->white : "?"; + char * black = gameInfo->black ? gameInfo->black : "?"; + char * round = gameInfo->round ? gameInfo->round : "?"; + char * date = gameInfo->date ? gameInfo->date : "?"; + char * oob = gameInfo->outOfBook ? gameInfo->outOfBook : ""; + + int len = 64 + strlen(event) + strlen(site) + strlen(white) + strlen(black) + strlen(date) + strlen(oob); + + char *ret = (char *) malloc(len); + + sprintf(ret, "%d, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"", number, event, site, round, white, black, PGNResult(gameInfo->result), date, oob ); + + return ret; +} diff --git a/pgntags.c b/pgntags.c index cd8f0d8..6317c8b 100644 --- a/pgntags.c +++ b/pgntags.c @@ -114,6 +114,9 @@ int ParsePGNTag(tag, gameInfo) /* xboard-defined extension */ gameInfo->variant = StringToVariant(value); success = TRUE; + } else if (StrCaseCmp(name, PGN_OUT_OF_BOOK) == 0) { + /* [AS] Out of book annotation */ + success = StrSavePtr(value, &gameInfo->outOfBook) != NULL; } else { if (gameInfo->extraTags == NULL) { oldTags = ""; diff --git a/winboard/wengineoutput.c b/winboard/wengineoutput.c new file mode 100644 index 0000000..6486508 --- /dev/null +++ b/winboard/wengineoutput.c @@ -0,0 +1,414 @@ +/* + * Engine output (PV) + * + * 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 EngineOutputPopUp(); +VOID EngineOutputPopDown(); +BOOL EngineOutputIsUp(); + +/* Imports from backend.c */ +char * SavePart(char *str); + +/* Imports from winboard.c */ +extern HWND engineOutputDialog; +extern BOOLEAN engineOutputDialogUp; + +extern HINSTANCE hInst; +extern HWND hwndMain; + +extern WindowPlacement wpEngineOutput; + +/* Module variables */ +#define H_MARGIN 2 +#define V_MARGIN 2 +#define LABEL_V_DISTANCE 1 /* Distance between label and memo */ +#define SPLITTER_SIZE 4 /* Distance between first memo and second label */ + +static int windowMode = 1; + +static int lastDepth[2] = { -1, -1 }; + +static VOID SetControlPos( HWND hDlg, int id, int x, int y, int width, int height ) +{ + HWND hControl = GetDlgItem( hDlg, id ); + + SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER ); +} + +static VOID HideControl( HWND hDlg, int id ) +{ + /* TODO: we should also hide/disable it!!! what about tab stops?!?! */ + SetControlPos( hDlg, id, 20000, 20000, 100, 100 ); +} + +static int GetControlWidth( HWND hDlg, int id ) +{ + RECT rc; + + GetWindowRect( GetDlgItem( hDlg, IDC_EngineLabel1 ), &rc ); + + return rc.right - rc.left; +} + +static VOID ResizeWindowControls( HWND hDlg, int mode ) +{ + RECT rc; + int labelHeight; + int clientWidth; + int clientHeight; + int maxControlWidth; + int npsWidth; + + /* Initialize variables */ + GetWindowRect( GetDlgItem( hDlg, IDC_EngineLabel1 ), &rc ); + + labelHeight = rc.bottom - rc.top; + + GetClientRect( hDlg, &rc ); + + clientWidth = rc.right - rc.left; + clientHeight = rc.bottom - rc.top; + + maxControlWidth = clientWidth - 2*H_MARGIN; + + npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS ); + + /* Resize controls */ + if( mode == 0 ) { + /* One engine */ + int memo_y = V_MARGIN + labelHeight + LABEL_V_DISTANCE; + int memo_h = clientHeight - memo_y - V_MARGIN; + + SetControlPos( hDlg, IDC_EngineLabel1, H_MARGIN, V_MARGIN, maxControlWidth / 2, labelHeight ); + SetControlPos( hDlg, IDC_EngineMemo1, H_MARGIN, memo_y, maxControlWidth, memo_h ); + + /* Hide controls for the second engine */ + HideControl( hDlg, IDC_EngineLabel2 ); + HideControl( hDlg, IDC_Engine2_NPS ); + HideControl( hDlg, IDC_EngineMemo2 ); + /* TODO: we should also hide/disable them!!! what about tab stops?!?! */ + } + else { + /* Two engines */ + int memo1_y = V_MARGIN + labelHeight + LABEL_V_DISTANCE; + int memo_h = (clientHeight - memo1_y - V_MARGIN - labelHeight - LABEL_V_DISTANCE - SPLITTER_SIZE) / 2; + int label2_y = memo1_y + memo_h + SPLITTER_SIZE; + int memo2_y = label2_y + labelHeight + LABEL_V_DISTANCE; + int nps_x = clientWidth - H_MARGIN - npsWidth; + + SetControlPos( hDlg, IDC_EngineLabel1, H_MARGIN, V_MARGIN, maxControlWidth / 2, labelHeight ); + SetControlPos( hDlg, IDC_Engine1_NPS, nps_x, V_MARGIN, npsWidth, labelHeight ); + SetControlPos( hDlg, IDC_EngineMemo1, H_MARGIN, memo1_y, maxControlWidth, memo_h ); + + SetControlPos( hDlg, IDC_EngineLabel2, H_MARGIN, label2_y, maxControlWidth / 2, labelHeight ); + SetControlPos( hDlg, IDC_Engine2_NPS, nps_x, label2_y, npsWidth, labelHeight ); + SetControlPos( hDlg, IDC_EngineMemo2, H_MARGIN, memo2_y, maxControlWidth, memo_h ); + } + + InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE ); + InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE ); +} + +static VOID SetDisplayMode( int mode ) +{ + if( windowMode != mode ) { + windowMode = mode; + + ResizeWindowControls( engineOutputDialog, mode ); + } +} + +static VOID VerifyDisplayMode() +{ + int mode; + + /* Get proper mode for current game */ + switch( gameMode ) { + case AnalyzeMode: + case AnalyzeFile: + case MachinePlaysWhite: + case MachinePlaysBlack: + mode = 0; + break; + case TwoMachinesPlay: + mode = 1; + break; + default: + /* Do not change */ + return; + } + + SetDisplayMode( mode ); +} + +static VOID InsertIntoMemo( HWND hMemo, char * text ) +{ + SendMessage( hMemo, EM_SETSEL, 0, 0 ); + + SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text ); +} + +#define MAX_NAME_LENGTH 32 + +static VOID UpdateControls( HWND hLabel, HWND hLabelNPS, HWND hMemo, char * name, int depth, unsigned long nodes, int score, int time, char * pv ) +{ + char s_label[MAX_NAME_LENGTH + 64]; + + /* Label */ + if( name == 0 || *name == '\0' ) { + name = "?"; + } + + strncpy( s_label, name, MAX_NAME_LENGTH ); + s_label[ MAX_NAME_LENGTH-1 ] = '\0'; + + SetWindowText( hLabel, s_label ); + + s_label[0] = '\0'; + + if( time > 0 && nodes > 0 ) { + unsigned long nps_100 = nodes / time; + + if( nps_100 < 100000 ) { + sprintf( s_label, "NPS: %lu", nps_100 * 100 ); + } + else { + sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 ); + } + } + + SetWindowText( hLabelNPS, s_label ); + + /* Memo */ + if( pv != 0 && *pv != '\0' ) { + char s_nodes[24]; + char s_score[16]; + char s_time[24]; + char buf[256]; + int buflen; + int time_secs = time / 100; + int time_cent = time % 100; + + /* Nodes */ + if( nodes < 1000000 ) { + sprintf( s_nodes, "%lu", nodes ); + } + else { + sprintf( s_nodes, "%.1fM", nodes / 1000000.0 ); + } + + /* Score */ + if( score > 0 ) { + sprintf( s_score, "+%.2f", score / 100.0 ); + } + else { + sprintf( s_score, "%.2f", score / 100.0 ); + } + + /* Time */ + sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent ); + + /* Put all together... */ + sprintf( buf, "%3d\t%s\t%s\t%s\t", depth, s_score, s_nodes, s_time ); + + /* Add PV */ + buflen = strlen(buf); + + strncpy( buf + buflen, pv, sizeof(buf) - buflen ); + + buf[ sizeof(buf) - 3 ] = '\0'; + + strcat( buf + buflen, "\r\n" ); + + /* Update memo */ + InsertIntoMemo( hMemo, buf ); + } +} + +LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) +{ + static SnapData sd; + + switch (message) { + case WM_INITDIALOG: + if( engineOutputDialog == NULL ) { + engineOutputDialog = hDlg; + + RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */ + + ResizeWindowControls( hDlg, windowMode ); + } + + 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_GETMINMAXINFO: + { + MINMAXINFO * mmi = (MINMAXINFO *) lParam; + + mmi->ptMinTrackSize.x = 100; + mmi->ptMinTrackSize.y = 160; + } + break; + + case WM_CLOSE: + EngineOutputPopDown(); + break; + + case WM_SIZE: + ResizeWindowControls( hDlg, windowMode ); + 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 EngineOutputPopUp() +{ + FARPROC lpProc; + + CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED); + + if( engineOutputDialog ) { + SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 ); + + if( ! engineOutputDialogUp ) { + ShowWindow(engineOutputDialog, SW_SHOW); + } + } + else { + lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst ); + + /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */ + CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc ); + + FreeProcInstance(lpProc); + } + + engineOutputDialogUp = TRUE; +} + +VOID EngineOutputPopDown() +{ + CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED); + + if( engineOutputDialog ) { + ShowWindow(engineOutputDialog, SW_HIDE); + } + + engineOutputDialogUp = FALSE; +} + +BOOL EngineOutputIsUp() +{ + return engineOutputDialogUp; +} + +VOID EngineOutputUpdate( int which, int depth, unsigned long nodes, int score, int time, char * pv ) +{ + HWND hLabel; + HWND hLabelNPS; + HWND hMemo; + char * name; + + if( which < 0 || which > 1 || depth < 0 || time < 0 || pv == 0 || *pv == '\0' ) { + return; + } + + if( engineOutputDialog == NULL ) { + return; + } + + VerifyDisplayMode(); + + /* Get target control */ + if( which == 0 ) { + hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 ); + hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS ); + hMemo = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 ); + name = first.tidy; + } + else { + hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 ); + hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS ); + hMemo = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 ); + name = second.tidy; + } + + /* Clear memo if needed */ + if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) { + SendMessage( hMemo, WM_SETTEXT, 0, (LPARAM) "" ); + } + + /* Update */ + lastDepth[which] = depth; + + if( pv[0] == ' ' ) { + if( strncmp( pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */ + pv = ""; + } + } + + UpdateControls( hLabel, hLabelNPS, hMemo, name, depth, nodes, score, time, pv ); +} diff --git a/winboard/wevalgraph.c b/winboard/wevalgraph.c new file mode 100644 index 0000000..2efb15e --- /dev/null +++ b/winboard/wevalgraph.c @@ -0,0 +1,620 @@ +/* + * Evaluation graph + * + * 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 EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo ); +VOID EvalGraphPopUp(); +VOID EvalGraphPopDown(); +BOOL EvalGraphIsUp(); + +#define WM_REFRESH_GRAPH (WM_USER + 1) + +/* Imports from backend.c */ +char * SavePart(char *str); + +/* Imports from winboard.c */ +extern HWND evalGraphDialog; +extern BOOLEAN evalGraphDialogUp; + +extern HINSTANCE hInst; +extern HWND hwndMain; + +extern WindowPlacement wpEvalGraph; + +/* Module globals */ +static ChessProgramStats_Move * currPvInfo; +static int currFirst = 0; +static int currLast = 0; +static int currCurrent = -1; + +static COLORREF crWhite = RGB( 0xFF, 0xFF, 0xB0 ); +static COLORREF crBlack = RGB( 0xAD, 0x5D, 0x3D ); + +static HDC hdcPB = NULL; +static HBITMAP hbmPB = NULL; +static int nWidthPB = 0; +static int nHeightPB = 0; +static HPEN hpenDotted = NULL; +static HPEN hpenBlueDotted = NULL; +static HPEN hpenBold[2] = { NULL, NULL }; +static HBRUSH hbrHist[2] = { NULL, NULL }; + +static int MarginX = 18; +static int MarginW = 4; +static int MarginH = 4; + +#define MIN_HIST_WIDTH 4 +#define MAX_HIST_WIDTH 10 + +static int GetPvScore( int index ) +{ + int score = currPvInfo[ index ].score; + + if( index & 1 ) score = -score; /* Flip score for black */ + + return score; +} + +static VOID DrawLine( int x1, int y1, int x2, int y2 ) +{ + MoveToEx( hdcPB, x1, y1, NULL ); + + LineTo( hdcPB, x2, y2 ); +} + +static VOID DrawLineEx( int x1, int y1, int x2, int y2 ) +{ + POINT stPT; + + MoveToEx( hdcPB, x1, y1, &stPT ); + + LineTo( hdcPB, x2, y2 ); + + MoveToEx( hdcPB, stPT.x, stPT.y, NULL ); +} + +static HBRUSH CreateBrush( UINT style, COLORREF color ) +{ + LOGBRUSH stLB; + + stLB.lbStyle = style; + stLB.lbColor = color; + stLB.lbHatch = 0; + + return CreateBrushIndirect( &stLB ); +} + +/* + For a centipawn value, this function returns the height of the corresponding + histogram, centered on the reference axis. + + Note: height can be negative! +*/ +static int GetValueY( int value ) +{ + if( value < -700 ) value = -700; + if( value > +700 ) value = +700; + + return (nHeightPB / 2) - (int)(value * (nHeightPB - 2*MarginH) / 1400.0); +} + +static VOID DrawAxisSegmentHoriz( int value, BOOL drawValue ) +{ + int y = GetValueY( value*100 ); + + SelectObject( hdcPB, GetStockObject(BLACK_PEN) ); + DrawLine( MarginX, y, MarginX + MarginW, y ); + SelectObject( hdcPB, hpenDotted ); + DrawLine( MarginX + MarginW, y, nWidthPB - MarginW, y ); + + if( drawValue ) { + SIZE stSize; + char buf[8]; + int cbBuf; + + if( value > 0 ) { + buf[0] = '+'; + itoa( value, buf+1, 10 ); + } + else { + itoa( value, buf, 10 ); + } + + cbBuf = strlen( buf ); + + GetTextExtentPoint32( hdcPB, buf, cbBuf, &stSize ); + + TextOut( hdcPB, MarginX - stSize.cx - 2, y - stSize.cy / 2, buf, cbBuf ); + } +} + +static VOID DrawAxis() +{ + int cy = nHeightPB / 2; + + SelectObject( hdcPB, GetStockObject(NULL_BRUSH) ); + + SetBkMode( hdcPB, TRANSPARENT ); + + DrawAxisSegmentHoriz( +5, TRUE ); + DrawAxisSegmentHoriz( +3, FALSE ); + DrawAxisSegmentHoriz( +1, FALSE ); + DrawAxisSegmentHoriz( 0, TRUE ); + DrawAxisSegmentHoriz( -1, FALSE ); + DrawAxisSegmentHoriz( -3, FALSE ); + DrawAxisSegmentHoriz( -5, TRUE ); + + SelectObject( hdcPB, GetStockObject(BLACK_PEN) ); + + DrawLine( MarginX + MarginW, cy, nWidthPB - MarginW, cy ); + DrawLine( MarginX + MarginW, MarginH, MarginX + MarginW, nHeightPB - MarginH ); +} + +static VOID DrawHistogram( int x, int y, int width, int value, int side ) +{ + RECT rc; + + if( value > -25 && value < +25 ) return; + + rc.left = x; + rc.right = rc.left + width + 1; + + if( value > 0 ) { + rc.top = GetValueY( value ); + rc.bottom = y+1; + } + else { + rc.top = y; + rc.bottom = GetValueY( value ) + 1; + } + + + if( width == MIN_HIST_WIDTH ) { + rc.right--; + FillRect( hdcPB, &rc, hbrHist[side] ); + } + else { + SelectObject( hdcPB, hbrHist[side] ); + Rectangle( hdcPB, rc.left, rc.top, rc.right, rc.bottom ); + } +} + +static VOID DrawSeparator( int index, int x ) +{ + if( index > 0 ) { + if( index == currCurrent ) { + HPEN hp = SelectObject( hdcPB, hpenBlueDotted ); + DrawLineEx( x, MarginH, x, nHeightPB - MarginH ); + SelectObject( hdcPB, hp ); + } + else if( (index % 20) == 0 ) { + HPEN hp = SelectObject( hdcPB, hpenDotted ); + DrawLineEx( x, MarginH, x, nHeightPB - MarginH ); + SelectObject( hdcPB, hp ); + } + } +} + +/* Actually draw histogram as a diagram, cause there's too much data */ +static VOID DrawHistogramAsDiagram( int cy, int paint_width, int hist_count ) +{ + double step; + int i; + + /* Rescale the graph every few moves (as opposed to every move) */ + hist_count -= hist_count % 8; + hist_count += 8; + hist_count /= 2; + + step = (double) paint_width / (hist_count + 1); + + for( i=0; i<2; i++ ) { + int index = currFirst; + int side = (currCurrent + i + 1) & 1; /* Draw current side last */ + double x = MarginX + MarginW; + + if( (index & 1) != side ) { + x += step / 2; + index++; + } + + SelectObject( hdcPB, hpenBold[side] ); + + MoveToEx( hdcPB, (int) x, cy, NULL ); + + index += 2; + + while( index < currLast ) { + x += step; + + DrawSeparator( index, (int) x ); + + /* Extend line up to current point */ + if( currPvInfo[index].depth > 0 ) { + LineTo( hdcPB, (int) x, GetValueY( GetPvScore(index) ) ); + } + + index += 2; + } + } +} + +static VOID DrawHistogramFull( int cy, int hist_width, int hist_count ) +{ + int i; + + SelectObject( hdcPB, GetStockObject(BLACK_PEN) ); + + for( i=0; i 0 ) { + DrawHistogram( x, cy, hist_width, GetPvScore(index), index & 1 ); + } + } +} + +typedef struct { + int cy; + int hist_width; + int hist_count; + int paint_width; +} VisualizationData; + +static BOOL InitVisualization( VisualizationData * vd ) +{ + BOOL result = FALSE; + + vd->cy = nHeightPB / 2; + vd->hist_width = MIN_HIST_WIDTH; + vd->hist_count = currLast - currFirst; + vd->paint_width = nWidthPB - MarginX - 2*MarginW; + + if( vd->hist_count > 0 ) { + result = TRUE; + + /* Compute width */ + vd->hist_width = vd->paint_width / vd->hist_count; + + if( vd->hist_width > MAX_HIST_WIDTH ) vd->hist_width = MAX_HIST_WIDTH; + + vd->hist_width -= vd->hist_width % 2; + } + + return result; +} + +static VOID DrawHistograms() +{ + VisualizationData vd; + + if( InitVisualization( &vd ) ) { + if( vd.hist_width < MIN_HIST_WIDTH ) { + DrawHistogramAsDiagram( vd.cy, vd.paint_width, vd.hist_count ); + } + else { + DrawHistogramFull( vd.cy, vd.hist_width, vd.hist_count ); + } + } +} + +static int GetMoveIndexFromPoint( int x, int y ) +{ + int result = -1; + int start_x = MarginX + MarginW; + VisualizationData vd; + + if( x >= start_x && InitVisualization( &vd ) ) { + /* Almost an hack here... we duplicate some of the paint logic */ + if( vd.hist_width < MIN_HIST_WIDTH ) { + double step; + + vd.hist_count -= vd.hist_count % 8; + vd.hist_count += 8; + vd.hist_count /= 2; + + step = (double) vd.paint_width / (vd.hist_count + 1); + step /= 2; + + result = (int) (0.5 + (double) (x - start_x) / step); + } + else { + result = (x - start_x) / vd.hist_width; + } + } + + if( result >= currLast ) { + result = -1; + } + + return result; +} + +static VOID DrawBackground() +{ + HBRUSH hbr; + RECT rc; + + hbr = CreateBrush( BS_SOLID, GetSysColor( COLOR_3DFACE ) ); + + rc.left = 0; + rc.top = 0; + rc.right = nWidthPB; + rc.bottom = nHeightPB; + + FillRect( hdcPB, &rc, hbr ); + + DeleteObject( hbr ); +} + +static VOID PaintEvalGraph( HWND hWnd, HDC hDC ) +{ + RECT rcClient; + int width; + int height; + + /* Get client area */ + GetClientRect( hWnd, &rcClient ); + + width = rcClient.right - rcClient.left; + height = rcClient.bottom - rcClient.top; + + /* Create or recreate paint box if needed */ + if( hbmPB == NULL || width != nWidthPB || height != nHeightPB ) { + if( hpenDotted == NULL ) { + hpenDotted = CreatePen( PS_DOT, 0, RGB(0xA0,0xA0,0xA0) ); + hpenBlueDotted = CreatePen( PS_DOT, 0, RGB(0x00,0x00,0xFF) ); + hpenBold[0] = CreatePen( PS_SOLID, 2, crWhite ); + hpenBold[1] = CreatePen( PS_SOLID, 2, crBlack ); + hbrHist[0] = CreateBrush( BS_SOLID, crWhite ); + hbrHist[1] = CreateBrush( BS_SOLID, crBlack ); + } + + if( hdcPB != NULL ) { + DeleteDC( hdcPB ); + hdcPB = NULL; + } + + if( hbmPB != NULL ) { + DeleteObject( hbmPB ); + hbmPB = NULL; + } + + hdcPB = CreateCompatibleDC( hDC ); + + nWidthPB = width; + nHeightPB = height; + hbmPB = CreateCompatibleBitmap( hDC, nWidthPB, nHeightPB ); + + SelectObject( hdcPB, hbmPB ); + } + + /* Draw */ + DrawBackground(); + DrawAxis(); + DrawHistograms(); + + /* Copy bitmap into destination DC */ + BitBlt( hDC, 0, 0, width, height, hdcPB, 0, 0, SRCCOPY ); +} + +LRESULT CALLBACK EvalGraphProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) +{ + static SnapData sd; + + PAINTSTRUCT stPS; + HDC hDC; + + switch (message) { + case WM_INITDIALOG: + if( evalGraphDialog == NULL ) { + evalGraphDialog = hDlg; + + RestoreWindowPlacement( hDlg, &wpEvalGraph ); /* Restore window placement */ + } + + 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_ERASEBKGND: + return TRUE; + + case WM_PAINT: + hDC = BeginPaint( hDlg, &stPS ); + PaintEvalGraph( hDlg, hDC ); + EndPaint( hDlg, &stPS ); + break; + + case WM_REFRESH_GRAPH: + hDC = GetDC( hDlg ); + PaintEvalGraph( hDlg, hDC ); + ReleaseDC( hDlg, hDC ); + break; + + case WM_LBUTTONDBLCLK: + if( wParam == 0 || wParam == MK_LBUTTON ) { + int index = GetMoveIndexFromPoint( LOWORD(lParam), HIWORD(lParam) ); + + if( index >= 0 && index < currLast ) { + ToNrEvent( index + 1 ); + } + } + return TRUE; + + case WM_SIZE: + InvalidateRect( hDlg, NULL, FALSE ); + break; + + case WM_GETMINMAXINFO: + { + MINMAXINFO * mmi = (MINMAXINFO *) lParam; + + mmi->ptMinTrackSize.x = 100; + mmi->ptMinTrackSize.y = 100; + } + break; + + /* Support for captionless window */ +#if 0 + case WM_NCLBUTTONDBLCLK: + if( wParam == HTCAPTION ) { + int index; + POINT mouse_xy; + POINTS pts = MAKEPOINTS(lParam); + + mouse_xy.x = pts.x; + mouse_xy.y = pts.y; + ScreenToClient( hDlg, &mouse_xy ); + + index = GetMoveIndexFromPoint( mouse_xy.x, mouse_xy.y ); + + if( index >= 0 && index < currLast ) { + ToNrEvent( index + 1 ); + } + } + break; + + case WM_NCHITTEST: + { + LRESULT res = DefWindowProc( hDlg, message, wParam, lParam ); + + if( res == HTCLIENT ) res = HTCAPTION; + + SetWindowLong( hDlg, DWL_MSGRESULT, res ); + + return TRUE; + } + break; +#endif + + case WM_CLOSE: + EvalGraphPopDown(); + 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 EvalGraphPopUp() +{ + FARPROC lpProc; + + CheckMenuItem(GetMenu(hwndMain), IDM_ShowEvalGraph, MF_CHECKED); + + if( evalGraphDialog ) { + SendMessage( evalGraphDialog, WM_INITDIALOG, 0, 0 ); + + if( ! evalGraphDialogUp ) { + ShowWindow(evalGraphDialog, SW_SHOW); + } + } + else { + crWhite = appData.evalHistColorWhite; + crBlack = appData.evalHistColorBlack; + + lpProc = MakeProcInstance( (FARPROC) EvalGraphProc, hInst ); + + /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */ + CreateDialog( hInst, MAKEINTRESOURCE(DLG_EvalGraph), hwndMain, (DLGPROC)lpProc ); + + FreeProcInstance(lpProc); + } + + evalGraphDialogUp = TRUE; +} + +VOID EvalGraphPopDown() +{ + CheckMenuItem(GetMenu(hwndMain), IDM_ShowEvalGraph, MF_UNCHECKED); + + if( evalGraphDialog ) { + ShowWindow(evalGraphDialog, SW_HIDE); + } + + evalGraphDialogUp = FALSE; +} + +VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo ) +{ + /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */ + + currFirst = first; + currLast = last; + currCurrent = current; + currPvInfo = pvInfo; + + if( evalGraphDialog ) { + SendMessage( evalGraphDialog, WM_REFRESH_GRAPH, 0, 0 ); + } +} + +BOOL EvalGraphIsUp() +{ + return evalGraphDialogUp; +} diff --git a/winboard/wgamelist.c b/winboard/wgamelist.c index 34339d4..5fa191c 100644 --- a/winboard/wgamelist.c +++ b/winboard/wgamelist.c @@ -20,7 +20,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ------------------------------------------------------------------------ */ - #include "config.h" #include /* required for all Windows applications */ @@ -37,6 +36,8 @@ #include "frontend.h" #include "backend.h" +#include "wsnap.h" + /* Module globals */ HWND gameListDialog = NULL; BOOLEAN gameListUp = FALSE; @@ -206,6 +207,7 @@ GameListDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) static BOOL filterHasFocus = FALSE; int count; struct GameListStats stats; + static SnapData sd; switch (message) { case WM_INITDIALOG: @@ -269,6 +271,18 @@ GameListDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) sizeY = newSizeY; 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 ); + case WM_GETMINMAXINFO: /* Prevent resizing window too small */ mmi = (MINMAXINFO *) lParam; @@ -469,3 +483,56 @@ VOID ShowGameListProc() } } } + +HGLOBAL ExportGameListAsText() +{ + HGLOBAL result = NULL; + LPVOID lpMem = NULL; + ListGame * lg = (ListGame *) gameList.head; + int nItem; + DWORD dwLen = 0; + + if( ! gameFileName || ((ListGame *) gameList.tailPred)->number <= 0 ) { + DisplayError("Game list not loaded or empty", 0); + return NULL; + } + + /* Get list size */ + for (nItem = 0; nItem < ((ListGame *) gameList.tailPred)->number; nItem++){ + char * st = GameListLineFull(lg->number, &lg->gameInfo); + + dwLen += strlen(st) + 2; /* Add extra characters for "\r\n" */ + + free(st); + lg = (ListGame *) lg->node.succ; + } + + /* Allocate memory for the list */ + result = GlobalAlloc(GHND, dwLen+1 ); + + if( result != NULL ) { + lpMem = GlobalLock(result); + } + + /* Copy the list into the global memory block */ + if( lpMem != NULL ) { + char * dst = (char *) lpMem; + size_t len; + + lg = (ListGame *) gameList.head; + + for (nItem = 0; nItem < ((ListGame *) gameList.tailPred)->number; nItem++){ + char * st = GameListLineFull(lg->number, &lg->gameInfo); + + len = sprintf( dst, "%s\r\n", st ); + dst += len; + + free(st); + lg = (ListGame *) lg->node.succ; + } + + GlobalUnlock( result ); + } + + return result; +} 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; +} diff --git a/winboard/winboard.c b/winboard/winboard.c index 751e67e..368c68d 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -84,6 +84,8 @@ #include "wsockerr.h" #include "defaults.h" +#include "wsnap.h" + int myrandom(void); void mysrandom(unsigned int seed); @@ -144,7 +146,7 @@ char *icsNames; char *firstChessProgramNames; char *secondChessProgramNames; -#define ARG_MAX 64*1024 /* [AS] For Roger Brown's very long list! */ +#define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */ #define PALETTESIZE 256 @@ -415,7 +417,40 @@ VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def); void ParseIcsTextMenu(char *icsTextMenuString); VOID PopUpMoveDialog(char firstchar); VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca); + +/* [AS] */ int NewGameFRC(); +int GameListOptions(); + +HWND moveHistoryDialog = NULL; +BOOLEAN moveHistoryDialogUp = FALSE; + +WindowPlacement wpMoveHistory; + +HWND evalGraphDialog = NULL; +BOOLEAN evalGraphDialogUp = FALSE; + +WindowPlacement wpEvalGraph; + +HWND engineOutputDialog = NULL; +BOOLEAN engineOutputDialogUp = FALSE; + +WindowPlacement wpEngineOutput; + +VOID MoveHistoryPopUp(); +VOID MoveHistoryPopDown(); +VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo ); +BOOL MoveHistoryIsUp(); + +VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo ); +VOID EvalGraphPopUp(); +VOID EvalGraphPopDown(); +BOOL EvalGraphIsUp(); + +VOID EngineOutputPopUp(); +VOID EngineOutputPopDown(); +BOOL EngineOutputIsUp(); +VOID EngineOutputUpdate( int which, int depth, unsigned long nodes, int score, int time, char * pv ); /* * Setting "frozen" should disable all user input other than deleting @@ -463,7 +498,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; - HANDLE hAccelMain, hAccelNoAlt; + HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS; debugFP = stderr; @@ -479,6 +514,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, hAccelMain = LoadAccelerators (hInstance, szAppName); hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT"); + hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */ /* Acquire and dispatch messages until a WM_QUIT message is received. */ @@ -488,10 +524,14 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 0)) /* highest message to examine */ { if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) && + !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) && + !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) && + !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) && !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) && !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) && !(errorDialog && IsDialogMessage(errorDialog, &msg)) && !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && + !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) && !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) { TranslateMessage(&msg); /* Translates virtual key codes */ DispatchMessage(&msg); /* Dispatches message to window */ @@ -639,6 +679,19 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) ConsoleCreate(); } + /* [AS] Restore layout */ + if( wpMoveHistory.visible ) { + MoveHistoryPopUp(); + } + + if( wpEvalGraph.visible ) { + EvalGraphPopUp(); + } + + if( wpEngineOutput.visible ) { + EngineOutputPopUp(); + } + InitBackEnd2(); /* Make the window visible; update its client area; and return "success" */ @@ -1058,8 +1111,8 @@ ArgDescriptor argDescriptors[] = { { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE }, { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE }, /* [AS] New features */ - { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, TRUE }, - { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, TRUE }, + { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE }, + { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE }, { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE }, { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE }, { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE }, @@ -1081,6 +1134,37 @@ ArgDescriptor argDescriptors[] = { { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE }, { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE }, { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE }, + { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE }, + { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE }, + { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE }, + { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE }, + { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE }, + { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE }, + { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE }, + { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE }, + { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE }, + { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE }, + { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE }, + + /* [AS] Layout stuff */ + { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE }, + { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE }, + { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE }, + { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE }, + { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE }, + + { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE }, + { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE }, + { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE }, + { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE }, + { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE }, + + { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE }, + { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE }, + { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE }, + { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE }, + { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE }, + #ifdef ZIPPY { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE }, { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE }, @@ -1759,6 +1843,21 @@ InitAppData(LPSTR lpCmdLine) appData.nameOfDebugFile = "winboard.debug"; appData.pgnEventHeader = "Computer Chess Game"; appData.defaultFrcPosition = -1; + appData.gameListTags = GLT_DEFAULT_TAGS; + appData.saveOutOfBookInfo = TRUE; + appData.showEvalInMoveHistory = TRUE; + appData.evalHistColorWhite = ParseColorName( "#FFFFB0" ); + appData.evalHistColorBlack = ParseColorName( "#AD5D3D" ); + appData.highlightMoveWithArrow = FALSE; + appData.highlightArrowColor = ParseColorName( "#FFFF80" ); + appData.useStickyWindows = TRUE; + appData.adjudicateDrawMoves = 0; + appData.autoDisplayComment = TRUE; + appData.autoDisplayTags = TRUE; + + InitWindowPlacement( &wpMoveHistory ); + InitWindowPlacement( &wpEvalGraph ); + InitWindowPlacement( &wpEngineOutput ); #ifdef ZIPPY appData.zippyTalk = ZIPPY_TALK; @@ -1948,6 +2047,39 @@ SaveSettings(char* name) gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; } + /* [AS] Move history */ + wpMoveHistory.visible = MoveHistoryIsUp(); + + if( moveHistoryDialog ) { + GetWindowPlacement(moveHistoryDialog, &wp); + wpMoveHistory.x = wp.rcNormalPosition.left; + wpMoveHistory.y = wp.rcNormalPosition.top; + wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left; + wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; + } + + /* [AS] Eval graph */ + wpEvalGraph.visible = EvalGraphIsUp(); + + if( evalGraphDialog ) { + GetWindowPlacement(evalGraphDialog, &wp); + wpEvalGraph.x = wp.rcNormalPosition.left; + wpEvalGraph.y = wp.rcNormalPosition.top; + wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left; + wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; + } + + /* [AS] Engine output */ + wpEngineOutput.visible = EngineOutputIsUp(); + + if( engineOutputDialog ) { + GetWindowPlacement(engineOutputDialog, &wp); + wpEngineOutput.x = wp.rcNormalPosition.left; + wpEngineOutput.y = wp.rcNormalPosition.top; + wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left; + wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; + } + for (ad = argDescriptors; ad->argName != NULL; ad++) { if (!ad->save) continue; switch (ad->argType) { @@ -2334,6 +2466,10 @@ static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index ) SelectObject( hdc, hbm_old ); + if( hPieceFace[index] != NULL ) { + DeleteObject( hPieceFace[index] ); + } + hPieceFace[index] = hbm; } @@ -2398,6 +2534,7 @@ void CreatePiecesFromFont() else { for( i=0; i<12; i++ ) { hPieceMask[i] = NULL; + hPieceFace[i] = NULL; } } @@ -2965,7 +3102,7 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, /* [AS] Use font-based pieces if needed */ if( fontBitmapSquareSize >= 0 && squareSize > 32 ) { - /* Create piece bitmaps, or do nothing if piece set is up to data */ + /* Create piece bitmaps, or do nothing if piece set is up to date */ CreatePiecesFromFont(); if( fontBitmapSquareSize == squareSize ) { @@ -3110,6 +3247,295 @@ VOID RebuildTextureSquareInfo() } } +/* [AS] Arrow highlighting support */ + +static int A_WIDTH = 5; /* Width of arrow body */ + +#define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */ +#define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */ + +static double Sqr( double x ) +{ + return x*x; +} + +static int Round( double x ) +{ + return (int) (x + 0.5); +} + +/* Draw an arrow between two points using current settings */ +VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y ) +{ + POINT arrow[7]; + double dx, dy, j, k, x, y; + + if( d_x == s_x ) { + int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR; + + arrow[0].x = s_x + A_WIDTH; + arrow[0].y = s_y; + + arrow[1].x = s_x + A_WIDTH; + arrow[1].y = d_y - h; + + arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR; + arrow[2].y = d_y - h; + + arrow[3].x = d_x; + arrow[3].y = d_y; + + arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR; + arrow[4].y = d_y - h; + + arrow[5].x = s_x - A_WIDTH; + arrow[5].y = d_y - h; + + arrow[6].x = s_x - A_WIDTH; + arrow[6].y = s_y; + } + else if( d_y == s_y ) { + int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR; + + arrow[0].x = s_x; + arrow[0].y = s_y + A_WIDTH; + + arrow[1].x = d_x - w; + arrow[1].y = s_y + A_WIDTH; + + arrow[2].x = d_x - w; + arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR; + + arrow[3].x = d_x; + arrow[3].y = d_y; + + arrow[4].x = d_x - w; + arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR; + + arrow[5].x = d_x - w; + arrow[5].y = s_y - A_WIDTH; + + arrow[6].x = s_x; + arrow[6].y = s_y - A_WIDTH; + } + else { + /* [AS] Needed a lot of paper for this! :-) */ + dy = (double) (d_y - s_y) / (double) (d_x - s_x); + dx = (double) (s_x - d_x) / (double) (s_y - d_y); + + j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) ); + + k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) ); + + x = s_x; + y = s_y; + + arrow[0].x = Round(x - j); + arrow[0].y = Round(y + j*dx); + + arrow[1].x = Round(x + j); + arrow[1].y = Round(y - j*dx); + + if( d_x > s_x ) { + x = (double) d_x - k; + y = (double) d_y - k*dy; + } + else { + x = (double) d_x + k; + y = (double) d_y + k*dy; + } + + arrow[2].x = Round(x + j); + arrow[2].y = Round(y - j*dx); + + arrow[3].x = Round(x + j*A_WIDTH_FACTOR); + arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx); + + arrow[4].x = d_x; + arrow[4].y = d_y; + + arrow[5].x = Round(x - j*A_WIDTH_FACTOR); + arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx); + + arrow[6].x = Round(x - j); + arrow[6].y = Round(y + j*dx); + } + + Polygon( hdc, arrow, 7 ); +} + +/* [AS] Draw an arrow between two squares */ +VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row ) +{ + int s_x, s_y, d_x, d_y; + HPEN hpen; + HPEN holdpen; + HBRUSH hbrush; + HBRUSH holdbrush; + LOGBRUSH stLB; + + if( s_col == d_col && s_row == d_row ) { + return; + } + + /* Get source and destination points */ + SquareToPos( s_row, s_col, &s_x, &s_y); + SquareToPos( d_row, d_col, &d_x, &d_y); + + if( d_y > s_y ) { + d_y += squareSize / 4; + } + else if( d_y < s_y ) { + d_y += 3 * squareSize / 4; + } + else { + d_y += squareSize / 2; + } + + if( d_x > s_x ) { + d_x += squareSize / 4; + } + else if( d_x < s_x ) { + d_x += 3 * squareSize / 4; + } + else { + d_x += squareSize / 2; + } + + s_x += squareSize / 2; + s_y += squareSize / 2; + + /* Adjust width */ + A_WIDTH = squareSize / 14; + + /* Draw */ + stLB.lbStyle = BS_SOLID; + stLB.lbColor = appData.highlightArrowColor; + stLB.lbHatch = 0; + + hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) ); + holdpen = SelectObject( hdc, hpen ); + hbrush = CreateBrushIndirect( &stLB ); + holdbrush = SelectObject( hdc, hbrush ); + + DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y ); + + SelectObject( hdc, holdpen ); + SelectObject( hdc, holdbrush ); + DeleteObject( hpen ); + DeleteObject( hbrush ); +} + +BOOL HasHighlightInfo() +{ + BOOL result = FALSE; + + if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 && + highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 ) + { + result = TRUE; + } + + return result; +} + +BOOL IsDrawArrowEnabled() +{ + BOOL result = FALSE; + + if( appData.highlightMoveWithArrow && squareSize >= 32 ) { + result = TRUE; + } + + return result; +} + +VOID DrawArrowHighlight( HDC hdc ) +{ + if( IsDrawArrowEnabled() && HasHighlightInfo() ) { + DrawArrowBetweenSquares( hdc, + highlightInfo.sq[0].x, highlightInfo.sq[0].y, + highlightInfo.sq[1].x, highlightInfo.sq[1].y ); + } +} + +HRGN GetArrowHighlightClipRegion( HDC hdc ) +{ + HRGN result = NULL; + + if( HasHighlightInfo() ) { + int x1, y1, x2, y2; + int sx, sy, dx, dy; + + SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 ); + SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 ); + + sx = MIN( x1, x2 ); + sy = MIN( y1, y2 ); + dx = MAX( x1, x2 ) + squareSize; + dy = MAX( y1, y2 ) + squareSize; + + result = CreateRectRgn( sx, sy, dx, dy ); + } + + return result; +} + +/* + Warning: this function modifies the behavior of several other functions. + + Basically, Winboard is optimized to avoid drawing the whole board if not strictly + needed. Unfortunately, the decision whether or not to perform a full or partial + repaint is scattered all over the place, which is not good for features such as + "arrow highlighting" that require a full repaint of the board. + + So, I've tried to patch the code where I thought it made sense (e.g. after or during + user interaction, when speed is not so important) but especially to avoid errors + in the displayed graphics. + + In such patched places, I always try refer to this function so there is a single + place to maintain knowledge. + + To restore the original behavior, just return FALSE unconditionally. +*/ +BOOL IsFullRepaintPreferrable() +{ + BOOL result = FALSE; + + if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) { + /* Arrow may appear on the board */ + result = TRUE; + } + + return result; +} + +/* + This function is called by DrawPosition to know whether a full repaint must + be forced or not. + + Only DrawPosition may directly call this function, which makes use of + some state information. Other function should call DrawPosition specifying + the repaint flag, and can use IsFullRepaintPreferrable if needed. +*/ +BOOL DrawPositionNeedsFullRepaint() +{ + BOOL result = FALSE; + + /* + Probably a slightly better policy would be to trigger a full repaint + when animInfo.piece changes state (i.e. empty -> non-empty and viceversa), + but animation is fast enough that it's difficult to notice. + */ + if( animInfo.piece == EmptySquare ) { + if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) { + result = TRUE; + } + } + + return result; +} + VOID DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) { @@ -3208,6 +3634,21 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) */ Boolean fullrepaint = repaint; + if( DrawPositionNeedsFullRepaint() ) { + fullrepaint = TRUE; + } + +#if 0 + if( fullrepaint ) { + static int repaint_count = 0; + char buf[128]; + + repaint_count++; + sprintf( buf, "FULL repaint: %d\n", repaint_count ); + OutputDebugString( buf ); + } +#endif + if (board == NULL) { if (!lastReqValid) { return; @@ -3410,6 +3851,11 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) DrawGridOnDC(hdcmem); DrawHighlightsOnDC(hdcmem); DrawBoardOnDC(hdcmem, board, tmphdc); + + if( appData.highlightMoveWithArrow ) { + DrawArrowHighlight(hdcmem); + } + DrawCoordsOnDC(hdcmem); /* Put the dragged piece back into place and draw it */ @@ -3587,7 +4033,9 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) POINT pt; static int recursive = 0; HMENU hmenu; + BOOLEAN needsRedraw = FALSE; BOOLEAN saveAnimate; + BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */ static BOOLEAN sameAgain = FALSE; if (recursive) { @@ -3636,7 +4084,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } if (!appData.highlightLastMove) { ClearHighlights(); - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); } fromX = fromY = -1; dragInfo.start.x = dragInfo.start.y = -1; @@ -3647,7 +4095,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } else if (fromX == x && fromY == y) { /* Downclick on same square again */ ClearHighlights(); - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); sameAgain = TRUE; } else if (fromX != -1) { /* Downclick on different square */ @@ -3668,11 +4116,11 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) UserMoveEvent(fromX, fromY, toX, toY, 'q'); if (!appData.highlightLastMove) { ClearHighlights(); - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); } } else { SetHighlights(fromX, fromY, toX, toY); - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); PromotionPopup(hwnd); } } else { /* not a promotion */ @@ -3684,7 +4132,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR); if (appData.animate && !appData.highlightLastMove) { ClearHighlights(); - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); } } if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY); @@ -3692,7 +4140,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; } ClearHighlights(); - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); } /* First downclick, or restart on a square with same color piece */ if (!frozen && OKToStartUserMove(x, y)) { @@ -3707,6 +4155,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) fromX = fromY = -1; dragInfo.start.x = dragInfo.start.y = -1; dragInfo.from = dragInfo.start; + DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */ } break; @@ -3725,7 +4174,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* First square clicked: start click-click move */ SetHighlights(fromX, fromY, -1, -1); } - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) { /* Errant click; ignore */ break; @@ -3740,7 +4189,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (appData.alwaysPromoteToQueen) { UserMoveEvent(fromX, fromY, toX, toY, 'q'); } else { - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); PromotionPopup(hwnd); } } else { @@ -3754,7 +4203,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } if (appData.animate || appData.animateDragging || appData.highlightDragging || gotPremove) { - DrawPosition(FALSE, NULL); + DrawPosition(forceFullRepaint || FALSE, NULL); } } dragInfo.start.x = dragInfo.start.y = -1; @@ -3764,14 +4213,22 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_MOUSEMOVE: if ((appData.animateDragging || appData.highlightDragging) && (wParam & MK_LBUTTON) - && dragInfo.from.x >= 0) { + && dragInfo.from.x >= 0) + { + BOOL full_repaint = FALSE; + if (appData.animateDragging) { dragInfo.pos = pt; } if (appData.highlightDragging) { SetHighlights(fromX, fromY, x, y); + if( IsDrawArrowEnabled() && (x < 0 || x > 7 || y < 0 || y > y) ) { + full_repaint = TRUE; } - DrawPosition(FALSE, NULL); + } + + DrawPosition( full_repaint, NULL); + dragInfo.lastpos = dragInfo.pos; } break; @@ -4059,6 +4516,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) FILE *f; UINT number; char fileTitle[MSG_SIZ]; + static SnapData sd; switch (message) { @@ -4233,11 +4691,45 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) PasteGameFromClipboard(); break; + case IDM_CopyGameListToClipboard: + CopyGameListToClipboard(); + break; + /* [AS] Autodetect FEN or PGN data */ - case IDM_Paste: + case IDM_PasteAny: PasteGameOrFENFromClipboard(); break; + /* [AS] Move history */ + case IDM_ShowMoveHistory: + if( MoveHistoryIsUp() ) { + MoveHistoryPopDown(); + } + else { + MoveHistoryPopUp(); + } + break; + + /* [AS] Eval graph */ + case IDM_ShowEvalGraph: + if( EvalGraphIsUp() ) { + EvalGraphPopDown(); + } + else { + EvalGraphPopUp(); + } + break; + + /* [AS] Engine output */ + case IDM_ShowEngineOutput: + if( EngineOutputIsUp() ) { + EngineOutputPopDown(); + } + else { + EngineOutputPopUp(); + } + break; + /* [AS] User adjudication */ case IDM_UserAdjudication_White: UserAdjudicationEvent( +1 ); @@ -4251,6 +4743,11 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) UserAdjudicationEvent( 0 ); break; + /* [AS] Game list options dialog */ + case IDM_GameListOptions: + GameListOptions(); + break; + case IDM_CopyPosition: CopyFENToClipboard(); break; @@ -4462,12 +4959,17 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_GeneralOptions: GeneralOptionsPopup(hwnd); + DrawPosition(TRUE, NULL); break; case IDM_BoardOptions: BoardOptionsPopup(hwnd); break; + case IDM_EnginePlayOptions: + EnginePlayOptionsPopup(hwnd); + break; + case IDM_IcsOptions: IcsOptionsPopup(hwnd); break; @@ -4718,11 +5220,31 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) InputEvent(hwnd, message, wParam, lParam); break; + /* [AS] Also move "attached" child windows */ + case WM_WINDOWPOSCHANGING: + if( hwnd == hwndMain && appData.useStickyWindows ) { + LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam; + + if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) { + /* Window is moving */ + RECT rcMain; + + GetWindowRect( hwnd, &rcMain ); + + ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory ); + ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph ); + ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput ); + } + } + break; + + /* [AS] Snapping */ case WM_ENTERSIZEMOVE: if (hwnd == hwndMain) { doingSizing = TRUE; lastSizing = 0; } + return OnEnterSizeMove( &sd, hwnd, wParam, lParam ); break; case WM_SIZING: @@ -4731,6 +5253,9 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; + case WM_MOVING: + return OnMoving( &sd, hwnd, wParam, lParam ); + case WM_EXITSIZEMOVE: if (hwnd == hwndMain) { RECT client; @@ -4740,6 +5265,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) ResizeBoard(client.right, client.bottom, lastSizing); lastSizing = 0; } + return OnExitSizeMove( &sd, hwnd, wParam, lParam ); break; case WM_DESTROY: /* message: window being destroyed */ @@ -5132,8 +5658,7 @@ ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, EndDeferWindowPos(cl.hdwp); } -/* Center one window over another */ -BOOL CenterWindow (HWND hwndChild, HWND hwndParent) +BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode) { RECT rChild, rParent; int wChild, hChild, wParent, hParent; @@ -5165,7 +5690,13 @@ BOOL CenterWindow (HWND hwndChild, HWND hwndParent) } /* Calculate new Y position, then adjust for screen */ + if( mode == 0 ) { yNew = rParent.top + ((hParent - hChild) /2); + } + else { + yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3; + } + if (yNew < 0) { yNew = 0; } else if ((yNew+hChild) > hScreen) { @@ -5177,6 +5708,12 @@ BOOL CenterWindow (HWND hwndChild, HWND hwndParent) xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } +/* Center one window over another */ +BOOL CenterWindow (HWND hwndChild, HWND hwndParent) +{ + return CenterWindowEx( hwndChild, hwndParent, 0 ); +} + /*---------------------------------------------------------------------------*\ * * Startup Dialog functions @@ -5597,7 +6134,7 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_INITDIALOG: move[0] = (char) lParam; move[1] = NULLCHAR; - CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER)); + CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 ); hInput = GetDlgItem(hDlg, OPT_Move); SetWindowText(hInput, move); SetFocus(hInput); @@ -6244,6 +6781,7 @@ ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { + static SnapData sd; static HWND hText, hInput, hFocus; InputSource *is = consoleInputSource; RECT rect; @@ -6330,7 +6868,21 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) mmi->ptMinTrackSize.x = 100; mmi->ptMinTrackSize.y = 100; break; + + /* [AS] Snapping */ + 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 DefWindowProc(hDlg, message, wParam, lParam); } @@ -7319,6 +7871,207 @@ int NewGameFRC() return result; } +/* [AS] Game list options */ +typedef struct { + char id; + char * name; +} GLT_Item; + +static GLT_Item GLT_ItemInfo[] = { + { GLT_EVENT, "Event" }, + { GLT_SITE, "Site" }, + { GLT_DATE, "Date" }, + { GLT_ROUND, "Round" }, + { GLT_PLAYERS, "Players" }, + { GLT_RESULT, "Result" }, + { GLT_WHITE_ELO, "White Rating" }, + { GLT_BLACK_ELO, "Black Rating" }, + { GLT_TIME_CONTROL,"Time Control" }, + { GLT_VARIANT, "Variant" }, + { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK }, + { 0, 0 } +}; + +const char * GLT_FindItem( char id ) +{ + const char * result = 0; + + GLT_Item * list = GLT_ItemInfo; + + while( list->id != 0 ) { + if( list->id == id ) { + result = list->name; + break; + } + + list++; + } + + return result; +} + +void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index ) +{ + const char * name = GLT_FindItem( id ); + + if( name != 0 ) { + if( index >= 0 ) { + SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name ); + } + else { + SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name ); + } + } +} + +void GLT_TagsToList( HWND hDlg, char * tags ) +{ + char * pc = tags; + + SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 ); + + while( *pc ) { + GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 ); + pc++; + } + + SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" ); + + pc = GLT_ALL_TAGS; + + while( *pc ) { + if( strchr( tags, *pc ) == 0 ) { + GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 ); + } + pc++; + } + + SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 ); +} + +char GLT_ListItemToTag( HWND hDlg, int index ) +{ + char result = '\0'; + char name[128]; + + GLT_Item * list = GLT_ItemInfo; + + if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) { + while( list->id != 0 ) { + if( strcmp( list->name, name ) == 0 ) { + result = list->id; + break; + } + + list++; + } + } + + return result; +} + +void GLT_MoveSelection( HWND hDlg, int delta ) +{ + int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 ); + int idx2 = idx1 + delta; + int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 ); + + if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) { + char buf[128]; + + SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf ); + SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 ); + SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf ); + SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 ); + } +} + +LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static char glt[64]; + static char * lpUserGLT; + + switch( message ) + { + case WM_INITDIALOG: + lpUserGLT = (char *) lParam; + + strcpy( glt, lpUserGLT ); + + CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER)); + + /* Initialize list */ + GLT_TagsToList( hDlg, glt ); + + SetFocus( GetDlgItem(hDlg, IDC_GameListTags) ); + + break; + + case WM_COMMAND: + switch( LOWORD(wParam) ) { + case IDOK: + { + char * pc = lpUserGLT; + int idx = 0; + int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 ); + char id; + + do { + id = GLT_ListItemToTag( hDlg, idx ); + + *pc++ = id; + idx++; + } while( id != '\0' ); + } + EndDialog( hDlg, 0 ); + return TRUE; + case IDCANCEL: + EndDialog( hDlg, 1 ); + return TRUE; + + case IDC_GLT_Default: + strcpy( glt, GLT_DEFAULT_TAGS ); + GLT_TagsToList( hDlg, glt ); + return TRUE; + + case IDC_GLT_Restore: + strcpy( glt, lpUserGLT ); + GLT_TagsToList( hDlg, glt ); + return TRUE; + + case IDC_GLT_Up: + GLT_MoveSelection( hDlg, -1 ); + return TRUE; + + case IDC_GLT_Down: + GLT_MoveSelection( hDlg, +1 ); + return TRUE; + } + + break; + } + + return FALSE; +} + +int GameListOptions() +{ + char glt[64]; + int result; + FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst ); + + strcpy( glt, appData.gameListTags ); + + result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt ); + + if( result == 0 ) { + /* [AS] Memory leak here! */ + appData.gameListTags = strdup( glt ); + } + + return result; +} + VOID DisplayIcsInteractionTitle(char *str) @@ -8441,6 +9194,10 @@ AnalysisPopUp(char* title, char* str) FARPROC lpProc; char *p, *q; + /* [AS] */ + EngineOutputPopUp(); + return; + if (str == NULL) str = ""; p = (char *) malloc(2 * strlen(str) + 2); q = p; @@ -8653,11 +9410,9 @@ Tween(start, mid, finish, factor, frames, nFrames) } void -HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current) +HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current ) { - /* Currently not implemented in WinBoard */ -#if 1 - /* [AS] Let's see what this function is for... */ +#if 0 char buf[256]; sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n", @@ -8665,4 +9420,22 @@ HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current) OutputDebugString( buf ); #endif + + MoveHistorySet( movelist, first, last, current, pvInfoList ); + + EvalGraphSet( first, last, current, pvInfoList ); +} + +void SetProgramStats( int which, int depth, unsigned long nodes, int score, int time, char * pv ) +{ +#if 0 + char buf[1024]; + + sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n", + which, depth, nodes, score / 100.0, time / 100.0, pv == 0 ? "n/a" : pv ); + + OutputDebugString( buf ); +#endif + + EngineOutputUpdate( which, depth, nodes, score, time, pv ); } diff --git a/winboard/winboard.h b/winboard/winboard.h index 5823b2e..890e071 100644 --- a/winboard/winboard.h +++ b/winboard/winboard.h @@ -163,3 +163,18 @@ extern MyFont *font[NUM_SIZES][NUM_FONTS]; #define COPY_TMP "wbcopy.tmp" #define PASTE_TMP "wbpaste.tmp" + +/* [AS] Layout management */ +typedef struct { + Boolean visible; + int x; + int y; + int width; + int height; +} WindowPlacement; + +VOID InitWindowPlacement( WindowPlacement * wp ); + +VOID RestoreWindowPlacement( HWND hWnd, WindowPlacement * wp ); + +VOID ReattachAfterMove( LPRECT lprcOldPos, int new_x, int new_y, HWND hWndChild, WindowPlacement * pwpChild ); diff --git a/winboard/winboard.rc b/winboard/winboard.rc index 085f5b9..b4635b2 100644 --- a/winboard/winboard.rc +++ b/winboard/winboard.rc @@ -30,20 +30,23 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -ABOUTBOX DIALOG DISCARDABLE 22, 17, 167, 67 +ABOUTBOX DIALOG DISCARDABLE 22, 17, 180, 113 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About WinBoard" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,131,47,32,14,WS_GROUP - ICON "icon_white",-1,3,6,20,20 + DEFPUSHBUTTON "OK",IDOK,126,94,50,14,WS_GROUP + ICON "icon_white",IDC_STATIC,3,6,20,20 LTEXT "Chessboard for Windows",400,25,15,121,8 LTEXT "Copyright 1991 Digital Equipment Corporation",201,6,34, 149,8 LTEXT "Enhancements Copyright 1992-2003 Free Software Foundation", - OPT_TCtext1,6,44,121,17 + OPT_TCtext1,6,45,121,17 CONTROL "",OPT_TCTime,"Static",SS_BLACKRECT,4,28,159,1 - LTEXT "WinBoard 0.0.0",ABOUTBOX_Version,25,5,142,8 + LTEXT "WinBoard 0.0.0",ABOUTBOX_Version,25,5,61,8 + LTEXT "Enhancements Copyright 2005\r\nAlessandro Scotti", + IDC_STATIC,6,65,170,24 + LTEXT "(unofficial version ""X"")",IDC_STATIC,88,4,71,8 END DLG_TimeControl DIALOG DISCARDABLE 6, 18, 165, 114 @@ -68,20 +71,20 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,90,95,40,14 END -DLG_LoadOptions DIALOG DISCARDABLE 10, 18, 144, 55 +DLG_LoadOptions DIALOG DISCARDABLE 10, 18, 136, 55 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Load Game Options" FONT 8, "MS Sans Serif" BEGIN CONTROL "Load games with automatic stepping",OPT_Autostep,"Button", - BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,4,4,136,10 - EDITTEXT OPT_ASTimeDelay,23,18,28,12,ES_AUTOHSCROLL - LTEXT "seconds per move",OPT_AStext1,57,20,60,8,NOT WS_GROUP - PUSHBUTTON "OK",IDOK,24,37,40,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,80,37,40,14 + BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,4,4,130,10 + EDITTEXT OPT_ASTimeDelay,16,16,28,14,ES_AUTOHSCROLL + LTEXT "seconds per move",OPT_AStext1,46,20,60,8,NOT WS_GROUP + PUSHBUTTON "OK",IDOK,26,36,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,82,36,50,14 END -DLG_SaveOptions DIALOG DISCARDABLE 6, 17, 133, 119 +DLG_SaveOptions DIALOG DISCARDABLE 6, 17, 178, 119 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Save Game Options" FONT 8, "MS Sans Serif" @@ -89,17 +92,19 @@ BEGIN CONTROL "Save games automatically",OPT_Autosave,"Button", BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,4,4,97,10 CONTROL "Prompt for filename",OPT_AVPrompt,"Button", - BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,18,18,75,10 - CONTROL "To file:",OPT_AVToFile,"Button",BS_AUTORADIOBUTTON,18, - 31,36,10 - EDITTEXT OPT_AVFilename,18,44,97,12,ES_AUTOHSCROLL - GROUPBOX "Save Style",801,4,63,125,28,WS_GROUP - CONTROL "PGN",OPT_PGN,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, - 18,75,39,10 - CONTROL "Old",OPT_Old,"Button",BS_AUTORADIOBUTTON,73,75,39,10 - PUSHBUTTON "OK",IDOK,18,98,40,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,74,98,40,14 - PUSHBUTTON "Browse...",OPT_AVBrowse,76,31,39,14 + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,16,18,75,10 + CONTROL "To file:",OPT_AVToFile,"Button",BS_AUTORADIOBUTTON,16, + 32,36,10 + EDITTEXT OPT_AVFilename,54,30,97,14,ES_AUTOHSCROLL + PUSHBUTTON "...",OPT_AVBrowse,156,30,18,14 + GROUPBOX "Save As: ",801,4,48,170,28,WS_GROUP + CONTROL "PGN",OPT_PGN,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,8, + 60,39,10 + CONTROL "Old",OPT_Old,"Button",BS_AUTORADIOBUTTON,54,60,114,10 + CONTROL "Save out of book info in PGN",OPT_OutOfBookInfo,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,4,82,109,10 + PUSHBUTTON "OK",IDOK,68,100,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,124,100,50,14 END 1536 DIALOG DISCARDABLE 36, 24, 264, 134 @@ -132,32 +137,32 @@ BEGIN PUSHBUTTON "Net&work...",1037,208,113,50,14,WS_GROUP END -DLG_CommPort DIALOG DISCARDABLE 25, 30, 159, 98 +DLG_CommPort DIALOG DISCARDABLE 25, 30, 220, 79 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Communication Port Settings" FONT 8, "Helv" BEGIN + PUSHBUTTON "OK",IDOK,106,60,50,14 + PUSHBUTTON "Cancel",IDCANCEL,164,60,50,14 RTEXT "&Port:",-1,4,6,40,10 COMBOBOX OPT_Port,49,4,55,60,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP - RTEXT "Data &Rate:",-1,4,21,40,10,NOT WS_GROUP - COMBOBOX OPT_DataRate,49,19,55,100,CBS_DROPDOWN | WS_VSCROLL | + RTEXT "Data &Rate:",-1,114,6,40,10,NOT WS_GROUP + COMBOBOX OPT_DataRate,159,4,55,100,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP - RTEXT "Data &Bits:",-1,4,36,40,10,NOT WS_GROUP - COMBOBOX OPT_Bits,49,34,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | + RTEXT "Data &Bits:",-1,4,25,40,10,NOT WS_GROUP + COMBOBOX OPT_Bits,49,22,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP - RTEXT "P&arity:",-1,4,51,40,10,NOT WS_GROUP - COMBOBOX OPT_Parity,49,49,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | - WS_VSCROLL | WS_TABSTOP - RTEXT "&Stop Bits:",-1,4,66,40,10,NOT WS_GROUP - COMBOBOX OPT_StopBits,49,64,55,60,CBS_DROPDOWNLIST | + RTEXT "P&arity:",-1,114,24,40,10,NOT WS_GROUP + COMBOBOX OPT_Parity,159,22,55,60,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + RTEXT "&Stop Bits:",-1,4,42,40,10,NOT WS_GROUP + COMBOBOX OPT_StopBits,49,40,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP - RTEXT "F&low:",-1,4,81,40,10,NOT WS_GROUP - DEFPUSHBUTTON "OK",IDOK,115,4,40,14 - PUSHBUTTON "Cancel",IDCANCEL,115,24,40,14 - COMBOBOX OPT_Flow,49,79,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | + RTEXT "F&low:",-1,114,42,40,10,NOT WS_GROUP + COMBOBOX OPT_Flow,159,40,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Help",OPT_SerialHelp,115,80,40,14,NOT WS_VISIBLE + PUSHBUTTON "Help",OPT_SerialHelp,4,60,50,14,NOT WS_VISIBLE END DLG_EditComment DIALOG DISCARDABLE 6, 18, 306, 104 @@ -188,20 +193,23 @@ BEGIN LTEXT "Promote pawn to:",501,6,8,58,8 END -ABOUTBOX2 DIALOG DISCARDABLE 22, 17, 281, 198 +ABOUTBOX2 DIALOG DISCARDABLE 22, 17, 281, 223 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About WinBoard" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,244,180,32,14,WS_GROUP RTEXT "Chessboard for Windows",DLG_TimeControl,196,154,80,8 - LTEXT "Copyright 1991 Digital Equipment Corporation",201,4,167, + LTEXT "Copyright 1991 Digital Equipment Corporation",201,4,168, 151,8 LTEXT "Enhancements Copyright 1992-2003 Free Software Foundation", - OPT_TCtext1,4,177,126,17 + OPT_TCtext1,4,179,126,17 CONTROL "",OPT_TCTime,"Static",SS_BLACKRECT,4,164,272,1 LTEXT "WinBoard 0.0.0",ABOUTBOX_Version,4,154,64,8 CONTROL "galactic",IDC_STATIC,"Static",SS_BITMAP,4,4,15,13 + DEFPUSHBUTTON "OK",IDOK,226,204,50,14 + LTEXT "Enhancements Copyright 2005\r\nAlessandro Scotti", + IDC_STATIC,4,199,183,20 + LTEXT "(unofficial version ""X"")",IDC_STATIC,68,154,71,8 END DLG_GameList DIALOG DISCARDABLE 6, 18, 259, 153 @@ -269,37 +277,37 @@ BEGIN LTEXT "Sorry Charlie",OPT_ErrorText,27,4,130,25 END -DLG_Colorize DIALOGEX 0, 0, 183, 52 +DLG_Colorize DIALOGEX 0, 0, 174, 61 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ICS Interaction Colors" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN - PUSHBUTTON "&Choose Color...",OPT_ChooseColor,15,29,51,14,WS_GROUP + PUSHBUTTON "&Color...",OPT_ChooseColor,119,4,51,14,WS_GROUP CONTROL "&Bold",OPT_Bold,"Button",BS_AUTOCHECKBOX | WS_GROUP | - WS_TABSTOP,93,4,30,10 - CONTROL "&Italic",OPT_Italic,"Button",BS_AUTOCHECKBOX,93,14,30, + WS_TABSTOP,4,24,30,10 + CONTROL "&Italic",OPT_Italic,"Button",BS_AUTOCHECKBOX,40,24,30, 10 - CONTROL "&Underline",OPT_Underline,"Button",BS_AUTOCHECKBOX,93, + CONTROL "&Underline",OPT_Underline,"Button",BS_AUTOCHECKBOX,76, 24,45,10 - CONTROL "&Strikeout",OPT_Strikeout,"Button",BS_AUTOCHECKBOX,93, - 34,42,10 - DEFPUSHBUTTON "OK",IDOK,145,7,31,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,145,24,31,14 + CONTROL "&Strikeout",OPT_Strikeout,"Button",BS_AUTOCHECKBOX,128, + 24,42,10 + DEFPUSHBUTTON "OK",IDOK,64,42,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,120,42,50,14 CONTROL "",OPT_Sample,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_GROUP,4,9,75,15,WS_EX_CLIENTEDGE + ES_READONLY | WS_GROUP,4,4,106,15,WS_EX_CLIENTEDGE END -DLG_Question DIALOG DISCARDABLE 0, 0, 187, 60 +DLG_Question DIALOG DISCARDABLE 0, 0, 187, 77 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question" FONT 8, "MS Sans Serif" BEGIN - EDITTEXT OPT_QuestionInput,4,44,179,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "Enter",IDOK,133,4,50,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,133,24,50,14 + EDITTEXT OPT_QuestionInput,4,36,179,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,78,58,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,134,58,50,14 LTEXT "Enter a chess engine command or just type something stupid that will completely screw things up.", - OPT_QuestionText,27,4,101,33 - ICON 32514,IDC_STATIC,4,13,20,20 + OPT_QuestionText,30,2,153,28 + ICON 32514,IDC_STATIC,4,4,21,20 END DLG_Startup DIALOG DISCARDABLE 0, 0, 276, 127 @@ -337,14 +345,14 @@ BEGIN EDITTEXT OPT_IndexNumber,54,0,155,13,ES_AUTOHSCROLL END -DLG_TypeInMove DIALOG DISCARDABLE 0, 0, 186, 46 +DLG_TypeInMove DIALOG DISCARDABLE 0, 0, 206, 23 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Type in a move" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,129,7,50,14 - PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 - EDITTEXT OPT_Move,7,16,109,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,96,4,50,14 + PUSHBUTTON "Cancel",IDCANCEL,152,4,50,14 + EDITTEXT OPT_Move,4,4,86,13,ES_AUTOHSCROLL END DLG_Sound DIALOG DISCARDABLE 0, 0, 257, 95 @@ -373,7 +381,7 @@ BEGIN LTEXT "Event:",IDC_STATIC,19,9,26,9 END -DLG_GeneralOptions DIALOG DISCARDABLE 0, 0, 271, 150 +DLG_GeneralOptions DIALOG DISCARDABLE 0, 0, 271, 162 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "General Options" FONT 8, "MS Sans Serif" @@ -381,25 +389,25 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,207,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,208,25,50,14 CONTROL "Always on &Top",OPT_AlwaysOnTop,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,16,6,79,10 + BS_AUTOCHECKBOX | WS_TABSTOP,4,6,79,10 CONTROL "Always &Queen",OPT_AlwaysQueen,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,16,20,79,10 + WS_TABSTOP,4,20,79,10 CONTROL "Animate &Dragging",OPT_AnimateDragging,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,16,34,79,10 + BS_AUTOCHECKBOX | WS_TABSTOP,4,34,79,10 CONTROL "&Animate Moving",OPT_AnimateMoving,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,16,48,79,10 + BS_AUTOCHECKBOX | WS_TABSTOP,4,48,79,10 CONTROL "Auto &Flag",OPT_AutoFlag,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,16,62,79,10 + WS_TABSTOP,4,62,79,10 CONTROL "Auto Flip &View",OPT_AutoFlipView,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,16,76,79,10 + BS_AUTOCHECKBOX | WS_TABSTOP,4,76,79,10 CONTROL "Auto &Raise Board",OPT_AutoRaiseBoard,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,16,90,71,10 + BS_AUTOCHECKBOX | WS_TABSTOP,4,90,71,10 CONTROL "&Blindfold",OPT_Blindfold,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,16,104,79,10 + WS_TABSTOP,4,104,79,10 CONTROL "&Highlight Dragging",OPT_HighlightDragging,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,16,118,79,10 + BS_AUTOCHECKBOX | WS_TABSTOP,4,118,79,10 CONTROL "Extended PGN Info",OPT_SaveExtPGN,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,16,132,79,10 + BS_AUTOCHECKBOX | WS_TABSTOP,4,132,79,10 CONTROL "Highlight Last &Move",OPT_HighlightLastMove,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,109,6,79,10 CONTROL "Periodic &Updates",OPT_PeriodicUpdates,"Button", @@ -418,165 +426,168 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,109,104,79,10 CONTROL "Test &Legality",OPT_TestLegality,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,109,118,79,10 - CONTROL "Hide Thinking From Human",OPT_HideThinkFromHuman,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,109,132,102,10 + CONTROL "Hide Thinking from Human",OPT_HideThinkFromHuman,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,132,100,10 + CONTROL "Extra Info in Move History",OPT_ExtraInfoInMoveHistory, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,146,97,10 + CONTROL "Highlight Move with Arrow",OPT_HighlightMoveArrow, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,109,145,111,9 END -DLG_IcsOptions DIALOGEX 0, 0, 318, 271 +DLG_IcsOptions DIALOGEX 0, 0, 302, 265 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ICS Options" -FONT 8, "MS Sans Serif", 0, 0, 0x1 +FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,88,250,60,15 - PUSHBUTTON "Cancel",IDCANCEL,168,250,60,15 + DEFPUSHBUTTON "OK",IDOK,194,246,50,15 + PUSHBUTTON "Cancel",IDCANCEL,248,246,50,15 CONTROL "&Auto Comment",OPT_AutoComment,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,20,12,63,8 + WS_TABSTOP,10,12,63,8 CONTROL "Auto &Observe",OPT_AutoObserve,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,20,27,63,8 + WS_TABSTOP,10,25,63,8 CONTROL "&Get Move List",OPT_GetMoveList,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,20,42,63,8 + BS_AUTOCHECKBOX | WS_TABSTOP,10,38,63,8 CONTROL "&Local Line Editing",OPT_LocalLineEditing,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,20,57,84,8 + BS_AUTOCHECKBOX | WS_TABSTOP,10,51,84,8 CONTROL "&Quiet Play",OPT_QuietPlay,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,20,72,63,8 + WS_TABSTOP,10,64,63,8 CONTROL "&Premove",OPT_Premove,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,171,12,46,10 + WS_TABSTOP,160,12,46,10 CONTROL "&White first move",OPT_PremoveWhite,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,171,27,67,10 - EDITTEXT OPT_PremoveWhiteText,252,23,25,14,ES_AUTOHSCROLL + BS_AUTOCHECKBOX | WS_TABSTOP,160,26,67,10 + EDITTEXT OPT_PremoveWhiteText,236,22,25,14,ES_AUTOHSCROLL CONTROL "&Black first move",OPT_PremoveBlack,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,171,42,66,10 - EDITTEXT OPT_PremoveBlackText,252,39,25,14,ES_AUTOHSCROLL + BS_AUTOCHECKBOX | WS_TABSTOP,160,40,66,10 + EDITTEXT OPT_PremoveBlackText,236,38,25,14,ES_AUTOHSCROLL CONTROL "&Sound alarm at",OPT_IcsAlarm,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,171,72,63,10 - EDITTEXT OPT_IcsAlarmTime,243,70,20,13,ES_AUTOHSCROLL - LTEXT "seconds",IDC_STATIC,270,72,28,8 - PUSHBUTTON "Choose...",OPT_ChooseShoutColor,104,101,45,15 - PUSHBUTTON "Choose...",OPT_ChooseSShoutColor,104,121,45,15 - PUSHBUTTON "Choose...",OPT_ChooseChannel1Color,104,141,45,15 - PUSHBUTTON "Choose...",OPT_ChooseChannelColor,104,161,45,15 - PUSHBUTTON "Choose...",OPT_ChooseKibitzColor,104,181,45,15 - PUSHBUTTON "Choose...",OPT_ChooseTellColor,252,101,45,15 - PUSHBUTTON "Choose...",OPT_ChooseChallengeColor,252,121,45,15 - PUSHBUTTON "Choose...",OPT_ChooseRequestColor,252,141,45,15 - PUSHBUTTON "Choose...",OPT_ChooseSeekColor,252,161,45,15 - PUSHBUTTON "Choose...",OPT_ChooseNormalColor,252,181,45,15 + WS_TABSTOP,160,72,63,10 + EDITTEXT OPT_IcsAlarmTime,236,68,26,14,ES_AUTOHSCROLL + LTEXT "seconds",IDC_STATIC,264,72,28,8 + PUSHBUTTON "Choose...",OPT_ChooseShoutColor,98,101,45,15 + PUSHBUTTON "Choose...",OPT_ChooseSShoutColor,98,121,45,15 + PUSHBUTTON "Choose...",OPT_ChooseChannel1Color,98,141,45,15 + PUSHBUTTON "Choose...",OPT_ChooseChannelColor,98,161,45,15 + PUSHBUTTON "Choose...",OPT_ChooseKibitzColor,98,181,45,15 + PUSHBUTTON "Choose...",OPT_ChooseTellColor,246,101,45,15 + PUSHBUTTON "Choose...",OPT_ChooseChallengeColor,246,121,45,15 + PUSHBUTTON "Choose...",OPT_ChooseRequestColor,246,141,45,15 + PUSHBUTTON "Choose...",OPT_ChooseSeekColor,246,161,45,15 + PUSHBUTTON "Choose...",OPT_ChooseNormalColor,246,181,45,15 PUSHBUTTON "&Choose Background Color...",OPT_ChooseBackgroundColor, - 17,204,132,16 - PUSHBUTTON "&Default ICS Colors",OPT_DefaultColors,165,204,132,16 + 11,204,132,16 + PUSHBUTTON "&Default ICS Colors",OPT_DefaultColors,159,204,132,16 CONTROL "Do ¬ colorize messages",OPT_DontColorize,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,110,225,97,10 + BS_AUTOCHECKBOX | WS_TABSTOP,104,225,97,10 CONTROL "",OPT_SampleShout,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_DISABLED | WS_GROUP,17,101,75,15, + ES_READONLY | WS_DISABLED | WS_GROUP,11,101,75,15, WS_EX_CLIENTEDGE CONTROL "",OPT_SampleSShout,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_DISABLED | WS_GROUP,17,121,75,15, + ES_READONLY | WS_DISABLED | WS_GROUP,11,121,75,15, WS_EX_CLIENTEDGE CONTROL "",OPT_SampleChannel1,"RICHEDIT",ES_CENTER | - ES_MULTILINE | ES_READONLY | WS_DISABLED | WS_GROUP,17, + ES_MULTILINE | ES_READONLY | WS_DISABLED | WS_GROUP,11, 141,75,15,WS_EX_CLIENTEDGE CONTROL "",OPT_SampleChannel,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_DISABLED | WS_GROUP,17,161,75,15, + ES_READONLY | WS_DISABLED | WS_GROUP,11,161,75,15, WS_EX_CLIENTEDGE CONTROL "",OPT_SampleKibitz,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_GROUP,17,181,75,15,WS_EX_CLIENTEDGE + ES_READONLY | WS_GROUP,11,181,75,15,WS_EX_CLIENTEDGE CONTROL "",OPT_SampleTell,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_DISABLED | WS_GROUP,165,101,75,15, + ES_READONLY | WS_DISABLED | WS_GROUP,159,101,75,15, WS_EX_CLIENTEDGE CONTROL "",OPT_SampleChallenge,"RICHEDIT",ES_CENTER | - ES_MULTILINE | ES_READONLY | WS_DISABLED | WS_GROUP,165, + ES_MULTILINE | ES_READONLY | WS_DISABLED | WS_GROUP,159, 121,75,15,WS_EX_CLIENTEDGE CONTROL "",OPT_SampleRequest,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_DISABLED | WS_GROUP,165,141,75,15, + ES_READONLY | WS_DISABLED | WS_GROUP,159,141,75,15, WS_EX_CLIENTEDGE CONTROL "",OPT_SampleSeek,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_DISABLED | WS_GROUP,165,161,75,15, + ES_READONLY | WS_DISABLED | WS_GROUP,159,161,75,15, WS_EX_CLIENTEDGE CONTROL "",OPT_SampleNormal,"RICHEDIT",ES_CENTER | ES_MULTILINE | - ES_READONLY | WS_DISABLED | WS_GROUP,165,181,75,15, + ES_READONLY | WS_DISABLED | WS_GROUP,159,181,75,15, WS_EX_CLIENTEDGE - GROUPBOX "Interaction Colors",IDC_STATIC,10,90,295,150 - GROUPBOX "Premove",IDC_STATIC,159,0,146,59 - GROUPBOX "",IDC_STATIC,10,0,146,89 - GROUPBOX "Alarm",IDC_STATIC,159,59,146,30 + GROUPBOX "Interaction Colors",IDC_STATIC,4,90,294,150 + GROUPBOX "Premove",IDC_STATIC,154,0,144,56 + GROUPBOX "",IDC_STATIC,4,0,146,88 + GROUPBOX "Alarm",IDC_STATIC,154,58,144,30 END -DLG_BoardOptions DIALOG DISCARDABLE 0, 0, 262, 250 +DLG_BoardOptions DIALOG DISCARDABLE 0, 0, 194, 250 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Board Options" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,205,10,50,14 - PUSHBUTTON "Cancel",IDCANCEL,205,35,50,14 + DEFPUSHBUTTON "OK",IDOK,84,232,50,14 + PUSHBUTTON "Cancel",IDCANCEL,140,232,50,14 CONTROL "&Tiny",OPT_SizeTiny,"Button",BS_AUTORADIOBUTTON | - WS_GROUP | WS_TABSTOP,15,15,50,10 - CONTROL "T&eeny",OPT_SizeTeeny,"Button",BS_AUTORADIOBUTTON,15,25, - 50,10 - CONTROL "&Dinky",OPT_SizeDinky,"Button",BS_AUTORADIOBUTTON,15,35, + WS_GROUP | WS_TABSTOP,9,14,50,10 + CONTROL "T&eeny",OPT_SizeTeeny,"Button",BS_AUTORADIOBUTTON,9,25, 50,10 - CONTROL "&Petite",OPT_SizePetite,"Button",BS_AUTORADIOBUTTON,15, - 45,50,10 - CONTROL "Sl&im",OPT_SizeSlim,"Button",BS_AUTORADIOBUTTON,15,55, + CONTROL "&Dinky",OPT_SizeDinky,"Button",BS_AUTORADIOBUTTON,9,34, 50,10 - CONTROL "&Small",OPT_SizeSmall,"Button",BS_AUTORADIOBUTTON,15,65, + CONTROL "&Petite",OPT_SizePetite,"Button",BS_AUTORADIOBUTTON,9, + 44,50,10 + CONTROL "Sl&im",OPT_SizeSlim,"Button",BS_AUTORADIOBUTTON,9,54,50, + 10 + CONTROL "&Small",OPT_SizeSmall,"Button",BS_AUTORADIOBUTTON,9,65, 50,10 CONTROL "Medi&ocre",OPT_SizeMediocre,"Button",BS_AUTORADIOBUTTON, - 76,15,50,10 + 70,14,50,10 CONTROL "&Middling",OPT_SizeMiddling,"Button",BS_AUTORADIOBUTTON, - 76,25,50,10 + 70,25,50,10 CONTROL "&Average",OPT_SizeAverage,"Button",BS_AUTORADIOBUTTON, - 76,35,50,10 + 70,34,50,10 CONTROL "Mode&rate",OPT_SizeModerate,"Button",BS_AUTORADIOBUTTON, - 76,45,50,10 - CONTROL "Medi&um",OPT_SizeMedium,"Button",BS_AUTORADIOBUTTON,76, - 55,50,10 - CONTROL "Bul&ky",OPT_SizeBulky,"Button",BS_AUTORADIOBUTTON,76,65, + 70,44,50,10 + CONTROL "Medi&um",OPT_SizeMedium,"Button",BS_AUTORADIOBUTTON,70, + 54,50,10 + CONTROL "Bul&ky",OPT_SizeBulky,"Button",BS_AUTORADIOBUTTON,70,65, 50,10 - CONTROL "&Large",OPT_SizeLarge,"Button",BS_AUTORADIOBUTTON,140, - 15,50,10 - CONTROL "&Big",OPT_SizeBig,"Button",BS_AUTORADIOBUTTON,140,25,50, + CONTROL "&Large",OPT_SizeLarge,"Button",BS_AUTORADIOBUTTON,134, + 14,50,10 + CONTROL "&Big",OPT_SizeBig,"Button",BS_AUTORADIOBUTTON,134,25,50, 10 - CONTROL "&Huge",OPT_SizeHuge,"Button",BS_AUTORADIOBUTTON,140,35, + CONTROL "&Huge",OPT_SizeHuge,"Button",BS_AUTORADIOBUTTON,134,34, 50,10 - CONTROL "&Giant",OPT_SizeGiant,"Button",BS_AUTORADIOBUTTON,140, - 45,50,10 + CONTROL "&Giant",OPT_SizeGiant,"Button",BS_AUTORADIOBUTTON,134, + 44,50,10 CONTROL "&Colossal",OPT_SizeColossal,"Button",BS_AUTORADIOBUTTON, - 140,55,50,10 + 134,54,50,10 CONTROL "Tita&nic",OPT_SizeTitanic,"Button",BS_AUTORADIOBUTTON, - 140,65,50,10 - PUSHBUTTON "Choose...",OPT_ChooseLightSquareColor,144,100,40,15 - PUSHBUTTON "Choose...",OPT_ChooseDarkSquareColor,144,120,40,15 - PUSHBUTTON "Choose...",OPT_ChooseWhitePieceColor,144,140,40,15 - PUSHBUTTON "Choose...",OPT_ChooseBlackPieceColor,144,160,40,15 - PUSHBUTTON "Choose...",OPT_ChooseHighlightSquareColor,144,180,40,15 - PUSHBUTTON "Choose...",OPT_ChoosePremoveHighlightColor,144,200,40, - 15 - PUSHBUTTON "Defaults",OPT_DefaultBoardColors,118,225,65,15 - EDITTEXT OPT_DarkSquareColor,104,120,25,15,ES_READONLY | + 134,65,50,10 + PUSHBUTTON "...",OPT_ChooseLightSquareColor,110,94,20,15 + PUSHBUTTON "...",OPT_ChooseDarkSquareColor,110,112,20,15 + PUSHBUTTON "...",OPT_ChooseWhitePieceColor,110,130,20,15 + PUSHBUTTON "...",OPT_ChooseBlackPieceColor,110,148,20,15 + PUSHBUTTON "...",OPT_ChooseHighlightSquareColor,110,166,20,15 + PUSHBUTTON "...",OPT_ChoosePremoveHighlightColor,110,184,20,15 + PUSHBUTTON "Defaults",OPT_DefaultBoardColors,80,206,50,15 + EDITTEXT OPT_DarkSquareColor,80,112,25,15,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP - EDITTEXT OPT_LightSquareColor,104,100,25,15,ES_READONLY | + EDITTEXT OPT_LightSquareColor,80,94,25,15,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP - EDITTEXT OPT_WhitePieceColor,104,140,25,15,ES_READONLY | + EDITTEXT OPT_WhitePieceColor,80,130,25,15,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP - EDITTEXT OPT_BlackPieceColor,104,160,25,15,ES_READONLY | + EDITTEXT OPT_BlackPieceColor,80,148,25,15,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP - EDITTEXT OPT_HighlightSquareColor,104,180,25,15,ES_READONLY | + EDITTEXT OPT_HighlightSquareColor,80,166,25,15,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP - GROUPBOX "Colors",IDC_STATIC,10,90,185,155 - EDITTEXT OPT_PremoveHighlightColor,104,200,25,15,ES_READONLY | + GROUPBOX "Colors",IDC_STATIC,4,84,185,142 + EDITTEXT OPT_PremoveHighlightColor,80,184,25,15,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP - LTEXT "Light Squares",IDC_STATIC,25,105,60,10 - LTEXT "Dark Squares",IDC_STATIC,25,124,60,10 - LTEXT "White Pieces",IDC_STATIC,25,145,60,10 - LTEXT "Black Pieces",IDC_STATIC,25,165,60,10 - LTEXT "Square Highlights",IDC_STATIC,25,185,60,10 - LTEXT "Premove Highlights",IDC_STATIC,25,205,70,10 - GROUPBOX "Size",IDC_STATIC,10,5,185,75 + LTEXT "Light Squares",IDC_STATIC,10,98,60,10 + LTEXT "Dark Squares",IDC_STATIC,10,116,60,10 + LTEXT "White Pieces",IDC_STATIC,10,134,60,10 + LTEXT "Black Pieces",IDC_STATIC,10,152,60,10 + LTEXT "Square Highlights",IDC_STATIC,10,170,60,10 + LTEXT "Premove Highlights",IDC_STATIC,10,188,70,10 + GROUPBOX "Size",IDC_STATIC,4,4,185,75 CONTROL "Monochrome",OPT_Monochrome,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,25,225,75,10 - EDITTEXT OPT_SampleLightSquare,205,110,39,36,ES_READONLY | + WS_TABSTOP,10,210,64,10 + EDITTEXT OPT_SampleLightSquare,144,96,39,36,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP - EDITTEXT OPT_SampleDarkSquare,205,165,39,36,ES_READONLY | + EDITTEXT OPT_SampleDarkSquare,144,138,39,36,ES_READONLY | WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP END @@ -585,15 +596,15 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Fonts" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,155,210,50,14 - PUSHBUTTON "Cancel",IDCANCEL,215,210,50,14 + DEFPUSHBUTTON "OK",IDOK,168,212,50,14 + PUSHBUTTON "Cancel",IDCANCEL,224,212,50,14 PUSHBUTTON "Choose...",OPT_ChooseClockFont,221,17,45,15 PUSHBUTTON "Choose...",OPT_ChooseMessageFont,221,47,45,15 PUSHBUTTON "Choose...",OPT_ChooseCoordFont,221,77,45,15 PUSHBUTTON "Choose...",OPT_ChooseTagFont,221,120,45,15 PUSHBUTTON "Choose...",OPT_ChooseCommentsFont,221,150,45,15 PUSHBUTTON "Choose...",OPT_ChooseConsoleFont,221,180,45,15 - PUSHBUTTON "&Revert to Defaults",OPT_DefaultFonts,15,210,80,15 + PUSHBUTTON "&Revert to Defaults",OPT_DefaultFonts,6,210,80,15 CONTROL "",OPT_SampleCoordFont,"RICHEDIT",ES_READONLY | WS_DISABLED | WS_BORDER,70,72,140,20 CONTROL "",OPT_SampleTagFont,"RICHEDIT",ES_READONLY | @@ -625,8 +636,89 @@ BEGIN LTEXT "&Start Position Number:",IDC_NFG_Label,4,7,71,8 EDITTEXT IDC_NFG_Edit,76,4,42,14,ES_AUTOHSCROLL PUSHBUTTON "Random",IDC_NFG_Random,122,4,50,14 - DEFPUSHBUTTON "OK",IDOK,34,28,50,14 - PUSHBUTTON "Cancel",IDCANCEL,92,28,50,14 + DEFPUSHBUTTON "OK",IDOK,64,28,50,14 + PUSHBUTTON "Cancel",IDCANCEL,122,28,50,14 +END + +DLG_GameListOptions DIALOG DISCARDABLE 0, 0, 206, 140 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Game List Options" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "PGN &Tags:",IDC_GLT,2,2,36,8 + LISTBOX IDC_GameListTags,2,12,158,102,LBS_USETABSTOPS | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Up",IDC_GLT_Up,164,12,38,14 + PUSHBUTTON "&Down",IDC_GLT_Down,164,30,38,14 + PUSHBUTTON "Default",IDC_GLT_Restore,164,82,38,14 + PUSHBUTTON "Factory",IDC_GLT_Default,164,100,38,14 + DEFPUSHBUTTON "OK",IDOK,96,122,50,14 + PUSHBUTTON "Cancel",IDCANCEL,152,122,50,14 + LTEXT "Restore to:",IDC_GLT_RestoreTo,164,70,36,8 +END + +DLG_MoveHistory DIALOGEX 0, 0, 225, 130 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Move History" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_MoveHistory,"RICHEDIT",ES_MULTILINE | ES_READONLY | + WS_BORDER | WS_VSCROLL | WS_TABSTOP,2,2,222,128 +END + +DLG_EvalGraph DIALOGEX 0, 0, 215, 75 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Evaluation Graph" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN +END + +DLG_EngineOutput DIALOGEX 0, 0, 266, 167 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Engine output" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Engine #1",IDC_EngineLabel1,2,2,152,8 + RTEXT "",IDC_Engine1_NPS,194,2,69,8 + CONTROL "",IDC_EngineMemo1,"RICHEDIT",ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | + WS_HSCROLL | WS_TABSTOP,2,10,262,72 + LTEXT "Engine #2",IDC_EngineLabel2,2,84,152,8 + RTEXT "",IDC_Engine2_NPS,196,84,67,8 + CONTROL "",IDC_EngineMemo2,"RICHEDIT",ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | + WS_HSCROLL | WS_TABSTOP,2,92,262,74 +END + +DLG_EnginePlayOptions DIALOG DISCARDABLE 0, 0, 208, 129 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Engine Options" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Ponder Next Move",IDC_EpPonder,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,4,4,75,10 + CONTROL "Enable and Show Thinking (recommended)", + IDC_EpShowThinking,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 4,16,152,10 + CONTROL "Hide Thinking when Playing against Human", + IDC_EpHideThinkingHuman,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,4,28,153,10 + CONTROL "Periodic Updates (for Analysis Mode)", + IDC_EpPeriodicUpdates,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,4,40,131,10 + GROUPBOX "Engine-engine matches",IDC_STATIC,4,56,200,50 + LTEXT "Adjudicate draw after:",IDC_STATIC,10,72,70,8 + EDITTEXT IDC_EpDrawMoveCount,116,68,40,14,ES_AUTOHSCROLL + LTEXT "moves",IDC_STATIC,158,72,22,8 + LTEXT "Win/loss adjudication threshold:",IDC_STATIC,10,90,102, + 8 + EDITTEXT IDC_EpAdjudicationThreshold,116,86,40,14,ES_AUTOHSCROLL + LTEXT "centipawns",IDC_STATIC,158,90,37,8 + DEFPUSHBUTTON "OK",IDOK,98,112,50,14 + PUSHBUTTON "Cancel",IDCANCEL,154,112,50,14 END @@ -643,26 +735,31 @@ BEGIN RIGHTMARGIN, 258 END + DLG_Colorize, DIALOG + BEGIN + BOTTOMMARGIN, 32 + END + DLG_GeneralOptions, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 264 TOPMARGIN, 7 - BOTTOMMARGIN, 143 + BOTTOMMARGIN, 155 END DLG_IcsOptions, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 311 + RIGHTMARGIN, 295 TOPMARGIN, 7 - BOTTOMMARGIN, 264 + BOTTOMMARGIN, 258 END DLG_BoardOptions, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 255 + RIGHTMARGIN, 187 TOPMARGIN, 7 BOTTOMMARGIN, 243 END @@ -682,6 +779,46 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 40 END + + DLG_GameListOptions, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 199 + TOPMARGIN, 7 + BOTTOMMARGIN, 133 + END + + DLG_MoveHistory, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 218 + TOPMARGIN, 7 + BOTTOMMARGIN, 123 + END + + DLG_EvalGraph, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END + + DLG_EngineOutput, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 259 + TOPMARGIN, 7 + BOTTOMMARGIN, 160 + END + + DLG_EnginePlayOptions, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 201 + TOPMARGIN, 7 + BOTTOMMARGIN, 122 + END END #endif // APSTUDIO_INVOKED @@ -718,6 +855,8 @@ BEGIN MENUITEM "&Copy Game To Clipboard\tAlt+C", IDM_CopyGame MENUITEM "Paste Game &From Clipboard\tAlt+V", IDM_PasteGame MENUITEM SEPARATOR + MENUITEM "Copy Game List to Clipboard", IDM_CopyGameListToClipboard + MENUITEM SEPARATOR MENUITEM "L&oad Position...", IDM_LoadPosition MENUITEM "Load N&ext Position\tAlt+Shift+PgDn", IDM_LoadNextPosition MENUITEM "Load Pre&vious Position\tAlt+Shift+PgUp", @@ -744,7 +883,11 @@ BEGIN MENUITEM "&Edit Position", IDM_EditPosition MENUITEM "Trai&ning", IDM_Training, GRAYED MENUITEM SEPARATOR - MENUITEM "Show Game &List...", IDM_ShowGameList + MENUITEM "Show Engine Output", IDM_ShowEngineOutput + MENUITEM "Show Evaluation Graph", IDM_ShowEvalGraph + MENUITEM "Show Game &List", IDM_ShowGameList + MENUITEM "Show Move History", IDM_ShowMoveHistory + MENUITEM SEPARATOR MENUITEM "Edit &Tags...", IDM_EditTags MENUITEM "Edit &Comment...", IDM_EditComment MENUITEM "&Pause\tPause", IDM_Pause @@ -788,9 +931,11 @@ BEGIN MENUITEM SEPARATOR MENUITEM "&General...", IDM_GeneralOptions MENUITEM "&Board...", IDM_BoardOptions + MENUITEM "Engines...", IDM_EnginePlayOptions MENUITEM "&ICS...", IDM_IcsOptions, GRAYED MENUITEM "&Fonts...", IDM_Fonts MENUITEM "Soun&ds...", IDM_Sounds + MENUITEM "Game List...", IDM_GameListOptions MENUITEM SEPARATOR MENUITEM "Comm&unications...", IDM_CommPort MENUITEM "&Load Game...", IDM_LoadOptions @@ -926,11 +1071,13 @@ BEGIN "2", IDM_DirectCommand2, VIRTKEY, ALT, NOINVERT "C", IDM_CopyGame, VIRTKEY, ALT, NOINVERT "C", IDM_CopyPosition, VIRTKEY, SHIFT, ALT, NOINVERT + "M", IDM_TypeInMove, VIRTKEY, ALT, NOINVERT "N", IDM_NewGame, VIRTKEY, CONTROL, NOINVERT "O", IDM_LoadGame, VIRTKEY, CONTROL, NOINVERT "S", IDM_SaveGame, VIRTKEY, CONTROL, NOINVERT - "V", IDM_Paste, VIRTKEY, CONTROL, NOINVERT "V", IDM_PasteGame, VIRTKEY, ALT, NOINVERT + "V", IDM_PasteAny, VIRTKEY, SHIFT, CONTROL, + NOINVERT "V", IDM_PastePosition, VIRTKEY, SHIFT, ALT, NOINVERT VK_DELETE, IDM_RetractMove, VIRTKEY, ALT, NOINVERT VK_DOWN, IDM_ToEnd, VIRTKEY, ALT, NOINVERT @@ -978,6 +1125,12 @@ BEGIN VK_UP, IDM_ToStart, VIRTKEY, NOINVERT END +NO_ICS ACCELERATORS DISCARDABLE +BEGIN + "A", IDM_AnalysisMode, VIRTKEY, CONTROL, NOINVERT + "V", IDM_PasteAny, VIRTKEY, CONTROL, NOINVERT +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/winboard/wlayout.c b/winboard/wlayout.c new file mode 100644 index 0000000..169c7ea --- /dev/null +++ b/winboard/wlayout.c @@ -0,0 +1,156 @@ +/* + * Layout management + * + * 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 "common.h" +#include "winboard.h" + +VOID RestoreWindowPlacement( HWND hWnd, WindowPlacement * wp ) +{ + if( wp->x != CW_USEDEFAULT || + wp->y != CW_USEDEFAULT || + wp->width != CW_USEDEFAULT || + wp->height != CW_USEDEFAULT ) + { + WINDOWPLACEMENT stWP; + + ZeroMemory( &stWP, sizeof(stWP) ); + + EnsureOnScreen( &wp->x, &wp->y); + + stWP.length = sizeof(stWP); + stWP.flags = 0; + stWP.showCmd = SW_SHOW; + stWP.ptMaxPosition.x = 0; + stWP.ptMaxPosition.y = 0; + stWP.rcNormalPosition.left = wp->x; + stWP.rcNormalPosition.right = wp->x + wp->width; + stWP.rcNormalPosition.top = wp->y; + stWP.rcNormalPosition.bottom = wp->y + wp->height; + + SetWindowPlacement(hWnd, &stWP); + } +} + +VOID InitWindowPlacement( WindowPlacement * wp ) +{ + wp->visible = TRUE; + wp->x = CW_USEDEFAULT; + wp->y = CW_USEDEFAULT; + wp->width = CW_USEDEFAULT; + wp->height = CW_USEDEFAULT; +} + +static BOOL IsAttachDistance( int a, int b ) +{ + BOOL result = FALSE; + + if( a == b ) { + result = TRUE; + } + + return result; +} + +static BOOL IsDefaultPlacement( WindowPlacement * wp ) +{ + BOOL result = FALSE; + + if( wp->x == CW_USEDEFAULT || wp->y == CW_USEDEFAULT || wp->width == CW_USEDEFAULT || wp->height == CW_USEDEFAULT ) { + result = TRUE; + } + + return result; +} + +static BOOL GetActualPlacement( HWND hWnd, WindowPlacement * wp ) +{ + BOOL result = FALSE; + + if( hWnd != NULL ) { + WINDOWPLACEMENT stWP; + + ZeroMemory( &stWP, sizeof(stWP) ); + + stWP.length = sizeof(stWP); + + GetWindowPlacement( hWnd, &stWP ); + + wp->x = stWP.rcNormalPosition.left; + wp->y = stWP.rcNormalPosition.top; + wp->width = stWP.rcNormalPosition.right - stWP.rcNormalPosition.left; + wp->height = stWP.rcNormalPosition.bottom - stWP.rcNormalPosition.top; + + result = TRUE; + } + + return result; +} + +static BOOL IsAttachedByWindowPlacement( LPRECT lprcMain, WindowPlacement * wp ) +{ + BOOL result = FALSE; + + if( ! IsDefaultPlacement(wp) ) { + if( IsAttachDistance( lprcMain->right, wp->x ) || + IsAttachDistance( lprcMain->bottom, wp->y ) || + IsAttachDistance( lprcMain->left, (wp->x + wp->width) ) || + IsAttachDistance( lprcMain->top, (wp->y + wp->height) ) ) + { + result = TRUE; + } + } + + return result; +} + +VOID ReattachAfterMove( LPRECT lprcOldPos, int new_x, int new_y, HWND hWndChild, WindowPlacement * pwpChild ) +{ + if( ! IsDefaultPlacement( pwpChild ) ) { + GetActualPlacement( hWndChild, pwpChild ); + + if( IsAttachedByWindowPlacement( lprcOldPos, pwpChild ) ) { + /* Get position delta */ + int delta_x = pwpChild->x - lprcOldPos->left; + int delta_y = pwpChild->y - lprcOldPos->top; + + /* Adjust placement */ + pwpChild->x = new_x + delta_x; + pwpChild->y = new_y + delta_y; + + /* Move window */ + if( hWndChild != NULL ) { + SetWindowPos( hWndChild, HWND_TOP, + pwpChild->x, pwpChild->y, + 0, 0, + SWP_NOZORDER | SWP_NOSIZE ); + } + } + } +} diff --git a/winboard/woptions.c b/winboard/woptions.c index d568cee..41df86c 100644 --- a/winboard/woptions.c +++ b/winboard/woptions.c @@ -169,6 +169,8 @@ GeneralOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) CHECK_BOX(OPT_TestLegality, appData.testLegality); CHECK_BOX(OPT_HideThinkFromHuman, appData.hideThinkingFromHuman); CHECK_BOX(OPT_SaveExtPGN, appData.saveExtendedInfoInPGN); + CHECK_BOX(OPT_ExtraInfoInMoveHistory, appData.showEvalInMoveHistory); + CHECK_BOX(OPT_HighlightMoveArrow, appData.highlightMoveWithArrow); #undef CHECK_BOX @@ -212,6 +214,8 @@ GeneralOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) appData.testLegality = IS_CHECKED(OPT_TestLegality); appData.hideThinkingFromHuman= IS_CHECKED(OPT_HideThinkFromHuman); appData.saveExtendedInfoInPGN= IS_CHECKED(OPT_SaveExtPGN); + appData.showEvalInMoveHistory= IS_CHECKED(OPT_ExtraInfoInMoveHistory); + appData.highlightMoveWithArrow=IS_CHECKED(OPT_HighlightMoveArrow); #undef IS_CHECKED @@ -2237,6 +2241,7 @@ SaveOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) } else { CheckRadioButton(hDlg, OPT_PGN, OPT_Old, OPT_PGN); } + CheckDlgButton( hDlg, OPT_OutOfBookInfo, appData.saveOutOfBookInfo ); SetSaveOptionEnables(hDlg); return TRUE; @@ -2276,6 +2281,7 @@ SaveOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) appData.saveGameFile = ""; } appData.oldSaveStyle = IsDlgButtonChecked(hDlg, OPT_Old); + appData.saveOutOfBookInfo = IsDlgButtonChecked( hDlg, OPT_OutOfBookInfo ); EndDialog(hDlg, TRUE); return TRUE; @@ -2433,4 +2439,80 @@ TimeControlOptionsPopup(HWND hwnd) } } - +/*---------------------------------------------------------------------------*\ + * + * Engine Options Dialog functions + * +\*---------------------------------------------------------------------------*/ +#define CHECK_BOX(x,y) CheckDlgButton(hDlg, (x), (BOOL)(y)) +#define IS_CHECKED(x) (Boolean)IsDlgButtonChecked(hDlg, (x)) + +#define INT_ABS( n ) ((n) >= 0 ? (n) : -(n)) + +LRESULT CALLBACK EnginePlayOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ + + /* Center the dialog over the application window */ + CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER)); + + /* Initialize the dialog items */ + CHECK_BOX(IDC_EpPeriodicUpdates, appData.periodicUpdates); + CHECK_BOX(IDC_EpPonder, appData.ponderNextMove); + CHECK_BOX(IDC_EpShowThinking, appData.showThinking); + CHECK_BOX(IDC_EpHideThinkingHuman, appData.hideThinkingFromHuman); + + SetDlgItemInt( hDlg, IDC_EpDrawMoveCount, appData.adjudicateDrawMoves, TRUE ); + SendDlgItemMessage( hDlg, IDC_EpDrawMoveCount, EM_SETSEL, 0, -1 ); + + SetDlgItemInt( hDlg, IDC_EpAdjudicationThreshold, INT_ABS(appData.adjudicateLossThreshold), TRUE ); + SendDlgItemMessage( hDlg, IDC_EpAdjudicationThreshold, EM_SETSEL, 0, -1 ); + + return TRUE; + + case WM_COMMAND: /* message: received a command */ + switch (LOWORD(wParam)) { + case IDOK: + /* Read changed options from the dialog box */ + PeriodicUpdatesEvent( IS_CHECKED(IDC_EpPeriodicUpdates)); + PonderNextMoveEvent( IS_CHECKED(IDC_EpPonder)); + ShowThinkingEvent( IS_CHECKED(IDC_EpShowThinking)); + appData.hideThinkingFromHuman= IS_CHECKED(IDC_EpHideThinkingHuman); + + appData.adjudicateDrawMoves = GetDlgItemInt(hDlg, IDC_EpDrawMoveCount, NULL, FALSE ); + appData.adjudicateLossThreshold = - (int) GetDlgItemInt(hDlg, IDC_EpAdjudicationThreshold, NULL, FALSE ); + + EndDialog(hDlg, TRUE); + return TRUE; + + case IDCANCEL: + EndDialog(hDlg, FALSE); + return TRUE; + + case IDC_EpDrawMoveCount: + case IDC_EpAdjudicationThreshold: + if( HIWORD(wParam) == EN_CHANGE ) { + int n1_ok; + int n2_ok; + + GetDlgItemInt(hDlg, IDC_EpDrawMoveCount, &n1_ok, FALSE ); + GetDlgItemInt(hDlg, IDC_EpAdjudicationThreshold, &n2_ok, FALSE ); + + EnableWindow( GetDlgItem(hDlg, IDOK), n1_ok && n2_ok ? TRUE : FALSE ); + } + return TRUE; + } + break; + } + return FALSE; +} + +VOID EnginePlayOptionsPopup(HWND hwnd) +{ + FARPROC lpProc; + + lpProc = MakeProcInstance((FARPROC)EnginePlayOptionsDialog, hInst); + DialogBox(hInst, MAKEINTRESOURCE(DLG_EnginePlayOptions), hwnd, (DLGPROC) lpProc); + FreeProcInstance(lpProc); +} diff --git a/winboard/woptions.h b/winboard/woptions.h index a35d6a6..a26d8e4 100644 --- a/winboard/woptions.h +++ b/winboard/woptions.h @@ -32,3 +32,4 @@ VOID CommPortOptionsPopup(HWND hwnd); VOID LoadOptionsPopup(HWND hwnd); VOID SaveOptionsPopup(HWND hwnd); VOID TimeControlOptionsPopup(HWND hwnd); +VOID EnginePlayOptionsPopup(HWND hwnd); diff --git a/winboard/wsnap.c b/winboard/wsnap.c new file mode 100644 index 0000000..cba18c0 --- /dev/null +++ b/winboard/wsnap.c @@ -0,0 +1,202 @@ +/* + * wsnap.c -- Smart "snapping" for window moving and sizing + * + * 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 "wsnap.h" + +/* Imports from winboard.c */ +extern HINSTANCE hInst; + +extern HWND hwndMain; +extern HWND moveHistoryDialog; +extern HWND evalGraphDialog; +extern HWND gameListDialog; + +static BOOL SnappingEnabled = TRUE; + +static void AddSnapPoint( int * grid, int * grid_len, int value ) +{ + int len = *grid_len; + + if( len < MAX_SNAP_POINTS ) { + int i; + + for( i=0; ix_grid, &sd->x_grid_len, rc->left ); + AddSnapPoint( sd->x_grid, &sd->x_grid_len, rc->right ); + + AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->top ); + AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->bottom ); +} + +static void AddSnapWindow( HWND hWndCaller, SnapData * sd, HWND hWndSnapWindow ) +{ + if( hWndSnapWindow != NULL && hWndCaller != hWndSnapWindow && IsWindowVisible(hWndSnapWindow) ) { + RECT rc; + + GetWindowRect( hWndSnapWindow, &rc ); + + AddSnapRectangle( sd, &rc ); + } +} + +static BOOL AdjustToSnapPoint( int * grid, int grid_len, int value, int * snap_size, int * delta ) +{ + BOOL result = FALSE; + int i; + + for( i=0; ix_grid_len = 0; + snapData->y_grid_len = 0; + + /* Add desktop area */ + if( SystemParametersInfo( SPI_GETWORKAREA, 0, &rc, 0 ) ) { + AddSnapRectangle( snapData, &rc ); + } + + if( hWnd != hwndMain ) { + /* Add other windows */ + AddSnapWindow( hWnd, snapData, hwndMain ); + AddSnapWindow( hWnd, snapData, moveHistoryDialog ); + AddSnapWindow( hWnd, snapData, evalGraphDialog ); + AddSnapWindow( hWnd, snapData, gameListDialog ); + } + + return 0; +} + +LRESULT OnMoving( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + LPRECT lprc = (LPRECT) lParam; + int delta_x = 0; + int delta_y = 0; + int snap_size_x = SNAP_DISTANCE; + int snap_size_y = SNAP_DISTANCE; + + if( ! SnappingEnabled ) { + return FALSE; + } + + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x ); + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x ); + + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y ); + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y ); + + OffsetRect( lprc, delta_x, delta_y ); + + return TRUE; +} + +LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + LPRECT lprc = (LPRECT) lParam; + int delta_x = 0; + int delta_y = 0; + int snap_size_x = SNAP_DISTANCE; + int snap_size_y = SNAP_DISTANCE; + + if( ! SnappingEnabled ) { + return FALSE; + } + + switch( wParam ) { + case WMSZ_BOTTOM: + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y ); + lprc->bottom += delta_y; + break; + case WMSZ_BOTTOMLEFT: + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y ); + lprc->bottom += delta_y; + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x ); + lprc->left += delta_x; + break; + case WMSZ_BOTTOMRIGHT: + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y ); + lprc->bottom += delta_y; + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x ); + lprc->right += delta_x; + break; + case WMSZ_LEFT: + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x ); + lprc->left += delta_x; + break; + case WMSZ_RIGHT: + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x ); + lprc->right += delta_x; + break; + case WMSZ_TOP: + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y ); + lprc->top += delta_y; + break; + case WMSZ_TOPLEFT: + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y ); + lprc->top += delta_y; + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x ); + lprc->left += delta_x; + break; + case WMSZ_TOPRIGHT: + AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y ); + lprc->top += delta_y; + AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x ); + lprc->right += delta_x; + break; + default: + return FALSE; + } + + return TRUE; +} + +LRESULT OnExitSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + return 0; +} diff --git a/winboard/wsnap.h b/winboard/wsnap.h new file mode 100644 index 0000000..5fb226e --- /dev/null +++ b/winboard/wsnap.h @@ -0,0 +1,43 @@ +/* + * wsnap.h -- Smart "snapping" for window moving and sizing + * + * 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. + * ------------------------------------------------------------------------ + */ +#ifndef WSNAP_H_ +#define WSNAP_H_ + +#include + +#define MAX_SNAP_POINTS 12 + +#define SNAP_DISTANCE 4 + +typedef struct { + int x_grid[ MAX_SNAP_POINTS ]; + int x_grid_len; + int y_grid[ MAX_SNAP_POINTS ]; + int y_grid_len; +} SnapData; + +LRESULT OnEnterSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam ); +LRESULT OnMoving( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam ); +LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam ); +LRESULT OnExitSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam ); + +#endif // WSNAP_H_