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, 2014, 2015, 2016 Free
\r
9 * Software Foundation, Inc.
\r
11 * Enhancements Copyright 2005 Alessandro Scotti
\r
13 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
14 * which was written and is copyrighted by Wayne Christopher.
\r
16 * The following terms apply to Digital Equipment Corporation's copyright
\r
17 * interest in XBoard:
\r
18 * ------------------------------------------------------------------------
\r
19 * All Rights Reserved
\r
21 * Permission to use, copy, modify, and distribute this software and its
\r
22 * documentation for any purpose and without fee is hereby granted,
\r
23 * provided that the above copyright notice appear in all copies and that
\r
24 * both that copyright notice and this permission notice appear in
\r
25 * supporting documentation, and that the name of Digital not be
\r
26 * used in advertising or publicity pertaining to distribution of the
\r
27 * software without specific, written prior permission.
\r
29 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
30 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
31 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
32 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
33 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
34 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
36 * ------------------------------------------------------------------------
\r
38 * The following terms apply to the enhanced version of XBoard
\r
39 * distributed by the Free Software Foundation:
\r
40 * ------------------------------------------------------------------------
\r
42 * GNU XBoard is free software: you can redistribute it and/or modify
\r
43 * it under the terms of the GNU General Public License as published by
\r
44 * the Free Software Foundation, either version 3 of the License, or (at
\r
45 * your option) any later version.
\r
47 * GNU XBoard is distributed in the hope that it will be useful, but
\r
48 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
49 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
50 * General Public License for more details.
\r
52 * You should have received a copy of the GNU General Public License
\r
53 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
55 *------------------------------------------------------------------------
\r
56 ** See the file ChangeLog for a revision history. */
\r
60 #include <windows.h>
\r
61 #include <winuser.h>
\r
62 #include <winsock.h>
\r
63 #include <commctrl.h>
\r
69 #include <sys/stat.h>
\r
72 #include <commdlg.h>
\r
74 #include <richedit.h>
\r
75 #include <mmsystem.h>
\r
85 #include "frontend.h"
\r
86 #include "backend.h"
\r
87 #include "winboard.h"
\r
89 #include "wclipbrd.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
97 #define DATADIR "~~"
\r
99 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
101 int myrandom(void);
\r
102 void mysrandom(unsigned int seed);
\r
104 extern int whiteFlag, blackFlag;
\r
105 Boolean flipClock = FALSE;
\r
106 extern HANDLE chatHandle[];
\r
107 extern enum ICS_TYPE ics_type;
\r
109 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
110 int MyGetFullPathName P((char *name, char *fullname));
\r
111 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
112 VOID NewVariantPopup(HWND hwnd);
\r
113 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
114 /*char*/int promoChar));
\r
115 void DisplayMove P((int moveNumber));
\r
116 void ChatPopUp P((char *s));
\r
118 ChessSquare piece;
\r
119 POINT pos; /* window coordinates of current pos */
\r
120 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
121 POINT from; /* board coordinates of the piece's orig pos */
\r
122 POINT to; /* board coordinates of the piece's new pos */
\r
125 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
128 POINT start; /* window coordinates of start pos */
\r
129 POINT pos; /* window coordinates of current pos */
\r
130 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
131 POINT from; /* board coordinates of the piece's orig pos */
\r
135 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
138 POINT sq[2]; /* board coordinates of from, to squares */
\r
141 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
144 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
146 typedef struct { // [HGM] atomic
\r
147 int fromX, fromY, toX, toY, radius;
\r
150 static ExplodeInfo explodeInfo;
\r
152 /* Window class names */
\r
153 char szAppName[] = "WinBoard";
\r
154 char szConsoleName[] = "WBConsole";
\r
156 /* Title bar text */
\r
157 char szTitle[] = "WinBoard";
\r
158 char szConsoleTitle[] = "I C S Interaction";
\r
161 char *settingsFileName;
\r
162 Boolean saveSettingsOnExit;
\r
163 char installDir[MSG_SIZ];
\r
164 int errorExitStatus;
\r
166 BoardSize boardSize;
\r
167 Boolean chessProgram;
\r
168 //static int boardX, boardY;
\r
169 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
170 int squareSize, lineGap, minorSize;
\r
171 static int winW, winH;
\r
172 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
173 static int logoHeight = 0;
\r
174 static char messageText[MESSAGE_TEXT_MAX];
\r
175 static int clockTimerEvent = 0;
\r
176 static int loadGameTimerEvent = 0;
\r
177 static int analysisTimerEvent = 0;
\r
178 static DelayedEventCallback delayedTimerCallback;
\r
179 static int delayedTimerEvent = 0;
\r
180 static int buttonCount = 2;
\r
181 char *icsTextMenuString;
\r
183 char *firstChessProgramNames;
\r
184 char *secondChessProgramNames;
\r
186 #define PALETTESIZE 256
\r
188 HINSTANCE hInst; /* current instance */
\r
189 Boolean alwaysOnTop = FALSE;
\r
191 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
192 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
193 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
195 ColorClass currentColorClass;
\r
197 static HWND savedHwnd;
\r
198 HWND hCommPort = NULL; /* currently open comm port */
\r
199 static HWND hwndPause; /* pause button */
\r
200 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
201 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
202 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
203 explodeBrush, /* [HGM] atomic */
\r
204 markerBrush[8], /* [HGM] markers */
\r
205 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
206 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
207 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
208 static HPEN gridPen = NULL;
\r
209 static HPEN highlightPen = NULL;
\r
210 static HPEN premovePen = NULL;
\r
211 static NPLOGPALETTE pLogPal;
\r
212 static BOOL paletteChanged = FALSE;
\r
213 static HICON iconWhite, iconBlack, iconCurrent;
\r
214 static int doingSizing = FALSE;
\r
215 static int lastSizing = 0;
\r
216 static int prevStderrPort;
\r
217 static HBITMAP userLogo;
\r
219 static HBITMAP liteBackTexture = NULL;
\r
220 static HBITMAP darkBackTexture = NULL;
\r
221 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
223 static int backTextureSquareSize = 0;
\r
224 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
226 #if __GNUC__ && !defined(_winmajor)
\r
227 #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,
\r
265 OPT_Ranget, IDOK, IDCANCEL },
\r
266 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
267 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
268 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
269 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
270 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
271 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
272 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
273 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
274 { ABOUTBOX2, IDC_ChessBoard },
\r
275 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
276 OPT_GameListClose, IDC_GameListDoFilter },
\r
277 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
278 { DLG_Error, IDOK },
\r
279 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
280 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
281 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
282 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
283 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
284 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
285 { DLG_IndexNumber, IDC_Index },
\r
286 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
287 { DLG_TypeInName, IDOK, IDCANCEL },
\r
288 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
289 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
290 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
291 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
292 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
293 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
294 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
295 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
296 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
297 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
298 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
299 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
300 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
301 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
302 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
303 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
304 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
305 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
306 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
307 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
308 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
309 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
310 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
311 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
312 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
313 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
314 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
315 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
316 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
317 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
318 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
319 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
320 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
321 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
322 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
323 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
324 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
325 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
326 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
327 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
328 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
329 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
330 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
331 { DLG_MoveHistory },
\r
332 { DLG_EvalGraph },
\r
333 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
334 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
335 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
336 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
337 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
338 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
339 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
340 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
341 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
345 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
346 static int lastChecked;
\r
347 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
348 extern int tinyLayout;
\r
349 extern char * menuBarText[][10];
\r
352 LoadLanguageFile(char *name)
\r
353 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
355 int i=0, j=0, n=0, k;
\r
358 if(!name || name[0] == NULLCHAR) return;
\r
359 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
360 appData.language = oldLanguage;
\r
361 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
362 if((f = fopen(buf, "r")) == NULL) return;
\r
363 while((k = fgetc(f)) != EOF) {
\r
364 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
365 languageBuf[i] = k;
\r
367 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
369 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
370 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
371 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
372 english[j] = languageBuf + n + 1; *p = 0;
\r
373 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
374 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
379 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
381 case 'n': k = '\n'; break;
\r
382 case 'r': k = '\r'; break;
\r
383 case 't': k = '\t'; break;
\r
385 languageBuf[--i] = k;
\r
390 barbaric = (j != 0);
\r
391 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
396 { // return the translation of the given string
\r
397 // efficiency can be improved a lot...
\r
399 static char buf[MSG_SIZ];
\r
400 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
401 if(!barbaric) return s;
\r
402 if(!s) return ""; // sanity
\r
403 while(english[i]) {
\r
404 if(!strcmp(s, english[i])) return foreign[i];
\r
405 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
406 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
415 Translate(HWND hDlg, int dialogID)
\r
416 { // translate all text items in the given dialog
\r
418 char buf[MSG_SIZ], *s;
\r
419 if(!barbaric) return;
\r
420 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
421 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
422 GetWindowText( hDlg, buf, MSG_SIZ );
\r
424 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
425 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
426 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
427 if(strlen(buf) == 0) continue;
\r
429 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
434 TranslateOneMenu(int i, HMENU subMenu)
\r
437 static MENUITEMINFO info;
\r
439 info.cbSize = sizeof(MENUITEMINFO);
\r
440 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
441 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
443 info.dwTypeData = buf;
\r
444 info.cch = sizeof(buf);
\r
445 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
447 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
448 else menuText[i][j] = strdup(buf); // remember original on first change
\r
450 if(buf[0] == NULLCHAR) continue;
\r
451 info.dwTypeData = T_(buf);
\r
452 info.cch = strlen(buf)+1;
\r
453 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
459 TranslateMenus(int addLanguage)
\r
462 WIN32_FIND_DATA fileData;
\r
464 #define IDM_English 1970
\r
466 HMENU mainMenu = GetMenu(hwndMain);
\r
467 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
468 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
469 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
470 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
471 TranslateOneMenu(i, subMenu);
\r
473 DrawMenuBar(hwndMain);
\r
476 if(!addLanguage) return;
\r
477 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
478 HMENU mainMenu = GetMenu(hwndMain);
\r
479 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
480 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
481 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
482 i = 0; lastChecked = IDM_English;
\r
484 char *p, *q = fileData.cFileName;
\r
485 int checkFlag = MF_UNCHECKED;
\r
486 languageFile[i] = strdup(q);
\r
487 if(barbaric && !strcmp(oldLanguage, q)) {
\r
488 checkFlag = MF_CHECKED;
\r
489 lastChecked = IDM_English + i + 1;
\r
490 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
492 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
493 p = strstr(fileData.cFileName, ".lng");
\r
495 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
496 } while(FindNextFile(hFind, &fileData));
\r
503 #define IDM_RecentEngines 3000
\r
506 RecentEngineMenu (char *s)
\r
508 if(appData.icsActive) return;
\r
509 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
510 HMENU mainMenu = GetMenu(hwndMain);
\r
511 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
512 int i=IDM_RecentEngines;
\r
513 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
514 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
516 char *p = strchr(s, '\n');
\r
517 if(p == NULL) return; // malformed!
\r
519 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
533 int cliWidth, cliHeight;
\r
536 SizeInfo sizeInfo[] =
\r
538 { "tiny", 21, 0, 1, 2, 0, 0 },
\r
539 { "teeny", 25, 1, 1, 2, 0, 0 },
\r
540 { "dinky", 29, 1, 1, 2, 0, 0 },
\r
541 { "petite", 33, 1, 1, 2, 0, 0 },
\r
542 { "slim", 37, 2, 1, 1, 0, 0 },
\r
543 { "small", 40, 2, 1, 1, 0, 0 },
\r
544 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
545 { "middling", 49, 2, 0, 0, 0, 0 },
\r
546 { "average", 54, 2, 0, 0, 0, 0 },
\r
547 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
548 { "medium", 64, 3, 0, 0, 0, 0 },
\r
549 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
550 { "large", 80, 3, 0, 0, 0, 0 },
\r
551 { "big", 87, 3, 0, 0, 0, 0 },
\r
552 { "huge", 95, 3, 0, 0, 0, 0 },
\r
553 { "giant", 108, 3, 0, 0, 0, 0 },
\r
554 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
555 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
556 { NULL, 0, 0, 0, 0, 0, 0 }
\r
559 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
560 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
575 { 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
576 { 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
577 { 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
578 { 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
579 { 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
582 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
591 #define BUTTON_WIDTH (tinyLayout == 2 ? 16 : 32)
\r
592 #define N_BUTTONS 5
\r
594 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
596 {"<<", IDM_ToStart, NULL, NULL},
\r
597 {"<", IDM_Backward, NULL, NULL},
\r
598 {"P", IDM_Pause, NULL, NULL},
\r
599 {">", IDM_Forward, NULL, NULL},
\r
600 {">>", IDM_ToEnd, NULL, NULL},
\r
603 int tinyLayout = 0, smallLayout = 0;
\r
604 #define MENU_BAR_ITEMS 9
\r
605 char *menuBarText[3][MENU_BAR_ITEMS+1] = {
\r
606 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
607 { N_("&Fil"), N_("&Ed"), N_("&Vw"), N_("&Mod"), N_("&Act"), N_("E&ng"), N_("&Opt"), N_("&Hlp"), NULL },
\r
608 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
612 MySound sounds[(int)NSoundClasses];
\r
613 MyTextAttribs textAttribs[(int)NColorClasses];
\r
615 MyColorizeAttribs colorizeAttribs[] = {
\r
616 { (COLORREF)0, 0, N_("Shout Text") },
\r
617 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
618 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
619 { (COLORREF)0, 0, N_("Channel Text") },
\r
620 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
621 { (COLORREF)0, 0, N_("Tell Text") },
\r
622 { (COLORREF)0, 0, N_("Challenge Text") },
\r
623 { (COLORREF)0, 0, N_("Request Text") },
\r
624 { (COLORREF)0, 0, N_("Seek Text") },
\r
625 { (COLORREF)0, 0, N_("Normal Text") },
\r
626 { (COLORREF)0, 0, N_("None") }
\r
631 static char *commentTitle;
\r
632 static char *commentText;
\r
633 static int commentIndex;
\r
634 static Boolean editComment = FALSE;
\r
637 char errorTitle[MSG_SIZ];
\r
638 char errorMessage[2*MSG_SIZ];
\r
639 HWND errorDialog = NULL;
\r
640 BOOLEAN moveErrorMessageUp = FALSE;
\r
641 BOOLEAN consoleEcho = TRUE;
\r
642 CHARFORMAT consoleCF;
\r
643 COLORREF consoleBackgroundColor;
\r
645 char *programVersion;
\r
651 typedef int CPKind;
\r
660 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
663 #define INPUT_SOURCE_BUF_SIZE 4096
\r
665 typedef struct _InputSource {
\r
672 char buf[INPUT_SOURCE_BUF_SIZE];
\r
676 InputCallback func;
\r
677 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
681 InputSource *consoleInputSource;
\r
686 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
687 VOID ConsoleCreate();
\r
689 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
690 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
691 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
692 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
694 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
695 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
696 void ParseIcsTextMenu(char *icsTextMenuString);
\r
697 VOID PopUpNameDialog(char firstchar);
\r
698 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
702 int GameListOptions();
\r
704 int dummy; // [HGM] for obsolete args
\r
706 HWND hwndMain = NULL; /* root window*/
\r
707 HWND hwndConsole = NULL;
\r
708 HWND commentDialog = NULL;
\r
709 HWND moveHistoryDialog = NULL;
\r
710 HWND evalGraphDialog = NULL;
\r
711 HWND engineOutputDialog = NULL;
\r
712 HWND gameListDialog = NULL;
\r
713 HWND editTagsDialog = NULL;
\r
715 int commentUp = FALSE;
\r
717 WindowPlacement wpMain;
\r
718 WindowPlacement wpConsole;
\r
719 WindowPlacement wpComment;
\r
720 WindowPlacement wpMoveHistory;
\r
721 WindowPlacement wpEvalGraph;
\r
722 WindowPlacement wpEngineOutput;
\r
723 WindowPlacement wpGameList;
\r
724 WindowPlacement wpTags;
\r
726 VOID EngineOptionsPopup(); // [HGM] settings
\r
728 VOID GothicPopUp(char *title, VariantClass variant);
\r
730 * Setting "frozen" should disable all user input other than deleting
\r
731 * the window. We do this while engines are initializing themselves.
\r
733 static int frozen = 0;
\r
734 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
740 if (frozen) return;
\r
742 hmenu = GetMenu(hwndMain);
\r
743 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
744 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
746 DrawMenuBar(hwndMain);
\r
749 /* Undo a FreezeUI */
\r
755 if (!frozen) return;
\r
757 hmenu = GetMenu(hwndMain);
\r
758 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
759 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
761 DrawMenuBar(hwndMain);
\r
764 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
766 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
772 #define JAWS_ALT_INTERCEPT
\r
773 #define JAWS_KBUP_NAVIGATION
\r
774 #define JAWS_KBDOWN_NAVIGATION
\r
775 #define JAWS_MENU_ITEMS
\r
776 #define JAWS_SILENCE
\r
777 #define JAWS_REPLAY
\r
779 #define JAWS_COPYRIGHT
\r
780 #define JAWS_DELETE(X) X
\r
781 #define SAYMACHINEMOVE()
\r
785 /*---------------------------------------------------------------------------*\
\r
789 \*---------------------------------------------------------------------------*/
\r
791 static void HandleMessage P((MSG *message));
\r
792 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
795 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
796 LPSTR lpCmdLine, int nCmdShow)
\r
799 // INITCOMMONCONTROLSEX ex;
\r
803 LoadLibrary("RICHED32.DLL");
\r
804 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
806 if (!InitApplication(hInstance)) {
\r
809 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
816 // InitCommonControlsEx(&ex);
\r
817 InitCommonControls();
\r
819 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
820 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
821 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
823 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
825 while (GetMessage(&msg, /* message structure */
\r
826 NULL, /* handle of window receiving the message */
\r
827 0, /* lowest message to examine */
\r
828 0)) /* highest message to examine */
\r
830 HandleMessage(&msg);
\r
834 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
838 HandleMessage (MSG *message)
\r
840 MSG msg = *message;
\r
842 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
843 // [HGM] navigate: switch between all windows with tab
\r
844 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
845 int i, currentElement = 0;
\r
847 // first determine what element of the chain we come from (if any)
\r
848 if(appData.icsActive) {
\r
849 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
850 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
852 if(engineOutputDialog && EngineOutputIsUp()) {
\r
853 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
854 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
856 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
857 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
859 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
860 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
861 if(msg.hwnd == e1) currentElement = 2; else
\r
862 if(msg.hwnd == e2) currentElement = 3; else
\r
863 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
864 if(msg.hwnd == mh) currentElement = 4; else
\r
865 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
866 if(msg.hwnd == hText) currentElement = 5; else
\r
867 if(msg.hwnd == hInput) currentElement = 6; else
\r
868 for (i = 0; i < N_BUTTONS; i++) {
\r
869 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
872 // determine where to go to
\r
873 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
875 currentElement = (currentElement + direction) % 7;
\r
876 switch(currentElement) {
\r
878 h = hwndMain; break; // passing this case always makes the loop exit
\r
880 h = buttonDesc[0].hwnd; break; // could be NULL
\r
882 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
885 if(!EngineOutputIsUp()) continue;
\r
888 if(!MoveHistoryIsUp()) continue;
\r
890 // case 6: // input to eval graph does not seem to get here!
\r
891 // if(!EvalGraphIsUp()) continue;
\r
892 // h = evalGraphDialog; break;
\r
894 if(!appData.icsActive) continue;
\r
898 if(!appData.icsActive) continue;
\r
904 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
905 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
908 return; // this message now has been processed
\r
912 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
913 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
914 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
915 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
916 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
917 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
918 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
919 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
920 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
921 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
922 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
923 for(i=0; i<MAX_CHAT; i++)
\r
924 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
927 if(done) return; // [HGM] chat: end patch
\r
928 TranslateMessage(&msg); /* Translates virtual key codes */
\r
929 DispatchMessage(&msg); /* Dispatches message to window */
\r
935 { /* Dispatch pending messages */
\r
937 while (PeekMessage(&msg, /* message structure */
\r
938 NULL, /* handle of window receiving the message */
\r
939 0, /* lowest message to examine */
\r
940 0, /* highest message to examine */
\r
943 HandleMessage(&msg);
\r
947 /*---------------------------------------------------------------------------*\
\r
949 * Initialization functions
\r
951 \*---------------------------------------------------------------------------*/
\r
955 { // update user logo if necessary
\r
956 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
958 if(appData.autoLogo) {
\r
959 curName = UserName();
\r
960 if(strcmp(curName, oldUserName)) {
\r
961 GetCurrentDirectory(MSG_SIZ, dir);
\r
962 SetCurrentDirectory(installDir);
\r
963 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
964 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
965 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
966 if(userLogo == NULL)
\r
967 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
968 SetCurrentDirectory(dir); /* return to prev directory */
\r
974 InitApplication(HINSTANCE hInstance)
\r
978 /* Fill in window class structure with parameters that describe the */
\r
981 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
982 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
983 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
984 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
985 wc.hInstance = hInstance; /* Owner of this class */
\r
986 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
987 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
988 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
989 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
990 wc.lpszClassName = szAppName; /* Name to register as */
\r
992 /* Register the window class and return success/failure code. */
\r
993 if (!RegisterClass(&wc)) return FALSE;
\r
995 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
996 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
998 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
999 wc.hInstance = hInstance;
\r
1000 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
1001 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1002 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1003 wc.lpszMenuName = NULL;
\r
1004 wc.lpszClassName = szConsoleName;
\r
1006 if (!RegisterClass(&wc)) return FALSE;
\r
1011 /* Set by InitInstance, used by EnsureOnScreen */
\r
1012 int screenHeight, screenWidth;
\r
1013 RECT screenGeometry;
\r
1016 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1018 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1019 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1020 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1021 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1022 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1023 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1027 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1029 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1030 GetCurrentDirectory(MSG_SIZ, dir);
\r
1031 SetCurrentDirectory(installDir);
\r
1032 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1033 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1035 if (cps->programLogo == NULL && appData.debugMode) {
\r
1036 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1038 } else if(appData.autoLogo) {
\r
1039 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1040 char *opponent = "";
\r
1041 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1042 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1043 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1044 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1045 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1046 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1049 if(appData.directory[n] && appData.directory[n][0]) {
\r
1050 SetCurrentDirectory(appData.directory[n]);
\r
1051 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1054 SetCurrentDirectory(dir); /* return to prev directory */
\r
1060 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1061 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1063 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1064 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1065 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1066 liteBackTextureMode = appData.liteBackTextureMode;
\r
1068 if (liteBackTexture == NULL && appData.debugMode) {
\r
1069 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1073 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1074 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1075 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1076 darkBackTextureMode = appData.darkBackTextureMode;
\r
1078 if (darkBackTexture == NULL && appData.debugMode) {
\r
1079 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1084 #ifndef SM_CXVIRTUALSCREEN
\r
1085 #define SM_CXVIRTUALSCREEN 78
\r
1087 #ifndef SM_CYVIRTUALSCREEN
\r
1088 #define SM_CYVIRTUALSCREEN 79
\r
1090 #ifndef SM_XVIRTUALSCREEN
\r
1091 #define SM_XVIRTUALSCREEN 76
\r
1093 #ifndef SM_YVIRTUALSCREEN
\r
1094 #define SM_YVIRTUALSCREEN 77
\r
1100 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1101 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1102 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1103 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1104 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1105 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1106 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1107 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1110 ChessProgramState broadcast;
\r
1113 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1115 HWND hwnd; /* Main window handle. */
\r
1117 WINDOWPLACEMENT wp;
\r
1120 hInst = hInstance; /* Store instance handle in our global variable */
\r
1121 programName = szAppName;
\r
1123 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1124 *filepart = NULLCHAR;
\r
1125 SetCurrentDirectory(installDir);
\r
1127 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1129 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1131 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1132 /* xboard, and older WinBoards, controlled the move sound with the
\r
1133 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1134 always turn the option on (so that the backend will call us),
\r
1135 then let the user turn the sound off by setting it to silence if
\r
1136 desired. To accommodate old winboard.ini files saved by old
\r
1137 versions of WinBoard, we also turn off the sound if the option
\r
1138 was initially set to false. [HGM] taken out of InitAppData */
\r
1139 if (!appData.ringBellAfterMoves) {
\r
1140 sounds[(int)SoundMove].name = strdup("");
\r
1141 appData.ringBellAfterMoves = TRUE;
\r
1143 if (appData.debugMode) {
\r
1144 char *c = appData.nameOfDebugFile;
\r
1145 if(strstr(c, "///") == c) {
\r
1146 broadcast.which = "broadcaster";
\r
1147 broadcast.pr = NoProc;
\r
1148 broadcast.isr = NULL;
\r
1149 broadcast.program = c + 3;
\r
1150 broadcast.dir = ".";
\r
1151 broadcast.host = "localhost";
\r
1152 StartChessProgram(&broadcast);
\r
1153 debugFP = (FILE*) _fdopen(_open_osfhandle((long)(((ChildProc*)(broadcast.pr))->hTo), _O_WRONLY), "w");
\r
1155 debugFP = fopen(c, "w");
\r
1156 setbuf(debugFP, NULL);
\r
1159 LoadLanguageFile(appData.language);
\r
1163 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1164 // InitEngineUCI( installDir, &second );
\r
1166 /* Create a main window for this application instance. */
\r
1167 hwnd = CreateWindow(szAppName, szTitle,
\r
1168 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1169 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1170 NULL, NULL, hInstance, NULL);
\r
1173 /* If window could not be created, return "failure" */
\r
1178 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1179 LoadLogo(&first, 0, FALSE);
\r
1180 LoadLogo(&second, 1, appData.icsActive);
\r
1184 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1185 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1186 iconCurrent = iconWhite;
\r
1187 InitDrawingColors();
\r
1189 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1190 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1191 /* Compute window size for each board size, and use the largest
\r
1192 size that fits on this screen as the default. */
\r
1193 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1194 if (boardSize == (BoardSize)-1 &&
\r
1195 winH <= screenHeight
\r
1196 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1197 && winW <= screenWidth) {
\r
1198 boardSize = (BoardSize)ibs;
\r
1202 InitDrawingSizes(boardSize, 0);
\r
1203 RecentEngineMenu(appData.recentEngineList);
\r
1205 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1207 /* [AS] Load textures if specified */
\r
1210 mysrandom( (unsigned) time(NULL) );
\r
1212 /* [AS] Restore layout */
\r
1213 if( wpMoveHistory.visible ) {
\r
1214 MoveHistoryPopUp();
\r
1217 if( wpEvalGraph.visible ) {
\r
1221 if( wpEngineOutput.visible ) {
\r
1222 EngineOutputPopUp();
\r
1225 /* Make the window visible; update its client area; and return "success" */
\r
1226 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1227 wp.length = sizeof(WINDOWPLACEMENT);
\r
1229 wp.showCmd = nCmdShow;
\r
1230 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1231 wp.rcNormalPosition.left = wpMain.x;
\r
1232 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1233 wp.rcNormalPosition.top = wpMain.y;
\r
1234 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1235 SetWindowPlacement(hwndMain, &wp);
\r
1237 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1239 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1240 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1242 if (hwndConsole) {
\r
1244 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1245 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1247 ShowWindow(hwndConsole, nCmdShow);
\r
1248 SetActiveWindow(hwndConsole);
\r
1250 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1251 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1260 HMENU hmenu = GetMenu(hwndMain);
\r
1262 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1263 MF_BYCOMMAND|((appData.icsActive &&
\r
1264 *appData.icsCommPort != NULLCHAR) ?
\r
1265 MF_ENABLED : MF_GRAYED));
\r
1266 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1267 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1268 MF_CHECKED : MF_UNCHECKED));
\r
1269 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1272 //---------------------------------------------------------------------------------------------------------
\r
1274 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1275 #define XBOARD FALSE
\r
1277 #define OPTCHAR "/"
\r
1278 #define SEPCHAR "="
\r
1279 #define TOPLEVEL 0
\r
1283 // front-end part of option handling
\r
1286 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1288 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1289 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1292 lf->lfEscapement = 0;
\r
1293 lf->lfOrientation = 0;
\r
1294 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1295 lf->lfItalic = mfp->italic;
\r
1296 lf->lfUnderline = mfp->underline;
\r
1297 lf->lfStrikeOut = mfp->strikeout;
\r
1298 lf->lfCharSet = mfp->charset;
\r
1299 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1303 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1304 lf->lfQuality = DEFAULT_QUALITY;
\r
1305 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1306 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1310 CreateFontInMF(MyFont *mf)
\r
1312 LFfromMFP(&mf->lf, &mf->mfp);
\r
1313 if (mf->hf) DeleteObject(mf->hf);
\r
1314 mf->hf = CreateFontIndirect(&mf->lf);
\r
1317 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1319 colorVariable[] = {
\r
1320 &whitePieceColor,
\r
1321 &blackPieceColor,
\r
1322 &lightSquareColor,
\r
1323 &darkSquareColor,
\r
1324 &highlightSquareColor,
\r
1325 &premoveHighlightColor,
\r
1327 &consoleBackgroundColor,
\r
1328 &appData.fontForeColorWhite,
\r
1329 &appData.fontBackColorWhite,
\r
1330 &appData.fontForeColorBlack,
\r
1331 &appData.fontBackColorBlack,
\r
1332 &appData.evalHistColorWhite,
\r
1333 &appData.evalHistColorBlack,
\r
1334 &appData.highlightArrowColor,
\r
1337 /* Command line font name parser. NULL name means do nothing.
\r
1338 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1339 For backward compatibility, syntax without the colon is also
\r
1340 accepted, but font names with digits in them won't work in that case.
\r
1343 ParseFontName(char *name, MyFontParams *mfp)
\r
1346 if (name == NULL) return;
\r
1348 q = strchr(p, ':');
\r
1350 if (q - p >= sizeof(mfp->faceName))
\r
1351 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1352 memcpy(mfp->faceName, p, q - p);
\r
1353 mfp->faceName[q - p] = NULLCHAR;
\r
1356 q = mfp->faceName;
\r
1358 while (*p && !isdigit(*p)) {
\r
1360 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1361 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1363 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1366 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1367 mfp->pointSize = (float) atof(p);
\r
1368 mfp->bold = (strchr(p, 'b') != NULL);
\r
1369 mfp->italic = (strchr(p, 'i') != NULL);
\r
1370 mfp->underline = (strchr(p, 'u') != NULL);
\r
1371 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1372 mfp->charset = DEFAULT_CHARSET;
\r
1373 q = strchr(p, 'c');
\r
1375 mfp->charset = (BYTE) atoi(q+1);
\r
1379 ParseFont(char *name, int number)
\r
1380 { // wrapper to shield back-end from 'font'
\r
1381 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1386 { // in WB we have a 2D array of fonts; this initializes their description
\r
1388 /* Point font array elements to structures and
\r
1389 parse default font names */
\r
1390 for (i=0; i<NUM_FONTS; i++) {
\r
1391 for (j=0; j<NUM_SIZES; j++) {
\r
1392 font[j][i] = &fontRec[j][i];
\r
1393 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1400 { // here we create the actual fonts from the selected descriptions
\r
1402 for (i=0; i<NUM_FONTS; i++) {
\r
1403 for (j=0; j<NUM_SIZES; j++) {
\r
1404 CreateFontInMF(font[j][i]);
\r
1408 /* Color name parser.
\r
1409 X version accepts X color names, but this one
\r
1410 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1412 ParseColorName(char *name)
\r
1414 int red, green, blue, count;
\r
1415 char buf[MSG_SIZ];
\r
1417 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1419 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1420 &red, &green, &blue);
\r
1423 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1424 DisplayError(buf, 0);
\r
1425 return RGB(0, 0, 0);
\r
1427 return PALETTERGB(red, green, blue);
\r
1431 ParseColor(int n, char *name)
\r
1432 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1433 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1437 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1439 char *e = argValue;
\r
1443 if (*e == 'b') eff |= CFE_BOLD;
\r
1444 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1445 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1446 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1447 else if (*e == '#' || isdigit(*e)) break;
\r
1451 *color = ParseColorName(e);
\r
1455 ParseTextAttribs(ColorClass cc, char *s)
\r
1456 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1457 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1458 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1462 ParseBoardSize(void *addr, char *name)
\r
1463 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1464 BoardSize bs = SizeTiny;
\r
1465 while (sizeInfo[bs].name != NULL) {
\r
1466 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1467 *(BoardSize *)addr = bs;
\r
1472 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1477 { // [HGM] import name from appData first
\r
1480 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1481 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1482 textAttribs[cc].sound.data = NULL;
\r
1483 MyLoadSound(&textAttribs[cc].sound);
\r
1485 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1486 textAttribs[cc].sound.name = strdup("");
\r
1487 textAttribs[cc].sound.data = NULL;
\r
1489 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1490 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1491 sounds[sc].data = NULL;
\r
1492 MyLoadSound(&sounds[sc]);
\r
1497 SetCommPortDefaults()
\r
1499 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1500 dcb.DCBlength = sizeof(DCB);
\r
1501 dcb.BaudRate = 9600;
\r
1502 dcb.fBinary = TRUE;
\r
1503 dcb.fParity = FALSE;
\r
1504 dcb.fOutxCtsFlow = FALSE;
\r
1505 dcb.fOutxDsrFlow = FALSE;
\r
1506 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1507 dcb.fDsrSensitivity = FALSE;
\r
1508 dcb.fTXContinueOnXoff = TRUE;
\r
1509 dcb.fOutX = FALSE;
\r
1511 dcb.fNull = FALSE;
\r
1512 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1513 dcb.fAbortOnError = FALSE;
\r
1515 dcb.Parity = SPACEPARITY;
\r
1516 dcb.StopBits = ONESTOPBIT;
\r
1519 // [HGM] args: these three cases taken out to stay in front-end
\r
1521 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1522 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1523 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1524 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1526 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1527 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1528 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1529 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1530 ad->argName, mfp->faceName, mfp->pointSize,
\r
1531 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1532 mfp->bold ? "b" : "",
\r
1533 mfp->italic ? "i" : "",
\r
1534 mfp->underline ? "u" : "",
\r
1535 mfp->strikeout ? "s" : "",
\r
1536 (int)mfp->charset);
\r
1542 { // [HGM] copy the names from the internal WB variables to appData
\r
1545 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1546 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1547 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1548 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1552 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1553 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1554 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1555 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1556 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1557 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1558 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1559 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1560 (ta->effects) ? " " : "",
\r
1561 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1565 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1566 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1567 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1568 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1569 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1573 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1574 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1575 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1579 ParseCommPortSettings(char *s)
\r
1580 { // wrapper to keep dcb from back-end
\r
1581 ParseCommSettings(s, &dcb);
\r
1586 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1587 GetActualPlacement(hwndMain, &wpMain);
\r
1588 GetActualPlacement(hwndConsole, &wpConsole);
\r
1589 GetActualPlacement(commentDialog, &wpComment);
\r
1590 GetActualPlacement(editTagsDialog, &wpTags);
\r
1591 GetActualPlacement(gameListDialog, &wpGameList);
\r
1592 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1593 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1594 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1598 PrintCommPortSettings(FILE *f, char *name)
\r
1599 { // wrapper to shield back-end from DCB
\r
1600 PrintCommSettings(f, name, &dcb);
\r
1604 MySearchPath(char *installDir, char *name, char *fullname)
\r
1606 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1607 if(name[0]== '%') {
\r
1608 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1609 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1610 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1611 *strchr(buf, '%') = 0;
\r
1612 strcat(fullname, getenv(buf));
\r
1613 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1615 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1616 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1617 return (int) strlen(fullname);
\r
1619 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1623 MyGetFullPathName(char *name, char *fullname)
\r
1626 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1631 { // [HGM] args: allows testing if main window is realized from back-end
\r
1632 return hwndMain != NULL;
\r
1636 PopUpStartupDialog()
\r
1640 LoadLanguageFile(appData.language);
\r
1641 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1642 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1643 FreeProcInstance(lpProc);
\r
1646 /*---------------------------------------------------------------------------*\
\r
1648 * GDI board drawing routines
\r
1650 \*---------------------------------------------------------------------------*/
\r
1652 /* [AS] Draw square using background texture */
\r
1653 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1658 return; /* Should never happen! */
\r
1661 SetGraphicsMode( dst, GM_ADVANCED );
\r
1668 /* X reflection */
\r
1673 x.eDx = (FLOAT) dw + dx - 1;
\r
1676 SetWorldTransform( dst, &x );
\r
1679 /* Y reflection */
\r
1685 x.eDy = (FLOAT) dh + dy - 1;
\r
1687 SetWorldTransform( dst, &x );
\r
1695 x.eDx = (FLOAT) dx;
\r
1696 x.eDy = (FLOAT) dy;
\r
1699 SetWorldTransform( dst, &x );
\r
1703 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1711 SetWorldTransform( dst, &x );
\r
1713 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1716 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1718 PM_WP = (int) WhitePawn,
\r
1719 PM_WN = (int) WhiteKnight,
\r
1720 PM_WB = (int) WhiteBishop,
\r
1721 PM_WR = (int) WhiteRook,
\r
1722 PM_WQ = (int) WhiteQueen,
\r
1723 PM_WF = (int) WhiteFerz,
\r
1724 PM_WW = (int) WhiteWazir,
\r
1725 PM_WE = (int) WhiteAlfil,
\r
1726 PM_WM = (int) WhiteMan,
\r
1727 PM_WO = (int) WhiteCannon,
\r
1728 PM_WU = (int) WhiteUnicorn,
\r
1729 PM_WH = (int) WhiteNightrider,
\r
1730 PM_WA = (int) WhiteAngel,
\r
1731 PM_WC = (int) WhiteMarshall,
\r
1732 PM_WAB = (int) WhiteCardinal,
\r
1733 PM_WD = (int) WhiteDragon,
\r
1734 PM_WL = (int) WhiteLance,
\r
1735 PM_WS = (int) WhiteCobra,
\r
1736 PM_WV = (int) WhiteFalcon,
\r
1737 PM_WSG = (int) WhiteSilver,
\r
1738 PM_WG = (int) WhiteGrasshopper,
\r
1739 PM_WK = (int) WhiteKing,
\r
1740 PM_BP = (int) BlackPawn,
\r
1741 PM_BN = (int) BlackKnight,
\r
1742 PM_BB = (int) BlackBishop,
\r
1743 PM_BR = (int) BlackRook,
\r
1744 PM_BQ = (int) BlackQueen,
\r
1745 PM_BF = (int) BlackFerz,
\r
1746 PM_BW = (int) BlackWazir,
\r
1747 PM_BE = (int) BlackAlfil,
\r
1748 PM_BM = (int) BlackMan,
\r
1749 PM_BO = (int) BlackCannon,
\r
1750 PM_BU = (int) BlackUnicorn,
\r
1751 PM_BH = (int) BlackNightrider,
\r
1752 PM_BA = (int) BlackAngel,
\r
1753 PM_BC = (int) BlackMarshall,
\r
1754 PM_BG = (int) BlackGrasshopper,
\r
1755 PM_BAB = (int) BlackCardinal,
\r
1756 PM_BD = (int) BlackDragon,
\r
1757 PM_BL = (int) BlackLance,
\r
1758 PM_BS = (int) BlackCobra,
\r
1759 PM_BV = (int) BlackFalcon,
\r
1760 PM_BSG = (int) BlackSilver,
\r
1761 PM_BK = (int) BlackKing
\r
1764 static HFONT hPieceFont = NULL;
\r
1765 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1766 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1767 static int fontBitmapSquareSize = 0;
\r
1768 static char pieceToFontChar[(int) EmptySquare] =
\r
1769 { 'p', 'n', 'b', 'r', 'q',
\r
1770 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1771 'k', 'o', 'm', 'v', 't', 'w',
\r
1772 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1775 extern BOOL SetCharTable( char *table, const char * map );
\r
1776 /* [HGM] moved to backend.c */
\r
1778 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1781 BYTE r1 = GetRValue( color );
\r
1782 BYTE g1 = GetGValue( color );
\r
1783 BYTE b1 = GetBValue( color );
\r
1789 /* Create a uniform background first */
\r
1790 hbrush = CreateSolidBrush( color );
\r
1791 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1792 FillRect( hdc, &rc, hbrush );
\r
1793 DeleteObject( hbrush );
\r
1796 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1797 int steps = squareSize / 2;
\r
1800 for( i=0; i<steps; i++ ) {
\r
1801 BYTE r = r1 - (r1-r2) * i / steps;
\r
1802 BYTE g = g1 - (g1-g2) * i / steps;
\r
1803 BYTE b = b1 - (b1-b2) * i / steps;
\r
1805 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1806 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1807 FillRect( hdc, &rc, hbrush );
\r
1808 DeleteObject(hbrush);
\r
1811 else if( mode == 2 ) {
\r
1812 /* Diagonal gradient, good more or less for every piece */
\r
1813 POINT triangle[3];
\r
1814 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1815 HBRUSH hbrush_old;
\r
1816 int steps = squareSize;
\r
1819 triangle[0].x = squareSize - steps;
\r
1820 triangle[0].y = squareSize;
\r
1821 triangle[1].x = squareSize;
\r
1822 triangle[1].y = squareSize;
\r
1823 triangle[2].x = squareSize;
\r
1824 triangle[2].y = squareSize - steps;
\r
1826 for( i=0; i<steps; i++ ) {
\r
1827 BYTE r = r1 - (r1-r2) * i / steps;
\r
1828 BYTE g = g1 - (g1-g2) * i / steps;
\r
1829 BYTE b = b1 - (b1-b2) * i / steps;
\r
1831 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1832 hbrush_old = SelectObject( hdc, hbrush );
\r
1833 Polygon( hdc, triangle, 3 );
\r
1834 SelectObject( hdc, hbrush_old );
\r
1835 DeleteObject(hbrush);
\r
1840 SelectObject( hdc, hpen );
\r
1845 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1846 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1847 piece: follow the steps as explained below.
\r
1849 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1853 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1859 int backColor = whitePieceColor;
\r
1860 int foreColor = blackPieceColor;
\r
1862 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1863 backColor = appData.fontBackColorWhite;
\r
1864 foreColor = appData.fontForeColorWhite;
\r
1866 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1867 backColor = appData.fontBackColorBlack;
\r
1868 foreColor = appData.fontForeColorBlack;
\r
1872 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1874 hbm_old = SelectObject( hdc, hbm );
\r
1878 rc.right = squareSize;
\r
1879 rc.bottom = squareSize;
\r
1881 /* Step 1: background is now black */
\r
1882 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1884 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1886 pt.x = (squareSize - sz.cx) / 2;
\r
1887 pt.y = (squareSize - sz.cy) / 2;
\r
1889 SetBkMode( hdc, TRANSPARENT );
\r
1890 SetTextColor( hdc, chroma );
\r
1891 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1892 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1894 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1895 /* Step 3: the area outside the piece is filled with white */
\r
1896 // FloodFill( hdc, 0, 0, chroma );
\r
1897 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1898 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1899 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1900 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1901 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1903 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1904 but if the start point is not inside the piece we're lost!
\r
1905 There should be a better way to do this... if we could create a region or path
\r
1906 from the fill operation we would be fine for example.
\r
1908 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1909 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1911 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1912 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1913 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1915 SelectObject( dc2, bm2 );
\r
1916 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1917 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1918 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1919 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1920 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1923 DeleteObject( bm2 );
\r
1926 SetTextColor( hdc, 0 );
\r
1928 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1929 draw the piece again in black for safety.
\r
1931 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1933 SelectObject( hdc, hbm_old );
\r
1935 if( hPieceMask[index] != NULL ) {
\r
1936 DeleteObject( hPieceMask[index] );
\r
1939 hPieceMask[index] = hbm;
\r
1942 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1944 SelectObject( hdc, hbm );
\r
1947 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1948 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1949 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1951 SelectObject( dc1, hPieceMask[index] );
\r
1952 SelectObject( dc2, bm2 );
\r
1953 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1954 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1957 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1958 the piece background and deletes (makes transparent) the rest.
\r
1959 Thanks to that mask, we are free to paint the background with the greates
\r
1960 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1961 We use this, to make gradients and give the pieces a "roundish" look.
\r
1963 SetPieceBackground( hdc, backColor, 2 );
\r
1964 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1968 DeleteObject( bm2 );
\r
1971 SetTextColor( hdc, foreColor );
\r
1972 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1974 SelectObject( hdc, hbm_old );
\r
1976 if( hPieceFace[index] != NULL ) {
\r
1977 DeleteObject( hPieceFace[index] );
\r
1980 hPieceFace[index] = hbm;
\r
1983 static int TranslatePieceToFontPiece( int piece )
\r
2013 case BlackMarshall:
\r
2017 case BlackNightrider:
\r
2023 case BlackUnicorn:
\r
2027 case BlackGrasshopper:
\r
2039 case BlackCardinal:
\r
2046 case WhiteMarshall:
\r
2050 case WhiteNightrider:
\r
2056 case WhiteUnicorn:
\r
2060 case WhiteGrasshopper:
\r
2072 case WhiteCardinal:
\r
2081 void CreatePiecesFromFont()
\r
2084 HDC hdc_window = NULL;
\r
2090 if( fontBitmapSquareSize < 0 ) {
\r
2091 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2095 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2096 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2097 fontBitmapSquareSize = -1;
\r
2101 if( fontBitmapSquareSize != squareSize ) {
\r
2102 hdc_window = GetDC( hwndMain );
\r
2103 hdc = CreateCompatibleDC( hdc_window );
\r
2105 if( hPieceFont != NULL ) {
\r
2106 DeleteObject( hPieceFont );
\r
2109 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2110 hPieceMask[i] = NULL;
\r
2111 hPieceFace[i] = NULL;
\r
2117 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2118 fontHeight = appData.fontPieceSize;
\r
2121 fontHeight = (fontHeight * squareSize) / 100;
\r
2123 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2125 lf.lfEscapement = 0;
\r
2126 lf.lfOrientation = 0;
\r
2127 lf.lfWeight = FW_NORMAL;
\r
2129 lf.lfUnderline = 0;
\r
2130 lf.lfStrikeOut = 0;
\r
2131 lf.lfCharSet = DEFAULT_CHARSET;
\r
2132 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2133 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2134 lf.lfQuality = PROOF_QUALITY;
\r
2135 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2136 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2137 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2139 hPieceFont = CreateFontIndirect( &lf );
\r
2141 if( hPieceFont == NULL ) {
\r
2142 fontBitmapSquareSize = -2;
\r
2145 /* Setup font-to-piece character table */
\r
2146 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2147 /* No (or wrong) global settings, try to detect the font */
\r
2148 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2150 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2152 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2153 /* DiagramTT* family */
\r
2154 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2156 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2157 /* Fairy symbols */
\r
2158 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2160 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2161 /* Good Companion (Some characters get warped as literal :-( */
\r
2162 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2163 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2164 SetCharTable(pieceToFontChar, s);
\r
2167 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2168 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2172 /* Create bitmaps */
\r
2173 hfont_old = SelectObject( hdc, hPieceFont );
\r
2174 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2175 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2176 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2178 SelectObject( hdc, hfont_old );
\r
2180 fontBitmapSquareSize = squareSize;
\r
2184 if( hdc != NULL ) {
\r
2188 if( hdc_window != NULL ) {
\r
2189 ReleaseDC( hwndMain, hdc_window );
\r
2194 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2196 char name[128], buf[MSG_SIZ];
\r
2198 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2199 if(appData.pieceDirectory[0]) {
\r
2201 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2202 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2203 if(res) return res;
\r
2205 if (gameInfo.event &&
\r
2206 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2207 strcmp(name, "k80s") == 0) {
\r
2208 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2210 return LoadBitmap(hinst, name);
\r
2214 /* Insert a color into the program's logical palette
\r
2215 structure. This code assumes the given color is
\r
2216 the result of the RGB or PALETTERGB macro, and it
\r
2217 knows how those macros work (which is documented).
\r
2220 InsertInPalette(COLORREF color)
\r
2222 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2224 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2225 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2226 pLogPal->palNumEntries--;
\r
2230 pe->peFlags = (char) 0;
\r
2231 pe->peRed = (char) (0xFF & color);
\r
2232 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2233 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2239 InitDrawingColors()
\r
2242 if (pLogPal == NULL) {
\r
2243 /* Allocate enough memory for a logical palette with
\r
2244 * PALETTESIZE entries and set the size and version fields
\r
2245 * of the logical palette structure.
\r
2247 pLogPal = (NPLOGPALETTE)
\r
2248 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2249 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2250 pLogPal->palVersion = 0x300;
\r
2252 pLogPal->palNumEntries = 0;
\r
2254 InsertInPalette(lightSquareColor);
\r
2255 InsertInPalette(darkSquareColor);
\r
2256 InsertInPalette(whitePieceColor);
\r
2257 InsertInPalette(blackPieceColor);
\r
2258 InsertInPalette(highlightSquareColor);
\r
2259 InsertInPalette(premoveHighlightColor);
\r
2261 /* create a logical color palette according the information
\r
2262 * in the LOGPALETTE structure.
\r
2264 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2266 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2267 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2268 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2269 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2270 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2271 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2272 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2273 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2275 /* [AS] Force rendering of the font-based pieces */
\r
2276 if( fontBitmapSquareSize > 0 ) {
\r
2277 fontBitmapSquareSize = 0;
\r
2283 BoardWidth(int boardSize, int n)
\r
2284 { /* [HGM] argument n added to allow different width and height */
\r
2285 int lineGap = sizeInfo[boardSize].lineGap;
\r
2287 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2288 lineGap = appData.overrideLineGap;
\r
2291 return (n + 1) * lineGap +
\r
2292 n * sizeInfo[boardSize].squareSize;
\r
2295 /* Respond to board resize by dragging edge */
\r
2297 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2299 BoardSize newSize = NUM_SIZES - 1;
\r
2300 static int recurse = 0;
\r
2301 if (IsIconic(hwndMain)) return;
\r
2302 if (recurse > 0) return;
\r
2304 while (newSize > 0) {
\r
2305 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2306 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2307 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2310 boardSize = newSize;
\r
2311 InitDrawingSizes(boardSize, flags);
\r
2316 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2319 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2321 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2322 ChessSquare piece;
\r
2323 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2325 SIZE clockSize, messageSize;
\r
2327 char buf[MSG_SIZ];
\r
2329 HMENU hmenu = GetMenu(hwndMain);
\r
2330 RECT crect, wrect, oldRect;
\r
2332 LOGBRUSH logbrush;
\r
2333 VariantClass v = gameInfo.variant;
\r
2335 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2336 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2338 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2339 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2340 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2341 oldBoardSize = boardSize;
\r
2343 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2344 { // correct board size to one where built-in pieces exist
\r
2345 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2346 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2348 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2349 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2350 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2351 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2352 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2353 boardSize = SizeMiddling;
\r
2356 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2358 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2359 oldRect.top = wpMain.y;
\r
2360 oldRect.right = wpMain.x + wpMain.width;
\r
2361 oldRect.bottom = wpMain.y + wpMain.height;
\r
2363 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2364 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2365 squareSize = sizeInfo[boardSize].squareSize;
\r
2366 lineGap = sizeInfo[boardSize].lineGap;
\r
2367 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2368 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2370 // [HGM] decide on tininess based on total board width rather than square size
\r
2371 tinyLayout = squareSize * (BOARD_WIDTH);
\r
2372 tinyLayout = tinyLayout < 35*8 ? 2 : tinyLayout < 43*8 ? 1 : 0;
\r
2374 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2375 lineGap = appData.overrideLineGap;
\r
2378 if (tinyLayout != oldTinyLayout) {
\r
2379 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2380 if (tinyLayout == 2) {
\r
2381 style &= ~WS_SYSMENU;
\r
2382 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2383 "&Minimize\tCtrl+F4");
\r
2385 style |= WS_SYSMENU;
\r
2386 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2388 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2390 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2391 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2392 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2394 DrawMenuBar(hwndMain);
\r
2397 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2398 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2400 /* Get text area sizes */
\r
2401 hdc = GetDC(hwndMain);
\r
2402 if (appData.clockMode) {
\r
2403 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2405 snprintf(buf, MSG_SIZ, _("White"));
\r
2407 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2408 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2409 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2410 str = _("We only care about the height here");
\r
2411 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2412 SelectObject(hdc, oldFont);
\r
2413 ReleaseDC(hwndMain, hdc);
\r
2415 /* Compute where everything goes */
\r
2416 if((first.programLogo || second.programLogo) && tinyLayout != 2) {
\r
2417 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2418 logoHeight = 2*clockSize.cy;
\r
2419 leftLogoRect.left = OUTER_MARGIN;
\r
2420 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2421 leftLogoRect.top = OUTER_MARGIN;
\r
2422 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2424 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2425 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2426 rightLogoRect.top = OUTER_MARGIN;
\r
2427 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2430 whiteRect.left = leftLogoRect.right;
\r
2431 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2432 whiteRect.top = OUTER_MARGIN;
\r
2433 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2435 blackRect.right = rightLogoRect.left;
\r
2436 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2437 blackRect.top = whiteRect.top;
\r
2438 blackRect.bottom = whiteRect.bottom;
\r
2440 whiteRect.left = OUTER_MARGIN;
\r
2441 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2442 whiteRect.top = OUTER_MARGIN;
\r
2443 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2445 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2446 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2447 blackRect.top = whiteRect.top;
\r
2448 blackRect.bottom = whiteRect.bottom;
\r
2450 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2453 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2454 if (appData.showButtonBar) {
\r
2455 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2456 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2458 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2460 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2461 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2463 boardRect.left = OUTER_MARGIN;
\r
2464 boardRect.right = boardRect.left + boardWidth;
\r
2465 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2466 boardRect.bottom = boardRect.top + boardHeight;
\r
2468 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2469 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2470 oldTinyLayout = tinyLayout;
\r
2471 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2472 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2473 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2474 winW *= 1 + twoBoards;
\r
2475 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2476 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2477 wpMain.height = winH; // without disturbing window attachments
\r
2478 GetWindowRect(hwndMain, &wrect);
\r
2479 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2480 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2482 // [HGM] placement: let attached windows follow size change.
\r
2483 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2484 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2485 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2486 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2487 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2489 /* compensate if menu bar wrapped */
\r
2490 GetClientRect(hwndMain, &crect);
\r
2491 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2492 wpMain.height += offby;
\r
2494 case WMSZ_TOPLEFT:
\r
2495 SetWindowPos(hwndMain, NULL,
\r
2496 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2497 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2500 case WMSZ_TOPRIGHT:
\r
2502 SetWindowPos(hwndMain, NULL,
\r
2503 wrect.left, wrect.bottom - wpMain.height,
\r
2504 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2507 case WMSZ_BOTTOMLEFT:
\r
2509 SetWindowPos(hwndMain, NULL,
\r
2510 wrect.right - wpMain.width, wrect.top,
\r
2511 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2514 case WMSZ_BOTTOMRIGHT:
\r
2518 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2519 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2524 for (i = 0; i < N_BUTTONS; i++) {
\r
2525 if (buttonDesc[i].hwnd != NULL) {
\r
2526 DestroyWindow(buttonDesc[i].hwnd);
\r
2527 buttonDesc[i].hwnd = NULL;
\r
2529 if (appData.showButtonBar) {
\r
2530 buttonDesc[i].hwnd =
\r
2531 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2532 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2533 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2534 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2535 (HMENU) buttonDesc[i].id,
\r
2536 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2537 if (tinyLayout == 2) {
\r
2538 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2539 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2540 MAKELPARAM(FALSE, 0));
\r
2542 if (buttonDesc[i].id == IDM_Pause)
\r
2543 hwndPause = buttonDesc[i].hwnd;
\r
2544 buttonDesc[i].wndproc = (WNDPROC)
\r
2545 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2548 if (gridPen != NULL) DeleteObject(gridPen);
\r
2549 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2550 if (premovePen != NULL) DeleteObject(premovePen);
\r
2551 if (lineGap != 0) {
\r
2552 logbrush.lbStyle = BS_SOLID;
\r
2553 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2555 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2556 lineGap, &logbrush, 0, NULL);
\r
2557 logbrush.lbColor = highlightSquareColor;
\r
2559 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2560 lineGap, &logbrush, 0, NULL);
\r
2562 logbrush.lbColor = premoveHighlightColor;
\r
2564 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2565 lineGap, &logbrush, 0, NULL);
\r
2567 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2568 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2569 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2570 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2571 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2572 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2573 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2574 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2576 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2577 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2578 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2579 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2580 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2581 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2582 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2583 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2587 /* [HGM] Licensing requirement */
\r
2589 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2592 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2594 GothicPopUp( "", VariantNormal);
\r
2597 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2599 /* Load piece bitmaps for this board size */
\r
2600 for (i=0; i<=2; i++) {
\r
2601 for (piece = WhitePawn;
\r
2602 (int) piece < (int) BlackPawn;
\r
2603 piece = (ChessSquare) ((int) piece + 1)) {
\r
2604 if (pieceBitmap[i][piece] != NULL)
\r
2605 DeleteObject(pieceBitmap[i][piece]);
\r
2606 pieceBitmap[i][piece] = NULL;
\r
2610 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2612 // Orthodox Chess pieces
\r
2613 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2614 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2615 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2616 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2617 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2618 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2619 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2620 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2621 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2622 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2623 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2624 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2625 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2626 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2627 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2628 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2629 // in Shogi, Hijack the unused Queen for Lance
\r
2630 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2631 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2632 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2634 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2635 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2636 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2639 if(squareSize <= 72 && squareSize >= 33) {
\r
2640 /* A & C are available in most sizes now */
\r
2641 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2642 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2645 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2646 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2647 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2648 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2651 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2652 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2653 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2654 } else { // Smirf-like
\r
2655 if(gameInfo.variant == VariantSChess) {
\r
2656 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2657 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2658 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2660 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2665 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2666 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2667 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2668 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2669 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2670 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2671 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2672 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2673 } else { // WinBoard standard
\r
2674 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2681 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2682 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2683 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2684 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2685 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2686 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2687 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2688 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2689 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2690 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2691 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2692 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2693 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2694 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2695 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2696 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2697 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2698 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2699 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2700 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2701 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2702 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2703 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2704 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2705 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2706 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2707 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2708 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2709 pieceBitmap[0][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2710 pieceBitmap[1][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2711 pieceBitmap[2][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2712 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2713 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2714 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2715 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2716 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2717 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2718 pieceBitmap[0][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2719 pieceBitmap[1][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2720 pieceBitmap[2][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2721 pieceBitmap[0][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "s");
\r
2722 pieceBitmap[1][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "o");
\r
2723 pieceBitmap[2][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "w");
\r
2724 pieceBitmap[0][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "s");
\r
2725 pieceBitmap[1][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "o");
\r
2726 pieceBitmap[2][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "w");
\r
2727 pieceBitmap[0][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "s");
\r
2728 pieceBitmap[1][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "o");
\r
2729 pieceBitmap[2][WhiteZebra] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2731 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2732 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2733 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2734 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2735 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2736 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2737 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2738 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2739 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2740 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2741 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2742 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2743 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2745 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2746 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2747 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2748 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2749 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2750 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2751 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2752 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2753 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2754 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2755 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2756 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2759 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2760 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2761 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2762 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2763 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2764 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2765 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2766 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2767 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2768 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2769 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2770 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2771 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2772 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2773 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2777 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2778 /* special Shogi support in this size */
\r
2779 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2780 for (piece = WhitePawn;
\r
2781 (int) piece < (int) BlackPawn;
\r
2782 piece = (ChessSquare) ((int) piece + 1)) {
\r
2783 if (pieceBitmap[i][piece] != NULL)
\r
2784 DeleteObject(pieceBitmap[i][piece]);
\r
2787 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2788 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2789 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2790 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2791 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2792 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2793 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2794 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2795 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2796 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2797 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2798 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2799 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2800 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2801 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2802 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2803 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2804 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2805 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2806 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2807 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2808 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2809 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2810 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2811 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2812 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2813 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2814 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2815 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2816 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2817 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2818 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2819 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2820 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2821 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2822 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2823 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2824 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2825 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2826 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2827 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2828 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2832 if(appData.pieceDirectory[0]) for(i=WhitePawn; i<BlackPawn; i++) { // try for all missing pieces with new naming convention
\r
2833 char buf[MSG_SIZ];
\r
2834 if(pieceBitmap[0][i]) continue;
\r
2835 snprintf(buf, MSG_SIZ, "piece%d_", i);
\r
2836 pieceBitmap[0][i] = DoLoadBitmap(hInst, buf, squareSize, "s");
\r
2837 pieceBitmap[1][i] = DoLoadBitmap(hInst, buf, squareSize, "o");
\r
2838 pieceBitmap[2][i] = DoLoadBitmap(hInst, buf, squareSize, "w");
\r
2843 PieceBitmap(ChessSquare p, int kind)
\r
2845 if ((int) p >= (int) BlackPawn)
\r
2846 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2848 return pieceBitmap[kind][(int) p];
\r
2851 /***************************************************************/
\r
2853 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2854 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2856 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2857 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2861 SquareToPos(int row, int column, int * x, int * y)
\r
2864 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2865 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2867 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2868 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2873 DrawCoordsOnDC(HDC hdc)
\r
2875 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2876 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2877 char str[2] = { NULLCHAR, NULLCHAR };
\r
2878 int oldMode, oldAlign, x, y, start, i;
\r
2882 if (!appData.showCoords)
\r
2885 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2887 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2888 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2889 oldAlign = GetTextAlign(hdc);
\r
2890 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2892 y = boardRect.top + lineGap;
\r
2893 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2896 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2897 x += border - lineGap - 4; y += squareSize - 6;
\r
2899 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2900 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2901 str[0] = files[start + i];
\r
2902 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2903 y += squareSize + lineGap;
\r
2906 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2909 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2910 x += -border + 4; y += border - squareSize + 6;
\r
2912 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2913 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2914 str[0] = ranks[start + i];
\r
2915 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2916 x += squareSize + lineGap;
\r
2919 SelectObject(hdc, oldBrush);
\r
2920 SetBkMode(hdc, oldMode);
\r
2921 SetTextAlign(hdc, oldAlign);
\r
2922 SelectObject(hdc, oldFont);
\r
2926 DrawGridOnDC(HDC hdc)
\r
2930 if (lineGap != 0) {
\r
2931 oldPen = SelectObject(hdc, gridPen);
\r
2932 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2933 SelectObject(hdc, oldPen);
\r
2937 #define HIGHLIGHT_PEN 0
\r
2938 #define PREMOVE_PEN 1
\r
2941 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2944 HPEN oldPen, hPen;
\r
2945 if (lineGap == 0) return;
\r
2947 x1 = boardRect.left +
\r
2948 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2949 y1 = boardRect.top +
\r
2950 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2952 x1 = boardRect.left +
\r
2953 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2954 y1 = boardRect.top +
\r
2955 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2957 hPen = pen ? premovePen : highlightPen;
\r
2958 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2959 MoveToEx(hdc, x1, y1, NULL);
\r
2960 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2961 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2962 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2963 LineTo(hdc, x1, y1);
\r
2964 SelectObject(hdc, oldPen);
\r
2968 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2971 for (i=0; i<2; i++) {
\r
2972 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2973 DrawHighlightOnDC(hdc, TRUE,
\r
2974 h->sq[i].x, h->sq[i].y,
\r
2979 /* Note: sqcolor is used only in monoMode */
\r
2980 /* Note that this code is largely duplicated in woptions.c,
\r
2981 function DrawSampleSquare, so that needs to be updated too */
\r
2983 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2985 HBITMAP oldBitmap;
\r
2989 if (appData.blindfold) return;
\r
2991 /* [AS] Use font-based pieces if needed */
\r
2992 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2993 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2994 CreatePiecesFromFont();
\r
2996 if( fontBitmapSquareSize == squareSize ) {
\r
2997 int index = TranslatePieceToFontPiece(piece);
\r
2999 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3001 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
3002 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
3006 squareSize, squareSize,
\r
3011 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3013 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
3014 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
3018 squareSize, squareSize,
\r
3027 if (appData.monoMode) {
\r
3028 SelectObject(tmphdc, PieceBitmap(piece,
\r
3029 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3030 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3031 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3033 HBRUSH xBrush = whitePieceBrush;
\r
3034 tmpSize = squareSize;
\r
3035 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
3037 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3038 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3039 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3040 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3041 x += (squareSize - minorSize)>>1;
\r
3042 y += squareSize - minorSize - 2;
\r
3043 tmpSize = minorSize;
\r
3045 if (color || appData.allWhite ) {
\r
3046 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3048 oldBrush = SelectObject(hdc, xBrush);
\r
3049 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3050 if(appData.upsideDown && color==flipView)
\r
3051 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3053 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3054 /* Use black for outline of white pieces */
\r
3055 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3056 if(appData.upsideDown && color==flipView)
\r
3057 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3059 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3060 } else if(appData.pieceDirectory[0]) {
\r
3061 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3062 oldBrush = SelectObject(hdc, xBrush);
\r
3063 if(appData.upsideDown && color==flipView)
\r
3064 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3066 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3067 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3068 if(appData.upsideDown && color==flipView)
\r
3069 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3071 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3073 /* Use square color for details of black pieces */
\r
3074 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3075 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3076 if(appData.upsideDown && !flipView)
\r
3077 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3079 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3081 SelectObject(hdc, oldBrush);
\r
3082 SelectObject(tmphdc, oldBitmap);
\r
3086 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3087 int GetBackTextureMode( int algo )
\r
3089 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3093 case BACK_TEXTURE_MODE_PLAIN:
\r
3094 result = 1; /* Always use identity map */
\r
3096 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3097 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3105 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3106 to handle redraws cleanly (as random numbers would always be different).
\r
3108 VOID RebuildTextureSquareInfo()
\r
3118 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3120 if( liteBackTexture != NULL ) {
\r
3121 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3122 lite_w = bi.bmWidth;
\r
3123 lite_h = bi.bmHeight;
\r
3127 if( darkBackTexture != NULL ) {
\r
3128 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3129 dark_w = bi.bmWidth;
\r
3130 dark_h = bi.bmHeight;
\r
3134 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3135 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3136 if( (col + row) & 1 ) {
\r
3138 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3139 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3140 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3142 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3143 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3144 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3146 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3147 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3152 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3153 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3154 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3156 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3157 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3158 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3160 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3161 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3168 /* [AS] Arrow highlighting support */
\r
3170 static double A_WIDTH = 5; /* Width of arrow body */
\r
3172 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3173 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3175 static double Sqr( double x )
\r
3180 static int Round( double x )
\r
3182 return (int) (x + 0.5);
\r