2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
97 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
100 void mysrandom(unsigned int seed);
\r
102 extern int whiteFlag, blackFlag;
\r
103 Boolean flipClock = FALSE;
\r
104 extern HANDLE chatHandle[];
\r
105 extern enum ICS_TYPE ics_type;
\r
107 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
108 int MyGetFullPathName P((char *name, char *fullname));
\r
109 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
110 VOID NewVariantPopup(HWND hwnd);
\r
111 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
112 /*char*/int promoChar));
\r
113 void DisplayMove P((int moveNumber));
\r
114 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
115 void ChatPopUp P((char *s));
\r
117 ChessSquare piece;
\r
118 POINT pos; /* window coordinates of current pos */
\r
119 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
120 POINT from; /* board coordinates of the piece's orig pos */
\r
121 POINT to; /* board coordinates of the piece's new pos */
\r
124 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
127 POINT start; /* window coordinates of start pos */
\r
128 POINT pos; /* window coordinates of current pos */
\r
129 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
130 POINT from; /* board coordinates of the piece's orig pos */
\r
134 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
137 POINT sq[2]; /* board coordinates of from, to squares */
\r
140 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
145 typedef struct { // [HGM] atomic
\r
146 int fromX, fromY, toX, toY, radius;
\r
149 static ExplodeInfo explodeInfo;
\r
151 /* Window class names */
\r
152 char szAppName[] = "WinBoard";
\r
153 char szConsoleName[] = "WBConsole";
\r
155 /* Title bar text */
\r
156 char szTitle[] = "WinBoard";
\r
157 char szConsoleTitle[] = "I C S Interaction";
\r
160 char *settingsFileName;
\r
161 Boolean saveSettingsOnExit;
\r
162 char installDir[MSG_SIZ];
\r
163 int errorExitStatus;
\r
165 BoardSize boardSize;
\r
166 Boolean chessProgram;
\r
167 //static int boardX, boardY;
\r
168 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
169 int squareSize, lineGap, minorSize, border;
\r
170 static int winW, winH;
\r
171 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
172 static int logoHeight = 0;
\r
173 static char messageText[MESSAGE_TEXT_MAX];
\r
174 static int clockTimerEvent = 0;
\r
175 static int loadGameTimerEvent = 0;
\r
176 static int analysisTimerEvent = 0;
\r
177 static DelayedEventCallback delayedTimerCallback;
\r
178 static int delayedTimerEvent = 0;
\r
179 static int buttonCount = 2;
\r
180 char *icsTextMenuString;
\r
182 char *firstChessProgramNames;
\r
183 char *secondChessProgramNames;
\r
185 #define PALETTESIZE 256
\r
187 HINSTANCE hInst; /* current instance */
\r
188 Boolean alwaysOnTop = FALSE;
\r
190 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
191 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
193 ColorClass currentColorClass;
\r
195 static HWND savedHwnd;
\r
196 HWND hCommPort = NULL; /* currently open comm port */
\r
197 static HWND hwndPause; /* pause button */
\r
198 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
199 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
200 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
201 explodeBrush, /* [HGM] atomic */
\r
202 markerBrush, /* [HGM] markers */
\r
203 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
204 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
205 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
206 static HPEN gridPen = NULL;
\r
207 static HPEN highlightPen = NULL;
\r
208 static HPEN premovePen = NULL;
\r
209 static NPLOGPALETTE pLogPal;
\r
210 static BOOL paletteChanged = FALSE;
\r
211 static HICON iconWhite, iconBlack, iconCurrent;
\r
212 static int doingSizing = FALSE;
\r
213 static int lastSizing = 0;
\r
214 static int prevStderrPort;
\r
215 static HBITMAP userLogo;
\r
217 static HBITMAP liteBackTexture = NULL;
\r
218 static HBITMAP darkBackTexture = NULL;
\r
219 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
220 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int backTextureSquareSize = 0;
\r
222 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
224 #if __GNUC__ && !defined(_winmajor)
\r
225 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
230 #if defined(_winmajor)
\r
231 #define oldDialog (_winmajor < 4)
\r
233 #define oldDialog 0
\r
237 #define INTERNATIONAL
\r
239 #ifdef INTERNATIONAL
\r
240 # define _(s) T_(s)
\r
246 # define Translate(x, y)
\r
247 # define LoadLanguageFile(s)
\r
250 #ifdef INTERNATIONAL
\r
252 Boolean barbaric; // flag indicating if translation is needed
\r
254 // list of item numbers used in each dialog (used to alter language at run time)
\r
256 #define ABOUTBOX -1 /* not sure why these are needed */
\r
257 #define ABOUTBOX2 -1
\r
259 int dialogItems[][42] = {
\r
260 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
261 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
262 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
263 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
264 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
265 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
266 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
267 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
268 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
269 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
270 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
271 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
272 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
273 { ABOUTBOX2, IDC_ChessBoard },
\r
274 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
275 OPT_GameListClose, IDC_GameListDoFilter },
\r
276 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
277 { DLG_Error, IDOK },
\r
278 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
279 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
280 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
281 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
282 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
283 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
284 { DLG_IndexNumber, IDC_Index },
\r
285 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
286 { DLG_TypeInName, IDOK, IDCANCEL },
\r
287 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
288 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
289 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
290 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
291 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
292 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
293 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
294 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
295 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
296 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
297 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
298 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
299 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
300 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
301 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
302 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
303 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
304 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
305 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
306 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
307 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
308 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
309 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
310 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
311 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
312 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
313 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
314 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
315 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
316 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
317 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
318 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
319 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
320 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
321 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
322 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
323 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
324 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
325 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
326 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
327 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
328 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
329 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
330 { DLG_MoveHistory },
\r
331 { DLG_EvalGraph },
\r
332 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
333 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
334 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
335 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
336 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
337 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
338 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
339 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
340 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
344 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
345 static int lastChecked;
\r
346 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
347 extern int tinyLayout;
\r
348 extern char * menuBarText[][10];
\r
351 LoadLanguageFile(char *name)
\r
352 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
354 int i=0, j=0, n=0, k;
\r
357 if(!name || name[0] == NULLCHAR) return;
\r
358 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
359 appData.language = oldLanguage;
\r
360 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
361 if((f = fopen(buf, "r")) == NULL) return;
\r
362 while((k = fgetc(f)) != EOF) {
\r
363 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
364 languageBuf[i] = k;
\r
366 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
368 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
369 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
370 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
371 english[j] = languageBuf + n + 1; *p = 0;
\r
372 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
373 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
378 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
380 case 'n': k = '\n'; break;
\r
381 case 'r': k = '\r'; break;
\r
382 case 't': k = '\t'; break;
\r
384 languageBuf[--i] = k;
\r
389 barbaric = (j != 0);
\r
390 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
395 { // return the translation of the given string
\r
396 // efficiency can be improved a lot...
\r
398 static char buf[MSG_SIZ];
\r
399 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
400 if(!barbaric) return s;
\r
401 if(!s) return ""; // sanity
\r
402 while(english[i]) {
\r
403 if(!strcmp(s, english[i])) return foreign[i];
\r
404 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
405 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
414 Translate(HWND hDlg, int dialogID)
\r
415 { // translate all text items in the given dialog
\r
417 char buf[MSG_SIZ], *s;
\r
418 if(!barbaric) return;
\r
419 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
420 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
421 GetWindowText( hDlg, buf, MSG_SIZ );
\r
423 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
424 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
425 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
426 if(strlen(buf) == 0) continue;
\r
428 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
433 TranslateOneMenu(int i, HMENU subMenu)
\r
436 static MENUITEMINFO info;
\r
438 info.cbSize = sizeof(MENUITEMINFO);
\r
439 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
440 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
442 info.dwTypeData = buf;
\r
443 info.cch = sizeof(buf);
\r
444 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
446 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
447 else menuText[i][j] = strdup(buf); // remember original on first change
\r
449 if(buf[0] == NULLCHAR) continue;
\r
450 info.dwTypeData = T_(buf);
\r
451 info.cch = strlen(buf)+1;
\r
452 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
458 TranslateMenus(int addLanguage)
\r
461 WIN32_FIND_DATA fileData;
\r
463 #define IDM_English 1970
\r
465 HMENU mainMenu = GetMenu(hwndMain);
\r
466 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
467 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
468 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
469 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
470 TranslateOneMenu(i, subMenu);
\r
472 DrawMenuBar(hwndMain);
\r
475 if(!addLanguage) return;
\r
476 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
477 HMENU mainMenu = GetMenu(hwndMain);
\r
478 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
479 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
480 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
481 i = 0; lastChecked = IDM_English;
\r
483 char *p, *q = fileData.cFileName;
\r
484 int checkFlag = MF_UNCHECKED;
\r
485 languageFile[i] = strdup(q);
\r
486 if(barbaric && !strcmp(oldLanguage, q)) {
\r
487 checkFlag = MF_CHECKED;
\r
488 lastChecked = IDM_English + i + 1;
\r
489 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
491 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
492 p = strstr(fileData.cFileName, ".lng");
\r
494 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
495 } while(FindNextFile(hFind, &fileData));
\r
502 #define IDM_RecentEngines 3000
\r
505 RecentEngineMenu (char *s)
\r
507 if(appData.icsActive) return;
\r
508 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
509 HMENU mainMenu = GetMenu(hwndMain);
\r
510 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
511 int i=IDM_RecentEngines;
\r
512 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
513 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
515 char *p = strchr(s, '\n');
\r
516 if(p == NULL) return; // malformed!
\r
518 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
532 int cliWidth, cliHeight;
\r
535 SizeInfo sizeInfo[] =
\r
537 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
540 { "petite", 33, 1, 1, 1, 0, 0 },
\r
541 { "slim", 37, 2, 1, 0, 0, 0 },
\r
542 { "small", 40, 2, 1, 0, 0, 0 },
\r
543 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
544 { "middling", 49, 2, 0, 0, 0, 0 },
\r
545 { "average", 54, 2, 0, 0, 0, 0 },
\r
546 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
547 { "medium", 64, 3, 0, 0, 0, 0 },
\r
548 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
549 { "large", 80, 3, 0, 0, 0, 0 },
\r
550 { "big", 87, 3, 0, 0, 0, 0 },
\r
551 { "huge", 95, 3, 0, 0, 0, 0 },
\r
552 { "giant", 108, 3, 0, 0, 0, 0 },
\r
553 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
554 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
555 { NULL, 0, 0, 0, 0, 0, 0 }
\r
558 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
559 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
561 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
562 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
578 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
581 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
590 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
591 #define N_BUTTONS 5
\r
593 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
595 {"<<", IDM_ToStart, NULL, NULL},
\r
596 {"<", IDM_Backward, NULL, NULL},
\r
597 {"P", IDM_Pause, NULL, NULL},
\r
598 {">", IDM_Forward, NULL, NULL},
\r
599 {">>", IDM_ToEnd, NULL, NULL},
\r
602 int tinyLayout = 0, smallLayout = 0;
\r
603 #define MENU_BAR_ITEMS 9
\r
604 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
605 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
606 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
610 MySound sounds[(int)NSoundClasses];
\r
611 MyTextAttribs textAttribs[(int)NColorClasses];
\r
613 MyColorizeAttribs colorizeAttribs[] = {
\r
614 { (COLORREF)0, 0, N_("Shout Text") },
\r
615 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
616 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
617 { (COLORREF)0, 0, N_("Channel Text") },
\r
618 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
619 { (COLORREF)0, 0, N_("Tell Text") },
\r
620 { (COLORREF)0, 0, N_("Challenge Text") },
\r
621 { (COLORREF)0, 0, N_("Request Text") },
\r
622 { (COLORREF)0, 0, N_("Seek Text") },
\r
623 { (COLORREF)0, 0, N_("Normal Text") },
\r
624 { (COLORREF)0, 0, N_("None") }
\r
629 static char *commentTitle;
\r
630 static char *commentText;
\r
631 static int commentIndex;
\r
632 static Boolean editComment = FALSE;
\r
635 char errorTitle[MSG_SIZ];
\r
636 char errorMessage[2*MSG_SIZ];
\r
637 HWND errorDialog = NULL;
\r
638 BOOLEAN moveErrorMessageUp = FALSE;
\r
639 BOOLEAN consoleEcho = TRUE;
\r
640 CHARFORMAT consoleCF;
\r
641 COLORREF consoleBackgroundColor;
\r
643 char *programVersion;
\r
649 typedef int CPKind;
\r
658 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
661 #define INPUT_SOURCE_BUF_SIZE 4096
\r
663 typedef struct _InputSource {
\r
670 char buf[INPUT_SOURCE_BUF_SIZE];
\r
674 InputCallback func;
\r
675 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
679 InputSource *consoleInputSource;
\r
684 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
685 VOID ConsoleCreate();
\r
687 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
689 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
690 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
692 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
693 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
694 void ParseIcsTextMenu(char *icsTextMenuString);
\r
695 VOID PopUpNameDialog(char firstchar);
\r
696 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
700 int GameListOptions();
\r
702 int dummy; // [HGM] for obsolete args
\r
704 HWND hwndMain = NULL; /* root window*/
\r
705 HWND hwndConsole = NULL;
\r
706 HWND commentDialog = NULL;
\r
707 HWND moveHistoryDialog = NULL;
\r
708 HWND evalGraphDialog = NULL;
\r
709 HWND engineOutputDialog = NULL;
\r
710 HWND gameListDialog = NULL;
\r
711 HWND editTagsDialog = NULL;
\r
713 int commentUp = FALSE;
\r
715 WindowPlacement wpMain;
\r
716 WindowPlacement wpConsole;
\r
717 WindowPlacement wpComment;
\r
718 WindowPlacement wpMoveHistory;
\r
719 WindowPlacement wpEvalGraph;
\r
720 WindowPlacement wpEngineOutput;
\r
721 WindowPlacement wpGameList;
\r
722 WindowPlacement wpTags;
\r
724 VOID EngineOptionsPopup(); // [HGM] settings
\r
726 VOID GothicPopUp(char *title, VariantClass variant);
\r
728 * Setting "frozen" should disable all user input other than deleting
\r
729 * the window. We do this while engines are initializing themselves.
\r
731 static int frozen = 0;
\r
732 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
738 if (frozen) return;
\r
740 hmenu = GetMenu(hwndMain);
\r
741 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
742 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
744 DrawMenuBar(hwndMain);
\r
747 /* Undo a FreezeUI */
\r
753 if (!frozen) return;
\r
755 hmenu = GetMenu(hwndMain);
\r
756 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
757 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
759 DrawMenuBar(hwndMain);
\r
762 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
764 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
770 #define JAWS_ALT_INTERCEPT
\r
771 #define JAWS_KBUP_NAVIGATION
\r
772 #define JAWS_KBDOWN_NAVIGATION
\r
773 #define JAWS_MENU_ITEMS
\r
774 #define JAWS_SILENCE
\r
775 #define JAWS_REPLAY
\r
777 #define JAWS_COPYRIGHT
\r
778 #define JAWS_DELETE(X) X
\r
779 #define SAYMACHINEMOVE()
\r
783 /*---------------------------------------------------------------------------*\
\r
787 \*---------------------------------------------------------------------------*/
\r
790 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
791 LPSTR lpCmdLine, int nCmdShow)
\r
794 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
795 // INITCOMMONCONTROLSEX ex;
\r
799 LoadLibrary("RICHED32.DLL");
\r
800 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
802 if (!InitApplication(hInstance)) {
\r
805 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
812 // InitCommonControlsEx(&ex);
\r
813 InitCommonControls();
\r
815 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
816 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
817 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
819 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
821 while (GetMessage(&msg, /* message structure */
\r
822 NULL, /* handle of window receiving the message */
\r
823 0, /* lowest message to examine */
\r
824 0)) /* highest message to examine */
\r
827 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
828 // [HGM] navigate: switch between all windows with tab
\r
829 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
830 int i, currentElement = 0;
\r
832 // first determine what element of the chain we come from (if any)
\r
833 if(appData.icsActive) {
\r
834 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
835 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
837 if(engineOutputDialog && EngineOutputIsUp()) {
\r
838 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
839 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
841 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
842 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
844 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
845 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
846 if(msg.hwnd == e1) currentElement = 2; else
\r
847 if(msg.hwnd == e2) currentElement = 3; else
\r
848 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
849 if(msg.hwnd == mh) currentElement = 4; else
\r
850 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
851 if(msg.hwnd == hText) currentElement = 5; else
\r
852 if(msg.hwnd == hInput) currentElement = 6; else
\r
853 for (i = 0; i < N_BUTTONS; i++) {
\r
854 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
857 // determine where to go to
\r
858 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
860 currentElement = (currentElement + direction) % 7;
\r
861 switch(currentElement) {
\r
863 h = hwndMain; break; // passing this case always makes the loop exit
\r
865 h = buttonDesc[0].hwnd; break; // could be NULL
\r
867 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
870 if(!EngineOutputIsUp()) continue;
\r
873 if(!MoveHistoryIsUp()) continue;
\r
875 // case 6: // input to eval graph does not seem to get here!
\r
876 // if(!EvalGraphIsUp()) continue;
\r
877 // h = evalGraphDialog; break;
\r
879 if(!appData.icsActive) continue;
\r
883 if(!appData.icsActive) continue;
\r
889 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
890 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
893 continue; // this message now has been processed
\r
897 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
898 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
899 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
900 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
901 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
902 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
903 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
904 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
905 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
906 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
907 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
908 for(i=0; i<MAX_CHAT; i++)
\r
909 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
912 if(done) continue; // [HGM] chat: end patch
\r
913 TranslateMessage(&msg); /* Translates virtual key codes */
\r
914 DispatchMessage(&msg); /* Dispatches message to window */
\r
919 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
922 /*---------------------------------------------------------------------------*\
\r
924 * Initialization functions
\r
926 \*---------------------------------------------------------------------------*/
\r
930 { // update user logo if necessary
\r
931 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
933 if(appData.autoLogo) {
\r
934 curName = UserName();
\r
935 if(strcmp(curName, oldUserName)) {
\r
936 GetCurrentDirectory(MSG_SIZ, dir);
\r
937 SetCurrentDirectory(installDir);
\r
938 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
939 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
940 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
941 if(userLogo == NULL)
\r
942 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
943 SetCurrentDirectory(dir); /* return to prev directory */
\r
949 InitApplication(HINSTANCE hInstance)
\r
953 /* Fill in window class structure with parameters that describe the */
\r
956 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
957 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
958 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
959 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
960 wc.hInstance = hInstance; /* Owner of this class */
\r
961 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
962 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
963 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
964 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
965 wc.lpszClassName = szAppName; /* Name to register as */
\r
967 /* Register the window class and return success/failure code. */
\r
968 if (!RegisterClass(&wc)) return FALSE;
\r
970 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
971 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
973 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
974 wc.hInstance = hInstance;
\r
975 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
976 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
977 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
978 wc.lpszMenuName = NULL;
\r
979 wc.lpszClassName = szConsoleName;
\r
981 if (!RegisterClass(&wc)) return FALSE;
\r
986 /* Set by InitInstance, used by EnsureOnScreen */
\r
987 int screenHeight, screenWidth;
\r
988 RECT screenGeometry;
\r
991 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
993 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
994 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
995 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
996 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
997 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
998 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1002 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1004 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1005 GetCurrentDirectory(MSG_SIZ, dir);
\r
1006 SetCurrentDirectory(installDir);
\r
1007 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1008 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1010 if (cps->programLogo == NULL && appData.debugMode) {
\r
1011 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1013 } else if(appData.autoLogo) {
\r
1014 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1015 char *opponent = "";
\r
1016 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1017 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1018 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1019 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1020 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1021 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1024 if(appData.directory[n] && appData.directory[n][0]) {
\r
1025 SetCurrentDirectory(appData.directory[n]);
\r
1026 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1029 SetCurrentDirectory(dir); /* return to prev directory */
\r
1035 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1036 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1038 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1039 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1040 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1041 liteBackTextureMode = appData.liteBackTextureMode;
\r
1043 if (liteBackTexture == NULL && appData.debugMode) {
\r
1044 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1048 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1049 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1050 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1051 darkBackTextureMode = appData.darkBackTextureMode;
\r
1053 if (darkBackTexture == NULL && appData.debugMode) {
\r
1054 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1059 #ifndef SM_CXVIRTUALSCREEN
\r
1060 #define SM_CXVIRTUALSCREEN 78
\r
1062 #ifndef SM_CYVIRTUALSCREEN
\r
1063 #define SM_CYVIRTUALSCREEN 79
\r
1065 #ifndef SM_XVIRTUALSCREEN
\r
1066 #define SM_XVIRTUALSCREEN 76
\r
1068 #ifndef SM_YVIRTUALSCREEN
\r
1069 #define SM_YVIRTUALSCREEN 77
\r
1075 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1076 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1077 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1078 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1079 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1080 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1081 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1082 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1086 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1088 HWND hwnd; /* Main window handle. */
\r
1090 WINDOWPLACEMENT wp;
\r
1093 hInst = hInstance; /* Store instance handle in our global variable */
\r
1094 programName = szAppName;
\r
1096 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1097 *filepart = NULLCHAR;
\r
1098 SetCurrentDirectory(installDir);
\r
1100 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1102 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1104 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1105 /* xboard, and older WinBoards, controlled the move sound with the
\r
1106 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1107 always turn the option on (so that the backend will call us),
\r
1108 then let the user turn the sound off by setting it to silence if
\r
1109 desired. To accommodate old winboard.ini files saved by old
\r
1110 versions of WinBoard, we also turn off the sound if the option
\r
1111 was initially set to false. [HGM] taken out of InitAppData */
\r
1112 if (!appData.ringBellAfterMoves) {
\r
1113 sounds[(int)SoundMove].name = strdup("");
\r
1114 appData.ringBellAfterMoves = TRUE;
\r
1116 if (appData.debugMode) {
\r
1117 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1118 setbuf(debugFP, NULL);
\r
1121 LoadLanguageFile(appData.language);
\r
1125 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1126 // InitEngineUCI( installDir, &second );
\r
1128 /* Create a main window for this application instance. */
\r
1129 hwnd = CreateWindow(szAppName, szTitle,
\r
1130 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1131 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1132 NULL, NULL, hInstance, NULL);
\r
1135 /* If window could not be created, return "failure" */
\r
1140 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1141 LoadLogo(&first, 0, FALSE);
\r
1142 LoadLogo(&second, 1, appData.icsActive);
\r
1146 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1147 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1148 iconCurrent = iconWhite;
\r
1149 InitDrawingColors();
\r
1151 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1152 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1153 /* Compute window size for each board size, and use the largest
\r
1154 size that fits on this screen as the default. */
\r
1155 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1156 if (boardSize == (BoardSize)-1 &&
\r
1157 winH <= screenHeight
\r
1158 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1159 && winW <= screenWidth) {
\r
1160 boardSize = (BoardSize)ibs;
\r
1164 InitDrawingSizes(boardSize, 0);
\r
1165 RecentEngineMenu(appData.recentEngineList);
\r
1167 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1169 /* [AS] Load textures if specified */
\r
1172 mysrandom( (unsigned) time(NULL) );
\r
1174 /* [AS] Restore layout */
\r
1175 if( wpMoveHistory.visible ) {
\r
1176 MoveHistoryPopUp();
\r
1179 if( wpEvalGraph.visible ) {
\r
1183 if( wpEngineOutput.visible ) {
\r
1184 EngineOutputPopUp();
\r
1187 /* Make the window visible; update its client area; and return "success" */
\r
1188 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1189 wp.length = sizeof(WINDOWPLACEMENT);
\r
1191 wp.showCmd = nCmdShow;
\r
1192 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1193 wp.rcNormalPosition.left = wpMain.x;
\r
1194 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1195 wp.rcNormalPosition.top = wpMain.y;
\r
1196 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1197 SetWindowPlacement(hwndMain, &wp);
\r
1199 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1201 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1202 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1204 if (hwndConsole) {
\r
1206 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1207 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1209 ShowWindow(hwndConsole, nCmdShow);
\r
1210 SetActiveWindow(hwndConsole);
\r
1212 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1213 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1222 HMENU hmenu = GetMenu(hwndMain);
\r
1224 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1225 MF_BYCOMMAND|((appData.icsActive &&
\r
1226 *appData.icsCommPort != NULLCHAR) ?
\r
1227 MF_ENABLED : MF_GRAYED));
\r
1228 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1229 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1230 MF_CHECKED : MF_UNCHECKED));
\r
1233 //---------------------------------------------------------------------------------------------------------
\r
1235 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1236 #define XBOARD FALSE
\r
1238 #define OPTCHAR "/"
\r
1239 #define SEPCHAR "="
\r
1240 #define TOPLEVEL 0
\r
1244 // front-end part of option handling
\r
1247 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1249 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1250 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1253 lf->lfEscapement = 0;
\r
1254 lf->lfOrientation = 0;
\r
1255 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1256 lf->lfItalic = mfp->italic;
\r
1257 lf->lfUnderline = mfp->underline;
\r
1258 lf->lfStrikeOut = mfp->strikeout;
\r
1259 lf->lfCharSet = mfp->charset;
\r
1260 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1261 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1262 lf->lfQuality = DEFAULT_QUALITY;
\r
1263 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1264 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1268 CreateFontInMF(MyFont *mf)
\r
1270 LFfromMFP(&mf->lf, &mf->mfp);
\r
1271 if (mf->hf) DeleteObject(mf->hf);
\r
1272 mf->hf = CreateFontIndirect(&mf->lf);
\r
1275 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1277 colorVariable[] = {
\r
1278 &whitePieceColor,
\r
1279 &blackPieceColor,
\r
1280 &lightSquareColor,
\r
1281 &darkSquareColor,
\r
1282 &highlightSquareColor,
\r
1283 &premoveHighlightColor,
\r
1285 &consoleBackgroundColor,
\r
1286 &appData.fontForeColorWhite,
\r
1287 &appData.fontBackColorWhite,
\r
1288 &appData.fontForeColorBlack,
\r
1289 &appData.fontBackColorBlack,
\r
1290 &appData.evalHistColorWhite,
\r
1291 &appData.evalHistColorBlack,
\r
1292 &appData.highlightArrowColor,
\r
1295 /* Command line font name parser. NULL name means do nothing.
\r
1296 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1297 For backward compatibility, syntax without the colon is also
\r
1298 accepted, but font names with digits in them won't work in that case.
\r
1301 ParseFontName(char *name, MyFontParams *mfp)
\r
1304 if (name == NULL) return;
\r
1306 q = strchr(p, ':');
\r
1308 if (q - p >= sizeof(mfp->faceName))
\r
1309 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1310 memcpy(mfp->faceName, p, q - p);
\r
1311 mfp->faceName[q - p] = NULLCHAR;
\r
1314 q = mfp->faceName;
\r
1316 while (*p && !isdigit(*p)) {
\r
1318 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1319 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1321 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1324 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1325 mfp->pointSize = (float) atof(p);
\r
1326 mfp->bold = (strchr(p, 'b') != NULL);
\r
1327 mfp->italic = (strchr(p, 'i') != NULL);
\r
1328 mfp->underline = (strchr(p, 'u') != NULL);
\r
1329 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1330 mfp->charset = DEFAULT_CHARSET;
\r
1331 q = strchr(p, 'c');
\r
1333 mfp->charset = (BYTE) atoi(q+1);
\r
1337 ParseFont(char *name, int number)
\r
1338 { // wrapper to shield back-end from 'font'
\r
1339 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1344 { // in WB we have a 2D array of fonts; this initializes their description
\r
1346 /* Point font array elements to structures and
\r
1347 parse default font names */
\r
1348 for (i=0; i<NUM_FONTS; i++) {
\r
1349 for (j=0; j<NUM_SIZES; j++) {
\r
1350 font[j][i] = &fontRec[j][i];
\r
1351 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1358 { // here we create the actual fonts from the selected descriptions
\r
1360 for (i=0; i<NUM_FONTS; i++) {
\r
1361 for (j=0; j<NUM_SIZES; j++) {
\r
1362 CreateFontInMF(font[j][i]);
\r
1366 /* Color name parser.
\r
1367 X version accepts X color names, but this one
\r
1368 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1370 ParseColorName(char *name)
\r
1372 int red, green, blue, count;
\r
1373 char buf[MSG_SIZ];
\r
1375 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1377 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1378 &red, &green, &blue);
\r
1381 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1382 DisplayError(buf, 0);
\r
1383 return RGB(0, 0, 0);
\r
1385 return PALETTERGB(red, green, blue);
\r
1389 ParseColor(int n, char *name)
\r
1390 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1391 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1395 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1397 char *e = argValue;
\r
1401 if (*e == 'b') eff |= CFE_BOLD;
\r
1402 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1403 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1404 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1405 else if (*e == '#' || isdigit(*e)) break;
\r
1409 *color = ParseColorName(e);
\r
1413 ParseTextAttribs(ColorClass cc, char *s)
\r
1414 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1415 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1416 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1420 ParseBoardSize(void *addr, char *name)
\r
1421 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1422 BoardSize bs = SizeTiny;
\r
1423 while (sizeInfo[bs].name != NULL) {
\r
1424 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1425 *(BoardSize *)addr = bs;
\r
1430 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1435 { // [HGM] import name from appData first
\r
1438 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1439 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1440 textAttribs[cc].sound.data = NULL;
\r
1441 MyLoadSound(&textAttribs[cc].sound);
\r
1443 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1444 textAttribs[cc].sound.name = strdup("");
\r
1445 textAttribs[cc].sound.data = NULL;
\r
1447 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1448 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1449 sounds[sc].data = NULL;
\r
1450 MyLoadSound(&sounds[sc]);
\r
1455 SetCommPortDefaults()
\r
1457 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1458 dcb.DCBlength = sizeof(DCB);
\r
1459 dcb.BaudRate = 9600;
\r
1460 dcb.fBinary = TRUE;
\r
1461 dcb.fParity = FALSE;
\r
1462 dcb.fOutxCtsFlow = FALSE;
\r
1463 dcb.fOutxDsrFlow = FALSE;
\r
1464 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1465 dcb.fDsrSensitivity = FALSE;
\r
1466 dcb.fTXContinueOnXoff = TRUE;
\r
1467 dcb.fOutX = FALSE;
\r
1469 dcb.fNull = FALSE;
\r
1470 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1471 dcb.fAbortOnError = FALSE;
\r
1473 dcb.Parity = SPACEPARITY;
\r
1474 dcb.StopBits = ONESTOPBIT;
\r
1477 // [HGM] args: these three cases taken out to stay in front-end
\r
1479 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1480 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1481 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1482 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1484 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1485 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1486 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1487 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1488 ad->argName, mfp->faceName, mfp->pointSize,
\r
1489 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1490 mfp->bold ? "b" : "",
\r
1491 mfp->italic ? "i" : "",
\r
1492 mfp->underline ? "u" : "",
\r
1493 mfp->strikeout ? "s" : "",
\r
1494 (int)mfp->charset);
\r
1500 { // [HGM] copy the names from the internal WB variables to appData
\r
1503 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1504 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1505 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1506 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1510 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1511 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1512 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1513 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1514 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1515 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1516 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1517 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1518 (ta->effects) ? " " : "",
\r
1519 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1523 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1524 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1525 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1526 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1527 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1531 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1532 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1533 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1537 ParseCommPortSettings(char *s)
\r
1538 { // wrapper to keep dcb from back-end
\r
1539 ParseCommSettings(s, &dcb);
\r
1544 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1545 GetActualPlacement(hwndMain, &wpMain);
\r
1546 GetActualPlacement(hwndConsole, &wpConsole);
\r
1547 GetActualPlacement(commentDialog, &wpComment);
\r
1548 GetActualPlacement(editTagsDialog, &wpTags);
\r
1549 GetActualPlacement(gameListDialog, &wpGameList);
\r
1550 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1551 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1552 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1556 PrintCommPortSettings(FILE *f, char *name)
\r
1557 { // wrapper to shield back-end from DCB
\r
1558 PrintCommSettings(f, name, &dcb);
\r
1562 MySearchPath(char *installDir, char *name, char *fullname)
\r
1564 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1565 if(name[0]== '%') {
\r
1566 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1567 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1568 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1569 *strchr(buf, '%') = 0;
\r
1570 strcat(fullname, getenv(buf));
\r
1571 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1573 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1574 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1575 return (int) strlen(fullname);
\r
1577 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1581 MyGetFullPathName(char *name, char *fullname)
\r
1584 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1589 { // [HGM] args: allows testing if main window is realized from back-end
\r
1590 return hwndMain != NULL;
\r
1594 PopUpStartupDialog()
\r
1598 LoadLanguageFile(appData.language);
\r
1599 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1600 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1601 FreeProcInstance(lpProc);
\r
1604 /*---------------------------------------------------------------------------*\
\r
1606 * GDI board drawing routines
\r
1608 \*---------------------------------------------------------------------------*/
\r
1610 /* [AS] Draw square using background texture */
\r
1611 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1616 return; /* Should never happen! */
\r
1619 SetGraphicsMode( dst, GM_ADVANCED );
\r
1626 /* X reflection */
\r
1631 x.eDx = (FLOAT) dw + dx - 1;
\r
1634 SetWorldTransform( dst, &x );
\r
1637 /* Y reflection */
\r
1643 x.eDy = (FLOAT) dh + dy - 1;
\r
1645 SetWorldTransform( dst, &x );
\r
1653 x.eDx = (FLOAT) dx;
\r
1654 x.eDy = (FLOAT) dy;
\r
1657 SetWorldTransform( dst, &x );
\r
1661 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1669 SetWorldTransform( dst, &x );
\r
1671 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1674 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1676 PM_WP = (int) WhitePawn,
\r
1677 PM_WN = (int) WhiteKnight,
\r
1678 PM_WB = (int) WhiteBishop,
\r
1679 PM_WR = (int) WhiteRook,
\r
1680 PM_WQ = (int) WhiteQueen,
\r
1681 PM_WF = (int) WhiteFerz,
\r
1682 PM_WW = (int) WhiteWazir,
\r
1683 PM_WE = (int) WhiteAlfil,
\r
1684 PM_WM = (int) WhiteMan,
\r
1685 PM_WO = (int) WhiteCannon,
\r
1686 PM_WU = (int) WhiteUnicorn,
\r
1687 PM_WH = (int) WhiteNightrider,
\r
1688 PM_WA = (int) WhiteAngel,
\r
1689 PM_WC = (int) WhiteMarshall,
\r
1690 PM_WAB = (int) WhiteCardinal,
\r
1691 PM_WD = (int) WhiteDragon,
\r
1692 PM_WL = (int) WhiteLance,
\r
1693 PM_WS = (int) WhiteCobra,
\r
1694 PM_WV = (int) WhiteFalcon,
\r
1695 PM_WSG = (int) WhiteSilver,
\r
1696 PM_WG = (int) WhiteGrasshopper,
\r
1697 PM_WK = (int) WhiteKing,
\r
1698 PM_BP = (int) BlackPawn,
\r
1699 PM_BN = (int) BlackKnight,
\r
1700 PM_BB = (int) BlackBishop,
\r
1701 PM_BR = (int) BlackRook,
\r
1702 PM_BQ = (int) BlackQueen,
\r
1703 PM_BF = (int) BlackFerz,
\r
1704 PM_BW = (int) BlackWazir,
\r
1705 PM_BE = (int) BlackAlfil,
\r
1706 PM_BM = (int) BlackMan,
\r
1707 PM_BO = (int) BlackCannon,
\r
1708 PM_BU = (int) BlackUnicorn,
\r
1709 PM_BH = (int) BlackNightrider,
\r
1710 PM_BA = (int) BlackAngel,
\r
1711 PM_BC = (int) BlackMarshall,
\r
1712 PM_BG = (int) BlackGrasshopper,
\r
1713 PM_BAB = (int) BlackCardinal,
\r
1714 PM_BD = (int) BlackDragon,
\r
1715 PM_BL = (int) BlackLance,
\r
1716 PM_BS = (int) BlackCobra,
\r
1717 PM_BV = (int) BlackFalcon,
\r
1718 PM_BSG = (int) BlackSilver,
\r
1719 PM_BK = (int) BlackKing
\r
1722 static HFONT hPieceFont = NULL;
\r
1723 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1724 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1725 static int fontBitmapSquareSize = 0;
\r
1726 static char pieceToFontChar[(int) EmptySquare] =
\r
1727 { 'p', 'n', 'b', 'r', 'q',
\r
1728 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1729 'k', 'o', 'm', 'v', 't', 'w',
\r
1730 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1733 extern BOOL SetCharTable( char *table, const char * map );
\r
1734 /* [HGM] moved to backend.c */
\r
1736 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1739 BYTE r1 = GetRValue( color );
\r
1740 BYTE g1 = GetGValue( color );
\r
1741 BYTE b1 = GetBValue( color );
\r
1747 /* Create a uniform background first */
\r
1748 hbrush = CreateSolidBrush( color );
\r
1749 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1750 FillRect( hdc, &rc, hbrush );
\r
1751 DeleteObject( hbrush );
\r
1754 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1755 int steps = squareSize / 2;
\r
1758 for( i=0; i<steps; i++ ) {
\r
1759 BYTE r = r1 - (r1-r2) * i / steps;
\r
1760 BYTE g = g1 - (g1-g2) * i / steps;
\r
1761 BYTE b = b1 - (b1-b2) * i / steps;
\r
1763 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1764 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1765 FillRect( hdc, &rc, hbrush );
\r
1766 DeleteObject(hbrush);
\r
1769 else if( mode == 2 ) {
\r
1770 /* Diagonal gradient, good more or less for every piece */
\r
1771 POINT triangle[3];
\r
1772 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1773 HBRUSH hbrush_old;
\r
1774 int steps = squareSize;
\r
1777 triangle[0].x = squareSize - steps;
\r
1778 triangle[0].y = squareSize;
\r
1779 triangle[1].x = squareSize;
\r
1780 triangle[1].y = squareSize;
\r
1781 triangle[2].x = squareSize;
\r
1782 triangle[2].y = squareSize - steps;
\r
1784 for( i=0; i<steps; i++ ) {
\r
1785 BYTE r = r1 - (r1-r2) * i / steps;
\r
1786 BYTE g = g1 - (g1-g2) * i / steps;
\r
1787 BYTE b = b1 - (b1-b2) * i / steps;
\r
1789 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1790 hbrush_old = SelectObject( hdc, hbrush );
\r
1791 Polygon( hdc, triangle, 3 );
\r
1792 SelectObject( hdc, hbrush_old );
\r
1793 DeleteObject(hbrush);
\r
1798 SelectObject( hdc, hpen );
\r
1803 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1804 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1805 piece: follow the steps as explained below.
\r
1807 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1811 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1815 int backColor = whitePieceColor;
\r
1816 int foreColor = blackPieceColor;
\r
1818 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1819 backColor = appData.fontBackColorWhite;
\r
1820 foreColor = appData.fontForeColorWhite;
\r
1822 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1823 backColor = appData.fontBackColorBlack;
\r
1824 foreColor = appData.fontForeColorBlack;
\r
1828 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1830 hbm_old = SelectObject( hdc, hbm );
\r
1834 rc.right = squareSize;
\r
1835 rc.bottom = squareSize;
\r
1837 /* Step 1: background is now black */
\r
1838 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1840 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1842 pt.x = (squareSize - sz.cx) / 2;
\r
1843 pt.y = (squareSize - sz.cy) / 2;
\r
1845 SetBkMode( hdc, TRANSPARENT );
\r
1846 SetTextColor( hdc, chroma );
\r
1847 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1848 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1850 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1851 /* Step 3: the area outside the piece is filled with white */
\r
1852 // FloodFill( hdc, 0, 0, chroma );
\r
1853 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1854 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1855 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1856 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1857 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1859 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1860 but if the start point is not inside the piece we're lost!
\r
1861 There should be a better way to do this... if we could create a region or path
\r
1862 from the fill operation we would be fine for example.
\r
1864 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1865 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1867 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1868 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1869 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1871 SelectObject( dc2, bm2 );
\r
1872 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1873 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1874 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1875 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1876 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1879 DeleteObject( bm2 );
\r
1882 SetTextColor( hdc, 0 );
\r
1884 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1885 draw the piece again in black for safety.
\r
1887 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1889 SelectObject( hdc, hbm_old );
\r
1891 if( hPieceMask[index] != NULL ) {
\r
1892 DeleteObject( hPieceMask[index] );
\r
1895 hPieceMask[index] = hbm;
\r
1898 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1900 SelectObject( hdc, hbm );
\r
1903 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1904 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1905 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1907 SelectObject( dc1, hPieceMask[index] );
\r
1908 SelectObject( dc2, bm2 );
\r
1909 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1910 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1913 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1914 the piece background and deletes (makes transparent) the rest.
\r
1915 Thanks to that mask, we are free to paint the background with the greates
\r
1916 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1917 We use this, to make gradients and give the pieces a "roundish" look.
\r
1919 SetPieceBackground( hdc, backColor, 2 );
\r
1920 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1924 DeleteObject( bm2 );
\r
1927 SetTextColor( hdc, foreColor );
\r
1928 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1930 SelectObject( hdc, hbm_old );
\r
1932 if( hPieceFace[index] != NULL ) {
\r
1933 DeleteObject( hPieceFace[index] );
\r
1936 hPieceFace[index] = hbm;
\r
1939 static int TranslatePieceToFontPiece( int piece )
\r
1969 case BlackMarshall:
\r
1973 case BlackNightrider:
\r
1979 case BlackUnicorn:
\r
1983 case BlackGrasshopper:
\r
1995 case BlackCardinal:
\r
2002 case WhiteMarshall:
\r
2006 case WhiteNightrider:
\r
2012 case WhiteUnicorn:
\r
2016 case WhiteGrasshopper:
\r
2028 case WhiteCardinal:
\r
2037 void CreatePiecesFromFont()
\r
2040 HDC hdc_window = NULL;
\r
2046 if( fontBitmapSquareSize < 0 ) {
\r
2047 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2051 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2052 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2053 fontBitmapSquareSize = -1;
\r
2057 if( fontBitmapSquareSize != squareSize ) {
\r
2058 hdc_window = GetDC( hwndMain );
\r
2059 hdc = CreateCompatibleDC( hdc_window );
\r
2061 if( hPieceFont != NULL ) {
\r
2062 DeleteObject( hPieceFont );
\r
2065 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2066 hPieceMask[i] = NULL;
\r
2067 hPieceFace[i] = NULL;
\r
2073 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2074 fontHeight = appData.fontPieceSize;
\r
2077 fontHeight = (fontHeight * squareSize) / 100;
\r
2079 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2081 lf.lfEscapement = 0;
\r
2082 lf.lfOrientation = 0;
\r
2083 lf.lfWeight = FW_NORMAL;
\r
2085 lf.lfUnderline = 0;
\r
2086 lf.lfStrikeOut = 0;
\r
2087 lf.lfCharSet = DEFAULT_CHARSET;
\r
2088 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2089 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2090 lf.lfQuality = PROOF_QUALITY;
\r
2091 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2092 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2093 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2095 hPieceFont = CreateFontIndirect( &lf );
\r
2097 if( hPieceFont == NULL ) {
\r
2098 fontBitmapSquareSize = -2;
\r
2101 /* Setup font-to-piece character table */
\r
2102 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2103 /* No (or wrong) global settings, try to detect the font */
\r
2104 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2106 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2108 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2109 /* DiagramTT* family */
\r
2110 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2112 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2113 /* Fairy symbols */
\r
2114 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2116 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2117 /* Good Companion (Some characters get warped as literal :-( */
\r
2118 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2119 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2120 SetCharTable(pieceToFontChar, s);
\r
2123 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2124 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2128 /* Create bitmaps */
\r
2129 hfont_old = SelectObject( hdc, hPieceFont );
\r
2130 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2131 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2132 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2134 SelectObject( hdc, hfont_old );
\r
2136 fontBitmapSquareSize = squareSize;
\r
2140 if( hdc != NULL ) {
\r
2144 if( hdc_window != NULL ) {
\r
2145 ReleaseDC( hwndMain, hdc_window );
\r
2150 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2152 char name[128], buf[MSG_SIZ];
\r
2154 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2155 if(appData.pieceDirectory[0]) {
\r
2157 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2158 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2159 if(res) return res;
\r
2161 if (gameInfo.event &&
\r
2162 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2163 strcmp(name, "k80s") == 0) {
\r
2164 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2166 return LoadBitmap(hinst, name);
\r
2170 /* Insert a color into the program's logical palette
\r
2171 structure. This code assumes the given color is
\r
2172 the result of the RGB or PALETTERGB macro, and it
\r
2173 knows how those macros work (which is documented).
\r
2176 InsertInPalette(COLORREF color)
\r
2178 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2180 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2181 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2182 pLogPal->palNumEntries--;
\r
2186 pe->peFlags = (char) 0;
\r
2187 pe->peRed = (char) (0xFF & color);
\r
2188 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2189 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2195 InitDrawingColors()
\r
2197 if (pLogPal == NULL) {
\r
2198 /* Allocate enough memory for a logical palette with
\r
2199 * PALETTESIZE entries and set the size and version fields
\r
2200 * of the logical palette structure.
\r
2202 pLogPal = (NPLOGPALETTE)
\r
2203 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2204 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2205 pLogPal->palVersion = 0x300;
\r
2207 pLogPal->palNumEntries = 0;
\r
2209 InsertInPalette(lightSquareColor);
\r
2210 InsertInPalette(darkSquareColor);
\r
2211 InsertInPalette(whitePieceColor);
\r
2212 InsertInPalette(blackPieceColor);
\r
2213 InsertInPalette(highlightSquareColor);
\r
2214 InsertInPalette(premoveHighlightColor);
\r
2216 /* create a logical color palette according the information
\r
2217 * in the LOGPALETTE structure.
\r
2219 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2221 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2222 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2223 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2224 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2225 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2226 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2227 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2228 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2229 /* [AS] Force rendering of the font-based pieces */
\r
2230 if( fontBitmapSquareSize > 0 ) {
\r
2231 fontBitmapSquareSize = 0;
\r
2237 BoardWidth(int boardSize, int n)
\r
2238 { /* [HGM] argument n added to allow different width and height */
\r
2239 int lineGap = sizeInfo[boardSize].lineGap;
\r
2241 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2242 lineGap = appData.overrideLineGap;
\r
2245 return (n + 1) * lineGap +
\r
2246 n * sizeInfo[boardSize].squareSize;
\r
2249 /* Respond to board resize by dragging edge */
\r
2251 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2253 BoardSize newSize = NUM_SIZES - 1;
\r
2254 static int recurse = 0;
\r
2255 if (IsIconic(hwndMain)) return;
\r
2256 if (recurse > 0) return;
\r
2258 while (newSize > 0) {
\r
2259 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2260 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2261 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2264 boardSize = newSize;
\r
2265 InitDrawingSizes(boardSize, flags);
\r
2270 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2273 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2275 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2276 ChessSquare piece;
\r
2277 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2279 SIZE clockSize, messageSize;
\r
2281 char buf[MSG_SIZ];
\r
2283 HMENU hmenu = GetMenu(hwndMain);
\r
2284 RECT crect, wrect, oldRect;
\r
2286 LOGBRUSH logbrush;
\r
2287 VariantClass v = gameInfo.variant;
\r
2289 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2290 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2292 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2293 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2294 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2295 oldBoardSize = boardSize;
\r
2297 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2298 { // correct board size to one where built-in pieces exist
\r
2299 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2300 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2301 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2302 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2303 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {
\r
2304 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2305 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2306 boardSize = SizeMiddling;
\r
2309 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2311 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2312 oldRect.top = wpMain.y;
\r
2313 oldRect.right = wpMain.x + wpMain.width;
\r
2314 oldRect.bottom = wpMain.y + wpMain.height;
\r
2316 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2317 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2318 squareSize = sizeInfo[boardSize].squareSize;
\r
2319 lineGap = sizeInfo[boardSize].lineGap;
\r
2320 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2321 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2323 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2324 lineGap = appData.overrideLineGap;
\r
2327 if (tinyLayout != oldTinyLayout) {
\r
2328 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2330 style &= ~WS_SYSMENU;
\r
2331 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2332 "&Minimize\tCtrl+F4");
\r
2334 style |= WS_SYSMENU;
\r
2335 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2337 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2339 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2340 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2341 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2343 DrawMenuBar(hwndMain);
\r
2346 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2347 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2349 /* Get text area sizes */
\r
2350 hdc = GetDC(hwndMain);
\r
2351 if (appData.clockMode) {
\r
2352 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2354 snprintf(buf, MSG_SIZ, _("White"));
\r
2356 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2357 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2358 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2359 str = _("We only care about the height here");
\r
2360 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2361 SelectObject(hdc, oldFont);
\r
2362 ReleaseDC(hwndMain, hdc);
\r
2364 /* Compute where everything goes */
\r
2365 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2366 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2367 logoHeight = 2*clockSize.cy;
\r
2368 leftLogoRect.left = OUTER_MARGIN;
\r
2369 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2370 leftLogoRect.top = OUTER_MARGIN;
\r
2371 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2373 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2374 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2375 rightLogoRect.top = OUTER_MARGIN;
\r
2376 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2379 whiteRect.left = leftLogoRect.right;
\r
2380 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2381 whiteRect.top = OUTER_MARGIN;
\r
2382 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2384 blackRect.right = rightLogoRect.left;
\r
2385 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2386 blackRect.top = whiteRect.top;
\r
2387 blackRect.bottom = whiteRect.bottom;
\r
2389 whiteRect.left = OUTER_MARGIN;
\r
2390 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2391 whiteRect.top = OUTER_MARGIN;
\r
2392 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2394 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2395 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2396 blackRect.top = whiteRect.top;
\r
2397 blackRect.bottom = whiteRect.bottom;
\r
2399 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2402 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2403 if (appData.showButtonBar) {
\r
2404 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2405 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2407 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2409 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2410 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2412 boardRect.left = OUTER_MARGIN;
\r
2413 boardRect.right = boardRect.left + boardWidth;
\r
2414 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2415 boardRect.bottom = boardRect.top + boardHeight;
\r
2417 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2418 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2419 oldTinyLayout = tinyLayout;
\r
2420 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2421 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2422 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2423 winW *= 1 + twoBoards;
\r
2424 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2425 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2426 wpMain.height = winH; // without disturbing window attachments
\r
2427 GetWindowRect(hwndMain, &wrect);
\r
2428 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2429 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2431 // [HGM] placement: let attached windows follow size change.
\r
2432 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2433 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2434 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2435 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2436 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2438 /* compensate if menu bar wrapped */
\r
2439 GetClientRect(hwndMain, &crect);
\r
2440 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2441 wpMain.height += offby;
\r
2443 case WMSZ_TOPLEFT:
\r
2444 SetWindowPos(hwndMain, NULL,
\r
2445 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2446 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2449 case WMSZ_TOPRIGHT:
\r
2451 SetWindowPos(hwndMain, NULL,
\r
2452 wrect.left, wrect.bottom - wpMain.height,
\r
2453 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2456 case WMSZ_BOTTOMLEFT:
\r
2458 SetWindowPos(hwndMain, NULL,
\r
2459 wrect.right - wpMain.width, wrect.top,
\r
2460 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2463 case WMSZ_BOTTOMRIGHT:
\r
2467 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2468 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2473 for (i = 0; i < N_BUTTONS; i++) {
\r
2474 if (buttonDesc[i].hwnd != NULL) {
\r
2475 DestroyWindow(buttonDesc[i].hwnd);
\r
2476 buttonDesc[i].hwnd = NULL;
\r
2478 if (appData.showButtonBar) {
\r
2479 buttonDesc[i].hwnd =
\r
2480 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2481 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2482 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2483 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2484 (HMENU) buttonDesc[i].id,
\r
2485 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2487 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2488 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2489 MAKELPARAM(FALSE, 0));
\r
2491 if (buttonDesc[i].id == IDM_Pause)
\r
2492 hwndPause = buttonDesc[i].hwnd;
\r
2493 buttonDesc[i].wndproc = (WNDPROC)
\r
2494 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2497 if (gridPen != NULL) DeleteObject(gridPen);
\r
2498 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2499 if (premovePen != NULL) DeleteObject(premovePen);
\r
2500 if (lineGap != 0) {
\r
2501 logbrush.lbStyle = BS_SOLID;
\r
2502 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2504 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2505 lineGap, &logbrush, 0, NULL);
\r
2506 logbrush.lbColor = highlightSquareColor;
\r
2508 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2509 lineGap, &logbrush, 0, NULL);
\r
2511 logbrush.lbColor = premoveHighlightColor;
\r
2513 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2514 lineGap, &logbrush, 0, NULL);
\r
2516 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2517 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2518 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2519 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2520 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2521 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2522 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2523 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2525 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2526 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2527 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2528 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2529 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2530 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2531 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2532 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2536 /* [HGM] Licensing requirement */
\r
2538 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2541 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2543 GothicPopUp( "", VariantNormal);
\r
2546 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2548 /* Load piece bitmaps for this board size */
\r
2549 for (i=0; i<=2; i++) {
\r
2550 for (piece = WhitePawn;
\r
2551 (int) piece < (int) BlackPawn;
\r
2552 piece = (ChessSquare) ((int) piece + 1)) {
\r
2553 if (pieceBitmap[i][piece] != NULL)
\r
2554 DeleteObject(pieceBitmap[i][piece]);
\r
2558 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2559 // Orthodox Chess pieces
\r
2560 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2561 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2562 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2563 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2564 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2565 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2566 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2567 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2568 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2569 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2570 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2571 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2572 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2573 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2574 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2575 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2576 // in Shogi, Hijack the unused Queen for Lance
\r
2577 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2578 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2579 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2581 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2582 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2583 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2586 if(squareSize <= 72 && squareSize >= 33) {
\r
2587 /* A & C are available in most sizes now */
\r
2588 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2589 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2590 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2591 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2592 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2593 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2594 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2595 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2596 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2597 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2598 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2599 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2600 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2601 } else { // Smirf-like
\r
2602 if(gameInfo.variant == VariantSChess) {
\r
2603 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2604 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2605 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2607 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2608 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2609 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2612 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2613 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2614 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2615 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2616 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2617 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2618 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2619 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2620 } else { // WinBoard standard
\r
2621 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2622 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2623 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2628 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2629 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2630 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2631 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2632 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2633 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2634 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2635 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2636 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2637 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2638 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2639 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2640 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2641 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2642 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2643 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2644 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2647 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2648 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2649 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2650 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2653 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2654 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2655 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2656 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2657 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2658 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2660 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2661 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2662 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2663 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2664 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2665 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2666 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2667 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2668 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2669 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2670 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2671 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2672 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2674 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2677 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2678 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2679 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2680 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2681 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2682 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2683 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2684 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2685 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2688 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2689 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2690 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2691 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2692 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2693 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2694 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2695 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2696 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2697 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2698 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2699 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2700 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2701 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2702 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2706 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2707 /* special Shogi support in this size */
\r
2708 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2709 for (piece = WhitePawn;
\r
2710 (int) piece < (int) BlackPawn;
\r
2711 piece = (ChessSquare) ((int) piece + 1)) {
\r
2712 if (pieceBitmap[i][piece] != NULL)
\r
2713 DeleteObject(pieceBitmap[i][piece]);
\r
2716 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2717 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2718 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2719 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2720 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2721 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2722 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2723 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2724 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2725 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2726 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2727 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2728 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2729 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2730 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2731 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2732 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2733 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2734 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2735 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2736 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2737 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2738 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2739 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2740 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2741 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2742 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2743 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2744 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2745 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2746 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2747 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2748 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2749 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2750 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2751 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2752 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2753 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2754 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2755 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2756 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2757 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2763 PieceBitmap(ChessSquare p, int kind)
\r
2765 if ((int) p >= (int) BlackPawn)
\r
2766 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2768 return pieceBitmap[kind][(int) p];
\r
2771 /***************************************************************/
\r
2773 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2774 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2776 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2777 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2781 SquareToPos(int row, int column, int * x, int * y)
\r
2784 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2785 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2787 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2788 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2793 DrawCoordsOnDC(HDC hdc)
\r
2795 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2796 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2797 char str[2] = { NULLCHAR, NULLCHAR };
\r
2798 int oldMode, oldAlign, x, y, start, i;
\r
2802 if (!appData.showCoords)
\r
2805 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2807 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2808 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2809 oldAlign = GetTextAlign(hdc);
\r
2810 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2812 y = boardRect.top + lineGap;
\r
2813 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2816 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2817 x += border - lineGap - 4; y += squareSize - 6;
\r
2819 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2820 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2821 str[0] = files[start + i];
\r
2822 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2823 y += squareSize + lineGap;
\r
2826 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2829 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2830 x += -border + 4; y += border - squareSize + 6;
\r
2832 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2833 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2834 str[0] = ranks[start + i];
\r
2835 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2836 x += squareSize + lineGap;
\r
2839 SelectObject(hdc, oldBrush);
\r
2840 SetBkMode(hdc, oldMode);
\r
2841 SetTextAlign(hdc, oldAlign);
\r
2842 SelectObject(hdc, oldFont);
\r
2846 DrawGridOnDC(HDC hdc)
\r
2850 if (lineGap != 0) {
\r
2851 oldPen = SelectObject(hdc, gridPen);
\r
2852 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2853 SelectObject(hdc, oldPen);
\r
2857 #define HIGHLIGHT_PEN 0
\r
2858 #define PREMOVE_PEN 1
\r
2861 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2864 HPEN oldPen, hPen;
\r
2865 if (lineGap == 0) return;
\r
2867 x1 = boardRect.left +
\r
2868 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2869 y1 = boardRect.top +
\r
2870 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2872 x1 = boardRect.left +
\r
2873 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2874 y1 = boardRect.top +
\r
2875 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2877 hPen = pen ? premovePen : highlightPen;
\r
2878 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2879 MoveToEx(hdc, x1, y1, NULL);
\r
2880 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2881 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2882 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2883 LineTo(hdc, x1, y1);
\r
2884 SelectObject(hdc, oldPen);
\r
2888 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2891 for (i=0; i<2; i++) {
\r
2892 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2893 DrawHighlightOnDC(hdc, TRUE,
\r
2894 h->sq[i].x, h->sq[i].y,
\r
2899 /* Note: sqcolor is used only in monoMode */
\r
2900 /* Note that this code is largely duplicated in woptions.c,
\r
2901 function DrawSampleSquare, so that needs to be updated too */
\r
2903 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2905 HBITMAP oldBitmap;
\r
2909 if (appData.blindfold) return;
\r
2911 /* [AS] Use font-based pieces if needed */
\r
2912 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2913 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2914 CreatePiecesFromFont();
\r
2916 if( fontBitmapSquareSize == squareSize ) {
\r
2917 int index = TranslatePieceToFontPiece(piece);
\r
2919 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2921 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2922 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2926 squareSize, squareSize,
\r
2931 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2933 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2934 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2938 squareSize, squareSize,
\r
2947 if (appData.monoMode) {
\r
2948 SelectObject(tmphdc, PieceBitmap(piece,
\r
2949 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2950 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2951 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2953 HBRUSH xBrush = whitePieceBrush;
\r
2954 tmpSize = squareSize;
\r
2955 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2957 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2958 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2959 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2960 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2961 x += (squareSize - minorSize)>>1;
\r
2962 y += squareSize - minorSize - 2;
\r
2963 tmpSize = minorSize;
\r
2965 if (color || appData.allWhite ) {
\r
2966 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2968 oldBrush = SelectObject(hdc, xBrush);
\r
2969 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2970 if(appData.upsideDown && color==flipView)
\r
2971 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2973 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2974 /* Use black for outline of white pieces */
\r
2975 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2976 if(appData.upsideDown && color==flipView)
\r
2977 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2979 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2980 } else if(appData.pieceDirectory[0]) {
\r
2981 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2982 oldBrush = SelectObject(hdc, xBrush);
\r
2983 if(appData.upsideDown && color==flipView)
\r
2984 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2986 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2987 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2988 if(appData.upsideDown && color==flipView)
\r
2989 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2991 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2993 /* Use square color for details of black pieces */
\r
2994 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2995 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2996 if(appData.upsideDown && !flipView)
\r
2997 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2999 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3001 SelectObject(hdc, oldBrush);
\r
3002 SelectObject(tmphdc, oldBitmap);
\r
3006 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3007 int GetBackTextureMode( int algo )
\r
3009 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3013 case BACK_TEXTURE_MODE_PLAIN:
\r
3014 result = 1; /* Always use identity map */
\r
3016 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3017 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3025 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3026 to handle redraws cleanly (as random numbers would always be different).
\r
3028 VOID RebuildTextureSquareInfo()
\r
3038 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3040 if( liteBackTexture != NULL ) {
\r
3041 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3042 lite_w = bi.bmWidth;
\r
3043 lite_h = bi.bmHeight;
\r
3047 if( darkBackTexture != NULL ) {
\r
3048 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3049 dark_w = bi.bmWidth;
\r
3050 dark_h = bi.bmHeight;
\r
3054 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3055 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3056 if( (col + row) & 1 ) {
\r
3058 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3059 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3060 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3062 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3063 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3064 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3066 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3067 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3072 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3073 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3074 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3076 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3077 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3078 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3080 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3081 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3088 /* [AS] Arrow highlighting support */
\r
3090 static double A_WIDTH = 5; /* Width of arrow body */
\r
3092 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3093 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3095 static double Sqr( double x )
\r
3100 static int Round( double x )
\r
3102 return (int) (x + 0.5);
\r
3105 /* Draw an arrow between two points using current settings */
\r
3106 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3109 double dx, dy, j, k, x, y;
\r
3111 if( d_x == s_x ) {
\r
3112 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3114 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3117 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3118 arrow[1].y = d_y - h;
\r
3120 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3121 arrow[2].y = d_y - h;
\r
3126 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3127 arrow[5].y = d_y - h;
\r
3129 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3130 arrow[4].y = d_y - h;
\r
3132 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3135 else if( d_y == s_y ) {
\r
3136 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3139 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3141 arrow[1].x = d_x - w;
\r
3142 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3144 arrow[2].x = d_x - w;
\r
3145 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3150 arrow[5].x = d_x - w;
\r
3151 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3153 arrow[4].x = d_x - w;
\r
3154 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3157 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3160 /* [AS] Needed a lot of paper for this! :-) */
\r
3161 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3162 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3164 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3166 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3171 arrow[0].x = Round(x - j);
\r
3172 arrow[0].y = Round(y + j*dx);
\r
3174 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3175 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3178 x = (double) d_x - k;
\r
3179 y = (double) d_y - k*dy;
\r
3182 x = (double) d_x + k;
\r
3183 y = (double) d_y + k*dy;
\r
3186 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r