X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=winboard%2Fwinboard.c;h=293b643e9a5b3653501b39f1870bda687555d3e1;hb=0c326a397b77561e9cd232549eb98c756f5a8baf;hp=a24c8e437e8188ef26df49063211bde0d7183565;hpb=4df745f07a4fb7fa7136763be313779df2a26255;p=xboard.git diff --git a/winboard/winboard.c b/winboard/winboard.c index a24c8e4..293b643 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -2,10 +2,11 @@ * 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, 2012, 2013 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free + * Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -54,6 +55,10 @@ *------------------------------------------------------------------------ ** See the file ChangeLog for a revision history. */ +#ifndef WINVER +#define WINVER 0x0500 +#endif + #include "config.h" #include @@ -92,6 +97,9 @@ #include "help.h" #include "wsnap.h" +#define SLASH '/' +#define DATADIR "~~" + //void InitEngineUCI( const char * iniDir, ChessProgramState * cps ); int myrandom(void); @@ -109,7 +117,6 @@ 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; @@ -164,7 +171,7 @@ BoardSize boardSize; Boolean chessProgram; //static int boardX, boardY; int minX, minY; // [HGM] placement: volatile limits on upper-left corner -int squareSize, lineGap, minorSize, border; +int squareSize, lineGap, minorSize; static int winW, winH; static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo static int logoHeight = 0; @@ -187,6 +194,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; @@ -197,7 +205,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]; @@ -223,8 +231,6 @@ static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOA #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */ #else - - #if defined(_winmajor) #define oldDialog (_winmajor < 4) #else @@ -259,7 +265,8 @@ int dialogItems[][42] = { { 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_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, IDOK, IDCANCEL }, + 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 }, @@ -532,12 +539,12 @@ typedef struct { SizeInfo sizeInfo[] = { - { "tiny", 21, 0, 1, 1, 0, 0 }, - { "teeny", 25, 1, 1, 1, 0, 0 }, - { "dinky", 29, 1, 1, 1, 0, 0 }, - { "petite", 33, 1, 1, 1, 0, 0 }, - { "slim", 37, 2, 1, 0, 0, 0 }, - { "small", 40, 2, 1, 0, 0, 0 }, + { "tiny", 21, 0, 1, 2, 0, 0 }, + { "teeny", 25, 1, 1, 2, 0, 0 }, + { "dinky", 29, 1, 1, 2, 0, 0 }, + { "petite", 33, 1, 1, 2, 0, 0 }, + { "slim", 37, 2, 1, 1, 0, 0 }, + { "small", 40, 2, 1, 1, 0, 0 }, { "mediocre", 45, 2, 1, 0, 0, 0 }, { "middling", 49, 2, 0, 0, 0, 0 }, { "average", 54, 2, 0, 0, 0, 0 }, @@ -585,7 +592,7 @@ typedef struct { WNDPROC wndproc; } MyButtonDesc; -#define BUTTON_WIDTH (tinyLayout ? 16 : 32) +#define BUTTON_WIDTH (tinyLayout == 2 ? 16 : 32) #define N_BUTTONS 5 MyButtonDesc buttonDesc[N_BUTTONS] = @@ -599,8 +606,9 @@ MyButtonDesc buttonDesc[N_BUTTONS] = int tinyLayout = 0, smallLayout = 0; #define MENU_BAR_ITEMS 9 -char *menuBarText[2][MENU_BAR_ITEMS+1] = { +char *menuBarText[3][MENU_BAR_ITEMS+1] = { { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL }, + { N_("&Fil"), N_("&Ed"), N_("&Vw"), N_("&Mod"), N_("&Act"), N_("E&ng"), N_("&Opt"), N_("&Hlp"), NULL }, { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL }, }; @@ -784,12 +792,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; @@ -821,6 +831,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 @@ -888,7 +909,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 } } @@ -907,14 +928,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); + } } /*---------------------------------------------------------------------------*\ @@ -1080,6 +1111,8 @@ InitGeometry() screenGeometry.bottom = screenGeometry.top + screenHeight; } +ChessProgramState broadcast; + BOOL InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) { @@ -1112,7 +1145,18 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) appData.ringBellAfterMoves = TRUE; } if (appData.debugMode) { - debugFP = fopen(appData.nameOfDebugFile, "w"); + char *c = appData.nameOfDebugFile; + if(strstr(c, "///") == c) { + broadcast.which = "broadcaster"; + broadcast.pr = NoProc; + broadcast.isr = NULL; + broadcast.program = c + 3; + broadcast.dir = "."; + broadcast.host = "localhost"; + StartChessProgram(&broadcast); + debugFP = (FILE*) _fdopen(_open_osfhandle((long)(((ChildProc*)(broadcast.pr))->hTo), _O_WRONLY), "w"); + } else + debugFP = fopen(c, "w"); setbuf(debugFP, NULL); } @@ -1226,6 +1270,7 @@ InitMenuChecks() (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit, MF_BYCOMMAND|(saveSettingsOnExit ? MF_CHECKED : MF_UNCHECKED)); + EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED); } //--------------------------------------------------------------------------------------------------------- @@ -1256,6 +1301,9 @@ 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; @@ -1809,6 +1857,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; @@ -2147,7 +2197,7 @@ void CreatePiecesFromFont() HBITMAP DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix) { - char name[128], buf[MSG_SIZ]; + char name[128], buf[MSG_SIZ], *ids = "pnbrqfeicwmohajgdvlsukaacvdklnwpwnwlwswolfgnuzebracameltowersword", *p; snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix); if(appData.pieceDirectory[0]) { @@ -2155,6 +2205,30 @@ DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix) snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name); res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); if(res) return res; + p = strstr(ids, piece); + if(p) { // if we could reconstruct canonical piece number, try the pieceNNN_ format before falling back on built-ins + int n = p - ids; + switch(n) { + case 21: n = WhiteKing; break; + case 22: n = WhiteAngel; break; + case 24: n = WhiteSilver; break; + case 26: n = WhiteDragon; break; + case 28: n = WhiteLion; break; + case 30: n = WhiteTokin; break; + case 32: n = WhitePKnight; break; + case 34: n = WhitePLance; break; + case 36: n = WhitePSilver; break; + case 38: n = WhiteWolf; break; + case 42: n = WhiteGnu; break; + case 45: n = WhiteZebra; break; + case 50: n = WhiteCamel; break; + case 55: n = WhiteTower; break; + case 60: n = WhiteSword; break; + } + snprintf(buf, MSG_SIZ, "%s\\piece%d_%d%s.bmp", appData.pieceDirectory, n, squareSize, suffix); + res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + if(res) return res; + } } if (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0 && @@ -2192,6 +2266,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 @@ -2223,8 +2298,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; } @@ -2296,9 +2372,10 @@ InitDrawingSizes(BoardSize boardSize, int flags) { // 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 == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) { if(boardSize < SizeMediocre) boardSize = SizePetite; else if(boardSize > SizeModerate) boardSize = SizeBulky; else boardSize = SizeMiddling; @@ -2318,13 +2395,17 @@ InitDrawingSizes(BoardSize boardSize, int flags) minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */ border = appData.useBorder && appData.border[0] ? squareSize/2 : 0; + // [HGM] decide on tininess based on total board width rather than square size + tinyLayout = squareSize * (BOARD_WIDTH); + tinyLayout = tinyLayout < 35*8 ? 2 : tinyLayout < 43*8 ? 1 : 0; + if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) { lineGap = appData.overrideLineGap; } if (tinyLayout != oldTinyLayout) { long style = GetWindowLongPtr(hwndMain, GWL_STYLE); - if (tinyLayout) { + if (tinyLayout == 2) { style &= ~WS_SYSMENU; InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize, "&Minimize\tCtrl+F4"); @@ -2360,7 +2441,7 @@ InitDrawingSizes(BoardSize boardSize, int flags) ReleaseDC(hwndMain, hdc); /* Compute where everything goes */ - if((first.programLogo || second.programLogo) && !tinyLayout) { + if((first.programLogo || second.programLogo) && tinyLayout != 2) { /* [HGM] logo: if either logo is on, reserve space for it */ logoHeight = 2*clockSize.cy; leftLogoRect.left = OUTER_MARGIN; @@ -2481,7 +2562,7 @@ InitDrawingSizes(BoardSize boardSize, int flags) messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain, (HMENU) buttonDesc[i].id, (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL); - if (tinyLayout) { + if (tinyLayout == 2) { SendMessage(buttonDesc[i].hwnd, WM_SETFONT, (WPARAM)font[boardSize][MESSAGE_FONT]->hf, MAKELPARAM(FALSE, 0)); @@ -2550,10 +2631,12 @@ InitDrawingSizes(BoardSize boardSize, int flags) piece = (ChessSquare) ((int) piece + 1)) { if (pieceBitmap[i][piece] != NULL) DeleteObject(pieceBitmap[i][piece]); + pieceBitmap[i][piece] = NULL; } } fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */ + // Orthodox Chess pieces pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s"); pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s"); @@ -2651,11 +2734,38 @@ InitDrawingSizes(BoardSize boardSize, int flags) pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s"); pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o"); pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w"); + pieceBitmap[0][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "s"); + pieceBitmap[1][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "o"); + pieceBitmap[2][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "w"); pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s"); pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o"); pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w"); - - if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */ + pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s"); + pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o"); + pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w"); + pieceBitmap[0][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "s"); + pieceBitmap[1][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "o"); + pieceBitmap[2][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "w"); + pieceBitmap[0][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "s"); + pieceBitmap[1][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "o"); + pieceBitmap[2][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "w"); + pieceBitmap[0][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "s"); + pieceBitmap[1][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "o"); + pieceBitmap[2][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "w"); + pieceBitmap[0][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "s"); + pieceBitmap[1][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "o"); + pieceBitmap[2][WhiteZebra] = DoLoadBitmap(hInst, "n", squareSize, "w"); + pieceBitmap[0][WhiteTower] = DoLoadBitmap(hInst, "tower", squareSize, "s"); + pieceBitmap[1][WhiteTower] = DoLoadBitmap(hInst, "tower", squareSize, "o"); + pieceBitmap[2][WhiteTower] = DoLoadBitmap(hInst, "tower", squareSize, "w"); + pieceBitmap[0][WhiteSword] = DoLoadBitmap(hInst, "sword", squareSize, "s"); + pieceBitmap[1][WhiteSword] = DoLoadBitmap(hInst, "sword", squareSize, "o"); + pieceBitmap[2][WhiteSword] = DoLoadBitmap(hInst, "sword", squareSize, "w"); + pieceBitmap[0][WhiteGnu] = DoLoadBitmap(hInst, "gnu", squareSize, "s"); + pieceBitmap[1][WhiteGnu] = DoLoadBitmap(hInst, "gnu", squareSize, "o"); + pieceBitmap[2][WhiteGnu] = DoLoadBitmap(hInst, "gnu", squareSize, "w"); + + 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"); @@ -2755,6 +2865,15 @@ InitDrawingSizes(BoardSize boardSize, int flags) pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w"); minorSize = 0; } + + if(appData.pieceDirectory[0]) for(i=WhitePawn; i= 0x0500 + HBITMAP pbm = PieceBitmap(piece, color ? OUTLINE_PIECE : SOLID_PIECE); + BITMAP b; + GetObject(pbm, sizeof(BITMAP), &b); + if(b.bmBitsPixel == 32) { // for now this is a kludge to indicate bitmaps with alpha channel + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + oldBitmap = SelectObject(tmphdc, pbm); + AlphaBlend(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, bf); + } else +#endif if (color || appData.allWhite ) { oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE)); if( color ) @@ -2996,7 +3129,7 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, else BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A); } - SelectObject(hdc, oldBrush); + if(oldBrush) SelectObject(hdc, oldBrush); SelectObject(tmphdc, oldBitmap); } } @@ -3275,6 +3408,9 @@ BOOL HasHighlightInfo() } return result; + + + } BOOL IsDrawArrowEnabled() @@ -3466,6 +3602,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) { @@ -3648,7 +3785,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, @@ -3667,6 +3804,10 @@ void DrawSeekClose() { } + + + + VOID HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) { @@ -3887,6 +4028,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) explodes. The old and new positions both had an empty square at the destination, but animation has drawn a piece there and we have to remember to erase it. [HGM] moved until after setting lastDrawn */ + lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece; } } @@ -3941,8 +4083,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); @@ -3952,6 +4093,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) } if( appData.highlightMoveWithArrow ) { + DrawArrowHighlight(hdcmem); } @@ -3968,6 +4110,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; @@ -4019,7 +4162,12 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) if(saveDiagFlag) { BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData; BITMAPINFOHEADER bih; int color[16], nrColors=0; + HBITMAP src = bufferBitmap, obmp; HDC tmp = CreateCompatibleDC(hdc); + bufferBitmap = CreateCompatibleBitmap(hdc, boardRect.right-boardRect.left, Rect.bottom-Rect.top-2*OUTER_MARGIN); + obmp = SelectObject(tmp, bufferBitmap); + BitBlt(tmp, 0, 0, boardRect.right - boardRect.left, Rect.bottom - Rect.top - 2*OUTER_MARGIN, + tmphdc, boardRect.left, OUTER_MARGIN, SRCCOPY); GetObject(bufferBitmap, sizeof(b), &b); if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) { bih.biSize = sizeof(BITMAPINFOHEADER); @@ -4083,10 +4231,14 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) if(fac) for(i=0; i<16; i++) fputDW(diagFile, color[i]); // write bitmap data + for(i=0; i= 0) { BOOL full_repaint = FALSE; @@ -4328,7 +4482,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; } @@ -4463,13 +4617,17 @@ 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) { + char promoChar; switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ /* Center the dialog over the application window */ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER)); @@ -4493,13 +4651,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?"); @@ -4520,7 +4674,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)); @@ -4537,7 +4691,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; @@ -4568,8 +4723,9 @@ PromotionPopup(HWND hwnd) } void -PromotionPopUp() +PromotionPopUp(char choice) { + promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant)); DrawPosition(TRUE, NULL); PromotionPopup(hwndMain); } @@ -4707,7 +4863,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { FARPROC lpProc; - int wmId, wmEvent; + int wmId; char *defName; FILE *f; UINT number; @@ -4786,6 +4942,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); @@ -4809,7 +4966,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: @@ -4902,6 +5058,16 @@ 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; @@ -5030,12 +5196,14 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games + if(matchMode) EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_GRAYED); MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1) break; case IDM_TwoMachines: TwoMachinesEvent(); /* + * refresh the tags dialog only if it's visible */ if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) { @@ -5128,6 +5296,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_Rematch: + RematchEvent(); break; @@ -5617,7 +5786,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; @@ -5634,6 +5803,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole ); wpMain.x = lpwp->x; wpMain.y = lpwp->y; + } } break; @@ -5686,6 +5856,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) default: /* Passes it on if unprocessed */ return (DefWindowProc(hwnd, message, wParam, lParam)); } + + return 0; } @@ -6154,6 +6326,8 @@ InitComboStringsFromOption(HANDLE hwndCombo, char *str) str = buf1; } + + SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0); for (;;) { @@ -6285,6 +6459,7 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 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)) { @@ -6375,7 +6550,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; @@ -6403,7 +6578,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; @@ -6649,7 +6823,7 @@ TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) case IDOK: GetDlgItemText(hDlg, OPT_Name, move, sizeof(move)); appData.userName = strdup(move); - SetUserLogo(); + SetUserLogo(); DisplayLogos(); SetGameInfo(); if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) { snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black); @@ -6740,7 +6914,6 @@ ErrorPopDown() LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - HANDLE hwndText; RECT rChild; switch (message) { @@ -6764,7 +6937,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; @@ -6790,7 +6962,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); @@ -6809,7 +6980,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; @@ -6862,6 +7032,7 @@ GothicPopUp(char *title, VariantClass variant) static char *history[HISTORY_SIZE]; int histIn = 0, histP = 0; + VOID SaveInHistory(char *cmd) { @@ -6874,6 +7045,7 @@ SaveInHistory(char *cmd) histIn = (histIn + 1) % HISTORY_SIZE; if (history[histIn] != NULL) { free(history[histIn]); + history[histIn] = NULL; } histP = histIn; @@ -7591,7 +7763,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight, if (twoBoards && partnerUp) return; if (appData.clockMode) { - if (tinyLayout) + if (tinyLayout == 2) snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell); else snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell); @@ -7607,6 +7779,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight, oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */ oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */ } + oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf); JAWS_SILENCE @@ -7684,6 +7857,7 @@ DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount, else err = GetLastError(); } + } return err; } @@ -7922,6 +8096,7 @@ Enables gnuEnables[] = { { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED }, { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED }, + // Needed to switch from ncp to GNU mode on Engine Load { ACTION_POS, MF_BYPOSITION|MF_ENABLED }, { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED }, @@ -8151,6 +8326,8 @@ ModeHighlight() nowChecked = 0; break; } + if(prevChecked == IDM_TwoMachines) // [HGM] 'Machine Match' might have gotten disabled when stopping match + EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_ENABLED); CheckMark(prevChecked, MF_UNCHECKED); CheckMark(nowChecked, MF_CHECKED); CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED); @@ -8395,6 +8572,7 @@ DisplayFatalError(char *str, int error, int exitStatus) fprintf(debugFP, "%s: %s\n", label, str); } if (appData.popupExitMessage) { + if(appData.icsActive) SendToICS("logout\n"); // [HGM] make sure no new games will be started! (void) MessageBox(hwndMain, str, label, MB_OK| (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION)); } @@ -8408,6 +8586,11 @@ DisplayInformation(char *str) (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION); } +char * +Shorten (char *s) +{ + return s; +} VOID DisplayNote(char *str) @@ -8549,6 +8732,7 @@ HWND gameListOptionsDialog; // low-level front-end: clear text edit / list widget void + GLT_ClearList() { SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 ); @@ -8657,8 +8841,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; @@ -8740,6 +8927,13 @@ EditCommentPopUp(int index, char *title, char *str) } +int +Roar() +{ + MyPlaySound(&sounds[(int)SoundRoar]); + return 1; +} + VOID RingBell() { @@ -8897,6 +9091,7 @@ DisplayBlackClock(long timeRemaining, int highlight) HDC hdc; char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : ""; + if(appData.noGUI) return; hdc = GetDC(hwndMain); if (!IsIconic(hwndMain)) { @@ -9005,6 +9200,7 @@ IDLE_PRIORITY_CLASS 0x00000040 */ if (nice < -15) return 0x00000080; if (nice < 0) return 0x00008000; + if (nice == 0) return 0x00000020; if (nice < 15) return 0x00004000; return 0x00000040; @@ -9208,15 +9404,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 ); @@ -9713,6 +9909,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) @@ -9914,17 +10111,28 @@ AnimateMove(board, fromX, fromY, toX, toY) int toX; int toY; { - ChessSquare piece; + ChessSquare piece, victim = EmptySquare, victim2 = EmptySquare; + int x = toX, y = toY, x2 = kill2X; 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(x2 >= 0) toX = kill2X, toY = kill2Y, victim = board[killY][killX], victim2 = board[kill2Y][kill2X]; else + if(killX >= 0) toX = killX, toY = killY, victim = board[killY][killX]; // [HGM] lion: first to kill square + + animInfo.from.x = fromX; + animInfo.from.y = fromY; + +again: + ScreenSquare(fromX, fromY, &start); ScreenSquare(toX, toY, &finish); @@ -9949,20 +10157,31 @@ AnimateMove(board, fromX, fromY, toX, toY) else Tween(&start, &mid, &finish, kFactor, frames, &nFrames); - animInfo.from.x = fromX; - animInfo.from.y = fromY; animInfo.to.x = toX; animInfo.to.y = toY; animInfo.lastpos = start; animInfo.piece = piece; for (n = 0; n < nFrames; n++) { animInfo.pos = frames[n]; - DrawPosition(FALSE, NULL); + DrawPosition(FALSE, board); animInfo.lastpos = animInfo.pos; Sleep(appData.animSpeed); } animInfo.pos = finish; - DrawPosition(FALSE, NULL); + DrawPosition(FALSE, board); + + if(toX == x2 && toY == kill2Y) { + fromX = toX; fromY = toY; toX = killX; toY = killY; x2 = -1; + board[kill2Y][kill2X] = EmptySquare; goto again; + } // second leg + if(toX != x || toY != y) { + fromX = toX; fromY = toY; toX = x; toY = y; + board[killY][killX] = EmptySquare; goto again; + } // second leg + +if(victim2 != EmptySquare) board[kill2Y][kill2X] = victim2; +if(victim != EmptySquare) board[killY][killX] = victim; + animInfo.piece = EmptySquare; Explode(board, fromX, fromY, toX, toY); } @@ -10040,6 +10259,7 @@ 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;