X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=winboard%2Fwinboard.c;h=c82ae8aaf3f4230182b8f121ccb326a52850fbd0;hb=4011e8678d85310eedf19fd00aa5d96a9a60770a;hp=223a6f873a5583db9bc20b57e3c1d056659665b6;hpb=20da18ecff230e9460827a80d4c2608da12190fa;p=xboard.git diff --git a/winboard/winboard.c b/winboard/winboard.c index 223a6f8..c82ae8a 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -2,10 +2,10 @@ * WinBoard.c -- Windows NT front end to XBoard * * Copyright 1991 by Digital Equipment Corporation, Maynard, - * Massachusetts. + * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -92,6 +92,9 @@ #include "help.h" #include "wsnap.h" +#define SLASH '/' +#define DATADIR "~~" + //void InitEngineUCI( const char * iniDir, ChessProgramState * cps ); int myrandom(void); @@ -100,14 +103,15 @@ extern int whiteFlag, blackFlag; Boolean flipClock = FALSE; extern HANDLE chatHandle[]; -extern int ics_type; +extern enum ICS_TYPE ics_type; +int MySearchPath P((char *installDir, char *name, char *fullname)); +int MyGetFullPathName P((char *name, char *fullname)); void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber); VOID NewVariantPopup(HWND hwnd); int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY, /*char*/int promoChar)); void DisplayMove P((int moveNumber)); -Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen)); void ChatPopUp P((char *s)); typedef struct { ChessSquare piece; @@ -185,6 +189,7 @@ Boolean alwaysOnTop = FALSE; RECT boardRect; COLORREF lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor, highlightSquareColor, premoveHighlightColor; +COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 }; HPALETTE hPal; ColorClass currentColorClass; @@ -195,7 +200,7 @@ static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred static HBRUSH lightSquareBrush, darkSquareBrush, blackSquareBrush, /* [HGM] for band between board and holdings */ explodeBrush, /* [HGM] atomic */ - markerBrush, /* [HGM] markers */ + markerBrush[8], /* [HGM] markers */ whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/; static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2]; static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2]; @@ -220,6 +225,7 @@ static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOA #if __GNUC__ && !defined(_winmajor) #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */ #else + #if defined(_winmajor) #define oldDialog (_winmajor < 4) #else @@ -249,12 +255,13 @@ Boolean barbaric; // flag indicating if translation is needed #define ABOUTBOX -1 /* not sure why these are needed */ #define ABOUTBOX2 -1 -int dialogItems[][41 ] = { +int dialogItems[][42] = { { ABOUTBOX, IDOK, OPT_MESS, 400 }, { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed, OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL }, -{ DLG_LoadOptions, OPT_Autostep, OPT_AStext1, - OPT_elo1, OPT_elo2, OPT_date, IDOK, IDCANCEL }, +{ DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference, + OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, + OPT_Ranget, IDOK, IDCANCEL }, { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse, 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL }, { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 }, @@ -294,7 +301,7 @@ int dialogItems[][41 ] = { OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor, OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor, OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove, - GPB_General, GPB_Alarm }, + GPB_General, GPB_Alarm, OPT_AutoCreate }, { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky, OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling, OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge, @@ -302,7 +309,7 @@ int dialogItems[][41 ] = { OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor, OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor, OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors, - IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont }, + IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid }, { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle, OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide, OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse, @@ -334,7 +341,7 @@ int dialogItems[][41 ] = { { 0 } }; -static char languageBuf[50000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ]; +static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ]; static int lastChecked; static char oldLanguage[MSG_SIZ], *menuText[10][30]; extern int tinyLayout; @@ -388,11 +395,16 @@ T_(char *s) { // return the translation of the given string // efficiency can be improved a lot... int i=0; + static char buf[MSG_SIZ]; //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s); if(!barbaric) return s; if(!s) return ""; // sanity while(english[i]) { if(!strcmp(s, english[i])) return foreign[i]; + if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending + snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion + return buf; + } i++; } return s; @@ -430,7 +442,7 @@ TranslateOneMenu(int i, HMENU subMenu) info.dwTypeData = buf; info.cch = sizeof(buf); GetMenuItemInfo(subMenu, j, TRUE, &info); - if(i < 10) { + if(i < 10) { if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) ); else menuText[i][j] = strdup(buf); // remember original on first change } @@ -487,6 +499,30 @@ TranslateMenus(int addLanguage) #endif +#define IDM_RecentEngines 3000 + +void +RecentEngineMenu (char *s) +{ + if(appData.icsActive) return; + if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty + HMENU mainMenu = GetMenu(hwndMain); + HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu + int i=IDM_RecentEngines; + recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu + AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL); + while(*s) { + char *p = strchr(s, '\n'); + if(p == NULL) return; // malformed! + *p = NULLCHAR; + AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s); + *p = '\n'; + s = p+1; + } + } +} + + typedef struct { char *name; int squareSize; @@ -732,7 +768,8 @@ void ThawUI() #define JAWS_INIT #define JAWS_ARGS #define JAWS_ALT_INTERCEPT -#define JAWS_KB_NAVIGATION +#define JAWS_KBUP_NAVIGATION +#define JAWS_KBDOWN_NAVIGATION #define JAWS_MENU_ITEMS #define JAWS_SILENCE #define JAWS_REPLAY @@ -749,12 +786,14 @@ void ThawUI() * \*---------------------------------------------------------------------------*/ +static void HandleMessage P((MSG *message)); +static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS; + int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; - HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS; // INITCOMMONCONTROLSEX ex; debugFP = stderr; @@ -786,6 +825,17 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 0, /* lowest message to examine */ 0)) /* highest message to examine */ { + HandleMessage(&msg); + } + + + return (msg.wParam); /* Returns the value from PostQuitMessage */ +} + +static void +HandleMessage (MSG *message) +{ + MSG msg = *message; if(msg.message == WM_CHAR && msg.wParam == '\t') { // [HGM] navigate: switch between all windows with tab @@ -853,7 +903,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together SetFocus(h); - continue; // this message now has been processed + return; // this message now has been processed } } @@ -872,14 +922,24 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) { done = 1; break; } - if(done) continue; // [HGM] chat: end patch + if(done) return; // [HGM] chat: end patch TranslateMessage(&msg); /* Translates virtual key codes */ DispatchMessage(&msg); /* Dispatches message to window */ } - } - +} - return (msg.wParam); /* Returns the value from PostQuitMessage */ +void +DoEvents () +{ /* Dispatch pending messages */ + MSG msg; + while (PeekMessage(&msg, /* message structure */ + NULL, /* handle of window receiving the message */ + 0, /* lowest message to examine */ + 0, /* highest message to examine */ + PM_REMOVE)) + { + HandleMessage(&msg); + } } /*---------------------------------------------------------------------------*\ @@ -948,16 +1008,17 @@ InitApplication(HINSTANCE hInstance) /* Set by InitInstance, used by EnsureOnScreen */ int screenHeight, screenWidth; +RECT screenGeometry; void EnsureOnScreen(int *x, int *y, int minX, int minY) { // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION); /* Be sure window at (x,y) is not off screen (or even mostly off screen) */ - if (*x > screenWidth - 32) *x = 0; - if (*y > screenHeight - 32) *y = 0; - if (*x < minX) *x = minX; - if (*y < minY) *y = minY; + if (*x > screenGeometry.right - 32) *x = screenGeometry.left; + if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top; + if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX; + if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY; } VOID @@ -974,8 +1035,14 @@ LoadLogo(ChessProgramState *cps, int n, Boolean ics) } } else if(appData.autoLogo) { if(ics) { // [HGM] logo: in ICS mode second can be used for ICS - sprintf(buf, "logos\\%s.bmp", appData.icsHost); - cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + char *opponent = ""; + if(gameMode == IcsPlayingWhite) opponent = gameInfo.black; + if(gameMode == IcsPlayingBlack) opponent = gameInfo.white; + sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent); + if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) { + sprintf(buf, "logos\\%s.bmp", appData.icsHost); + cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + } } else if(appData.directory[n] && appData.directory[n][0]) { SetCurrentDirectory(appData.directory[n]); @@ -992,6 +1059,7 @@ InitTextures() backTextureSquareSize = 0; // kludge to force recalculation of texturemode if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) { + if(liteBackTexture) DeleteObject(liteBackTexture); liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); liteBackTextureMode = appData.liteBackTextureMode; @@ -1001,6 +1069,7 @@ InitTextures() } if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) { + if(darkBackTexture) DeleteObject(darkBackTexture); darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); darkBackTextureMode = appData.darkBackTextureMode; @@ -1010,6 +1079,32 @@ InitTextures() } } +#ifndef SM_CXVIRTUALSCREEN +#define SM_CXVIRTUALSCREEN 78 +#endif +#ifndef SM_CYVIRTUALSCREEN +#define SM_CYVIRTUALSCREEN 79 +#endif +#ifndef SM_XVIRTUALSCREEN +#define SM_XVIRTUALSCREEN 76 +#endif +#ifndef SM_YVIRTUALSCREEN +#define SM_YVIRTUALSCREEN 77 +#endif + +VOID +InitGeometry() +{ + screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); + if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN); + screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); + if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN); + screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN); + screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN); + screenGeometry.right = screenGeometry.left + screenWidth; + screenGeometry.bottom = screenGeometry.top + screenHeight; +} + BOOL InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) { @@ -1023,11 +1118,12 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) { *filepart = NULLCHAR; + SetCurrentDirectory(installDir); } else { GetCurrentDirectory(MSG_SIZ, installDir); } gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise - screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData + InitGeometry(); InitAppData(lpCmdLine); /* Get run-time parameters */ /* xboard, and older WinBoards, controlled the move sound with the appData.ringBellAfterMoves option. In the current WinBoard, we @@ -1074,8 +1170,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) iconBlack = LoadIcon(hInstance, "icon_black"); iconCurrent = iconWhite; InitDrawingColors(); - screenHeight = GetSystemMetrics(SM_CYSCREEN); - screenWidth = GetSystemMetrics(SM_CXSCREEN); + + InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) { /* Compute window size for each board size, and use the largest size that fits on this screen as the default. */ @@ -1089,6 +1185,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) } InitDrawingSizes(boardSize, 0); + RecentEngineMenu(appData.recentEngineList); InitMenuChecks(); buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS); @@ -1133,15 +1230,6 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); #endif ShowWindow(hwndConsole, nCmdShow); - if(appData.chatBoxes) { // [HGM] chat: open chat boxes - char buf[MSG_SIZ], *p = buf, *q; - safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) ); - do { - q = strchr(p, ';'); - if(q) *q++ = 0; - if(*p) ChatPopUp(p); - } while(p=q); - } SetActiveWindow(hwndConsole); } if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE); @@ -1163,6 +1251,7 @@ InitMenuChecks() (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit, MF_BYCOMMAND|(saveSettingsOnExit ? MF_CHECKED : MF_UNCHECKED)); + EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED); } //--------------------------------------------------------------------------------------------------------- @@ -1172,6 +1261,7 @@ InitMenuChecks() #define OPTCHAR "/" #define SEPCHAR "=" +#define TOPLEVEL 0 #include "args.h" @@ -1192,6 +1282,7 @@ LFfromMFP(LOGFONT* lf, MyFontParams *mfp) lf->lfStrikeOut = mfp->strikeout; lf->lfCharSet = mfp->charset; lf->lfOutPrecision = OUT_DEFAULT_PRECIS; + lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; lf->lfQuality = DEFAULT_QUALITY; lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; @@ -1246,6 +1337,7 @@ ParseFontName(char *name, MyFontParams *mfp) p = q + 1; } else { q = mfp->faceName; + while (*p && !isdigit(*p)) { *q++ = *p++; if (q - mfp->faceName >= sizeof(mfp->faceName)) @@ -1744,6 +1836,8 @@ static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index ) COLORREF chroma = RGB(0xFF,0x00,0xFF); RECT rc; SIZE sz; + + POINT pt; int backColor = whitePieceColor; int foreColor = blackPieceColor; @@ -2082,9 +2176,15 @@ void CreatePiecesFromFont() HBITMAP DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix) { - char name[128]; + char name[128], buf[MSG_SIZ]; snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix); + if(appData.pieceDirectory[0]) { + HBITMAP res; + snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name); + res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + if(res) return res; + } if (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0 && strcmp(name, "k80s") == 0) { @@ -2121,6 +2221,7 @@ InsertInPalette(COLORREF color) VOID InitDrawingColors() { + int i; if (pLogPal == NULL) { /* Allocate enough memory for a logical palette with * PALETTESIZE entries and set the size and version fields @@ -2152,8 +2253,9 @@ InitDrawingColors() blackPieceBrush = CreateSolidBrush(blackPieceColor); iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND)); explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic - markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers - /* [AS] Force rendering of the font-based pieces */ + for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers + + /* [AS] Force rendering of the font-based pieces */ if( fontBitmapSquareSize > 0 ) { fontBitmapSquareSize = 0; } @@ -2211,12 +2313,30 @@ InitDrawingSizes(BoardSize boardSize, int flags) RECT crect, wrect, oldRect; int offby; LOGBRUSH logbrush; + VariantClass v = gameInfo.variant; int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; } /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */ if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize; + if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition) + oldBoardSize = boardSize; + + if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont) + { // correct board size to one where built-in pieces exist + if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper) + && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range + + || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi + || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan + || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) { + if(boardSize < SizeMediocre) boardSize = SizePetite; else + if(boardSize > SizeModerate) boardSize = SizeBulky; else + boardSize = SizeMiddling; + } + } + if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite oldRect.left = wpMain.x; //[HGM] placement: remember previous window params oldRect.top = wpMain.y; @@ -2228,6 +2348,7 @@ InitDrawingSizes(BoardSize boardSize, int flags) squareSize = sizeInfo[boardSize].squareSize; lineGap = sizeInfo[boardSize].lineGap; minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */ + border = appData.useBorder && appData.border[0] ? squareSize/2 : 0; if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) { lineGap = appData.overrideLineGap; @@ -2252,8 +2373,8 @@ InitDrawingSizes(BoardSize boardSize, int flags) DrawMenuBar(hwndMain); } - boardWidth = BoardWidth(boardSize, BOARD_WIDTH); - boardHeight = BoardWidth(boardSize, BOARD_HEIGHT); + boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border; + boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border; /* Get text area sizes */ hdc = GetDC(hwndMain); @@ -2325,7 +2446,6 @@ InitDrawingSizes(BoardSize boardSize, int flags) sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN; sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN; - oldBoardSize = boardSize; oldTinyLayout = tinyLayout; winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN; winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) + @@ -2425,20 +2545,20 @@ InitDrawingSizes(BoardSize boardSize, int flags) /* [HGM] Loop had to be split in part for vert. and hor. lines */ for (i = 0; i < BOARD_HEIGHT + 1; i++) { - gridEndpoints[i*2].x = boardRect.left + lineGap / 2; + gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border; gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y = - boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)); + boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border; gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 + - BOARD_WIDTH * (squareSize + lineGap); + BOARD_WIDTH * (squareSize + lineGap) + border; gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2; } for (i = 0; i < BOARD_WIDTH + 1; i++) { - gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2; + gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border; gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x = gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left + - lineGap / 2 + (i * (squareSize + lineGap)); + lineGap / 2 + (i * (squareSize + lineGap)) + border; gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y = - boardRect.top + BOARD_HEIGHT * (squareSize + lineGap); + boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border; gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2; } } @@ -2566,8 +2686,11 @@ InitDrawingSizes(BoardSize boardSize, int flags) pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s"); pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o"); pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w"); + pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s"); + pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o"); + pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w"); - if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */ + if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/ pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s"); pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o"); pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w"); @@ -2691,11 +2814,11 @@ VOID SquareToPos(int row, int column, int * x, int * y) { if (flipView) { - *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap); - *y = boardRect.top + lineGap + row * (squareSize + lineGap); + *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border; + *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border; } else { - *x = boardRect.left + lineGap + column * (squareSize + lineGap); - *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap); + *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border; + *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border; } } @@ -2722,15 +2845,23 @@ DrawCoordsOnDC(HDC hdc) y = boardRect.top + lineGap; x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap); + if(border) { + SetTextAlign(hdc, TA_RIGHT|TA_TOP); + x += border - lineGap - 4; y += squareSize - 6; + } else SetTextAlign(hdc, TA_LEFT|TA_TOP); for (i = 0; i < BOARD_HEIGHT; i++) { str[0] = files[start + i]; - ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL); + ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL); y += squareSize + lineGap; } start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23; + if(border) { + SetTextAlign(hdc, TA_LEFT|TA_TOP); + x += -border + 4; y += border - squareSize + 6; + } else SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM); for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) { str[0] = ranks[start + i]; @@ -2767,14 +2898,14 @@ DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen) if (lineGap == 0) return; if (flipView) { x1 = boardRect.left + - lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap); + lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border; y1 = boardRect.top + - lineGap/2 + y * (squareSize + lineGap); + lineGap/2 + y * (squareSize + lineGap) + border; } else { x1 = boardRect.left + - lineGap/2 + x * (squareSize + lineGap); + lineGap/2 + x * (squareSize + lineGap) + border; y1 = boardRect.top + - lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap); + lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border; } hPen = pen ? premovePen : highlightPen; oldPen = SelectObject(hdc, on ? hPen : gridPen); @@ -2852,7 +2983,9 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, sqcolor ? SRCCOPY : NOTSRCCOPY); } else { + HBRUSH xBrush = whitePieceBrush; tmpSize = squareSize; + if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH); if(minorSize && ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) || (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) { @@ -2865,7 +2998,7 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, if (color || appData.allWhite ) { oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE)); if( color ) - oldBrush = SelectObject(hdc, whitePieceBrush); + oldBrush = SelectObject(hdc, xBrush); else oldBrush = SelectObject(hdc, blackPieceBrush); if(appData.upsideDown && color==flipView) StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A); @@ -2877,6 +3010,18 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND); else BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND); + } else if(appData.pieceDirectory[0]) { + oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE)); + oldBrush = SelectObject(hdc, xBrush); + if(appData.upsideDown && color==flipView) + StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A); + else + BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A); + SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE)); + if(appData.upsideDown && color==flipView) + StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND); + else + BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND); } else { /* Use square color for details of black pieces */ oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE)); @@ -3165,6 +3310,9 @@ BOOL HasHighlightInfo() } return result; + + + } BOOL IsDrawArrowEnabled() @@ -3264,6 +3412,40 @@ BOOL DrawPositionNeedsFullRepaint() return result; } +static HBITMAP borderBitmap; + +VOID +DrawBackgroundOnDC(HDC hdc) +{ + + BITMAP bi; + HDC tmphdc; + HBITMAP hbm; + static char oldBorder[MSG_SIZ]; + int w = 600, h = 600, mode; + + if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid + strncpy(oldBorder, appData.border, MSG_SIZ-1); + borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + } + if(borderBitmap == NULL) { // loading failed, use white + FillRect( hdc, &boardRect, whitePieceBrush ); + return; + } + tmphdc = CreateCompatibleDC(hdc); + hbm = SelectObject(tmphdc, borderBitmap); + if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) { + w = bi.bmWidth; + h = bi.bmHeight; + } + mode = SetStretchBltMode(hdc, COLORONCOLOR); + StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left, + boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY); + SetStretchBltMode(hdc, mode); + SelectObject(tmphdc, hbm); + DeleteDC(tmphdc); +} + VOID DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) { @@ -3322,6 +3504,7 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]); else if( column == BOARD_RGHT) /* right align */ DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]); + else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0); else if (appData.monoMode) { if (piece == EmptySquare) { @@ -3504,7 +3687,7 @@ void DrawSeekDot(int x, int y, int color) { int square = color & 0x80; HBRUSH oldBrush = SelectObject(hdcSeek, - color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush); + color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush); color &= 0x7F; if(square) Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9, @@ -3515,6 +3698,14 @@ void DrawSeekDot(int x, int y, int color) SelectObject(hdcSeek, oldBrush); } +void DrawSeekOpen() +{ +} + +void DrawSeekClose() +{ +} + VOID HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) { @@ -3774,6 +3965,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) Ellipse(hdcmem, x-r, y-r, x+r, y+r); SelectObject(hdcmem, oldBrush); } else { + if(border) DrawBackgroundOnDC(hdcmem); DrawGridOnDC(hdcmem); if(nr == 0) { // [HGM] dual: decide which highlights to draw DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN); @@ -3788,8 +3980,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) for (row = 0; row < BOARD_HEIGHT; row++) { for (column = 0; column < BOARD_WIDTH; column++) { if (marker[row][column]) { // marker changes only occur with full repaint! - HBRUSH oldBrush = SelectObject(hdcmem, - marker[row][column] == 2 ? markerBrush : explodeBrush); + HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]); SquareToPos(row, column, &x, &y); Ellipse(hdcmem, x + squareSize/4, y + squareSize/4, x + 3*squareSize/4, y + 3*squareSize/4); @@ -3815,6 +4006,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) else if(dragInfo.from.x == BOARD_RGHT+1 ) board[dragInfo.from.y][dragInfo.from.x-1]++; + board[dragInfo.from.y][dragInfo.from.x] = dragged_piece; x = dragInfo.pos.x - squareSize / 2; y = dragInfo.pos.y - squareSize / 2; @@ -4027,11 +4219,11 @@ PaintProc(HWND hwnd) int EventToSquare(x, limit) int x, limit; { - if (x <= 0) + if (x <= border) return -2; - if (x < lineGap) + if (x < lineGap + border) return -1; - x -= lineGap; + x -= lineGap + border; if ((x % (squareSize + lineGap)) >= squareSize) return -1; x /= (squareSize + lineGap); @@ -4136,16 +4328,19 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status + controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status switch (message) { case WM_LBUTTONDOWN: if (PtInRect((LPRECT) &whiteRect, pt)) { - ClockClick(flipClock); + ClockClick(flipClock); break; } else if (PtInRect((LPRECT) &blackRect, pt)) { - ClockClick(!flipClock); + ClockClick(!flipClock); break; } + if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging dragInfo.start.x = dragInfo.start.y = -1; dragInfo.from = dragInfo.start; + } if(fromX == -1 && frozen) { // not sure where this is for fromX = fromY = -1; DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */ @@ -4165,7 +4360,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break; MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top); if ((appData.animateDragging || appData.highlightDragging) - && (wParam & MK_LBUTTON) + && (wParam & MK_LBUTTON || dragging == 2) && dragInfo.from.x >= 0) { BOOL full_repaint = FALSE; @@ -4174,7 +4369,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) dragInfo.pos = pt; } if (appData.highlightDragging) { - SetHighlights(fromX, fromY, x, y); + HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y); if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) { full_repaint = TRUE; } @@ -4222,9 +4417,9 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if(y == -2) { /* [HGM] right mouse button in clock area edit-game mode ups clock */ if (PtInRect((LPRECT) &whiteRect, pt)) { - if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1); + if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1); } else if (PtInRect((LPRECT) &blackRect, pt)) { - if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1); + if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1); } break; } @@ -4250,7 +4445,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case 2: - SetCapture(hwndMain); + SetCapture(hwndMain); break; case 1: hmenu = LoadMenu(hInst, "DropPieceMenu"); @@ -4309,6 +4504,8 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam); } +static int promoStyle; + /* Process messages for Promotion dialog box */ LRESULT CALLBACK Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) @@ -4316,6 +4513,7 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) char promoChar; switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ /* Center the dialog over the application window */ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER)); @@ -4339,13 +4537,9 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) PieceToChar(BlackMarshall) != '~') ) ? SW_SHOW : SW_HIDE); /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */ - ShowWindow(GetDlgItem(hDlg, PB_Rook), - gameInfo.variant != VariantShogi ? - SW_SHOW : SW_HIDE); - ShowWindow(GetDlgItem(hDlg, PB_Bishop), - gameInfo.variant != VariantShogi ? - SW_SHOW : SW_HIDE); - if(gameInfo.variant == VariantShogi) { + ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE); + if(promoStyle) { SetDlgItemText(hDlg, PB_Queen, "YES"); SetDlgItemText(hDlg, PB_Knight, "NO"); SetWindowText(hDlg, "Promote?"); @@ -4366,7 +4560,7 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing); break; case PB_Queen: - promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen)); + promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen)); break; case PB_Rook: promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook)); @@ -4383,7 +4577,8 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel)); break; case PB_Knight: - promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight); + promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR : + ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight)); break; default: return FALSE; @@ -4414,20 +4609,13 @@ PromotionPopup(HWND hwnd) } void -PromotionPopUp() +PromotionPopUp(char choice) { + promoStyle = (choice == '+'); DrawPosition(TRUE, NULL); PromotionPopup(hwndMain); } -/* Toggle ShowThinking */ -VOID -ToggleShowThinking() -{ - appData.showThinking = !appData.showThinking; - ShowThinkingEvent(); -} - VOID LoadGameDialog(HWND hwnd, char* title) { @@ -4561,13 +4749,13 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { FARPROC lpProc; - int wmId, wmEvent; + int wmId; char *defName; FILE *f; UINT number; char fileTitle[MSG_SIZ]; - char buf[MSG_SIZ]; static SnapData sd; + static int peek=0; switch (message) { @@ -4595,7 +4783,23 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) MouseEvent(hwnd, message, wParam, lParam); break; - JAWS_KB_NAVIGATION + case WM_KEYUP: + if((char)wParam == '\b') { + ForwardEvent(); peek = 0; + } + + JAWS_KBUP_NAVIGATION + + break; + + case WM_KEYDOWN: + if((char)wParam == '\b') { + if(!peek) BackwardEvent(), peek = 1; + } + + JAWS_KBDOWN_NAVIGATION + + break; case WM_CHAR: @@ -4624,6 +4828,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) nnew = RealizePalette(hdc); if (nnew > 0) { paletteChanged = TRUE; + InvalidateRect(hwnd, &boardRect, FALSE); } ReleaseDC(hwnd, hdc); @@ -4647,7 +4852,6 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_COMMAND: /* message: command from application menu */ wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); switch (wmId) { case IDM_NewGame: @@ -4740,6 +4944,20 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; + case IDM_SaveSelected: + f = OpenFileDialog(hwnd, "a", "", + "pgn", + GAME_FILT, + _("Save Game to File"), NULL, fileTitle, NULL); + if (f != NULL) { + SaveSelected(f, 0, ""); + } + break; + + case IDM_CreateBook: + CreateBookEvent(); + break; + case IDM_CopyGame: CopyGameToClipboard(); break; @@ -4882,52 +5100,13 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_AnalysisMode: - if (!first.analysisSupport) { - snprintf(buf, MSG_SIZ, _("%s does not support analysis"), first.tidy); - DisplayError(buf, 0); - } else { + if(AnalyzeModeEvent()) { SAY("analyzing current position"); - /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */ - if (appData.icsActive) { - if (gameMode != IcsObserving) { - snprintf(buf, MSG_SIZ, "You are not observing a game"); - DisplayError(buf, 0); - /* secure check */ - if (appData.icsEngineAnalyze) { - if (appData.debugMode) - fprintf(debugFP, "Found unexpected active ICS engine analyze \n"); - ExitAnalyzeMode(); - ModeHighlight(); - break; - } - break; - } else { - /* if enable, user want disable icsEngineAnalyze */ - if (appData.icsEngineAnalyze) { - ExitAnalyzeMode(); - ModeHighlight(); - break; - } - appData.icsEngineAnalyze = TRUE; - if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n"); - } - } - if (!appData.showThinking) ToggleShowThinking(); - AnalyzeModeEvent(); } break; case IDM_AnalyzeFile: - if (!first.analysisSupport) { - char buf[MSG_SIZ]; - snprintf(buf, MSG_SIZ, _("%s does not support analysis"), first.tidy); - DisplayError(buf, 0); - } else { - if (!appData.showThinking) ToggleShowThinking(); - AnalyzeFileEvent(); -// LoadGameDialog(hwnd, _("Analyze Game from File")); - AnalysisPeriodicEvent(1); - } + AnalyzeFileEvent(); break; case IDM_IcsClient: @@ -4958,9 +5137,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames); break; - case IDM_EditProgs2: - LoadEnginePopUp(hwndMain); -// EditTagsPopUp(secondChessProgramNames, &secondChessProgramNames); + case IDM_LoadProg1: + LoadEnginePopUp(hwndMain, 0); + break; + + case IDM_LoadProg2: + LoadEnginePopUp(hwndMain, 1); break; case IDM_EditServers: @@ -4998,6 +5180,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_Rematch: + RematchEvent(); break; @@ -5063,6 +5246,11 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) SetFocus(hwndMain); break; + case OPT_GameListNext: // [HGM] forward these two accelerators to Game List + case OPT_GameListPrev: + if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0); + break; + case IDM_Revert: RevertEvent(FALSE); break; @@ -5109,6 +5297,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) BoardOptionsPopup(hwnd); break; + case IDM_ThemeOptions: + ThemeOptionsPopup(hwnd); + break; + case IDM_EnginePlayOptions: EnginePlayOptionsPopup(hwnd); break; @@ -5424,6 +5616,9 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; default: + if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines) + RecentEngineEvent(wmId - IDM_RecentEngines); + else if(wmId > IDM_English && wmId < IDM_English+20) { LoadLanguageFile(languageFile[wmId - IDM_English - 1]); TranslateMenus(0); @@ -5475,7 +5670,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if( hwnd == hwndMain && appData.useStickyWindows ) { LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam; - if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) { + if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move? /* Window is moving */ RECT rcMain; @@ -5544,6 +5739,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) default: /* Passes it on if unprocessed */ return (DefWindowProc(hwnd, message, wParam, lParam)); } + + return 0; } @@ -6135,13 +6332,15 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) ); GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf)); p = buf; + comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox ParseArgs(StringGet, &p); safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) ); GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf)); - p = buf; + p = buf; SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ... ParseArgs(StringGet, &p); SwapEngines(singleList); // ... and then make it 'second' + appData.noChessProgram = FALSE; appData.icsActive = FALSE; } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) { @@ -6232,7 +6431,7 @@ LRESULT CALLBACK CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HANDLE hwndText = NULL; - int len, newSizeX, newSizeY, flags; + int len, newSizeX, newSizeY; static int sizeX, sizeY; char *str; RECT rect; @@ -6260,7 +6459,6 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) /* Size and position the dialog */ if (!commentDialog) { commentDialog = hDlg; - flags = SWP_NOZORDER; GetClientRect(hDlg, &rect); sizeX = rect.right; sizeY = rect.bottom; @@ -6448,10 +6646,10 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_COMMAND: switch (LOWORD(wParam)) { - case IDOK: + case IDOK: shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status - GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); + GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); TypeInDoneEvent(move); EndDialog(hDlg, TRUE); return TRUE; @@ -6597,7 +6795,6 @@ ErrorPopDown() LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - HANDLE hwndText; RECT rChild; switch (message) { @@ -6621,7 +6818,6 @@ ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) errorDialog = hDlg; SetWindowText(hDlg, errorTitle); - hwndText = GetDlgItem(hDlg, OPT_ErrorText); SetDlgItemText(hDlg, OPT_ErrorText, errorMessage); return FALSE; @@ -6647,7 +6843,6 @@ HWND gothicDialog = NULL; LRESULT CALLBACK GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - HANDLE hwndText; RECT rChild; int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME); @@ -6666,7 +6861,6 @@ GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) */ gothicDialog = hDlg; SetWindowText(hDlg, errorTitle); - hwndText = GetDlgItem(hDlg, OPT_ErrorText); SetDlgItemText(hDlg, OPT_ErrorText, errorMessage); return FALSE; @@ -6719,6 +6913,7 @@ GothicPopUp(char *title, VariantClass variant) static char *history[HISTORY_SIZE]; int histIn = 0, histP = 0; + VOID SaveInHistory(char *cmd) { @@ -6731,6 +6926,7 @@ SaveInHistory(char *cmd) histIn = (histIn + 1) % HISTORY_SIZE; if (history[histIn] != NULL) { free(history[histIn]); + history[histIn] = NULL; } histP = histIn; @@ -7414,7 +7610,7 @@ DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber) HFONT oldFont; RECT rect; - if(copyNumber > 1) + if(copyNumber > 1) snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0; oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */ @@ -7446,6 +7642,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight, COLORREF oldFg, oldBg; HFONT oldFont; + if (twoBoards && partnerUp) return; if (appData.clockMode) { if (tinyLayout) snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell); @@ -7540,6 +7737,7 @@ DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount, else err = GetLastError(); } + } return err; } @@ -7810,7 +8008,8 @@ Enables icsEnables[] = { { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED }, { IDM_Hint, MF_BYCOMMAND|MF_GRAYED }, { IDM_Book, MF_BYCOMMAND|MF_GRAYED }, - { IDM_EditProgs2, MF_BYCOMMAND|MF_GRAYED }, + { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED }, + { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED }, { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED }, { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED }, { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED }, @@ -8164,8 +8363,8 @@ DisplayMessage(char *str1, char *str2) if (len > remain) len = remain; strncat(messageText, str2, len); } - messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR; - safeStrCpy(lastMsg, messageText, MSG_SIZ); + messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR; + safeStrCpy(lastMsg, messageText, MSG_SIZ); if (hwndMain == NULL || IsIconic(hwndMain)) return; @@ -8404,6 +8603,7 @@ HWND gameListOptionsDialog; // low-level front-end: clear text edit / list widget void + GLT_ClearList() { SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 ); @@ -8512,8 +8712,11 @@ int GameListOptions() result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT ); if( result == 0 ) { + char *oldTags = appData.gameListTags; /* [AS] Memory leak here! */ appData.gameListTags = strdup( lpUserGLT ); + if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something + GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all } return result; @@ -8525,7 +8728,19 @@ DisplayIcsInteractionTitle(char *str) char consoleTitle[MSG_SIZ]; snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str); - SetWindowText(hwndConsole, consoleTitle); + SetWindowText(hwndConsole, consoleTitle); + + if(appData.chatBoxes) { // [HGM] chat: open chat boxes + char buf[MSG_SIZ], *p = buf, *q; + safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) ); + do { + q = strchr(p, ';'); + if(q) *q++ = 0; + if(*p) ChatPopUp(p); + } while(p=q); + } + + SetActiveWindow(hwndMain); } void @@ -8583,6 +8798,13 @@ EditCommentPopUp(int index, char *title, char *str) } +int +Roar() +{ + MyPlaySound(&sounds[(int)SoundRoar]); + return 1; +} + VOID RingBell() { @@ -8740,6 +8962,7 @@ DisplayBlackClock(long timeRemaining, int highlight) HDC hdc; char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : ""; + if(appData.noGUI) return; hdc = GetDC(hwndMain); if (!IsIconic(hwndMain)) { @@ -8853,6 +9076,37 @@ IDLE_PRIORITY_CLASS 0x00000040 return 0x00000040; } +void RunCommand(char *cmdLine) +{ + /* Now create the child process. */ + STARTUPINFO siStartInfo; + PROCESS_INFORMATION piProcInfo; + + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.lpReserved = NULL; + siStartInfo.lpDesktop = NULL; + siStartInfo.lpTitle = NULL; + siStartInfo.dwFlags = STARTF_USESTDHANDLES; + siStartInfo.cbReserved2 = 0; + siStartInfo.lpReserved2 = NULL; + siStartInfo.hStdInput = NULL; + siStartInfo.hStdOutput = NULL; + siStartInfo.hStdError = NULL; + + CreateProcess(NULL, + cmdLine, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attrs */ + TRUE, /* handles are inherited */ + DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP, + NULL, /* use parent's environment */ + NULL, + &siStartInfo, /* STARTUPINFO pointer */ + &piProcInfo); /* receives PROCESS_INFORMATION */ + + CloseHandle(piProcInfo.hThread); +} + /* Start a child process running the given program. The process's standard output can be read from "from", and its standard input can be written to "to". @@ -9020,15 +9274,15 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal) /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/ /* [AS] Special termination modes for misbehaving programs... */ - if( signal == 9 ) { + if( signal & 8 ) { result = TerminateProcess( cp->hProcess, 0 ); if ( appData.debugMode) { fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result ); } } - else if( signal == 10 ) { - DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most + else if( signal & 4 ) { + DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most if( dw != WAIT_OBJECT_0 ) { result = TerminateProcess( cp->hProcess, 0 ); @@ -9112,6 +9366,7 @@ OpenTCP(char *host, char *port, ProcRef *pr) ChildProc *cp; int err; SOCKET s; + struct sockaddr_in sa, mysa; struct hostent FAR *hp; unsigned short uport; @@ -9524,6 +9779,7 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError) int outCount = SOCKET_ERROR; ChildProc *cp = (ChildProc *) pr; static OVERLAPPED ovl; + static int line = 0; if (pr == NoProc) @@ -9588,6 +9844,12 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError) return outCount; } +void +DoSleep(int n) +{ + if(n != 0) Sleep(n); +} + int OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError, long msdelay) @@ -9608,7 +9870,7 @@ CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure, /* see wedittags.c for Edit Tags functions */ -VOID +int ICSInitScript() { FILE *f; @@ -9620,8 +9882,10 @@ ICSInitScript() if (f != NULL) { ProcessICSInitScript(f); fclose(f); + return TRUE; } } + return FALSE; } @@ -9718,16 +9982,23 @@ AnimateMove(board, fromX, fromY, toX, toY) int toY; { ChessSquare piece; + int x = toX, y = toY; POINT start, finish, mid; POINT frames[kFactor * 2 + 1]; int nFrames, n; + if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar(); + if (!appData.animate) return; if (doingSizing) return; if (fromY < 0 || fromX < 0) return; piece = board[fromY][fromX]; if (piece >= EmptySquare) return; + if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square + +again: + ScreenSquare(fromX, fromY, &start); ScreenSquare(toX, toY, &finish); @@ -9766,6 +10037,9 @@ AnimateMove(board, fromX, fromY, toX, toY) } animInfo.pos = finish; DrawPosition(FALSE, NULL); + + if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg + animInfo.piece = EmptySquare; Explode(board, fromX, fromY, toX, toY); } @@ -9777,11 +10051,11 @@ ScreenSquare(column, row, pt) int column; int row; POINT * pt; { if (flipView) { - pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap); - pt->y = lineGap + row * (squareSize + lineGap); + pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border; + pt->y = lineGap + row * (squareSize + lineGap) + border; } else { - pt->x = lineGap + column * (squareSize + lineGap); - pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap); + pt->x = lineGap + column * (squareSize + lineGap) + border; + pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border; } } @@ -9829,16 +10103,6 @@ Tween(start, mid, finish, factor, frames, nFrames) } void -HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current ) -{ - MoveHistorySet( movelist, first, last, current, pvInfoList ); - - EvalGraphSet( first, last, current, pvInfoList ); - - MakeEngineOutputTitle(); -} - -void SettingsPopUp(ChessProgramState *cps) { // [HGM] wrapper needed because handles must not be passed through back-end EngineOptionsPopup(savedHwnd, cps); @@ -9853,9 +10117,31 @@ int flock(int fid, int code) ov.OffsetHigh = 0; switch(code) { case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH + case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN default: return -1; } return 0; } + +char * +Col2Text (int n) +{ + static int i=0; + static char col[8][20]; + COLORREF color = *(COLORREF *) colorVariable[n]; + i = i+1 & 7; + snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff); + return col[i]; +} + +void +ActivateTheme (int new) +{ // Redo initialization of features depending on options that can occur in themes + InitTextures(); + if(new) InitDrawingColors(); + fontBitmapSquareSize = 0; // request creation of new font pieces + InitDrawingSizes(boardSize, 0); + InvalidateRect(hwndMain, NULL, TRUE); +}