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 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
96 #define DATADIR "~~"
\r
98 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
100 int myrandom(void);
\r
101 void mysrandom(unsigned int seed);
\r
103 extern int whiteFlag, blackFlag;
\r
104 Boolean flipClock = FALSE;
\r
105 extern HANDLE chatHandle[];
\r
106 extern enum ICS_TYPE ics_type;
\r
108 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
109 int MyGetFullPathName P((char *name, char *fullname));
\r
110 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
111 VOID NewVariantPopup(HWND hwnd);
\r
112 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
113 /*char*/int promoChar));
\r
114 void DisplayMove P((int moveNumber));
\r
115 void ChatPopUp P((char *s));
\r
117 ChessSquare piece;
\r
118 POINT pos; /* window coordinates of current pos */
\r
119 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
120 POINT from; /* board coordinates of the piece's orig pos */
\r
121 POINT to; /* board coordinates of the piece's new pos */
\r
124 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
127 POINT start; /* window coordinates of start pos */
\r
128 POINT pos; /* window coordinates of current pos */
\r
129 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
130 POINT from; /* board coordinates of the piece's orig pos */
\r
134 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
137 POINT sq[2]; /* board coordinates of from, to squares */
\r
140 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
145 typedef struct { // [HGM] atomic
\r
146 int fromX, fromY, toX, toY, radius;
\r
149 static ExplodeInfo explodeInfo;
\r
151 /* Window class names */
\r
152 char szAppName[] = "WinBoard";
\r
153 char szConsoleName[] = "WBConsole";
\r
155 /* Title bar text */
\r
156 char szTitle[] = "WinBoard";
\r
157 char szConsoleTitle[] = "I C S Interaction";
\r
160 char *settingsFileName;
\r
161 Boolean saveSettingsOnExit;
\r
162 char installDir[MSG_SIZ];
\r
163 int errorExitStatus;
\r
165 BoardSize boardSize;
\r
166 Boolean chessProgram;
\r
167 //static int boardX, boardY;
\r
168 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
169 int squareSize, lineGap, minorSize;
\r
170 static int winW, winH;
\r
171 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
172 static int logoHeight = 0;
\r
173 static char messageText[MESSAGE_TEXT_MAX];
\r
174 static int clockTimerEvent = 0;
\r
175 static int loadGameTimerEvent = 0;
\r
176 static int analysisTimerEvent = 0;
\r
177 static DelayedEventCallback delayedTimerCallback;
\r
178 static int delayedTimerEvent = 0;
\r
179 static int buttonCount = 2;
\r
180 char *icsTextMenuString;
\r
182 char *firstChessProgramNames;
\r
183 char *secondChessProgramNames;
\r
185 #define PALETTESIZE 256
\r
187 HINSTANCE hInst; /* current instance */
\r
188 Boolean alwaysOnTop = FALSE;
\r
190 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
191 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
192 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
194 ColorClass currentColorClass;
\r
196 static HWND savedHwnd;
\r
197 HWND hCommPort = NULL; /* currently open comm port */
\r
198 static HWND hwndPause; /* pause button */
\r
199 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
200 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
201 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
202 explodeBrush, /* [HGM] atomic */
\r
203 markerBrush[8], /* [HGM] markers */
\r
204 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
205 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
206 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
207 static HPEN gridPen = NULL;
\r
208 static HPEN highlightPen = NULL;
\r
209 static HPEN premovePen = NULL;
\r
210 static NPLOGPALETTE pLogPal;
\r
211 static BOOL paletteChanged = FALSE;
\r
212 static HICON iconWhite, iconBlack, iconCurrent;
\r
213 static int doingSizing = FALSE;
\r
214 static int lastSizing = 0;
\r
215 static int prevStderrPort;
\r
216 static HBITMAP userLogo;
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
229 #if defined(_winmajor)
\r
230 #define oldDialog (_winmajor < 4)
\r
232 #define oldDialog 0
\r
236 #define INTERNATIONAL
\r
238 #ifdef INTERNATIONAL
\r
239 # define _(s) T_(s)
\r
245 # define Translate(x, y)
\r
246 # define LoadLanguageFile(s)
\r
249 #ifdef INTERNATIONAL
\r
251 Boolean barbaric; // flag indicating if translation is needed
\r
253 // list of item numbers used in each dialog (used to alter language at run time)
\r
255 #define ABOUTBOX -1 /* not sure why these are needed */
\r
256 #define ABOUTBOX2 -1
\r
258 int dialogItems[][42] = {
\r
259 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
260 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
261 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
262 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
263 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds,
\r
264 OPT_Ranget, IDOK, IDCANCEL },
\r
265 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
266 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
267 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
268 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
269 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
270 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
271 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
272 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
273 { ABOUTBOX2, IDC_ChessBoard },
\r
274 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
275 OPT_GameListClose, IDC_GameListDoFilter },
\r
276 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
277 { DLG_Error, IDOK },
\r
278 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
279 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
280 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
281 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
282 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
283 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
284 { DLG_IndexNumber, IDC_Index },
\r
285 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
286 { DLG_TypeInName, IDOK, IDCANCEL },
\r
287 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
288 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
289 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
290 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
291 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
292 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
293 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
294 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
295 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
296 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
297 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
298 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
299 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
300 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
301 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
302 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
303 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
304 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
305 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
306 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
307 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
308 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
309 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
310 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
311 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
312 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
313 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
314 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
315 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
316 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
317 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
318 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
319 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
320 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
321 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
322 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
323 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
324 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
325 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
326 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
327 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
328 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
329 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
330 { DLG_MoveHistory },
\r
331 { DLG_EvalGraph },
\r
332 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
333 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
334 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
335 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
336 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
337 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
338 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
339 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
340 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
344 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
345 static int lastChecked;
\r
346 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
347 extern int tinyLayout;
\r
348 extern char * menuBarText[][10];
\r
351 LoadLanguageFile(char *name)
\r
352 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
354 int i=0, j=0, n=0, k;
\r
357 if(!name || name[0] == NULLCHAR) return;
\r
358 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
359 appData.language = oldLanguage;
\r
360 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
361 if((f = fopen(buf, "r")) == NULL) return;
\r
362 while((k = fgetc(f)) != EOF) {
\r
363 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
364 languageBuf[i] = k;
\r
366 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
368 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
369 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
370 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
371 english[j] = languageBuf + n + 1; *p = 0;
\r
372 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
373 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
378 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
380 case 'n': k = '\n'; break;
\r
381 case 'r': k = '\r'; break;
\r
382 case 't': k = '\t'; break;
\r
384 languageBuf[--i] = k;
\r
389 barbaric = (j != 0);
\r
390 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
395 { // return the translation of the given string
\r
396 // efficiency can be improved a lot...
\r
398 static char buf[MSG_SIZ];
\r
399 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
400 if(!barbaric) return s;
\r
401 if(!s) return ""; // sanity
\r
402 while(english[i]) {
\r
403 if(!strcmp(s, english[i])) return foreign[i];
\r
404 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
405 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
414 Translate(HWND hDlg, int dialogID)
\r
415 { // translate all text items in the given dialog
\r
417 char buf[MSG_SIZ], *s;
\r
418 if(!barbaric) return;
\r
419 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
420 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
421 GetWindowText( hDlg, buf, MSG_SIZ );
\r
423 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
424 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
425 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
426 if(strlen(buf) == 0) continue;
\r
428 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
433 TranslateOneMenu(int i, HMENU subMenu)
\r
436 static MENUITEMINFO info;
\r
438 info.cbSize = sizeof(MENUITEMINFO);
\r
439 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
440 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
442 info.dwTypeData = buf;
\r
443 info.cch = sizeof(buf);
\r
444 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
446 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
447 else menuText[i][j] = strdup(buf); // remember original on first change
\r
449 if(buf[0] == NULLCHAR) continue;
\r
450 info.dwTypeData = T_(buf);
\r
451 info.cch = strlen(buf)+1;
\r
452 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
458 TranslateMenus(int addLanguage)
\r
461 WIN32_FIND_DATA fileData;
\r
463 #define IDM_English 1970
\r
465 HMENU mainMenu = GetMenu(hwndMain);
\r
466 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
467 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
468 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
469 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
470 TranslateOneMenu(i, subMenu);
\r
472 DrawMenuBar(hwndMain);
\r
475 if(!addLanguage) return;
\r
476 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
477 HMENU mainMenu = GetMenu(hwndMain);
\r
478 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
479 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
480 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
481 i = 0; lastChecked = IDM_English;
\r
483 char *p, *q = fileData.cFileName;
\r
484 int checkFlag = MF_UNCHECKED;
\r
485 languageFile[i] = strdup(q);
\r
486 if(barbaric && !strcmp(oldLanguage, q)) {
\r
487 checkFlag = MF_CHECKED;
\r
488 lastChecked = IDM_English + i + 1;
\r
489 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
491 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
492 p = strstr(fileData.cFileName, ".lng");
\r
494 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
495 } while(FindNextFile(hFind, &fileData));
\r
502 #define IDM_RecentEngines 3000
\r
505 RecentEngineMenu (char *s)
\r
507 if(appData.icsActive) return;
\r
508 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
509 HMENU mainMenu = GetMenu(hwndMain);
\r
510 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
511 int i=IDM_RecentEngines;
\r
512 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
513 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
515 char *p = strchr(s, '\n');
\r
516 if(p == NULL) return; // malformed!
\r
518 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
532 int cliWidth, cliHeight;
\r
535 SizeInfo sizeInfo[] =
\r
537 { "tiny", 21, 0, 1, 2, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 2, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 2, 0, 0 },
\r
540 { "petite", 33, 1, 1, 2, 0, 0 },
\r
541 { "slim", 37, 2, 1, 1, 0, 0 },
\r
542 { "small", 40, 2, 1, 1, 0, 0 },
\r
543 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
544 { "middling", 49, 2, 0, 0, 0, 0 },
\r
545 { "average", 54, 2, 0, 0, 0, 0 },
\r
546 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
547 { "medium", 64, 3, 0, 0, 0, 0 },
\r
548 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
549 { "large", 80, 3, 0, 0, 0, 0 },
\r
550 { "big", 87, 3, 0, 0, 0, 0 },
\r
551 { "huge", 95, 3, 0, 0, 0, 0 },
\r
552 { "giant", 108, 3, 0, 0, 0, 0 },
\r
553 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
554 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
555 { NULL, 0, 0, 0, 0, 0, 0 }
\r
558 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
559 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
561 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
562 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
578 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
581 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
590 #define BUTTON_WIDTH (tinyLayout == 2 ? 16 : 32)
\r
591 #define N_BUTTONS 5
\r
593 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
595 {"<<", IDM_ToStart, NULL, NULL},
\r
596 {"<", IDM_Backward, NULL, NULL},
\r
597 {"P", IDM_Pause, NULL, NULL},
\r
598 {">", IDM_Forward, NULL, NULL},
\r
599 {">>", IDM_ToEnd, NULL, NULL},
\r
602 int tinyLayout = 0, smallLayout = 0;
\r
603 #define MENU_BAR_ITEMS 9
\r
604 char *menuBarText[3][MENU_BAR_ITEMS+1] = {
\r
605 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
606 { N_("&Fil"), N_("&Ed"), N_("&Vw"), N_("&Mod"), N_("&Act"), N_("E&ng"), N_("&Opt"), N_("&Hlp"), NULL },
\r
607 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
611 MySound sounds[(int)NSoundClasses];
\r
612 MyTextAttribs textAttribs[(int)NColorClasses];
\r
614 MyColorizeAttribs colorizeAttribs[] = {
\r
615 { (COLORREF)0, 0, N_("Shout Text") },
\r
616 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
617 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
618 { (COLORREF)0, 0, N_("Channel Text") },
\r
619 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
620 { (COLORREF)0, 0, N_("Tell Text") },
\r
621 { (COLORREF)0, 0, N_("Challenge Text") },
\r
622 { (COLORREF)0, 0, N_("Request Text") },
\r
623 { (COLORREF)0, 0, N_("Seek Text") },
\r
624 { (COLORREF)0, 0, N_("Normal Text") },
\r
625 { (COLORREF)0, 0, N_("None") }
\r
630 static char *commentTitle;
\r
631 static char *commentText;
\r
632 static int commentIndex;
\r
633 static Boolean editComment = FALSE;
\r
636 char errorTitle[MSG_SIZ];
\r
637 char errorMessage[2*MSG_SIZ];
\r
638 HWND errorDialog = NULL;
\r
639 BOOLEAN moveErrorMessageUp = FALSE;
\r
640 BOOLEAN consoleEcho = TRUE;
\r
641 CHARFORMAT consoleCF;
\r
642 COLORREF consoleBackgroundColor;
\r
644 char *programVersion;
\r
650 typedef int CPKind;
\r
659 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
662 #define INPUT_SOURCE_BUF_SIZE 4096
\r
664 typedef struct _InputSource {
\r
671 char buf[INPUT_SOURCE_BUF_SIZE];
\r
675 InputCallback func;
\r
676 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
680 InputSource *consoleInputSource;
\r
685 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
686 VOID ConsoleCreate();
\r
688 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
689 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
690 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
691 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
693 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
694 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
695 void ParseIcsTextMenu(char *icsTextMenuString);
\r
696 VOID PopUpNameDialog(char firstchar);
\r
697 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
701 int GameListOptions();
\r
703 int dummy; // [HGM] for obsolete args
\r
705 HWND hwndMain = NULL; /* root window*/
\r
706 HWND hwndConsole = NULL;
\r
707 HWND commentDialog = NULL;
\r
708 HWND moveHistoryDialog = NULL;
\r
709 HWND evalGraphDialog = NULL;
\r
710 HWND engineOutputDialog = NULL;
\r
711 HWND gameListDialog = NULL;
\r
712 HWND editTagsDialog = NULL;
\r
714 int commentUp = FALSE;
\r
716 WindowPlacement wpMain;
\r
717 WindowPlacement wpConsole;
\r
718 WindowPlacement wpComment;
\r
719 WindowPlacement wpMoveHistory;
\r
720 WindowPlacement wpEvalGraph;
\r
721 WindowPlacement wpEngineOutput;
\r
722 WindowPlacement wpGameList;
\r
723 WindowPlacement wpTags;
\r
725 VOID EngineOptionsPopup(); // [HGM] settings
\r
727 VOID GothicPopUp(char *title, VariantClass variant);
\r
729 * Setting "frozen" should disable all user input other than deleting
\r
730 * the window. We do this while engines are initializing themselves.
\r
732 static int frozen = 0;
\r
733 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
739 if (frozen) return;
\r
741 hmenu = GetMenu(hwndMain);
\r
742 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
743 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
745 DrawMenuBar(hwndMain);
\r
748 /* Undo a FreezeUI */
\r
754 if (!frozen) return;
\r
756 hmenu = GetMenu(hwndMain);
\r
757 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
758 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
760 DrawMenuBar(hwndMain);
\r
763 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
765 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
771 #define JAWS_ALT_INTERCEPT
\r
772 #define JAWS_KBUP_NAVIGATION
\r
773 #define JAWS_KBDOWN_NAVIGATION
\r
774 #define JAWS_MENU_ITEMS
\r
775 #define JAWS_SILENCE
\r
776 #define JAWS_REPLAY
\r
778 #define JAWS_COPYRIGHT
\r
779 #define JAWS_DELETE(X) X
\r
780 #define SAYMACHINEMOVE()
\r
784 /*---------------------------------------------------------------------------*\
\r
788 \*---------------------------------------------------------------------------*/
\r
790 static void HandleMessage P((MSG *message));
\r
791 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
794 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
795 LPSTR lpCmdLine, int nCmdShow)
\r
798 // INITCOMMONCONTROLSEX ex;
\r
802 LoadLibrary("RICHED32.DLL");
\r
803 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
805 if (!InitApplication(hInstance)) {
\r
808 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
815 // InitCommonControlsEx(&ex);
\r
816 InitCommonControls();
\r
818 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
819 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
820 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
822 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
824 while (GetMessage(&msg, /* message structure */
\r
825 NULL, /* handle of window receiving the message */
\r
826 0, /* lowest message to examine */
\r
827 0)) /* highest message to examine */
\r
829 HandleMessage(&msg);
\r
833 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
837 HandleMessage (MSG *message)
\r
839 MSG msg = *message;
\r
841 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
842 // [HGM] navigate: switch between all windows with tab
\r
843 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
844 int i, currentElement = 0;
\r
846 // first determine what element of the chain we come from (if any)
\r
847 if(appData.icsActive) {
\r
848 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
849 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
851 if(engineOutputDialog && EngineOutputIsUp()) {
\r
852 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
853 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
855 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
856 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
858 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
859 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
860 if(msg.hwnd == e1) currentElement = 2; else
\r
861 if(msg.hwnd == e2) currentElement = 3; else
\r
862 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
863 if(msg.hwnd == mh) currentElement = 4; else
\r
864 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
865 if(msg.hwnd == hText) currentElement = 5; else
\r
866 if(msg.hwnd == hInput) currentElement = 6; else
\r
867 for (i = 0; i < N_BUTTONS; i++) {
\r
868 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
871 // determine where to go to
\r
872 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
874 currentElement = (currentElement + direction) % 7;
\r
875 switch(currentElement) {
\r
877 h = hwndMain; break; // passing this case always makes the loop exit
\r
879 h = buttonDesc[0].hwnd; break; // could be NULL
\r
881 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
884 if(!EngineOutputIsUp()) continue;
\r
887 if(!MoveHistoryIsUp()) continue;
\r
889 // case 6: // input to eval graph does not seem to get here!
\r
890 // if(!EvalGraphIsUp()) continue;
\r
891 // h = evalGraphDialog; break;
\r
893 if(!appData.icsActive) continue;
\r
897 if(!appData.icsActive) continue;
\r
903 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
904 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
907 return; // this message now has been processed
\r
911 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
912 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
913 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
914 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
915 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
916 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
917 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
918 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
920 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
921 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
922 for(i=0; i<MAX_CHAT; i++)
\r
923 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
926 if(done) return; // [HGM] chat: end patch
\r
927 TranslateMessage(&msg); /* Translates virtual key codes */
\r
928 DispatchMessage(&msg); /* Dispatches message to window */
\r
934 { /* Dispatch pending messages */
\r
936 while (PeekMessage(&msg, /* message structure */
\r
937 NULL, /* handle of window receiving the message */
\r
938 0, /* lowest message to examine */
\r
939 0, /* highest message to examine */
\r
942 HandleMessage(&msg);
\r
946 /*---------------------------------------------------------------------------*\
\r
948 * Initialization functions
\r
950 \*---------------------------------------------------------------------------*/
\r
954 { // update user logo if necessary
\r
955 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
957 if(appData.autoLogo) {
\r
958 curName = UserName();
\r
959 if(strcmp(curName, oldUserName)) {
\r
960 GetCurrentDirectory(MSG_SIZ, dir);
\r
961 SetCurrentDirectory(installDir);
\r
962 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
963 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
964 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
965 if(userLogo == NULL)
\r
966 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
967 SetCurrentDirectory(dir); /* return to prev directory */
\r
973 InitApplication(HINSTANCE hInstance)
\r
977 /* Fill in window class structure with parameters that describe the */
\r
980 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
981 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
982 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
983 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
984 wc.hInstance = hInstance; /* Owner of this class */
\r
985 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
986 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
987 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
988 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
989 wc.lpszClassName = szAppName; /* Name to register as */
\r
991 /* Register the window class and return success/failure code. */
\r
992 if (!RegisterClass(&wc)) return FALSE;
\r
994 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
995 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
997 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
998 wc.hInstance = hInstance;
\r
999 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
1000 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1001 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1002 wc.lpszMenuName = NULL;
\r
1003 wc.lpszClassName = szConsoleName;
\r
1005 if (!RegisterClass(&wc)) return FALSE;
\r
1010 /* Set by InitInstance, used by EnsureOnScreen */
\r
1011 int screenHeight, screenWidth;
\r
1012 RECT screenGeometry;
\r
1015 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1017 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1018 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1019 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1020 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1021 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1022 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1026 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1028 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1029 GetCurrentDirectory(MSG_SIZ, dir);
\r
1030 SetCurrentDirectory(installDir);
\r
1031 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1032 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1034 if (cps->programLogo == NULL && appData.debugMode) {
\r
1035 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1037 } else if(appData.autoLogo) {
\r
1038 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1039 char *opponent = "";
\r
1040 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1041 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1042 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1043 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1044 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1045 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1048 if(appData.directory[n] && appData.directory[n][0]) {
\r
1049 SetCurrentDirectory(appData.directory[n]);
\r
1050 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1053 SetCurrentDirectory(dir); /* return to prev directory */
\r
1059 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1060 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1062 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1063 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1064 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1065 liteBackTextureMode = appData.liteBackTextureMode;
\r
1067 if (liteBackTexture == NULL && appData.debugMode) {
\r
1068 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1072 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1073 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1074 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1075 darkBackTextureMode = appData.darkBackTextureMode;
\r
1077 if (darkBackTexture == NULL && appData.debugMode) {
\r
1078 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1083 #ifndef SM_CXVIRTUALSCREEN
\r
1084 #define SM_CXVIRTUALSCREEN 78
\r
1086 #ifndef SM_CYVIRTUALSCREEN
\r
1087 #define SM_CYVIRTUALSCREEN 79
\r
1089 #ifndef SM_XVIRTUALSCREEN
\r
1090 #define SM_XVIRTUALSCREEN 76
\r
1092 #ifndef SM_YVIRTUALSCREEN
\r
1093 #define SM_YVIRTUALSCREEN 77
\r
1099 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1100 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1101 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1102 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1103 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1104 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1105 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1106 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1110 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1112 HWND hwnd; /* Main window handle. */
\r
1114 WINDOWPLACEMENT wp;
\r
1117 hInst = hInstance; /* Store instance handle in our global variable */
\r
1118 programName = szAppName;
\r
1120 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1121 *filepart = NULLCHAR;
\r
1122 SetCurrentDirectory(installDir);
\r
1124 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1126 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1128 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1129 /* xboard, and older WinBoards, controlled the move sound with the
\r
1130 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1131 always turn the option on (so that the backend will call us),
\r
1132 then let the user turn the sound off by setting it to silence if
\r
1133 desired. To accommodate old winboard.ini files saved by old
\r
1134 versions of WinBoard, we also turn off the sound if the option
\r
1135 was initially set to false. [HGM] taken out of InitAppData */
\r
1136 if (!appData.ringBellAfterMoves) {
\r
1137 sounds[(int)SoundMove].name = strdup("");
\r
1138 appData.ringBellAfterMoves = TRUE;
\r
1140 if (appData.debugMode) {
\r
1141 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1142 setbuf(debugFP, NULL);
\r
1145 LoadLanguageFile(appData.language);
\r
1149 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1150 // InitEngineUCI( installDir, &second );
\r
1152 /* Create a main window for this application instance. */
\r
1153 hwnd = CreateWindow(szAppName, szTitle,
\r
1154 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1155 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1156 NULL, NULL, hInstance, NULL);
\r
1159 /* If window could not be created, return "failure" */
\r
1164 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1165 LoadLogo(&first, 0, FALSE);
\r
1166 LoadLogo(&second, 1, appData.icsActive);
\r
1170 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1171 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1172 iconCurrent = iconWhite;
\r
1173 InitDrawingColors();
\r
1175 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1176 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1177 /* Compute window size for each board size, and use the largest
\r
1178 size that fits on this screen as the default. */
\r
1179 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1180 if (boardSize == (BoardSize)-1 &&
\r
1181 winH <= screenHeight
\r
1182 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1183 && winW <= screenWidth) {
\r
1184 boardSize = (BoardSize)ibs;
\r
1188 InitDrawingSizes(boardSize, 0);
\r
1189 RecentEngineMenu(appData.recentEngineList);
\r
1191 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1193 /* [AS] Load textures if specified */
\r
1196 mysrandom( (unsigned) time(NULL) );
\r
1198 /* [AS] Restore layout */
\r
1199 if( wpMoveHistory.visible ) {
\r
1200 MoveHistoryPopUp();
\r
1203 if( wpEvalGraph.visible ) {
\r
1207 if( wpEngineOutput.visible ) {
\r
1208 EngineOutputPopUp();
\r
1211 /* Make the window visible; update its client area; and return "success" */
\r
1212 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1213 wp.length = sizeof(WINDOWPLACEMENT);
\r
1215 wp.showCmd = nCmdShow;
\r
1216 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1217 wp.rcNormalPosition.left = wpMain.x;
\r
1218 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1219 wp.rcNormalPosition.top = wpMain.y;
\r
1220 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1221 SetWindowPlacement(hwndMain, &wp);
\r
1223 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1225 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1226 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1228 if (hwndConsole) {
\r
1230 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1231 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1233 ShowWindow(hwndConsole, nCmdShow);
\r
1234 SetActiveWindow(hwndConsole);
\r
1236 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1237 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1246 HMENU hmenu = GetMenu(hwndMain);
\r
1248 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1249 MF_BYCOMMAND|((appData.icsActive &&
\r
1250 *appData.icsCommPort != NULLCHAR) ?
\r
1251 MF_ENABLED : MF_GRAYED));
\r
1252 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1253 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1254 MF_CHECKED : MF_UNCHECKED));
\r
1255 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1258 //---------------------------------------------------------------------------------------------------------
\r
1260 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1261 #define XBOARD FALSE
\r
1263 #define OPTCHAR "/"
\r
1264 #define SEPCHAR "="
\r
1265 #define TOPLEVEL 0
\r
1269 // front-end part of option handling
\r
1272 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1274 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1275 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1278 lf->lfEscapement = 0;
\r
1279 lf->lfOrientation = 0;
\r
1280 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1281 lf->lfItalic = mfp->italic;
\r
1282 lf->lfUnderline = mfp->underline;
\r
1283 lf->lfStrikeOut = mfp->strikeout;
\r
1284 lf->lfCharSet = mfp->charset;
\r
1285 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1289 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1290 lf->lfQuality = DEFAULT_QUALITY;
\r
1291 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1292 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1296 CreateFontInMF(MyFont *mf)
\r
1298 LFfromMFP(&mf->lf, &mf->mfp);
\r
1299 if (mf->hf) DeleteObject(mf->hf);
\r
1300 mf->hf = CreateFontIndirect(&mf->lf);
\r
1303 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1305 colorVariable[] = {
\r
1306 &whitePieceColor,
\r
1307 &blackPieceColor,
\r
1308 &lightSquareColor,
\r
1309 &darkSquareColor,
\r
1310 &highlightSquareColor,
\r
1311 &premoveHighlightColor,
\r
1313 &consoleBackgroundColor,
\r
1314 &appData.fontForeColorWhite,
\r
1315 &appData.fontBackColorWhite,
\r
1316 &appData.fontForeColorBlack,
\r
1317 &appData.fontBackColorBlack,
\r
1318 &appData.evalHistColorWhite,
\r
1319 &appData.evalHistColorBlack,
\r
1320 &appData.highlightArrowColor,
\r
1323 /* Command line font name parser. NULL name means do nothing.
\r
1324 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1325 For backward compatibility, syntax without the colon is also
\r
1326 accepted, but font names with digits in them won't work in that case.
\r
1329 ParseFontName(char *name, MyFontParams *mfp)
\r
1332 if (name == NULL) return;
\r
1334 q = strchr(p, ':');
\r
1336 if (q - p >= sizeof(mfp->faceName))
\r
1337 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1338 memcpy(mfp->faceName, p, q - p);
\r
1339 mfp->faceName[q - p] = NULLCHAR;
\r
1342 q = mfp->faceName;
\r
1344 while (*p && !isdigit(*p)) {
\r
1346 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1347 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1349 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1352 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1353 mfp->pointSize = (float) atof(p);
\r
1354 mfp->bold = (strchr(p, 'b') != NULL);
\r
1355 mfp->italic = (strchr(p, 'i') != NULL);
\r
1356 mfp->underline = (strchr(p, 'u') != NULL);
\r
1357 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1358 mfp->charset = DEFAULT_CHARSET;
\r
1359 q = strchr(p, 'c');
\r
1361 mfp->charset = (BYTE) atoi(q+1);
\r
1365 ParseFont(char *name, int number)
\r
1366 { // wrapper to shield back-end from 'font'
\r
1367 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1372 { // in WB we have a 2D array of fonts; this initializes their description
\r
1374 /* Point font array elements to structures and
\r
1375 parse default font names */
\r
1376 for (i=0; i<NUM_FONTS; i++) {
\r
1377 for (j=0; j<NUM_SIZES; j++) {
\r
1378 font[j][i] = &fontRec[j][i];
\r
1379 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1386 { // here we create the actual fonts from the selected descriptions
\r
1388 for (i=0; i<NUM_FONTS; i++) {
\r
1389 for (j=0; j<NUM_SIZES; j++) {
\r
1390 CreateFontInMF(font[j][i]);
\r
1394 /* Color name parser.
\r
1395 X version accepts X color names, but this one
\r
1396 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1398 ParseColorName(char *name)
\r
1400 int red, green, blue, count;
\r
1401 char buf[MSG_SIZ];
\r
1403 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1405 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1406 &red, &green, &blue);
\r
1409 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1410 DisplayError(buf, 0);
\r
1411 return RGB(0, 0, 0);
\r
1413 return PALETTERGB(red, green, blue);
\r
1417 ParseColor(int n, char *name)
\r
1418 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1419 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1423 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1425 char *e = argValue;
\r
1429 if (*e == 'b') eff |= CFE_BOLD;
\r
1430 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1431 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1432 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1433 else if (*e == '#' || isdigit(*e)) break;
\r
1437 *color = ParseColorName(e);
\r
1441 ParseTextAttribs(ColorClass cc, char *s)
\r
1442 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1443 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1444 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1448 ParseBoardSize(void *addr, char *name)
\r
1449 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1450 BoardSize bs = SizeTiny;
\r
1451 while (sizeInfo[bs].name != NULL) {
\r
1452 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1453 *(BoardSize *)addr = bs;
\r
1458 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1463 { // [HGM] import name from appData first
\r
1466 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1467 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1468 textAttribs[cc].sound.data = NULL;
\r
1469 MyLoadSound(&textAttribs[cc].sound);
\r
1471 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1472 textAttribs[cc].sound.name = strdup("");
\r
1473 textAttribs[cc].sound.data = NULL;
\r
1475 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1476 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1477 sounds[sc].data = NULL;
\r
1478 MyLoadSound(&sounds[sc]);
\r
1483 SetCommPortDefaults()
\r
1485 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1486 dcb.DCBlength = sizeof(DCB);
\r
1487 dcb.BaudRate = 9600;
\r
1488 dcb.fBinary = TRUE;
\r
1489 dcb.fParity = FALSE;
\r
1490 dcb.fOutxCtsFlow = FALSE;
\r
1491 dcb.fOutxDsrFlow = FALSE;
\r
1492 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1493 dcb.fDsrSensitivity = FALSE;
\r
1494 dcb.fTXContinueOnXoff = TRUE;
\r
1495 dcb.fOutX = FALSE;
\r
1497 dcb.fNull = FALSE;
\r
1498 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1499 dcb.fAbortOnError = FALSE;
\r
1501 dcb.Parity = SPACEPARITY;
\r
1502 dcb.StopBits = ONESTOPBIT;
\r
1505 // [HGM] args: these three cases taken out to stay in front-end
\r
1507 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1508 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1509 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1510 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1512 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1513 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1514 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1515 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1516 ad->argName, mfp->faceName, mfp->pointSize,
\r
1517 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1518 mfp->bold ? "b" : "",
\r
1519 mfp->italic ? "i" : "",
\r
1520 mfp->underline ? "u" : "",
\r
1521 mfp->strikeout ? "s" : "",
\r
1522 (int)mfp->charset);
\r
1528 { // [HGM] copy the names from the internal WB variables to appData
\r
1531 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1532 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1533 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1534 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1538 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1539 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1540 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1541 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1542 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1543 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1544 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1545 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1546 (ta->effects) ? " " : "",
\r
1547 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1551 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1552 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1553 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1554 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1555 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1559 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1560 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1561 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1565 ParseCommPortSettings(char *s)
\r
1566 { // wrapper to keep dcb from back-end
\r
1567 ParseCommSettings(s, &dcb);
\r
1572 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1573 GetActualPlacement(hwndMain, &wpMain);
\r
1574 GetActualPlacement(hwndConsole, &wpConsole);
\r
1575 GetActualPlacement(commentDialog, &wpComment);
\r
1576 GetActualPlacement(editTagsDialog, &wpTags);
\r
1577 GetActualPlacement(gameListDialog, &wpGameList);
\r
1578 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1579 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1580 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1584 PrintCommPortSettings(FILE *f, char *name)
\r
1585 { // wrapper to shield back-end from DCB
\r
1586 PrintCommSettings(f, name, &dcb);
\r
1590 MySearchPath(char *installDir, char *name, char *fullname)
\r
1592 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1593 if(name[0]== '%') {
\r
1594 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1595 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1596 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1597 *strchr(buf, '%') = 0;
\r
1598 strcat(fullname, getenv(buf));
\r
1599 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1601 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1602 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1603 return (int) strlen(fullname);
\r
1605 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1609 MyGetFullPathName(char *name, char *fullname)
\r
1612 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1617 { // [HGM] args: allows testing if main window is realized from back-end
\r
1618 return hwndMain != NULL;
\r
1622 PopUpStartupDialog()
\r
1626 LoadLanguageFile(appData.language);
\r
1627 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1628 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1629 FreeProcInstance(lpProc);
\r
1632 /*---------------------------------------------------------------------------*\
\r
1634 * GDI board drawing routines
\r
1636 \*---------------------------------------------------------------------------*/
\r
1638 /* [AS] Draw square using background texture */
\r
1639 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1644 return; /* Should never happen! */
\r
1647 SetGraphicsMode( dst, GM_ADVANCED );
\r
1654 /* X reflection */
\r
1659 x.eDx = (FLOAT) dw + dx - 1;
\r
1662 SetWorldTransform( dst, &x );
\r
1665 /* Y reflection */
\r
1671 x.eDy = (FLOAT) dh + dy - 1;
\r
1673 SetWorldTransform( dst, &x );
\r
1681 x.eDx = (FLOAT) dx;
\r
1682 x.eDy = (FLOAT) dy;
\r
1685 SetWorldTransform( dst, &x );
\r
1689 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1697 SetWorldTransform( dst, &x );
\r
1699 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1702 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1704 PM_WP = (int) WhitePawn,
\r
1705 PM_WN = (int) WhiteKnight,
\r
1706 PM_WB = (int) WhiteBishop,
\r
1707 PM_WR = (int) WhiteRook,
\r
1708 PM_WQ = (int) WhiteQueen,
\r
1709 PM_WF = (int) WhiteFerz,
\r
1710 PM_WW = (int) WhiteWazir,
\r
1711 PM_WE = (int) WhiteAlfil,
\r
1712 PM_WM = (int) WhiteMan,
\r
1713 PM_WO = (int) WhiteCannon,
\r
1714 PM_WU = (int) WhiteUnicorn,
\r
1715 PM_WH = (int) WhiteNightrider,
\r
1716 PM_WA = (int) WhiteAngel,
\r
1717 PM_WC = (int) WhiteMarshall,
\r
1718 PM_WAB = (int) WhiteCardinal,
\r
1719 PM_WD = (int) WhiteDragon,
\r
1720 PM_WL = (int) WhiteLance,
\r
1721 PM_WS = (int) WhiteCobra,
\r
1722 PM_WV = (int) WhiteFalcon,
\r
1723 PM_WSG = (int) WhiteSilver,
\r
1724 PM_WG = (int) WhiteGrasshopper,
\r
1725 PM_WK = (int) WhiteKing,
\r
1726 PM_BP = (int) BlackPawn,
\r
1727 PM_BN = (int) BlackKnight,
\r
1728 PM_BB = (int) BlackBishop,
\r
1729 PM_BR = (int) BlackRook,
\r
1730 PM_BQ = (int) BlackQueen,
\r
1731 PM_BF = (int) BlackFerz,
\r
1732 PM_BW = (int) BlackWazir,
\r
1733 PM_BE = (int) BlackAlfil,
\r
1734 PM_BM = (int) BlackMan,
\r
1735 PM_BO = (int) BlackCannon,
\r
1736 PM_BU = (int) BlackUnicorn,
\r
1737 PM_BH = (int) BlackNightrider,
\r
1738 PM_BA = (int) BlackAngel,
\r
1739 PM_BC = (int) BlackMarshall,
\r
1740 PM_BG = (int) BlackGrasshopper,
\r
1741 PM_BAB = (int) BlackCardinal,
\r
1742 PM_BD = (int) BlackDragon,
\r
1743 PM_BL = (int) BlackLance,
\r
1744 PM_BS = (int) BlackCobra,
\r
1745 PM_BV = (int) BlackFalcon,
\r
1746 PM_BSG = (int) BlackSilver,
\r
1747 PM_BK = (int) BlackKing
\r
1750 static HFONT hPieceFont = NULL;
\r
1751 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1752 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1753 static int fontBitmapSquareSize = 0;
\r
1754 static char pieceToFontChar[(int) EmptySquare] =
\r
1755 { 'p', 'n', 'b', 'r', 'q',
\r
1756 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1757 'k', 'o', 'm', 'v', 't', 'w',
\r
1758 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1761 extern BOOL SetCharTable( char *table, const char * map );
\r
1762 /* [HGM] moved to backend.c */
\r
1764 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1767 BYTE r1 = GetRValue( color );
\r
1768 BYTE g1 = GetGValue( color );
\r
1769 BYTE b1 = GetBValue( color );
\r
1775 /* Create a uniform background first */
\r
1776 hbrush = CreateSolidBrush( color );
\r
1777 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1778 FillRect( hdc, &rc, hbrush );
\r
1779 DeleteObject( hbrush );
\r
1782 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1783 int steps = squareSize / 2;
\r
1786 for( i=0; i<steps; i++ ) {
\r
1787 BYTE r = r1 - (r1-r2) * i / steps;
\r
1788 BYTE g = g1 - (g1-g2) * i / steps;
\r
1789 BYTE b = b1 - (b1-b2) * i / steps;
\r
1791 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1792 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1793 FillRect( hdc, &rc, hbrush );
\r
1794 DeleteObject(hbrush);
\r
1797 else if( mode == 2 ) {
\r
1798 /* Diagonal gradient, good more or less for every piece */
\r
1799 POINT triangle[3];
\r
1800 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1801 HBRUSH hbrush_old;
\r
1802 int steps = squareSize;
\r
1805 triangle[0].x = squareSize - steps;
\r
1806 triangle[0].y = squareSize;
\r
1807 triangle[1].x = squareSize;
\r
1808 triangle[1].y = squareSize;
\r
1809 triangle[2].x = squareSize;
\r
1810 triangle[2].y = squareSize - steps;
\r
1812 for( i=0; i<steps; i++ ) {
\r
1813 BYTE r = r1 - (r1-r2) * i / steps;
\r
1814 BYTE g = g1 - (g1-g2) * i / steps;
\r
1815 BYTE b = b1 - (b1-b2) * i / steps;
\r
1817 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1818 hbrush_old = SelectObject( hdc, hbrush );
\r
1819 Polygon( hdc, triangle, 3 );
\r
1820 SelectObject( hdc, hbrush_old );
\r
1821 DeleteObject(hbrush);
\r
1826 SelectObject( hdc, hpen );
\r
1831 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1832 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1833 piece: follow the steps as explained below.
\r
1835 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1839 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1845 int backColor = whitePieceColor;
\r
1846 int foreColor = blackPieceColor;
\r
1848 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1849 backColor = appData.fontBackColorWhite;
\r
1850 foreColor = appData.fontForeColorWhite;
\r
1852 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1853 backColor = appData.fontBackColorBlack;
\r
1854 foreColor = appData.fontForeColorBlack;
\r
1858 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1860 hbm_old = SelectObject( hdc, hbm );
\r
1864 rc.right = squareSize;
\r
1865 rc.bottom = squareSize;
\r
1867 /* Step 1: background is now black */
\r
1868 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1870 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1872 pt.x = (squareSize - sz.cx) / 2;
\r
1873 pt.y = (squareSize - sz.cy) / 2;
\r
1875 SetBkMode( hdc, TRANSPARENT );
\r
1876 SetTextColor( hdc, chroma );
\r
1877 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1878 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1880 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1881 /* Step 3: the area outside the piece is filled with white */
\r
1882 // FloodFill( hdc, 0, 0, chroma );
\r
1883 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1884 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1885 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1886 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1887 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1889 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1890 but if the start point is not inside the piece we're lost!
\r
1891 There should be a better way to do this... if we could create a region or path
\r
1892 from the fill operation we would be fine for example.
\r
1894 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1895 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1897 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1898 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1899 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1901 SelectObject( dc2, bm2 );
\r
1902 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1903 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1904 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1905 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1906 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1909 DeleteObject( bm2 );
\r
1912 SetTextColor( hdc, 0 );
\r
1914 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1915 draw the piece again in black for safety.
\r
1917 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1919 SelectObject( hdc, hbm_old );
\r
1921 if( hPieceMask[index] != NULL ) {
\r
1922 DeleteObject( hPieceMask[index] );
\r
1925 hPieceMask[index] = hbm;
\r
1928 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1930 SelectObject( hdc, hbm );
\r
1933 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1934 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1935 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1937 SelectObject( dc1, hPieceMask[index] );
\r
1938 SelectObject( dc2, bm2 );
\r
1939 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1940 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1943 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1944 the piece background and deletes (makes transparent) the rest.
\r
1945 Thanks to that mask, we are free to paint the background with the greates
\r
1946 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1947 We use this, to make gradients and give the pieces a "roundish" look.
\r
1949 SetPieceBackground( hdc, backColor, 2 );
\r
1950 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1954 DeleteObject( bm2 );
\r
1957 SetTextColor( hdc, foreColor );
\r
1958 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1960 SelectObject( hdc, hbm_old );
\r
1962 if( hPieceFace[index] != NULL ) {
\r
1963 DeleteObject( hPieceFace[index] );
\r
1966 hPieceFace[index] = hbm;
\r
1969 static int TranslatePieceToFontPiece( int piece )
\r
1999 case BlackMarshall:
\r
2003 case BlackNightrider:
\r
2009 case BlackUnicorn:
\r
2013 case BlackGrasshopper:
\r
2025 case BlackCardinal:
\r
2032 case WhiteMarshall:
\r
2036 case WhiteNightrider:
\r
2042 case WhiteUnicorn:
\r
2046 case WhiteGrasshopper:
\r
2058 case WhiteCardinal:
\r
2067 void CreatePiecesFromFont()
\r
2070 HDC hdc_window = NULL;
\r
2076 if( fontBitmapSquareSize < 0 ) {
\r
2077 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2081 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2082 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2083 fontBitmapSquareSize = -1;
\r
2087 if( fontBitmapSquareSize != squareSize ) {
\r
2088 hdc_window = GetDC( hwndMain );
\r
2089 hdc = CreateCompatibleDC( hdc_window );
\r
2091 if( hPieceFont != NULL ) {
\r
2092 DeleteObject( hPieceFont );
\r
2095 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2096 hPieceMask[i] = NULL;
\r
2097 hPieceFace[i] = NULL;
\r
2103 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2104 fontHeight = appData.fontPieceSize;
\r
2107 fontHeight = (fontHeight * squareSize) / 100;
\r
2109 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2111 lf.lfEscapement = 0;
\r
2112 lf.lfOrientation = 0;
\r
2113 lf.lfWeight = FW_NORMAL;
\r
2115 lf.lfUnderline = 0;
\r
2116 lf.lfStrikeOut = 0;
\r
2117 lf.lfCharSet = DEFAULT_CHARSET;
\r
2118 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2119 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2120 lf.lfQuality = PROOF_QUALITY;
\r
2121 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2122 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2123 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2125 hPieceFont = CreateFontIndirect( &lf );
\r
2127 if( hPieceFont == NULL ) {
\r
2128 fontBitmapSquareSize = -2;
\r
2131 /* Setup font-to-piece character table */
\r
2132 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2133 /* No (or wrong) global settings, try to detect the font */
\r
2134 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2136 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2138 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2139 /* DiagramTT* family */
\r
2140 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2142 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2143 /* Fairy symbols */
\r
2144 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2146 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2147 /* Good Companion (Some characters get warped as literal :-( */
\r
2148 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2149 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2150 SetCharTable(pieceToFontChar, s);
\r
2153 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2154 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2158 /* Create bitmaps */
\r
2159 hfont_old = SelectObject( hdc, hPieceFont );
\r
2160 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2161 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2162 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2164 SelectObject( hdc, hfont_old );
\r
2166 fontBitmapSquareSize = squareSize;
\r
2170 if( hdc != NULL ) {
\r
2174 if( hdc_window != NULL ) {
\r
2175 ReleaseDC( hwndMain, hdc_window );
\r
2180 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2182 char name[128], buf[MSG_SIZ];
\r
2184 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2185 if(appData.pieceDirectory[0]) {
\r
2187 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2188 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2189 if(res) return res;
\r
2191 if (gameInfo.event &&
\r
2192 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2193 strcmp(name, "k80s") == 0) {
\r
2194 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2196 return LoadBitmap(hinst, name);
\r
2200 /* Insert a color into the program's logical palette
\r
2201 structure. This code assumes the given color is
\r
2202 the result of the RGB or PALETTERGB macro, and it
\r
2203 knows how those macros work (which is documented).
\r
2206 InsertInPalette(COLORREF color)
\r
2208 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2210 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2211 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2212 pLogPal->palNumEntries--;
\r
2216 pe->peFlags = (char) 0;
\r
2217 pe->peRed = (char) (0xFF & color);
\r
2218 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2219 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2225 InitDrawingColors()
\r
2228 if (pLogPal == NULL) {
\r
2229 /* Allocate enough memory for a logical palette with
\r
2230 * PALETTESIZE entries and set the size and version fields
\r
2231 * of the logical palette structure.
\r
2233 pLogPal = (NPLOGPALETTE)
\r
2234 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2235 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2236 pLogPal->palVersion = 0x300;
\r
2238 pLogPal->palNumEntries = 0;
\r
2240 InsertInPalette(lightSquareColor);
\r
2241 InsertInPalette(darkSquareColor);
\r
2242 InsertInPalette(whitePieceColor);
\r
2243 InsertInPalette(blackPieceColor);
\r
2244 InsertInPalette(highlightSquareColor);
\r
2245 InsertInPalette(premoveHighlightColor);
\r
2247 /* create a logical color palette according the information
\r
2248 * in the LOGPALETTE structure.
\r
2250 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2252 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2253 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2254 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2255 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2256 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2257 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2258 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2259 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2261 /* [AS] Force rendering of the font-based pieces */
\r
2262 if( fontBitmapSquareSize > 0 ) {
\r
2263 fontBitmapSquareSize = 0;
\r
2269 BoardWidth(int boardSize, int n)
\r
2270 { /* [HGM] argument n added to allow different width and height */
\r
2271 int lineGap = sizeInfo[boardSize].lineGap;
\r
2273 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2274 lineGap = appData.overrideLineGap;
\r
2277 return (n + 1) * lineGap +
\r
2278 n * sizeInfo[boardSize].squareSize;
\r
2281 /* Respond to board resize by dragging edge */
\r
2283 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2285 BoardSize newSize = NUM_SIZES - 1;
\r
2286 static int recurse = 0;
\r
2287 if (IsIconic(hwndMain)) return;
\r
2288 if (recurse > 0) return;
\r
2290 while (newSize > 0) {
\r
2291 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2292 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2293 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2296 boardSize = newSize;
\r
2297 InitDrawingSizes(boardSize, flags);
\r
2302 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2305 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2307 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2308 ChessSquare piece;
\r
2309 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2311 SIZE clockSize, messageSize;
\r
2313 char buf[MSG_SIZ];
\r
2315 HMENU hmenu = GetMenu(hwndMain);
\r
2316 RECT crect, wrect, oldRect;
\r
2318 LOGBRUSH logbrush;
\r
2319 VariantClass v = gameInfo.variant;
\r
2321 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2322 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2324 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2325 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2326 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2327 oldBoardSize = boardSize;
\r
2329 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2330 { // correct board size to one where built-in pieces exist
\r
2331 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2332 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2334 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2335 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2336 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2337 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2338 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2339 boardSize = SizeMiddling;
\r
2342 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2344 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2345 oldRect.top = wpMain.y;
\r
2346 oldRect.right = wpMain.x + wpMain.width;
\r
2347 oldRect.bottom = wpMain.y + wpMain.height;
\r
2349 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2350 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2351 squareSize = sizeInfo[boardSize].squareSize;
\r
2352 lineGap = sizeInfo[boardSize].lineGap;
\r
2353 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2354 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2356 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2357 lineGap = appData.overrideLineGap;
\r
2360 if (tinyLayout != oldTinyLayout) {
\r
2361 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2362 if (tinyLayout == 2) {
\r
2363 style &= ~WS_SYSMENU;
\r
2364 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2365 "&Minimize\tCtrl+F4");
\r
2367 style |= WS_SYSMENU;
\r
2368 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2370 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2372 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2373 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2374 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2376 DrawMenuBar(hwndMain);
\r
2379 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2380 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2382 /* Get text area sizes */
\r
2383 hdc = GetDC(hwndMain);
\r
2384 if (appData.clockMode) {
\r
2385 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2387 snprintf(buf, MSG_SIZ, _("White"));
\r
2389 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2390 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2391 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2392 str = _("We only care about the height here");
\r
2393 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2394 SelectObject(hdc, oldFont);
\r
2395 ReleaseDC(hwndMain, hdc);
\r
2397 /* Compute where everything goes */
\r
2398 if((first.programLogo || second.programLogo) && tinyLayout != 2) {
\r
2399 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2400 logoHeight = 2*clockSize.cy;
\r
2401 leftLogoRect.left = OUTER_MARGIN;
\r
2402 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2403 leftLogoRect.top = OUTER_MARGIN;
\r
2404 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2406 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2407 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2408 rightLogoRect.top = OUTER_MARGIN;
\r
2409 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2412 whiteRect.left = leftLogoRect.right;
\r
2413 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2414 whiteRect.top = OUTER_MARGIN;
\r
2415 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2417 blackRect.right = rightLogoRect.left;
\r
2418 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2419 blackRect.top = whiteRect.top;
\r
2420 blackRect.bottom = whiteRect.bottom;
\r
2422 whiteRect.left = OUTER_MARGIN;
\r
2423 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2424 whiteRect.top = OUTER_MARGIN;
\r
2425 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2427 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2428 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2429 blackRect.top = whiteRect.top;
\r
2430 blackRect.bottom = whiteRect.bottom;
\r
2432 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2435 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2436 if (appData.showButtonBar) {
\r
2437 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2438 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2440 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2442 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2443 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2445 boardRect.left = OUTER_MARGIN;
\r
2446 boardRect.right = boardRect.left + boardWidth;
\r
2447 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2448 boardRect.bottom = boardRect.top + boardHeight;
\r
2450 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2451 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2452 oldTinyLayout = tinyLayout;
\r
2453 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2454 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2455 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2456 winW *= 1 + twoBoards;
\r
2457 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2458 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2459 wpMain.height = winH; // without disturbing window attachments
\r
2460 GetWindowRect(hwndMain, &wrect);
\r
2461 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2462 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2464 // [HGM] placement: let attached windows follow size change.
\r
2465 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2466 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2467 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2468 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2469 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2471 /* compensate if menu bar wrapped */
\r
2472 GetClientRect(hwndMain, &crect);
\r
2473 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2474 wpMain.height += offby;
\r
2476 case WMSZ_TOPLEFT:
\r
2477 SetWindowPos(hwndMain, NULL,
\r
2478 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2479 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2482 case WMSZ_TOPRIGHT:
\r
2484 SetWindowPos(hwndMain, NULL,
\r
2485 wrect.left, wrect.bottom - wpMain.height,
\r
2486 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2489 case WMSZ_BOTTOMLEFT:
\r
2491 SetWindowPos(hwndMain, NULL,
\r
2492 wrect.right - wpMain.width, wrect.top,
\r
2493 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2496 case WMSZ_BOTTOMRIGHT:
\r
2500 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2501 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2506 for (i = 0; i < N_BUTTONS; i++) {
\r
2507 if (buttonDesc[i].hwnd != NULL) {
\r
2508 DestroyWindow(buttonDesc[i].hwnd);
\r
2509 buttonDesc[i].hwnd = NULL;
\r
2511 if (appData.showButtonBar) {
\r
2512 buttonDesc[i].hwnd =
\r
2513 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2514 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2515 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2516 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2517 (HMENU) buttonDesc[i].id,
\r
2518 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2519 if (tinyLayout == 2) {
\r
2520 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2521 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2522 MAKELPARAM(FALSE, 0));
\r
2524 if (buttonDesc[i].id == IDM_Pause)
\r
2525 hwndPause = buttonDesc[i].hwnd;
\r
2526 buttonDesc[i].wndproc = (WNDPROC)
\r
2527 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2530 if (gridPen != NULL) DeleteObject(gridPen);
\r
2531 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2532 if (premovePen != NULL) DeleteObject(premovePen);
\r
2533 if (lineGap != 0) {
\r
2534 logbrush.lbStyle = BS_SOLID;
\r
2535 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2537 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2538 lineGap, &logbrush, 0, NULL);
\r
2539 logbrush.lbColor = highlightSquareColor;
\r
2541 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2542 lineGap, &logbrush, 0, NULL);
\r
2544 logbrush.lbColor = premoveHighlightColor;
\r
2546 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2547 lineGap, &logbrush, 0, NULL);
\r
2549 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2550 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2551 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2552 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2553 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2554 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2555 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2556 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2558 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2559 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2560 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2561 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2562 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2563 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2564 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2565 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2569 /* [HGM] Licensing requirement */
\r
2571 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2574 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2576 GothicPopUp( "", VariantNormal);
\r
2579 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2581 /* Load piece bitmaps for this board size */
\r
2582 for (i=0; i<=2; i++) {
\r
2583 for (piece = WhitePawn;
\r
2584 (int) piece < (int) BlackPawn;
\r
2585 piece = (ChessSquare) ((int) piece + 1)) {
\r
2586 if (pieceBitmap[i][piece] != NULL)
\r
2587 DeleteObject(pieceBitmap[i][piece]);
\r
2591 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2592 // Orthodox Chess pieces
\r
2593 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2594 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2595 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2596 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2597 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2598 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2599 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2600 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2601 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2602 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2603 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2604 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2605 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2606 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2607 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2608 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2609 // in Shogi, Hijack the unused Queen for Lance
\r
2610 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2611 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2612 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2614 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2619 if(squareSize <= 72 && squareSize >= 33) {
\r
2620 /* A & C are available in most sizes now */
\r
2621 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2622 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2623 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2624 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2625 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2626 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2627 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2628 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2629 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2630 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2631 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2632 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2633 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2634 } else { // Smirf-like
\r
2635 if(gameInfo.variant == VariantSChess) {
\r
2636 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2637 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2638 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2640 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2641 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2642 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2645 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2646 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2647 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2648 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2649 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2650 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2653 } else { // WinBoard standard
\r
2654 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2655 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2656 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2661 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2662 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2663 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2664 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2665 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2666 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2667 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2668 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2669 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2670 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2671 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2672 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2673 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2674 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2677 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2678 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2679 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2680 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2681 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2682 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2683 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2684 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2685 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2686 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2687 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2688 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2689 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2690 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2691 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2692 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2693 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2694 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2696 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2697 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2698 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2699 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2700 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2701 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2702 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2703 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2704 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2705 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2706 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2707 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2708 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2710 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2711 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2712 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2713 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2714 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2715 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2716 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2717 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2718 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2719 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2720 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2721 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2724 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2725 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2726 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2727 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2728 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2729 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2730 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2731 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2732 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2733 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2734 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2735 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2736 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2737 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2738 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2742 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2743 /* special Shogi support in this size */
\r
2744 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2745 for (piece = WhitePawn;
\r
2746 (int) piece < (int) BlackPawn;
\r
2747 piece = (ChessSquare) ((int) piece + 1)) {
\r
2748 if (pieceBitmap[i][piece] != NULL)
\r
2749 DeleteObject(pieceBitmap[i][piece]);
\r
2752 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2753 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2754 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2755 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2756 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2757 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2758 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2762 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2763 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2764 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2765 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2766 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2767 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2768 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2769 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2770 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2771 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2772 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2776 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2777 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2778 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2779 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2780 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2781 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2782 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2783 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2784 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2785 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2786 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2790 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2791 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2792 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2793 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2799 PieceBitmap(ChessSquare p, int kind)
\r
2801 if ((int) p >= (int) BlackPawn)
\r
2802 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2804 return pieceBitmap[kind][(int) p];
\r
2807 /***************************************************************/
\r
2809 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2810 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2812 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2813 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2817 SquareToPos(int row, int column, int * x, int * y)
\r
2820 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2821 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2823 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2824 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2829 DrawCoordsOnDC(HDC hdc)
\r
2831 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2832 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2833 char str[2] = { NULLCHAR, NULLCHAR };
\r
2834 int oldMode, oldAlign, x, y, start, i;
\r
2838 if (!appData.showCoords)
\r
2841 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2843 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2844 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2845 oldAlign = GetTextAlign(hdc);
\r
2846 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2848 y = boardRect.top + lineGap;
\r
2849 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2852 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2853 x += border - lineGap - 4; y += squareSize - 6;
\r
2855 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2856 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2857 str[0] = files[start + i];
\r
2858 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2859 y += squareSize + lineGap;
\r
2862 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2865 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2866 x += -border + 4; y += border - squareSize + 6;
\r
2868 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2869 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2870 str[0] = ranks[start + i];
\r
2871 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2872 x += squareSize + lineGap;
\r
2875 SelectObject(hdc, oldBrush);
\r
2876 SetBkMode(hdc, oldMode);
\r
2877 SetTextAlign(hdc, oldAlign);
\r
2878 SelectObject(hdc, oldFont);
\r
2882 DrawGridOnDC(HDC hdc)
\r
2886 if (lineGap != 0) {
\r
2887 oldPen = SelectObject(hdc, gridPen);
\r
2888 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2889 SelectObject(hdc, oldPen);
\r
2893 #define HIGHLIGHT_PEN 0
\r
2894 #define PREMOVE_PEN 1
\r
2897 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2900 HPEN oldPen, hPen;
\r
2901 if (lineGap == 0) return;
\r
2903 x1 = boardRect.left +
\r
2904 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2905 y1 = boardRect.top +
\r
2906 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2908 x1 = boardRect.left +
\r
2909 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2910 y1 = boardRect.top +
\r
2911 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2913 hPen = pen ? premovePen : highlightPen;
\r
2914 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2915 MoveToEx(hdc, x1, y1, NULL);
\r
2916 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2917 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2918 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2919 LineTo(hdc, x1, y1);
\r
2920 SelectObject(hdc, oldPen);
\r
2924 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2927 for (i=0; i<2; i++) {
\r
2928 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2929 DrawHighlightOnDC(hdc, TRUE,
\r
2930 h->sq[i].x, h->sq[i].y,
\r
2935 /* Note: sqcolor is used only in monoMode */
\r
2936 /* Note that this code is largely duplicated in woptions.c,
\r
2937 function DrawSampleSquare, so that needs to be updated too */
\r
2939 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2941 HBITMAP oldBitmap;
\r
2945 if (appData.blindfold) return;
\r
2947 /* [AS] Use font-based pieces if needed */
\r
2948 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2949 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2950 CreatePiecesFromFont();
\r
2952 if( fontBitmapSquareSize == squareSize ) {
\r
2953 int index = TranslatePieceToFontPiece(piece);
\r
2955 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2957 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2958 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2962 squareSize, squareSize,
\r
2967 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2969 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2970 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2974 squareSize, squareSize,
\r
2983 if (appData.monoMode) {
\r
2984 SelectObject(tmphdc, PieceBitmap(piece,
\r
2985 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2986 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2987 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2989 HBRUSH xBrush = whitePieceBrush;
\r
2990 tmpSize = squareSize;
\r
2991 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2993 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2994 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2995 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2996 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2997 x += (squareSize - minorSize)>>1;
\r
2998 y += squareSize - minorSize - 2;
\r
2999 tmpSize = minorSize;
\r
3001 if (color || appData.allWhite ) {
\r
3002 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3004 oldBrush = SelectObject(hdc, xBrush);
\r
3005 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3006 if(appData.upsideDown && color==flipView)
\r
3007 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3009 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3010 /* Use black for outline of white pieces */
\r
3011 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3012 if(appData.upsideDown && color==flipView)
\r
3013 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3015 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3016 } else if(appData.pieceDirectory[0]) {
\r
3017 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3018 oldBrush = SelectObject(hdc, xBrush);
\r
3019 if(appData.upsideDown && color==flipView)
\r
3020 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3022 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3023 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3024 if(appData.upsideDown && color==flipView)
\r
3025 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3027 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3029 /* Use square color for details of black pieces */
\r
3030 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3031 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3032 if(appData.upsideDown && !flipView)
\r
3033 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3035 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3037 SelectObject(hdc, oldBrush);
\r
3038 SelectObject(tmphdc, oldBitmap);
\r
3042 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3043 int GetBackTextureMode( int algo )
\r
3045 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3049 case BACK_TEXTURE_MODE_PLAIN:
\r
3050 result = 1; /* Always use identity map */
\r
3052 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3053 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3061 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3062 to handle redraws cleanly (as random numbers would always be different).
\r
3064 VOID RebuildTextureSquareInfo()
\r
3074 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3076 if( liteBackTexture != NULL ) {
\r
3077 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3078 lite_w = bi.bmWidth;
\r
3079 lite_h = bi.bmHeight;
\r
3083 if( darkBackTexture != NULL ) {
\r
3084 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3085 dark_w = bi.bmWidth;
\r
3086 dark_h = bi.bmHeight;
\r
3090 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3091 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3092 if( (col + row) & 1 ) {
\r
3094 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3095 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3096 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3098 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3099 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3100 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3102 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3103 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3108 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3109 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3110 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3112 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3113 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3114 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3116 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3117 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3124 /* [AS] Arrow highlighting support */
\r
3126 static double A_WIDTH = 5; /* Width of arrow body */
\r
3128 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3129 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3131 static double Sqr( double x )
\r
3136 static int Round( double x )
\r
3138 return (int) (x + 0.5);
\r
3141 /* Draw an arrow between two points using current settings */
\r
3142 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3145 double dx, dy, j, k, x, y;
\r
3147 if( d_x == s_x ) {
\r
3148 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3150 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3153 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3154 arrow[1].y = d_y - h;
\r
3156 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3157 arrow[2].y = d_y - h;
\r
3162 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3163 arrow[5].y = d_y - h;
\r
3165 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3166 arrow[4].y = d_y - h;
\r
3168 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3171 else if( d_y == s_y ) {
\r
3172 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3175 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3177 arrow[1].x = d_x - w;
\r
3178 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3180 arrow[2].x = d_x - w;
\r
3181 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3186 arrow[5].x = d_x - w;
\r
3187 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r