Updated copyright notice to 2011
[xboard.git] / winboard / winboard.c
index 2ab9456..f27a1e6 100644 (file)
@@ -5,7 +5,7 @@
  * Massachusetts. \r
  *\r
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
- * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.\r
+ * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.\r
  *\r
  * Enhancements Copyright 2005 Alessandro Scotti\r
  *\r
@@ -186,6 +186,7 @@ COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
 HPALETTE hPal;\r
 ColorClass currentColorClass;\r
 \r
+static HWND savedHwnd;\r
 HWND hCommPort = NULL;    /* currently open comm port */\r
 static HWND hwndPause;    /* pause button */\r
 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
@@ -247,7 +248,7 @@ Boolean barbaric; // flag indicating if translation is needed
 #define ABOUTBOX2 -1\r
 \r
 int dialogItems[][40] = {\r
-{ ABOUTBOX, IDOK, 400 }, \r
+{ ABOUTBOX, IDOK, OPT_MESS, 400 }, \r
 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed, \r
   OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors,   IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL }, \r
 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, IDOK, IDCANCEL }, \r
@@ -281,7 +282,7 @@ int dialogItems[][40] = {
   OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,\r
   OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,\r
   OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,\r
-  OPT_HighlightMoveArrow, OPT_AutoLogo }, \r
+  OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove }, \r
 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,\r
   OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,\r
   OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,\r
@@ -305,7 +306,7 @@ int dialogItems[][40] = {
   OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,\r
   OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,\r
   OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,\r
-  OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat,\r
+  OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,\r
   OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,\r
   IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def }, \r
 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,\r
@@ -333,7 +334,7 @@ static char languageBuf[50000], *foreign[1000], *english[1000], *languageFile[MS
 static int lastChecked;\r
 static char oldLanguage[MSG_SIZ], *menuText[10][30];\r
 extern int tinyLayout;\r
-extern char * menuBarText[][8];\r
+extern char * menuBarText[][10];\r
 \r
 void\r
 LoadLanguageFile(char *name)\r
@@ -397,13 +398,11 @@ Translate(HWND hDlg, int dialogID)
 {   // translate all text items in the given dialog\r
     int i=0, j, k;\r
     char buf[MSG_SIZ], *s;\r
-//if(appData.debugMode) fprintf(debugFP, "Translate(%d)\n", dialogID);\r
     if(!barbaric) return;\r
     while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description\r
     if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen\r
     GetWindowText( hDlg, buf, MSG_SIZ );\r
     s = T_(buf);\r
-//if(appData.debugMode) fprintf(debugFP, "WindowText '%s' -> '%s'\n", buf, s);\r
     if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)\r
     for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items\r
         GetDlgItemText(hDlg, k, buf, MSG_SIZ);\r
@@ -413,10 +412,35 @@ Translate(HWND hDlg, int dialogID)
     }\r
 }\r
 \r
+HMENU\r
+TranslateOneMenu(int i, HMENU subMenu)\r
+{\r
+    int j;\r
+    static MENUITEMINFO info;\r
+\r
+    info.cbSize = sizeof(MENUITEMINFO);\r
+    info.fMask = MIIM_STATE | MIIM_TYPE;\r
+          for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){\r
+            char buf[MSG_SIZ];\r
+            info.dwTypeData = buf;\r
+            info.cch = sizeof(buf);\r
+            GetMenuItemInfo(subMenu, j, TRUE, &info);\r
+            if(i < 10) {
+                if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );\r
+                else menuText[i][j] = strdup(buf); // remember original on first change\r
+            }\r
+            if(buf[0] == NULLCHAR) continue;\r
+            info.dwTypeData = T_(buf);\r
+            info.cch = strlen(buf)+1;\r
+            SetMenuItemInfo(subMenu, j, TRUE, &info);\r
+          }\r
+    return subMenu;\r
+}\r
+\r
 void\r
 TranslateMenus(int addLanguage)\r
 {\r
-    int i, j;\r
+    int i;\r
     WIN32_FIND_DATA fileData;\r
     HANDLE hFind;\r
 #define IDM_English 1895\r
@@ -426,20 +450,7 @@ TranslateMenus(int addLanguage)
           HMENU subMenu = GetSubMenu(mainMenu, i);\r
           ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),\r
                                                                   (UINT) subMenu, T_(menuBarText[tinyLayout][i]));\r
-          for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){\r
-            char buf[MSG_SIZ];\r
-            UINT k = GetMenuItemID(subMenu, j);\r
-             if(menuText[i][j])
-               safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) ); else {\r
-                GetMenuString(subMenu, j, buf, MSG_SIZ, MF_BYPOSITION);\r
-                menuText[i][j] = strdup(buf); // remember original on first change\r
-            }\r
-            if(buf[0] == NULLCHAR) continue;\r
-//fprintf(debugFP, "menu(%d,%d) = %s (%08x, %08x) %d\n", i, j, buf, mainMenu, subMenu, k);\r
-            ModifyMenu(subMenu, j, MF_STRING|MF_BYPOSITION\r
-                                   |CheckMenuItem(subMenu, j, MF_BYPOSITION)\r
-                                   |EnableMenuItem(subMenu, j, MF_BYPOSITION), k, T_(buf));\r
-          }\r
+          TranslateOneMenu(i, subMenu);\r
         }\r
         DrawMenuBar(hwndMain);\r
     }\r
@@ -548,10 +559,10 @@ MyButtonDesc buttonDesc[N_BUTTONS] =
 };\r
 \r
 int tinyLayout = 0, smallLayout = 0;\r
-#define MENU_BAR_ITEMS 7\r
+#define MENU_BAR_ITEMS 9\r
 char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
-  { N_("&File"), N_("&Mode"), N_("&Action"), N_("&Step"), N_("&Options"), N_("&Help"), NULL },\r
-  { N_("&F"), N_("&M"), N_("&A"), N_("&S"), N_("&O"), N_("&H"), NULL },\r
+  { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },\r
+  { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },\r
 };\r
 \r
 \r
@@ -755,6 +766,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
   }\r
 \r
   JAWS_INIT\r
+  TranslateMenus(1);\r
 \r
 //  InitCommonControlsEx(&ex);\r
   InitCommonControls();\r
@@ -883,6 +895,8 @@ SetUserLogo()
            snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);\r
                userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
                safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );\r
+               if(userLogo == NULL)\r
+                   userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); \r
          }\r
     }\r
 }\r
@@ -1047,7 +1061,6 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   }\r
 \r
   InitDrawingSizes(boardSize, 0);\r
-  TranslateMenus(1);\r
   InitMenuChecks();\r
   buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
 \r
@@ -2485,14 +2498,24 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
       pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
     } else { // Smirf-like\r
-      pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
-      pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
-      pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
+      if(gameInfo.variant == VariantSChess) {\r
+        pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");\r
+        pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");\r
+        pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");\r
+      } else {\r
+        pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
+        pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
+        pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
+      }\r
     }\r
     if(gameInfo.variant == VariantGothic) { // Vortex-like\r
       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
       pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+    } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {\r
+      pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
+      pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
+      pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
     } else { // WinBoard standard\r
       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
@@ -2941,7 +2964,7 @@ VOID RebuildTextureSquareInfo()
 \r
 /* [AS] Arrow highlighting support */\r
 \r
-static int A_WIDTH = 5; /* Width of arrow body */\r
+static double A_WIDTH = 5; /* Width of arrow body */\r
 \r
 #define A_HEIGHT_FACTOR 6   /* Length of arrow "point", relative to body width */\r
 #define A_WIDTH_FACTOR  3   /* Width of arrow "point", relative to body width */\r
@@ -2965,50 +2988,50 @@ VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
     if( d_x == s_x ) {\r
         int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;\r
 \r
-        arrow[0].x = s_x + A_WIDTH;\r
+        arrow[0].x = s_x + A_WIDTH + 0.5;\r
         arrow[0].y = s_y;\r
 \r
-        arrow[1].x = s_x + A_WIDTH;\r
+        arrow[1].x = s_x + A_WIDTH + 0.5;\r
         arrow[1].y = d_y - h;\r
 \r
-        arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;\r
+        arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
         arrow[2].y = d_y - h;\r
 \r
         arrow[3].x = d_x;\r
         arrow[3].y = d_y;\r
 \r
-        arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;\r
-        arrow[4].y = d_y - h;\r
-\r
-        arrow[5].x = s_x - A_WIDTH;\r
+        arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;\r
         arrow[5].y = d_y - h;\r
 \r
-        arrow[6].x = s_x - A_WIDTH;\r
+        arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
+        arrow[4].y = d_y - h;\r
+\r
+        arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;\r
         arrow[6].y = s_y;\r
     }\r
     else if( d_y == s_y ) {\r
         int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;\r
 \r
         arrow[0].x = s_x;\r
-        arrow[0].y = s_y + A_WIDTH;\r
+        arrow[0].y = s_y + A_WIDTH + 0.5;\r
 \r
         arrow[1].x = d_x - w;\r
-        arrow[1].y = s_y + A_WIDTH;\r
+        arrow[1].y = s_y + A_WIDTH + 0.5;\r
 \r
         arrow[2].x = d_x - w;\r
-        arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;\r
+        arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
 \r
         arrow[3].x = d_x;\r
         arrow[3].y = d_y;\r
 \r
-        arrow[4].x = d_x - w;\r
-        arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;\r
-\r
         arrow[5].x = d_x - w;\r
-        arrow[5].y = s_y - A_WIDTH;\r
+        arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;\r
+\r
+        arrow[4].x = d_x - w;\r
+        arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
 \r
         arrow[6].x = s_x;\r
-        arrow[6].y = s_y - A_WIDTH;\r
+        arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;\r
     }\r
     else {\r
         /* [AS] Needed a lot of paper for this! :-) */\r
@@ -3025,8 +3048,8 @@ VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
         arrow[0].x = Round(x - j);\r
         arrow[0].y = Round(y + j*dx);\r
 \r
-        arrow[1].x = Round(x + j);\r
-        arrow[1].y = Round(y - j*dx);\r
+        arrow[1].x = Round(arrow[0].x + 2*j);   // [HGM] prevent width to be affected by rounding twice\r
+        arrow[1].y = Round(arrow[0].y - 2*j*dx);\r
 \r
         if( d_x > s_x ) {\r
             x = (double) d_x - k;\r
@@ -3037,20 +3060,22 @@ VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
             y = (double) d_y + k*dy;\r
         }\r
 \r
-        arrow[2].x = Round(x + j);\r
-        arrow[2].y = Round(y - j*dx);\r
+        x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends\r
+\r
+        arrow[6].x = Round(x - j);\r
+        arrow[6].y = Round(y + j*dx);\r
+\r
+        arrow[2].x = Round(arrow[6].x + 2*j);\r
+        arrow[2].y = Round(arrow[6].y - 2*j*dx);\r
 \r
-        arrow[3].x = Round(x + j*A_WIDTH_FACTOR);\r
-        arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);\r
+        arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));\r
+        arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);\r
 \r
         arrow[4].x = d_x;\r
         arrow[4].y = d_y;\r
 \r
-        arrow[5].x = Round(x - j*A_WIDTH_FACTOR);\r
-        arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);\r
-\r
-        arrow[6].x = Round(x - j);\r
-        arrow[6].y = Round(y + j*dx);\r
+        arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));\r
+        arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);\r
     }\r
 \r
     Polygon( hdc, arrow, 7 );\r
@@ -3075,20 +3100,20 @@ VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_ro
     SquareToPos( d_row, d_col, &d_x, &d_y);\r
 \r
     if( d_y > s_y ) {\r
-        d_y += squareSize / 4;\r
+        d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!\r
     }\r
     else if( d_y < s_y ) {\r
-        d_y += 3 * squareSize / 4;\r
+        d_y += squareSize / 2 + squareSize / 4;\r
     }\r
     else {\r
         d_y += squareSize / 2;\r
     }\r
 \r
     if( d_x > s_x ) {\r
-        d_x += squareSize / 4;\r
+        d_x += squareSize / 2 - squareSize / 4;\r
     }\r
     else if( d_x < s_x ) {\r
-        d_x += 3 * squareSize / 4;\r
+        d_x += squareSize / 2 + squareSize / 4;\r
     }\r
     else {\r
         d_x += squareSize / 2;\r
@@ -3098,7 +3123,7 @@ VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_ro
     s_y += squareSize / 2;\r
 \r
     /* Adjust width */\r
-    A_WIDTH = squareSize / 14;\r
+    A_WIDTH = squareSize / 14.; //[HGM] make float\r
 \r
     /* Draw */\r
     stLB.lbStyle = BS_SOLID;\r
@@ -3369,6 +3394,48 @@ DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
   DeleteDC(tmphdc);\r
 }\r
 \r
+VOID\r
+DisplayLogos()\r
+{\r
+  if(logoHeight) {\r
+       HDC hdc = GetDC(hwndMain);\r
+       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
+       if(appData.autoLogo) {\r
+         \r
+         switch(gameMode) { // pick logos based on game mode\r
+           case IcsObserving:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = second.programLogo;\r
+           default:\r
+               break;\r
+           case IcsPlayingWhite:\r
+               if(!appData.zippyPlay) whiteLogo = userLogo;\r
+               blackLogo = second.programLogo; // ICS logo\r
+               break;\r
+           case IcsPlayingBlack:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
+               break;\r
+           case TwoMachinesPlay:\r
+               if(first.twoMachinesColor[0] == 'b') {\r
+                   whiteLogo = second.programLogo;\r
+                   blackLogo = first.programLogo;\r
+               }\r
+               break;\r
+           case MachinePlaysWhite:\r
+               blackLogo = userLogo;\r
+               break;\r
+           case MachinePlaysBlack:\r
+               whiteLogo = userLogo;\r
+               blackLogo = first.programLogo;\r
+         }\r
+       }\r
+       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
+       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
+       ReleaseDC(hwndMain, hdc);\r
+  }\r
+}\r
+\r
 static HDC hdcSeek;\r
 \r
 // [HGM] seekgraph\r
@@ -3504,7 +3571,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
             if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )\r
         board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
     } else \r
-        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+        board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;\r
   }\r
 \r
   /* Figure out which squares need updating by comparing the \r
@@ -3707,41 +3774,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        }\r
     }\r
   }\r
-  if(logoHeight) {\r
-       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
-       if(appData.autoLogo) {\r
-         \r
-         switch(gameMode) { // pick logos based on game mode\r
-           case IcsObserving:\r
-               whiteLogo = second.programLogo; // ICS logo\r
-               blackLogo = second.programLogo;\r
-           default:\r
-               break;\r
-           case IcsPlayingWhite:\r
-               if(!appData.zippyPlay) whiteLogo = userLogo;\r
-               blackLogo = second.programLogo; // ICS logo\r
-               break;\r
-           case IcsPlayingBlack:\r
-               whiteLogo = second.programLogo; // ICS logo\r
-               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
-               break;\r
-           case TwoMachinesPlay:\r
-               if(first.twoMachinesColor[0] == 'b') {\r
-                   whiteLogo = second.programLogo;\r
-                   blackLogo = first.programLogo;\r
-               }\r
-               break;\r
-           case MachinePlaysWhite:\r
-               blackLogo = userLogo;\r
-               break;\r
-           case MachinePlaysBlack:\r
-               whiteLogo = userLogo;\r
-               blackLogo = first.programLogo;\r
-         }\r
-       }\r
-       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
-       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
-  }\r
 \r
   if( appData.highlightMoveWithArrow ) {\r
     DrawArrowHighlight(hdcmem);\r
@@ -3956,6 +3988,7 @@ PaintProc(HWND hwnd)
                 &messageRect, messageText, strlen(messageText), NULL);\r
       SelectObject(hdc, oldFont);\r
       DisplayBothClocks();\r
+      DisplayLogos();\r
     }\r
     EndPaint(hwnd,&ps);\r
   }\r
@@ -4079,23 +4112,9 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_LBUTTONDOWN:\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-        if (gameMode == EditPosition) {\r
-         SetWhiteToPlayEvent();\r
-        } else if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) {\r
-          AdjustClock(flipClock, -1);\r
-       } else if (gameMode == IcsPlayingBlack ||\r
-                  gameMode == MachinePlaysWhite) {\r
-         CallFlagEvent();\r
-        }\r
+        ClockClick(flipClock);\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
-       if (gameMode == EditPosition) {\r
-         SetBlackToPlayEvent();\r
-        } else if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) {\r
-          AdjustClock(!flipClock, -1);\r
-       } else if (gameMode == IcsPlayingWhite ||\r
-                  gameMode == MachinePlaysBlack) {\r
-         CallFlagEvent();\r
-       }\r
+       ClockClick(!flipClock);\r
       }\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
@@ -4274,19 +4293,20 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     Translate(hDlg, DLG_PromotionKing);\r
     ShowWindow(GetDlgItem(hDlg, PB_King), \r
       (!appData.testLegality || gameInfo.variant == VariantSuicide ||\r
+       gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||\r
        gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?\r
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Only allow C & A promotions if these pieces are defined */\r
     ShowWindow(GetDlgItem(hDlg, PB_Archbishop),\r
-       ((PieceToChar(WhiteAngel) >= 'A' &&\r
+       ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&\r
          PieceToChar(WhiteAngel) != '~') ||\r
-        (PieceToChar(BlackAngel) >= 'A' &&\r
+        (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&\r
          PieceToChar(BlackAngel) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
-       ((PieceToChar(WhiteMarshall) >= 'A' &&\r
+       ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&\r
          PieceToChar(WhiteMarshall) != '~') ||\r
-        (PieceToChar(BlackMarshall) >= 'A' &&\r
+        (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&\r
          PieceToChar(BlackMarshall) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
@@ -4296,12 +4316,11 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     ShowWindow(GetDlgItem(hDlg, PB_Bishop), \r
        gameInfo.variant != VariantShogi ?\r
               SW_SHOW : SW_HIDE);\r
-    ShowWindow(GetDlgItem(hDlg, IDC_Yes), \r
-       gameInfo.variant == VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
-    ShowWindow(GetDlgItem(hDlg, IDC_No), \r
-       gameInfo.variant == VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
+    if(gameInfo.variant == VariantShogi) {\r
+        SetDlgItemText(hDlg, PB_Queen, "YES");\r
+        SetDlgItemText(hDlg, PB_Knight, "NO");\r
+        SetWindowText(hDlg, "Promote?");\r
+    }\r
     ShowWindow(GetDlgItem(hDlg, IDC_Centaur), \r
        gameInfo.variant == VariantSuper ?\r
               SW_SHOW : SW_HIDE);\r
@@ -4318,31 +4337,30 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
       break;\r
     case PB_Queen:\r
-      promoChar = gameInfo.variant == VariantShogi ? '^' : PieceToChar(BlackQueen);\r
+      promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
       break;\r
     case PB_Rook:\r
-      promoChar = PieceToChar(BlackRook);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));\r
+      if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);\r
       break;\r
     case PB_Bishop:\r
-      promoChar = PieceToChar(BlackBishop);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));\r
+      if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);\r
       break;\r
     case PB_Chancellor:\r
-      promoChar = PieceToChar(BlackMarshall);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));\r
       break;\r
     case PB_Archbishop:\r
-      promoChar = PieceToChar(BlackAngel);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));\r
       break;\r
     case PB_Knight:\r
-      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);\r
+      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);\r
       break;\r
     default:\r
       return FALSE;\r
     }\r
+    if(promoChar == '.') return FALSE; // invalid piece chosen \r
     EndDialog(hDlg, TRUE); /* Exit the dialog */\r
-    /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we\r
-       only show the popup when we are already sure the move is valid or\r
-       legal. We pass a faulty move type, but the kludge is that FinishMove\r
-       will figure out it is a promotion from the promoChar. */\r
     UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
     fromX = fromY = -1;\r
     if (!appData.highlightLastMove) {\r
@@ -4817,10 +4835,13 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games\r
-      if(gameMode != BeginningOfGame) break; // allow menu item to remain enabled for better mode highligting\r
+      if(gameMode != BeginningOfGame) { // allow menu item to remain enabled for better mode highligting\r
+        DisplayError(_("You can only start a match from the initial position."), 0); break;\r
+      }\r
       matchMode = 2;// distinguish from command-line-triggered case (matchMode=1)\r
       appData.matchGames = appData.defaultMatchGames;\r
       matchGame = 1;\r
+      first.matchWins = second.matchWins = 0;\r
 \r
     case IDM_TwoMachines:\r
       TwoMachinesEvent();\r
@@ -4890,11 +4911,13 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_EditGame:\r
+    case IDM_EditGame2:\r
       EditGameEvent();\r
       SAY("edit game");\r
       break;\r
 \r
     case IDM_EditPosition:\r
+    case IDM_EditPosition2:\r
       EditPositionEvent();\r
       SAY("enter a FEN string or setup a position on the board using the control R pop up menu");\r
       break;\r
@@ -4907,11 +4930,25 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       ShowGameListProc();\r
       break;\r
 \r
+    case IDM_EditProgs1:\r
+      EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);\r
+      break;\r
+\r
+    case IDM_EditProgs2:\r
+      EditTagsPopUp(secondChessProgramNames, &secondChessProgramNames);\r
+      break;\r
+\r
+    case IDM_EditServers:\r
+      EditTagsPopUp(icsNames, &icsNames);\r
+      break;\r
+\r
     case IDM_EditTags:\r
+    case IDM_Tags:\r
       EditTagsProc();\r
       break;\r
 \r
     case IDM_EditComment:\r
+    case IDM_Comment:\r
       if (commentUp && editComment) {\r
        CommentPopDown();\r
       } else {\r
@@ -5025,7 +5062,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_FlipClock:\r
       flipClock = !flipClock;\r
       DisplayBothClocks();\r
-      DrawPosition(FALSE, NULL);\r
+      DisplayLogos();\r
       break;\r
 \r
     case IDM_MuteSounds:\r
@@ -5052,6 +5089,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Engine2Options:\r
+      savedHwnd = hwnd;\r
+      if(WaitForSecond(SettingsMenuIfReady)) break;\r
       EngineOptionsPopup(hwnd, &second);\r
       break;\r
 \r
@@ -5710,12 +5749,12 @@ OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] dia
 \r
   if (fileName == NULL) fileName = buf1;\r
   if (defName == NULL) {\r
-    safeStrCpy(fileName, "*.", sizeof(fileName)/sizeof(fileName[0]) );\r
+    safeStrCpy(fileName, "*.", 3 );\r
     strcat(fileName, defExt);\r
   } else {\r
-    safeStrCpy(fileName, defName, sizeof(fileName)/sizeof(fileName[0]) );\r
+    safeStrCpy(fileName, defName, MSG_SIZ );\r
   }\r
-    if (fileTitle) safeStrCpy(fileTitle, "", sizeof(fileTitle)/sizeof(fileTitle[0]) );\r
+    if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );\r
   if (number) *number = 0;\r
 \r
   openFileName.lStructSize       = sizeof(OPENFILENAME);\r
@@ -5772,6 +5811,7 @@ MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
    * menu that TrackPopupMenu displays.\r
    */\r
   hmenuTrackPopup = GetSubMenu(hmenu, 0);\r
+  TranslateOneMenu(10, hmenuTrackPopup);\r
 \r
   SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);\r
 \r
@@ -6210,7 +6250,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        sizeY = newSizeY;\r
       }\r
     }\r
-    SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS );\r
+    SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );\r
     return FALSE;\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -6259,13 +6299,19 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
         if( wParam == OPT_CommentText ) {\r
             MSGFILTER * lpMF = (MSGFILTER *) lParam;\r
 \r
-            if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ) {\r
+            if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||\r
+                lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {\r
                 POINTL pt;\r
                 LRESULT index;\r
 \r
                 pt.x = LOWORD( lpMF->lParam );\r
                 pt.y = HIWORD( lpMF->lParam );\r
 \r
+                if(lpMF->msg == WM_CHAR) {\r
+                        CHARRANGE sel;\r
+                        SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );\r
+                        index = sel.cpMin;\r
+                } else\r
                 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );\r
 \r
                hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above\r
@@ -6309,7 +6355,7 @@ EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
   FARPROC lpProc;\r
   char *p, *q;\r
 \r
-  CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);\r
+  CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);\r
 \r
   if (str == NULL) str = "";\r
   p = (char *) malloc(2 * strlen(str) + 2);\r
@@ -6369,6 +6415,7 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDOK:
+\r
       shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status\r
       GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
       { int n; Board board;\r
@@ -6395,8 +6442,6 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized\r
        if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
          &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-         if (gameMode != Training)\r
-             forwardMostMove = currentMove;\r
          UserMoveEvent(fromX, fromY, toX, toY, promoChar);     \r
        } else {\r
          DisplayMoveError(_("Could not parse move"));\r
@@ -6799,6 +6844,7 @@ CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
     SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);\r
   }\r
   if (immediate) {\r
+    if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else\r
     snprintf(buf, MSG_SIZ, "%s %s", command, name);\r
     SetWindowText(hInput, buf);\r
     SendMessage(hInput, WM_CHAR, '\r', 0);\r
@@ -6822,6 +6868,7 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_KEYDOWN:\r
     if (!(GetKeyState(VK_CONTROL) & ~1)) break;\r
+    if(wParam=='R') return 0;\r
     switch (wParam) {\r
     case VK_PRIOR:\r
       SendMessage(hwnd, EM_LINESCROLL, 0, -999999);\r
@@ -6855,7 +6902,8 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SendMessage(hInput, message, wParam, lParam);\r
     }\r
     return 0;\r
-   } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu\r
+   } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu\r
+   lParam = -1;\r
   case WM_RBUTTONDOWN:\r
     if (!(GetKeyState(VK_SHIFT) & ~1)) {\r
       /* Move selection here if it was empty */\r
@@ -6864,7 +6912,7 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       pt.y = HIWORD(lParam);\r
       SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
       if (sel.cpMin == sel.cpMax) {\r
-        sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/\r
+        if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/\r
        sel.cpMax = sel.cpMin;\r
        SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
       }\r
@@ -7428,7 +7476,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
             rect, str, strlen(str), NULL);\r
   if(logoHeight > 0 && appData.clockMode) {\r
       RECT r;\r
-      snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s %s", buf+7, flagFell);\r
+      str += strlen(color)+2;\r
       r.top = rect->top + logoHeight/2;\r
       r.left = rect->left;\r
       r.right = rect->right;\r
@@ -7789,11 +7837,13 @@ Enables ncpEnables[] = {
   { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
 Enables trainingOnEnables[] = {\r
   { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },\r
@@ -7806,6 +7856,7 @@ Enables trainingOnEnables[] = {
 \r
 Enables trainingOffEnables[] = {\r
   { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },\r
@@ -7962,6 +8013,7 @@ ModeHighlight()
                        MF_BYCOMMAND|MF_UNCHECKED);\r
        }\r
   }\r
+  DisplayLogos(); // [HGM] logos: mode change could have altered logos\r
 }\r
 \r
 VOID\r
@@ -7969,8 +8021,8 @@ SetICSMode()
 {\r
   HMENU hmenu = GetMenu(hwndMain);\r
   SetMenuEnables(hmenu, icsEnables);\r
-  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,\r
-    MF_BYPOSITION|MF_ENABLED);\r
+  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,\r
+    MF_BYCOMMAND|MF_ENABLED);\r
 #if ZIPPY\r
   if (appData.zippyPlay) {\r
     SetMenuEnables(hmenu, zippyEnables);\r
@@ -7992,8 +8044,6 @@ SetNCPMode()
 {\r
   HMENU hmenu = GetMenu(hwndMain);\r
   SetMenuEnables(hmenu, ncpEnables);\r
-  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,\r
-    MF_BYPOSITION|MF_GRAYED);\r
     DrawMenuBar(hwndMain);\r
 }\r
 \r
@@ -8503,7 +8553,7 @@ CommentPopUp(char *title, char *str)
 VOID\r
 CommentPopDown(void)\r
 {\r
-  CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);\r
+  CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);\r
   if (commentDialog) {\r
     ShowWindow(commentDialog, SW_HIDE);\r
   }\r
@@ -9763,3 +9813,9 @@ HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
 \r
     EvalGraphSet( first, last, current, pvInfoList );\r
 }\r
+\r
+void\r
+SettingsPopUp(ChessProgramState *cps)\r
+{     // [HGM] wrapper needed because handles must not be passed through back-end\r
+      EngineOptionsPopup(savedHwnd, cps);\r
+}\r