2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
95 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
98 void mysrandom(unsigned int seed);
\r
100 extern int whiteFlag, blackFlag;
\r
101 Boolean flipClock = FALSE;
\r
102 extern HANDLE chatHandle[];
\r
103 extern enum ICS_TYPE ics_type;
\r
105 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
106 int MyGetFullPathName P((char *name, char *fullname));
\r
107 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
108 VOID NewVariantPopup(HWND hwnd);
\r
109 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
110 /*char*/int promoChar));
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P((char *s));
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
132 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
135 POINT sq[2]; /* board coordinates of from, to squares */
\r
138 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
139 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
143 typedef struct { // [HGM] atomic
\r
144 int fromX, fromY, toX, toY, radius;
\r
147 static ExplodeInfo explodeInfo;
\r
149 /* Window class names */
\r
150 char szAppName[] = "WinBoard";
\r
151 char szConsoleName[] = "WBConsole";
\r
153 /* Title bar text */
\r
154 char szTitle[] = "WinBoard";
\r
155 char szConsoleTitle[] = "I C S Interaction";
\r
158 char *settingsFileName;
\r
159 Boolean saveSettingsOnExit;
\r
160 char installDir[MSG_SIZ];
\r
161 int errorExitStatus;
\r
163 BoardSize boardSize;
\r
164 Boolean chessProgram;
\r
165 //static int boardX, boardY;
\r
166 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
167 int squareSize, lineGap, minorSize, border;
\r
168 static int winW, winH;
\r
169 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
170 static int logoHeight = 0;
\r
171 static char messageText[MESSAGE_TEXT_MAX];
\r
172 static int clockTimerEvent = 0;
\r
173 static int loadGameTimerEvent = 0;
\r
174 static int analysisTimerEvent = 0;
\r
175 static DelayedEventCallback delayedTimerCallback;
\r
176 static int delayedTimerEvent = 0;
\r
177 static int buttonCount = 2;
\r
178 char *icsTextMenuString;
\r
180 char *firstChessProgramNames;
\r
181 char *secondChessProgramNames;
\r
183 #define PALETTESIZE 256
\r
185 HINSTANCE hInst; /* current instance */
\r
186 Boolean alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 static HWND savedHwnd;
\r
194 HWND hCommPort = NULL; /* currently open comm port */
\r
195 static HWND hwndPause; /* pause button */
\r
196 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
197 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
198 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
199 explodeBrush, /* [HGM] atomic */
\r
200 markerBrush, /* [HGM] markers */
\r
201 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
202 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
203 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
204 static HPEN gridPen = NULL;
\r
205 static HPEN highlightPen = NULL;
\r
206 static HPEN premovePen = NULL;
\r
207 static NPLOGPALETTE pLogPal;
\r
208 static BOOL paletteChanged = FALSE;
\r
209 static HICON iconWhite, iconBlack, iconCurrent;
\r
210 static int doingSizing = FALSE;
\r
211 static int lastSizing = 0;
\r
212 static int prevStderrPort;
\r
213 static HBITMAP userLogo;
\r
215 static HBITMAP liteBackTexture = NULL;
\r
216 static HBITMAP darkBackTexture = NULL;
\r
217 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
219 static int backTextureSquareSize = 0;
\r
220 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
222 #if __GNUC__ && !defined(_winmajor)
\r
223 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
226 #if defined(_winmajor)
\r
227 #define oldDialog (_winmajor < 4)
\r
229 #define oldDialog 0
\r
233 #define INTERNATIONAL
\r
235 #ifdef INTERNATIONAL
\r
236 # define _(s) T_(s)
\r
242 # define Translate(x, y)
\r
243 # define LoadLanguageFile(s)
\r
246 #ifdef INTERNATIONAL
\r
248 Boolean barbaric; // flag indicating if translation is needed
\r
250 // list of item numbers used in each dialog (used to alter language at run time)
\r
252 #define ABOUTBOX -1 /* not sure why these are needed */
\r
253 #define ABOUTBOX2 -1
\r
255 int dialogItems[][42] = {
\r
256 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
257 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
258 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
259 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
260 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
261 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
262 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
263 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
264 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
265 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
266 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
267 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
268 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
269 { ABOUTBOX2, IDC_ChessBoard },
\r
270 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
271 OPT_GameListClose, IDC_GameListDoFilter },
\r
272 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
273 { DLG_Error, IDOK },
\r
274 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
275 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
276 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
277 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
278 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
279 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
280 { DLG_IndexNumber, IDC_Index },
\r
281 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
282 { DLG_TypeInName, IDOK, IDCANCEL },
\r
283 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
284 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
285 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
286 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
287 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
288 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
289 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
290 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
291 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
292 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
293 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
294 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
295 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
296 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
297 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
298 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
299 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
300 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
301 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
302 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
303 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
304 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
305 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
306 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
307 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
308 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
309 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
310 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
311 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
312 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
313 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
314 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
315 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
316 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
317 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
318 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
319 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
320 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
321 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
322 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
323 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
324 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
325 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
326 { DLG_MoveHistory },
\r
327 { DLG_EvalGraph },
\r
328 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
329 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
330 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
331 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
332 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
333 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
334 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
335 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
336 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
340 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
341 static int lastChecked;
\r
342 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
343 extern int tinyLayout;
\r
344 extern char * menuBarText[][10];
\r
347 LoadLanguageFile(char *name)
\r
348 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
350 int i=0, j=0, n=0, k;
\r
353 if(!name || name[0] == NULLCHAR) return;
\r
354 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
355 appData.language = oldLanguage;
\r
356 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
357 if((f = fopen(buf, "r")) == NULL) return;
\r
358 while((k = fgetc(f)) != EOF) {
\r
359 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
360 languageBuf[i] = k;
\r
362 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
364 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
365 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
366 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
367 english[j] = languageBuf + n + 1; *p = 0;
\r
368 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
369 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
374 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
376 case 'n': k = '\n'; break;
\r
377 case 'r': k = '\r'; break;
\r
378 case 't': k = '\t'; break;
\r
380 languageBuf[--i] = k;
\r
385 barbaric = (j != 0);
\r
386 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
391 { // return the translation of the given string
\r
392 // efficiency can be improved a lot...
\r
394 static char buf[MSG_SIZ];
\r
395 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
396 if(!barbaric) return s;
\r
397 if(!s) return ""; // sanity
\r
398 while(english[i]) {
\r
399 if(!strcmp(s, english[i])) return foreign[i];
\r
400 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
401 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
410 Translate(HWND hDlg, int dialogID)
\r
411 { // translate all text items in the given dialog
\r
413 char buf[MSG_SIZ], *s;
\r
414 if(!barbaric) return;
\r
415 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
416 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
417 GetWindowText( hDlg, buf, MSG_SIZ );
\r
419 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
420 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
421 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
422 if(strlen(buf) == 0) continue;
\r
424 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
429 TranslateOneMenu(int i, HMENU subMenu)
\r
432 static MENUITEMINFO info;
\r
434 info.cbSize = sizeof(MENUITEMINFO);
\r
435 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
436 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
438 info.dwTypeData = buf;
\r
439 info.cch = sizeof(buf);
\r
440 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
442 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
443 else menuText[i][j] = strdup(buf); // remember original on first change
\r
445 if(buf[0] == NULLCHAR) continue;
\r
446 info.dwTypeData = T_(buf);
\r
447 info.cch = strlen(buf)+1;
\r
448 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
454 TranslateMenus(int addLanguage)
\r
457 WIN32_FIND_DATA fileData;
\r
459 #define IDM_English 1970
\r
461 HMENU mainMenu = GetMenu(hwndMain);
\r
462 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
463 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
464 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
465 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
466 TranslateOneMenu(i, subMenu);
\r
468 DrawMenuBar(hwndMain);
\r
471 if(!addLanguage) return;
\r
472 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
473 HMENU mainMenu = GetMenu(hwndMain);
\r
474 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
475 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
476 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
477 i = 0; lastChecked = IDM_English;
\r
479 char *p, *q = fileData.cFileName;
\r
480 int checkFlag = MF_UNCHECKED;
\r
481 languageFile[i] = strdup(q);
\r
482 if(barbaric && !strcmp(oldLanguage, q)) {
\r
483 checkFlag = MF_CHECKED;
\r
484 lastChecked = IDM_English + i + 1;
\r
485 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
487 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
488 p = strstr(fileData.cFileName, ".lng");
\r
490 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
491 } while(FindNextFile(hFind, &fileData));
\r
498 #define IDM_RecentEngines 3000
\r
501 RecentEngineMenu (char *s)
\r
503 if(appData.icsActive) return;
\r
504 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
505 HMENU mainMenu = GetMenu(hwndMain);
\r
506 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
507 int i=IDM_RecentEngines;
\r
508 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
509 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
511 char *p = strchr(s, '\n');
\r
512 if(p == NULL) return; // malformed!
\r
514 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
528 int cliWidth, cliHeight;
\r
531 SizeInfo sizeInfo[] =
\r
533 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
534 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
535 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
536 { "petite", 33, 1, 1, 1, 0, 0 },
\r
537 { "slim", 37, 2, 1, 0, 0, 0 },
\r
538 { "small", 40, 2, 1, 0, 0, 0 },
\r
539 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
540 { "middling", 49, 2, 0, 0, 0, 0 },
\r
541 { "average", 54, 2, 0, 0, 0, 0 },
\r
542 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
543 { "medium", 64, 3, 0, 0, 0, 0 },
\r
544 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
545 { "large", 80, 3, 0, 0, 0, 0 },
\r
546 { "big", 87, 3, 0, 0, 0, 0 },
\r
547 { "huge", 95, 3, 0, 0, 0, 0 },
\r
548 { "giant", 108, 3, 0, 0, 0, 0 },
\r
549 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
550 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
551 { NULL, 0, 0, 0, 0, 0, 0 }
\r
554 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
555 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
557 { 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
558 { 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
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
577 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
586 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
587 #define N_BUTTONS 5
\r
589 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
591 {"<<", IDM_ToStart, NULL, NULL},
\r
592 {"<", IDM_Backward, NULL, NULL},
\r
593 {"P", IDM_Pause, NULL, NULL},
\r
594 {">", IDM_Forward, NULL, NULL},
\r
595 {">>", IDM_ToEnd, NULL, NULL},
\r
598 int tinyLayout = 0, smallLayout = 0;
\r
599 #define MENU_BAR_ITEMS 9
\r
600 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
601 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
602 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
606 MySound sounds[(int)NSoundClasses];
\r
607 MyTextAttribs textAttribs[(int)NColorClasses];
\r
609 MyColorizeAttribs colorizeAttribs[] = {
\r
610 { (COLORREF)0, 0, N_("Shout Text") },
\r
611 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
612 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
613 { (COLORREF)0, 0, N_("Channel Text") },
\r
614 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
615 { (COLORREF)0, 0, N_("Tell Text") },
\r
616 { (COLORREF)0, 0, N_("Challenge Text") },
\r
617 { (COLORREF)0, 0, N_("Request Text") },
\r
618 { (COLORREF)0, 0, N_("Seek Text") },
\r
619 { (COLORREF)0, 0, N_("Normal Text") },
\r
620 { (COLORREF)0, 0, N_("None") }
\r
625 static char *commentTitle;
\r
626 static char *commentText;
\r
627 static int commentIndex;
\r
628 static Boolean editComment = FALSE;
\r
631 char errorTitle[MSG_SIZ];
\r
632 char errorMessage[2*MSG_SIZ];
\r
633 HWND errorDialog = NULL;
\r
634 BOOLEAN moveErrorMessageUp = FALSE;
\r
635 BOOLEAN consoleEcho = TRUE;
\r
636 CHARFORMAT consoleCF;
\r
637 COLORREF consoleBackgroundColor;
\r
639 char *programVersion;
\r
645 typedef int CPKind;
\r
654 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
657 #define INPUT_SOURCE_BUF_SIZE 4096
\r
659 typedef struct _InputSource {
\r
666 char buf[INPUT_SOURCE_BUF_SIZE];
\r
670 InputCallback func;
\r
671 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
675 InputSource *consoleInputSource;
\r
680 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
681 VOID ConsoleCreate();
\r
683 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
684 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
685 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
686 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
688 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
689 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
690 void ParseIcsTextMenu(char *icsTextMenuString);
\r
691 VOID PopUpNameDialog(char firstchar);
\r
692 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
696 int GameListOptions();
\r
698 int dummy; // [HGM] for obsolete args
\r
700 HWND hwndMain = NULL; /* root window*/
\r
701 HWND hwndConsole = NULL;
\r
702 HWND commentDialog = NULL;
\r
703 HWND moveHistoryDialog = NULL;
\r
704 HWND evalGraphDialog = NULL;
\r
705 HWND engineOutputDialog = NULL;
\r
706 HWND gameListDialog = NULL;
\r
707 HWND editTagsDialog = NULL;
\r
709 int commentUp = FALSE;
\r
711 WindowPlacement wpMain;
\r
712 WindowPlacement wpConsole;
\r
713 WindowPlacement wpComment;
\r
714 WindowPlacement wpMoveHistory;
\r
715 WindowPlacement wpEvalGraph;
\r
716 WindowPlacement wpEngineOutput;
\r
717 WindowPlacement wpGameList;
\r
718 WindowPlacement wpTags;
\r
720 VOID EngineOptionsPopup(); // [HGM] settings
\r
722 VOID GothicPopUp(char *title, VariantClass variant);
\r
724 * Setting "frozen" should disable all user input other than deleting
\r
725 * the window. We do this while engines are initializing themselves.
\r
727 static int frozen = 0;
\r
728 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
734 if (frozen) return;
\r
736 hmenu = GetMenu(hwndMain);
\r
737 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
738 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
740 DrawMenuBar(hwndMain);
\r
743 /* Undo a FreezeUI */
\r
749 if (!frozen) return;
\r
751 hmenu = GetMenu(hwndMain);
\r
752 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
753 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
755 DrawMenuBar(hwndMain);
\r
758 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
760 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
766 #define JAWS_ALT_INTERCEPT
\r
767 #define JAWS_KBUP_NAVIGATION
\r
768 #define JAWS_KBDOWN_NAVIGATION
\r
769 #define JAWS_MENU_ITEMS
\r
770 #define JAWS_SILENCE
\r
771 #define JAWS_REPLAY
\r
773 #define JAWS_COPYRIGHT
\r
774 #define JAWS_DELETE(X) X
\r
775 #define SAYMACHINEMOVE()
\r
779 /*---------------------------------------------------------------------------*\
\r
783 \*---------------------------------------------------------------------------*/
\r
786 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
787 LPSTR lpCmdLine, int nCmdShow)
\r
790 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
791 // INITCOMMONCONTROLSEX ex;
\r
795 LoadLibrary("RICHED32.DLL");
\r
796 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
798 if (!InitApplication(hInstance)) {
\r
801 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
808 // InitCommonControlsEx(&ex);
\r
809 InitCommonControls();
\r
811 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
812 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
813 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
815 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
817 while (GetMessage(&msg, /* message structure */
\r
818 NULL, /* handle of window receiving the message */
\r
819 0, /* lowest message to examine */
\r
820 0)) /* highest message to examine */
\r
823 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
824 // [HGM] navigate: switch between all windows with tab
\r
825 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
826 int i, currentElement = 0;
\r
828 // first determine what element of the chain we come from (if any)
\r
829 if(appData.icsActive) {
\r
830 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
831 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
833 if(engineOutputDialog && EngineOutputIsUp()) {
\r
834 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
835 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
837 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
838 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
840 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
841 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
842 if(msg.hwnd == e1) currentElement = 2; else
\r
843 if(msg.hwnd == e2) currentElement = 3; else
\r
844 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
845 if(msg.hwnd == mh) currentElement = 4; else
\r
846 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
847 if(msg.hwnd == hText) currentElement = 5; else
\r
848 if(msg.hwnd == hInput) currentElement = 6; else
\r
849 for (i = 0; i < N_BUTTONS; i++) {
\r
850 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
853 // determine where to go to
\r
854 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
856 currentElement = (currentElement + direction) % 7;
\r
857 switch(currentElement) {
\r
859 h = hwndMain; break; // passing this case always makes the loop exit
\r
861 h = buttonDesc[0].hwnd; break; // could be NULL
\r
863 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
866 if(!EngineOutputIsUp()) continue;
\r
869 if(!MoveHistoryIsUp()) continue;
\r
871 // case 6: // input to eval graph does not seem to get here!
\r
872 // if(!EvalGraphIsUp()) continue;
\r
873 // h = evalGraphDialog; break;
\r
875 if(!appData.icsActive) continue;
\r
879 if(!appData.icsActive) continue;
\r
885 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
886 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
889 continue; // this message now has been processed
\r
893 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
894 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
895 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
896 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
897 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
898 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
899 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
900 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
901 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
902 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
903 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
904 for(i=0; i<MAX_CHAT; i++)
\r
905 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
908 if(done) continue; // [HGM] chat: end patch
\r
909 TranslateMessage(&msg); /* Translates virtual key codes */
\r
910 DispatchMessage(&msg); /* Dispatches message to window */
\r
915 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
918 /*---------------------------------------------------------------------------*\
\r
920 * Initialization functions
\r
922 \*---------------------------------------------------------------------------*/
\r
926 { // update user logo if necessary
\r
927 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
929 if(appData.autoLogo) {
\r
930 curName = UserName();
\r
931 if(strcmp(curName, oldUserName)) {
\r
932 GetCurrentDirectory(MSG_SIZ, dir);
\r
933 SetCurrentDirectory(installDir);
\r
934 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
935 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
936 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
937 if(userLogo == NULL)
\r
938 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
939 SetCurrentDirectory(dir); /* return to prev directory */
\r
945 InitApplication(HINSTANCE hInstance)
\r
949 /* Fill in window class structure with parameters that describe the */
\r
952 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
953 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
954 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
955 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
956 wc.hInstance = hInstance; /* Owner of this class */
\r
957 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
958 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
959 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
960 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
961 wc.lpszClassName = szAppName; /* Name to register as */
\r
963 /* Register the window class and return success/failure code. */
\r
964 if (!RegisterClass(&wc)) return FALSE;
\r
966 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
967 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
969 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
970 wc.hInstance = hInstance;
\r
971 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
972 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
973 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
974 wc.lpszMenuName = NULL;
\r
975 wc.lpszClassName = szConsoleName;
\r
977 if (!RegisterClass(&wc)) return FALSE;
\r
982 /* Set by InitInstance, used by EnsureOnScreen */
\r
983 int screenHeight, screenWidth;
\r
986 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
988 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
989 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
990 if (*x > screenWidth - 32) *x = 0;
\r
991 if (*y > screenHeight - 32) *y = 0;
\r
992 if (*x < minX) *x = minX;
\r
993 if (*y < minY) *y = minY;
\r
997 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
999 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1000 GetCurrentDirectory(MSG_SIZ, dir);
\r
1001 SetCurrentDirectory(installDir);
\r
1002 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1003 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1005 if (cps->programLogo == NULL && appData.debugMode) {
\r
1006 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1008 } else if(appData.autoLogo) {
\r
1009 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1010 char *opponent = "";
\r
1011 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1012 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1013 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1014 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1015 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1016 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1019 if(appData.directory[n] && appData.directory[n][0]) {
\r
1020 SetCurrentDirectory(appData.directory[n]);
\r
1021 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1024 SetCurrentDirectory(dir); /* return to prev directory */
\r
1030 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1031 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1033 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1034 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1035 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1036 liteBackTextureMode = appData.liteBackTextureMode;
\r
1038 if (liteBackTexture == NULL && appData.debugMode) {
\r
1039 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1043 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1044 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1045 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1046 darkBackTextureMode = appData.darkBackTextureMode;
\r
1048 if (darkBackTexture == NULL && appData.debugMode) {
\r
1049 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1055 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1057 HWND hwnd; /* Main window handle. */
\r
1059 WINDOWPLACEMENT wp;
\r
1062 hInst = hInstance; /* Store instance handle in our global variable */
\r
1063 programName = szAppName;
\r
1065 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1066 *filepart = NULLCHAR;
\r
1067 SetCurrentDirectory(installDir);
\r
1069 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1071 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1072 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1073 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1074 /* xboard, and older WinBoards, controlled the move sound with the
\r
1075 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1076 always turn the option on (so that the backend will call us),
\r
1077 then let the user turn the sound off by setting it to silence if
\r
1078 desired. To accommodate old winboard.ini files saved by old
\r
1079 versions of WinBoard, we also turn off the sound if the option
\r
1080 was initially set to false. [HGM] taken out of InitAppData */
\r
1081 if (!appData.ringBellAfterMoves) {
\r
1082 sounds[(int)SoundMove].name = strdup("");
\r
1083 appData.ringBellAfterMoves = TRUE;
\r
1085 if (appData.debugMode) {
\r
1086 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1087 setbuf(debugFP, NULL);
\r
1090 LoadLanguageFile(appData.language);
\r
1094 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1095 // InitEngineUCI( installDir, &second );
\r
1097 /* Create a main window for this application instance. */
\r
1098 hwnd = CreateWindow(szAppName, szTitle,
\r
1099 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1100 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1101 NULL, NULL, hInstance, NULL);
\r
1104 /* If window could not be created, return "failure" */
\r
1109 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1110 LoadLogo(&first, 0, FALSE);
\r
1111 LoadLogo(&second, 1, appData.icsActive);
\r
1115 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1116 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1117 iconCurrent = iconWhite;
\r
1118 InitDrawingColors();
\r
1119 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1120 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1121 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1122 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1123 /* Compute window size for each board size, and use the largest
\r
1124 size that fits on this screen as the default. */
\r
1125 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1126 if (boardSize == (BoardSize)-1 &&
\r
1127 winH <= screenHeight
\r
1128 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1129 && winW <= screenWidth) {
\r
1130 boardSize = (BoardSize)ibs;
\r
1134 InitDrawingSizes(boardSize, 0);
\r
1135 RecentEngineMenu(appData.recentEngineList);
\r
1137 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1139 /* [AS] Load textures if specified */
\r
1142 mysrandom( (unsigned) time(NULL) );
\r
1144 /* [AS] Restore layout */
\r
1145 if( wpMoveHistory.visible ) {
\r
1146 MoveHistoryPopUp();
\r
1149 if( wpEvalGraph.visible ) {
\r
1153 if( wpEngineOutput.visible ) {
\r
1154 EngineOutputPopUp();
\r
1157 /* Make the window visible; update its client area; and return "success" */
\r
1158 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1159 wp.length = sizeof(WINDOWPLACEMENT);
\r
1161 wp.showCmd = nCmdShow;
\r
1162 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1163 wp.rcNormalPosition.left = wpMain.x;
\r
1164 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1165 wp.rcNormalPosition.top = wpMain.y;
\r
1166 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1167 SetWindowPlacement(hwndMain, &wp);
\r
1169 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1171 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1172 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1174 if (hwndConsole) {
\r
1176 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1177 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1179 ShowWindow(hwndConsole, nCmdShow);
\r
1180 SetActiveWindow(hwndConsole);
\r
1182 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1183 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1192 HMENU hmenu = GetMenu(hwndMain);
\r
1194 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1195 MF_BYCOMMAND|((appData.icsActive &&
\r
1196 *appData.icsCommPort != NULLCHAR) ?
\r
1197 MF_ENABLED : MF_GRAYED));
\r
1198 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1199 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1200 MF_CHECKED : MF_UNCHECKED));
\r
1203 //---------------------------------------------------------------------------------------------------------
\r
1205 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1206 #define XBOARD FALSE
\r
1208 #define OPTCHAR "/"
\r
1209 #define SEPCHAR "="
\r
1210 #define TOPLEVEL 0
\r
1214 // front-end part of option handling
\r
1217 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1219 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1220 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1223 lf->lfEscapement = 0;
\r
1224 lf->lfOrientation = 0;
\r
1225 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1226 lf->lfItalic = mfp->italic;
\r
1227 lf->lfUnderline = mfp->underline;
\r
1228 lf->lfStrikeOut = mfp->strikeout;
\r
1229 lf->lfCharSet = mfp->charset;
\r
1230 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1231 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1232 lf->lfQuality = DEFAULT_QUALITY;
\r
1233 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1234 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1238 CreateFontInMF(MyFont *mf)
\r
1240 LFfromMFP(&mf->lf, &mf->mfp);
\r
1241 if (mf->hf) DeleteObject(mf->hf);
\r
1242 mf->hf = CreateFontIndirect(&mf->lf);
\r
1245 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1247 colorVariable[] = {
\r
1248 &whitePieceColor,
\r
1249 &blackPieceColor,
\r
1250 &lightSquareColor,
\r
1251 &darkSquareColor,
\r
1252 &highlightSquareColor,
\r
1253 &premoveHighlightColor,
\r
1255 &consoleBackgroundColor,
\r
1256 &appData.fontForeColorWhite,
\r
1257 &appData.fontBackColorWhite,
\r
1258 &appData.fontForeColorBlack,
\r
1259 &appData.fontBackColorBlack,
\r
1260 &appData.evalHistColorWhite,
\r
1261 &appData.evalHistColorBlack,
\r
1262 &appData.highlightArrowColor,
\r
1265 /* Command line font name parser. NULL name means do nothing.
\r
1266 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1267 For backward compatibility, syntax without the colon is also
\r
1268 accepted, but font names with digits in them won't work in that case.
\r
1271 ParseFontName(char *name, MyFontParams *mfp)
\r
1274 if (name == NULL) return;
\r
1276 q = strchr(p, ':');
\r
1278 if (q - p >= sizeof(mfp->faceName))
\r
1279 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1280 memcpy(mfp->faceName, p, q - p);
\r
1281 mfp->faceName[q - p] = NULLCHAR;
\r
1284 q = mfp->faceName;
\r
1286 while (*p && !isdigit(*p)) {
\r
1288 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1289 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1291 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1294 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1295 mfp->pointSize = (float) atof(p);
\r
1296 mfp->bold = (strchr(p, 'b') != NULL);
\r
1297 mfp->italic = (strchr(p, 'i') != NULL);
\r
1298 mfp->underline = (strchr(p, 'u') != NULL);
\r
1299 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1300 mfp->charset = DEFAULT_CHARSET;
\r
1301 q = strchr(p, 'c');
\r
1303 mfp->charset = (BYTE) atoi(q+1);
\r
1307 ParseFont(char *name, int number)
\r
1308 { // wrapper to shield back-end from 'font'
\r
1309 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1314 { // in WB we have a 2D array of fonts; this initializes their description
\r
1316 /* Point font array elements to structures and
\r
1317 parse default font names */
\r
1318 for (i=0; i<NUM_FONTS; i++) {
\r
1319 for (j=0; j<NUM_SIZES; j++) {
\r
1320 font[j][i] = &fontRec[j][i];
\r
1321 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1328 { // here we create the actual fonts from the selected descriptions
\r
1330 for (i=0; i<NUM_FONTS; i++) {
\r
1331 for (j=0; j<NUM_SIZES; j++) {
\r
1332 CreateFontInMF(font[j][i]);
\r
1336 /* Color name parser.
\r
1337 X version accepts X color names, but this one
\r
1338 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1340 ParseColorName(char *name)
\r
1342 int red, green, blue, count;
\r
1343 char buf[MSG_SIZ];
\r
1345 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1347 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1348 &red, &green, &blue);
\r
1351 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1352 DisplayError(buf, 0);
\r
1353 return RGB(0, 0, 0);
\r
1355 return PALETTERGB(red, green, blue);
\r
1359 ParseColor(int n, char *name)
\r
1360 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1361 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1365 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1367 char *e = argValue;
\r
1371 if (*e == 'b') eff |= CFE_BOLD;
\r
1372 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1373 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1374 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1375 else if (*e == '#' || isdigit(*e)) break;
\r
1379 *color = ParseColorName(e);
\r
1383 ParseTextAttribs(ColorClass cc, char *s)
\r
1384 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1385 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1386 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1390 ParseBoardSize(void *addr, char *name)
\r
1391 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1392 BoardSize bs = SizeTiny;
\r
1393 while (sizeInfo[bs].name != NULL) {
\r
1394 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1395 *(BoardSize *)addr = bs;
\r
1400 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1405 { // [HGM] import name from appData first
\r
1408 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1409 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1410 textAttribs[cc].sound.data = NULL;
\r
1411 MyLoadSound(&textAttribs[cc].sound);
\r
1413 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1414 textAttribs[cc].sound.name = strdup("");
\r
1415 textAttribs[cc].sound.data = NULL;
\r
1417 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1418 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1419 sounds[sc].data = NULL;
\r
1420 MyLoadSound(&sounds[sc]);
\r
1425 SetCommPortDefaults()
\r
1427 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1428 dcb.DCBlength = sizeof(DCB);
\r
1429 dcb.BaudRate = 9600;
\r
1430 dcb.fBinary = TRUE;
\r
1431 dcb.fParity = FALSE;
\r
1432 dcb.fOutxCtsFlow = FALSE;
\r
1433 dcb.fOutxDsrFlow = FALSE;
\r
1434 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1435 dcb.fDsrSensitivity = FALSE;
\r
1436 dcb.fTXContinueOnXoff = TRUE;
\r
1437 dcb.fOutX = FALSE;
\r
1439 dcb.fNull = FALSE;
\r
1440 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1441 dcb.fAbortOnError = FALSE;
\r
1443 dcb.Parity = SPACEPARITY;
\r
1444 dcb.StopBits = ONESTOPBIT;
\r
1447 // [HGM] args: these three cases taken out to stay in front-end
\r
1449 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1450 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1451 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1452 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1454 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1455 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1456 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1457 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1458 ad->argName, mfp->faceName, mfp->pointSize,
\r
1459 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1460 mfp->bold ? "b" : "",
\r
1461 mfp->italic ? "i" : "",
\r
1462 mfp->underline ? "u" : "",
\r
1463 mfp->strikeout ? "s" : "",
\r
1464 (int)mfp->charset);
\r
1470 { // [HGM] copy the names from the internal WB variables to appData
\r
1473 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1474 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1475 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1476 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1480 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1481 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1482 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1483 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1484 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1485 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1486 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1487 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1488 (ta->effects) ? " " : "",
\r
1489 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1493 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1494 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1495 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1496 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1497 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1501 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1502 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1503 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1507 ParseCommPortSettings(char *s)
\r
1508 { // wrapper to keep dcb from back-end
\r
1509 ParseCommSettings(s, &dcb);
\r
1514 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1515 GetActualPlacement(hwndMain, &wpMain);
\r
1516 GetActualPlacement(hwndConsole, &wpConsole);
\r
1517 GetActualPlacement(commentDialog, &wpComment);
\r
1518 GetActualPlacement(editTagsDialog, &wpTags);
\r
1519 GetActualPlacement(gameListDialog, &wpGameList);
\r
1520 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1521 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1522 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1526 PrintCommPortSettings(FILE *f, char *name)
\r
1527 { // wrapper to shield back-end from DCB
\r
1528 PrintCommSettings(f, name, &dcb);
\r
1532 MySearchPath(char *installDir, char *name, char *fullname)
\r
1534 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1535 if(name[0]== '%') {
\r
1536 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1537 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1538 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1539 *strchr(buf, '%') = 0;
\r
1540 strcat(fullname, getenv(buf));
\r
1541 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1543 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1544 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1545 return (int) strlen(fullname);
\r
1547 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1551 MyGetFullPathName(char *name, char *fullname)
\r
1554 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1559 { // [HGM] args: allows testing if main window is realized from back-end
\r
1560 return hwndMain != NULL;
\r
1564 PopUpStartupDialog()
\r
1568 LoadLanguageFile(appData.language);
\r
1569 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1570 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1571 FreeProcInstance(lpProc);
\r
1574 /*---------------------------------------------------------------------------*\
\r
1576 * GDI board drawing routines
\r
1578 \*---------------------------------------------------------------------------*/
\r
1580 /* [AS] Draw square using background texture */
\r
1581 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1586 return; /* Should never happen! */
\r
1589 SetGraphicsMode( dst, GM_ADVANCED );
\r
1596 /* X reflection */
\r
1601 x.eDx = (FLOAT) dw + dx - 1;
\r
1604 SetWorldTransform( dst, &x );
\r
1607 /* Y reflection */
\r
1613 x.eDy = (FLOAT) dh + dy - 1;
\r
1615 SetWorldTransform( dst, &x );
\r
1623 x.eDx = (FLOAT) dx;
\r
1624 x.eDy = (FLOAT) dy;
\r
1627 SetWorldTransform( dst, &x );
\r
1631 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1639 SetWorldTransform( dst, &x );
\r
1641 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1644 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1646 PM_WP = (int) WhitePawn,
\r
1647 PM_WN = (int) WhiteKnight,
\r
1648 PM_WB = (int) WhiteBishop,
\r
1649 PM_WR = (int) WhiteRook,
\r
1650 PM_WQ = (int) WhiteQueen,
\r
1651 PM_WF = (int) WhiteFerz,
\r
1652 PM_WW = (int) WhiteWazir,
\r
1653 PM_WE = (int) WhiteAlfil,
\r
1654 PM_WM = (int) WhiteMan,
\r
1655 PM_WO = (int) WhiteCannon,
\r
1656 PM_WU = (int) WhiteUnicorn,
\r
1657 PM_WH = (int) WhiteNightrider,
\r
1658 PM_WA = (int) WhiteAngel,
\r
1659 PM_WC = (int) WhiteMarshall,
\r
1660 PM_WAB = (int) WhiteCardinal,
\r
1661 PM_WD = (int) WhiteDragon,
\r
1662 PM_WL = (int) WhiteLance,
\r
1663 PM_WS = (int) WhiteCobra,
\r
1664 PM_WV = (int) WhiteFalcon,
\r
1665 PM_WSG = (int) WhiteSilver,
\r
1666 PM_WG = (int) WhiteGrasshopper,
\r
1667 PM_WK = (int) WhiteKing,
\r
1668 PM_BP = (int) BlackPawn,
\r
1669 PM_BN = (int) BlackKnight,
\r
1670 PM_BB = (int) BlackBishop,
\r
1671 PM_BR = (int) BlackRook,
\r
1672 PM_BQ = (int) BlackQueen,
\r
1673 PM_BF = (int) BlackFerz,
\r
1674 PM_BW = (int) BlackWazir,
\r
1675 PM_BE = (int) BlackAlfil,
\r
1676 PM_BM = (int) BlackMan,
\r
1677 PM_BO = (int) BlackCannon,
\r
1678 PM_BU = (int) BlackUnicorn,
\r
1679 PM_BH = (int) BlackNightrider,
\r
1680 PM_BA = (int) BlackAngel,
\r
1681 PM_BC = (int) BlackMarshall,
\r
1682 PM_BG = (int) BlackGrasshopper,
\r
1683 PM_BAB = (int) BlackCardinal,
\r
1684 PM_BD = (int) BlackDragon,
\r
1685 PM_BL = (int) BlackLance,
\r
1686 PM_BS = (int) BlackCobra,
\r
1687 PM_BV = (int) BlackFalcon,
\r
1688 PM_BSG = (int) BlackSilver,
\r
1689 PM_BK = (int) BlackKing
\r
1692 static HFONT hPieceFont = NULL;
\r
1693 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1694 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1695 static int fontBitmapSquareSize = 0;
\r
1696 static char pieceToFontChar[(int) EmptySquare] =
\r
1697 { 'p', 'n', 'b', 'r', 'q',
\r
1698 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1699 'k', 'o', 'm', 'v', 't', 'w',
\r
1700 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1703 extern BOOL SetCharTable( char *table, const char * map );
\r
1704 /* [HGM] moved to backend.c */
\r
1706 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1709 BYTE r1 = GetRValue( color );
\r
1710 BYTE g1 = GetGValue( color );
\r
1711 BYTE b1 = GetBValue( color );
\r
1717 /* Create a uniform background first */
\r
1718 hbrush = CreateSolidBrush( color );
\r
1719 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1720 FillRect( hdc, &rc, hbrush );
\r
1721 DeleteObject( hbrush );
\r
1724 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1725 int steps = squareSize / 2;
\r
1728 for( i=0; i<steps; i++ ) {
\r
1729 BYTE r = r1 - (r1-r2) * i / steps;
\r
1730 BYTE g = g1 - (g1-g2) * i / steps;
\r
1731 BYTE b = b1 - (b1-b2) * i / steps;
\r
1733 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1734 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1735 FillRect( hdc, &rc, hbrush );
\r
1736 DeleteObject(hbrush);
\r
1739 else if( mode == 2 ) {
\r
1740 /* Diagonal gradient, good more or less for every piece */
\r
1741 POINT triangle[3];
\r
1742 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1743 HBRUSH hbrush_old;
\r
1744 int steps = squareSize;
\r
1747 triangle[0].x = squareSize - steps;
\r
1748 triangle[0].y = squareSize;
\r
1749 triangle[1].x = squareSize;
\r
1750 triangle[1].y = squareSize;
\r
1751 triangle[2].x = squareSize;
\r
1752 triangle[2].y = squareSize - steps;
\r
1754 for( i=0; i<steps; i++ ) {
\r
1755 BYTE r = r1 - (r1-r2) * i / steps;
\r
1756 BYTE g = g1 - (g1-g2) * i / steps;
\r
1757 BYTE b = b1 - (b1-b2) * i / steps;
\r
1759 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1760 hbrush_old = SelectObject( hdc, hbrush );
\r
1761 Polygon( hdc, triangle, 3 );
\r
1762 SelectObject( hdc, hbrush_old );
\r
1763 DeleteObject(hbrush);
\r
1768 SelectObject( hdc, hpen );
\r
1773 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1774 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1775 piece: follow the steps as explained below.
\r
1777 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1781 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1785 int backColor = whitePieceColor;
\r
1786 int foreColor = blackPieceColor;
\r
1788 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1789 backColor = appData.fontBackColorWhite;
\r
1790 foreColor = appData.fontForeColorWhite;
\r
1792 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1793 backColor = appData.fontBackColorBlack;
\r
1794 foreColor = appData.fontForeColorBlack;
\r
1798 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1800 hbm_old = SelectObject( hdc, hbm );
\r
1804 rc.right = squareSize;
\r
1805 rc.bottom = squareSize;
\r
1807 /* Step 1: background is now black */
\r
1808 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1810 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1812 pt.x = (squareSize - sz.cx) / 2;
\r
1813 pt.y = (squareSize - sz.cy) / 2;
\r
1815 SetBkMode( hdc, TRANSPARENT );
\r
1816 SetTextColor( hdc, chroma );
\r
1817 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1818 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1820 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1821 /* Step 3: the area outside the piece is filled with white */
\r
1822 // FloodFill( hdc, 0, 0, chroma );
\r
1823 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1824 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1825 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1826 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1827 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1829 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1830 but if the start point is not inside the piece we're lost!
\r
1831 There should be a better way to do this... if we could create a region or path
\r
1832 from the fill operation we would be fine for example.
\r
1834 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1835 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1837 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1838 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1839 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1841 SelectObject( dc2, bm2 );
\r
1842 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1843 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1844 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1845 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1846 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1849 DeleteObject( bm2 );
\r
1852 SetTextColor( hdc, 0 );
\r
1854 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1855 draw the piece again in black for safety.
\r
1857 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1859 SelectObject( hdc, hbm_old );
\r
1861 if( hPieceMask[index] != NULL ) {
\r
1862 DeleteObject( hPieceMask[index] );
\r
1865 hPieceMask[index] = hbm;
\r
1868 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1870 SelectObject( hdc, hbm );
\r
1873 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1874 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1875 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1877 SelectObject( dc1, hPieceMask[index] );
\r
1878 SelectObject( dc2, bm2 );
\r
1879 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1880 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1883 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1884 the piece background and deletes (makes transparent) the rest.
\r
1885 Thanks to that mask, we are free to paint the background with the greates
\r
1886 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1887 We use this, to make gradients and give the pieces a "roundish" look.
\r
1889 SetPieceBackground( hdc, backColor, 2 );
\r
1890 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1894 DeleteObject( bm2 );
\r
1897 SetTextColor( hdc, foreColor );
\r
1898 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1900 SelectObject( hdc, hbm_old );
\r
1902 if( hPieceFace[index] != NULL ) {
\r
1903 DeleteObject( hPieceFace[index] );
\r
1906 hPieceFace[index] = hbm;
\r
1909 static int TranslatePieceToFontPiece( int piece )
\r
1939 case BlackMarshall:
\r
1943 case BlackNightrider:
\r
1949 case BlackUnicorn:
\r
1953 case BlackGrasshopper:
\r
1965 case BlackCardinal:
\r
1972 case WhiteMarshall:
\r
1976 case WhiteNightrider:
\r
1982 case WhiteUnicorn:
\r
1986 case WhiteGrasshopper:
\r
1998 case WhiteCardinal:
\r
2007 void CreatePiecesFromFont()
\r
2010 HDC hdc_window = NULL;
\r
2016 if( fontBitmapSquareSize < 0 ) {
\r
2017 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2021 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2022 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2023 fontBitmapSquareSize = -1;
\r
2027 if( fontBitmapSquareSize != squareSize ) {
\r
2028 hdc_window = GetDC( hwndMain );
\r
2029 hdc = CreateCompatibleDC( hdc_window );
\r
2031 if( hPieceFont != NULL ) {
\r
2032 DeleteObject( hPieceFont );
\r
2035 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2036 hPieceMask[i] = NULL;
\r
2037 hPieceFace[i] = NULL;
\r
2043 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2044 fontHeight = appData.fontPieceSize;
\r
2047 fontHeight = (fontHeight * squareSize) / 100;
\r
2049 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2051 lf.lfEscapement = 0;
\r
2052 lf.lfOrientation = 0;
\r
2053 lf.lfWeight = FW_NORMAL;
\r
2055 lf.lfUnderline = 0;
\r
2056 lf.lfStrikeOut = 0;
\r
2057 lf.lfCharSet = DEFAULT_CHARSET;
\r
2058 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2059 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2060 lf.lfQuality = PROOF_QUALITY;
\r
2061 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2062 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2063 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2065 hPieceFont = CreateFontIndirect( &lf );
\r
2067 if( hPieceFont == NULL ) {
\r
2068 fontBitmapSquareSize = -2;
\r
2071 /* Setup font-to-piece character table */
\r
2072 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2073 /* No (or wrong) global settings, try to detect the font */
\r
2074 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2076 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2078 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2079 /* DiagramTT* family */
\r
2080 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2082 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2083 /* Fairy symbols */
\r
2084 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2086 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2087 /* Good Companion (Some characters get warped as literal :-( */
\r
2088 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2089 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2090 SetCharTable(pieceToFontChar, s);
\r
2093 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2094 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2098 /* Create bitmaps */
\r
2099 hfont_old = SelectObject( hdc, hPieceFont );
\r
2100 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2101 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2102 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2104 SelectObject( hdc, hfont_old );
\r
2106 fontBitmapSquareSize = squareSize;
\r
2110 if( hdc != NULL ) {
\r
2114 if( hdc_window != NULL ) {
\r
2115 ReleaseDC( hwndMain, hdc_window );
\r
2120 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2122 char name[128], buf[MSG_SIZ];
\r
2124 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2125 if(appData.pieceDirectory[0]) {
\r
2127 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2128 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2129 if(res) return res;
\r
2131 if (gameInfo.event &&
\r
2132 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2133 strcmp(name, "k80s") == 0) {
\r
2134 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2136 return LoadBitmap(hinst, name);
\r
2140 /* Insert a color into the program's logical palette
\r
2141 structure. This code assumes the given color is
\r
2142 the result of the RGB or PALETTERGB macro, and it
\r
2143 knows how those macros work (which is documented).
\r
2146 InsertInPalette(COLORREF color)
\r
2148 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2150 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2151 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2152 pLogPal->palNumEntries--;
\r
2156 pe->peFlags = (char) 0;
\r
2157 pe->peRed = (char) (0xFF & color);
\r
2158 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2159 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2165 InitDrawingColors()
\r
2167 if (pLogPal == NULL) {
\r
2168 /* Allocate enough memory for a logical palette with
\r
2169 * PALETTESIZE entries and set the size and version fields
\r
2170 * of the logical palette structure.
\r
2172 pLogPal = (NPLOGPALETTE)
\r
2173 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2174 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2175 pLogPal->palVersion = 0x300;
\r
2177 pLogPal->palNumEntries = 0;
\r
2179 InsertInPalette(lightSquareColor);
\r
2180 InsertInPalette(darkSquareColor);
\r
2181 InsertInPalette(whitePieceColor);
\r
2182 InsertInPalette(blackPieceColor);
\r
2183 InsertInPalette(highlightSquareColor);
\r
2184 InsertInPalette(premoveHighlightColor);
\r
2186 /* create a logical color palette according the information
\r
2187 * in the LOGPALETTE structure.
\r
2189 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2191 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2192 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2193 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2194 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2195 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2196 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2197 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2198 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2199 /* [AS] Force rendering of the font-based pieces */
\r
2200 if( fontBitmapSquareSize > 0 ) {
\r
2201 fontBitmapSquareSize = 0;
\r
2207 BoardWidth(int boardSize, int n)
\r
2208 { /* [HGM] argument n added to allow different width and height */
\r
2209 int lineGap = sizeInfo[boardSize].lineGap;
\r
2211 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2212 lineGap = appData.overrideLineGap;
\r
2215 return (n + 1) * lineGap +
\r
2216 n * sizeInfo[boardSize].squareSize;
\r
2219 /* Respond to board resize by dragging edge */
\r
2221 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2223 BoardSize newSize = NUM_SIZES - 1;
\r
2224 static int recurse = 0;
\r
2225 if (IsIconic(hwndMain)) return;
\r
2226 if (recurse > 0) return;
\r
2228 while (newSize > 0) {
\r
2229 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2230 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2231 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2234 boardSize = newSize;
\r
2235 InitDrawingSizes(boardSize, flags);
\r
2240 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2243 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2245 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2246 ChessSquare piece;
\r
2247 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2249 SIZE clockSize, messageSize;
\r
2251 char buf[MSG_SIZ];
\r
2253 HMENU hmenu = GetMenu(hwndMain);
\r
2254 RECT crect, wrect, oldRect;
\r
2256 LOGBRUSH logbrush;
\r
2257 VariantClass v = gameInfo.variant;
\r
2259 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2260 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2262 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2263 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2264 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2265 oldBoardSize = boardSize;
\r
2267 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2268 { // correct board size to one where built-in pieces exist
\r
2269 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2270 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2271 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2272 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2273 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {
\r
2274 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2275 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2276 boardSize = SizeMiddling;
\r
2279 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2281 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2282 oldRect.top = wpMain.y;
\r
2283 oldRect.right = wpMain.x + wpMain.width;
\r
2284 oldRect.bottom = wpMain.y + wpMain.height;
\r
2286 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2287 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2288 squareSize = sizeInfo[boardSize].squareSize;
\r
2289 lineGap = sizeInfo[boardSize].lineGap;
\r
2290 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2291 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2293 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2294 lineGap = appData.overrideLineGap;
\r
2297 if (tinyLayout != oldTinyLayout) {
\r
2298 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2300 style &= ~WS_SYSMENU;
\r
2301 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2302 "&Minimize\tCtrl+F4");
\r
2304 style |= WS_SYSMENU;
\r
2305 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2307 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2309 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2310 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2311 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2313 DrawMenuBar(hwndMain);
\r
2316 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2317 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2319 /* Get text area sizes */
\r
2320 hdc = GetDC(hwndMain);
\r
2321 if (appData.clockMode) {
\r
2322 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2324 snprintf(buf, MSG_SIZ, _("White"));
\r
2326 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2327 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2328 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2329 str = _("We only care about the height here");
\r
2330 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2331 SelectObject(hdc, oldFont);
\r
2332 ReleaseDC(hwndMain, hdc);
\r
2334 /* Compute where everything goes */
\r
2335 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2336 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2337 logoHeight = 2*clockSize.cy;
\r
2338 leftLogoRect.left = OUTER_MARGIN;
\r
2339 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2340 leftLogoRect.top = OUTER_MARGIN;
\r
2341 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2343 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2344 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2345 rightLogoRect.top = OUTER_MARGIN;
\r
2346 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2349 whiteRect.left = leftLogoRect.right;
\r
2350 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2351 whiteRect.top = OUTER_MARGIN;
\r
2352 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2354 blackRect.right = rightLogoRect.left;
\r
2355 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2356 blackRect.top = whiteRect.top;
\r
2357 blackRect.bottom = whiteRect.bottom;
\r
2359 whiteRect.left = OUTER_MARGIN;
\r
2360 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2361 whiteRect.top = OUTER_MARGIN;
\r
2362 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2364 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2365 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2366 blackRect.top = whiteRect.top;
\r
2367 blackRect.bottom = whiteRect.bottom;
\r
2369 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2372 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2373 if (appData.showButtonBar) {
\r
2374 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2375 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2377 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2379 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2380 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2382 boardRect.left = OUTER_MARGIN;
\r
2383 boardRect.right = boardRect.left + boardWidth;
\r
2384 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2385 boardRect.bottom = boardRect.top + boardHeight;
\r
2387 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2388 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2389 oldTinyLayout = tinyLayout;
\r
2390 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2391 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2392 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2393 winW *= 1 + twoBoards;
\r
2394 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2395 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2396 wpMain.height = winH; // without disturbing window attachments
\r
2397 GetWindowRect(hwndMain, &wrect);
\r
2398 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2399 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2401 // [HGM] placement: let attached windows follow size change.
\r
2402 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2403 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2404 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2405 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2406 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2408 /* compensate if menu bar wrapped */
\r
2409 GetClientRect(hwndMain, &crect);
\r
2410 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2411 wpMain.height += offby;
\r
2413 case WMSZ_TOPLEFT:
\r
2414 SetWindowPos(hwndMain, NULL,
\r
2415 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2416 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2419 case WMSZ_TOPRIGHT:
\r
2421 SetWindowPos(hwndMain, NULL,
\r
2422 wrect.left, wrect.bottom - wpMain.height,
\r
2423 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2426 case WMSZ_BOTTOMLEFT:
\r
2428 SetWindowPos(hwndMain, NULL,
\r
2429 wrect.right - wpMain.width, wrect.top,
\r
2430 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2433 case WMSZ_BOTTOMRIGHT:
\r
2437 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2438 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2443 for (i = 0; i < N_BUTTONS; i++) {
\r
2444 if (buttonDesc[i].hwnd != NULL) {
\r
2445 DestroyWindow(buttonDesc[i].hwnd);
\r
2446 buttonDesc[i].hwnd = NULL;
\r
2448 if (appData.showButtonBar) {
\r
2449 buttonDesc[i].hwnd =
\r
2450 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2451 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2452 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2453 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2454 (HMENU) buttonDesc[i].id,
\r
2455 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2457 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2458 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2459 MAKELPARAM(FALSE, 0));
\r
2461 if (buttonDesc[i].id == IDM_Pause)
\r
2462 hwndPause = buttonDesc[i].hwnd;
\r
2463 buttonDesc[i].wndproc = (WNDPROC)
\r
2464 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2467 if (gridPen != NULL) DeleteObject(gridPen);
\r
2468 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2469 if (premovePen != NULL) DeleteObject(premovePen);
\r
2470 if (lineGap != 0) {
\r
2471 logbrush.lbStyle = BS_SOLID;
\r
2472 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2474 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2475 lineGap, &logbrush, 0, NULL);
\r
2476 logbrush.lbColor = highlightSquareColor;
\r
2478 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2479 lineGap, &logbrush, 0, NULL);
\r
2481 logbrush.lbColor = premoveHighlightColor;
\r
2483 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2484 lineGap, &logbrush, 0, NULL);
\r
2486 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2487 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2488 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2489 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2490 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2491 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2492 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2493 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2495 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2496 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2497 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2498 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2499 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2500 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2501 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2502 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2506 /* [HGM] Licensing requirement */
\r
2508 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2511 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2513 GothicPopUp( "", VariantNormal);
\r
2516 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2518 /* Load piece bitmaps for this board size */
\r
2519 for (i=0; i<=2; i++) {
\r
2520 for (piece = WhitePawn;
\r
2521 (int) piece < (int) BlackPawn;
\r
2522 piece = (ChessSquare) ((int) piece + 1)) {
\r
2523 if (pieceBitmap[i][piece] != NULL)
\r
2524 DeleteObject(pieceBitmap[i][piece]);
\r
2528 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2529 // Orthodox Chess pieces
\r
2530 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2531 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2532 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2533 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2534 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2535 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2536 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2537 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2538 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2539 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2540 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2541 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2542 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2543 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2544 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2545 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2546 // in Shogi, Hijack the unused Queen for Lance
\r
2547 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2548 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2549 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2551 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2552 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2553 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2556 if(squareSize <= 72 && squareSize >= 33) {
\r
2557 /* A & C are available in most sizes now */
\r
2558 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2559 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2560 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2561 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2562 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2563 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2564 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2565 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2566 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2567 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2568 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2569 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2570 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2571 } else { // Smirf-like
\r
2572 if(gameInfo.variant == VariantSChess) {
\r
2573 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2574 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2575 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2577 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2578 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2579 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2582 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2583 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2584 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2585 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2586 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2587 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2588 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2589 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2590 } else { // WinBoard standard
\r
2591 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2592 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2593 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2598 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2599 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2600 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2601 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2602 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2603 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2604 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2605 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2606 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2607 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2608 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2609 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2610 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2611 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2612 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2613 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2614 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2617 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2618 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2619 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2620 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2621 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2622 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2623 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2624 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2625 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2626 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2627 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2628 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2630 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2631 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2632 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2633 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2634 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2635 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2636 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2637 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2638 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2639 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2640 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2641 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2642 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2644 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2647 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2648 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2649 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2650 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2653 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2654 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2655 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2658 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2659 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2660 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2661 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2662 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2663 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2664 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2665 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2666 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2667 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2668 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2669 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2670 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2671 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2672 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2676 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2677 /* special Shogi support in this size */
\r
2678 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2679 for (piece = WhitePawn;
\r
2680 (int) piece < (int) BlackPawn;
\r
2681 piece = (ChessSquare) ((int) piece + 1)) {
\r
2682 if (pieceBitmap[i][piece] != NULL)
\r
2683 DeleteObject(pieceBitmap[i][piece]);
\r
2686 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2687 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2688 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2689 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2690 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2691 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2692 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2693 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2694 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2695 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2696 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2697 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2698 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2699 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2700 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2701 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2702 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2703 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2704 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2705 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2706 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2707 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2708 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2709 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2710 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2711 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2712 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2713 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2714 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2715 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2716 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2717 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2718 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2719 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2720 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2721 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2722 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2723 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2724 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2725 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2726 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2727 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2733 PieceBitmap(ChessSquare p, int kind)
\r
2735 if ((int) p >= (int) BlackPawn)
\r
2736 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2738 return pieceBitmap[kind][(int) p];
\r
2741 /***************************************************************/
\r
2743 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2744 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2746 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2747 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2751 SquareToPos(int row, int column, int * x, int * y)
\r
2754 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2755 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2757 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2758 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2763 DrawCoordsOnDC(HDC hdc)
\r
2765 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2766 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2767 char str[2] = { NULLCHAR, NULLCHAR };
\r
2768 int oldMode, oldAlign, x, y, start, i;
\r
2772 if (!appData.showCoords)
\r
2775 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2777 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2778 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2779 oldAlign = GetTextAlign(hdc);
\r
2780 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2782 y = boardRect.top + lineGap;
\r
2783 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2786 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2787 x += border - lineGap - 4; y += squareSize - 6;
\r
2789 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2790 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2791 str[0] = files[start + i];
\r
2792 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2793 y += squareSize + lineGap;
\r
2796 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2799 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2800 x += -border + 4; y += border - squareSize + 6;
\r
2802 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2803 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2804 str[0] = ranks[start + i];
\r
2805 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2806 x += squareSize + lineGap;
\r
2809 SelectObject(hdc, oldBrush);
\r
2810 SetBkMode(hdc, oldMode);
\r
2811 SetTextAlign(hdc, oldAlign);
\r
2812 SelectObject(hdc, oldFont);
\r
2816 DrawGridOnDC(HDC hdc)
\r
2820 if (lineGap != 0) {
\r
2821 oldPen = SelectObject(hdc, gridPen);
\r
2822 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2823 SelectObject(hdc, oldPen);
\r
2827 #define HIGHLIGHT_PEN 0
\r
2828 #define PREMOVE_PEN 1
\r
2831 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2834 HPEN oldPen, hPen;
\r
2835 if (lineGap == 0) return;
\r
2837 x1 = boardRect.left +
\r
2838 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2839 y1 = boardRect.top +
\r
2840 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2842 x1 = boardRect.left +
\r
2843 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2844 y1 = boardRect.top +
\r
2845 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2847 hPen = pen ? premovePen : highlightPen;
\r
2848 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2849 MoveToEx(hdc, x1, y1, NULL);
\r
2850 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2851 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2852 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2853 LineTo(hdc, x1, y1);
\r
2854 SelectObject(hdc, oldPen);
\r
2858 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2861 for (i=0; i<2; i++) {
\r
2862 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2863 DrawHighlightOnDC(hdc, TRUE,
\r
2864 h->sq[i].x, h->sq[i].y,
\r
2869 /* Note: sqcolor is used only in monoMode */
\r
2870 /* Note that this code is largely duplicated in woptions.c,
\r
2871 function DrawSampleSquare, so that needs to be updated too */
\r
2873 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2875 HBITMAP oldBitmap;
\r
2879 if (appData.blindfold) return;
\r
2881 /* [AS] Use font-based pieces if needed */
\r
2882 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2883 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2884 CreatePiecesFromFont();
\r
2886 if( fontBitmapSquareSize == squareSize ) {
\r
2887 int index = TranslatePieceToFontPiece(piece);
\r
2889 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2891 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2892 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2896 squareSize, squareSize,
\r
2901 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2903 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2904 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2908 squareSize, squareSize,
\r
2917 if (appData.monoMode) {
\r
2918 SelectObject(tmphdc, PieceBitmap(piece,
\r
2919 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2920 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2921 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2923 HBRUSH xBrush = whitePieceBrush;
\r
2924 tmpSize = squareSize;
\r
2925 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2927 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2928 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2929 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2930 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2931 x += (squareSize - minorSize)>>1;
\r
2932 y += squareSize - minorSize - 2;
\r
2933 tmpSize = minorSize;
\r
2935 if (color || appData.allWhite ) {
\r
2936 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2938 oldBrush = SelectObject(hdc, xBrush);
\r
2939 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2940 if(appData.upsideDown && color==flipView)
\r
2941 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2943 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2944 /* Use black for outline of white pieces */
\r
2945 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2946 if(appData.upsideDown && color==flipView)
\r
2947 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2949 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2950 } else if(appData.pieceDirectory[0]) {
\r
2951 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2952 oldBrush = SelectObject(hdc, xBrush);
\r
2953 if(appData.upsideDown && color==flipView)
\r
2954 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2956 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2957 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2958 if(appData.upsideDown && color==flipView)
\r
2959 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2961 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2963 /* Use square color for details of black pieces */
\r
2964 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2965 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2966 if(appData.upsideDown && !flipView)
\r
2967 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2969 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2971 SelectObject(hdc, oldBrush);
\r
2972 SelectObject(tmphdc, oldBitmap);
\r
2976 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2977 int GetBackTextureMode( int algo )
\r
2979 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2983 case BACK_TEXTURE_MODE_PLAIN:
\r
2984 result = 1; /* Always use identity map */
\r
2986 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2987 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2995 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2996 to handle redraws cleanly (as random numbers would always be different).
\r
2998 VOID RebuildTextureSquareInfo()
\r
3008 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3010 if( liteBackTexture != NULL ) {
\r
3011 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3012 lite_w = bi.bmWidth;
\r
3013 lite_h = bi.bmHeight;
\r
3017 if( darkBackTexture != NULL ) {
\r
3018 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3019 dark_w = bi.bmWidth;
\r
3020 dark_h = bi.bmHeight;
\r
3024 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3025 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3026 if( (col + row) & 1 ) {
\r
3028 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3029 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3030 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3032 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3033 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3034 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3036 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3037 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3042 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3043 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3044 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3046 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3047 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3048 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3050 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3051 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3058 /* [AS] Arrow highlighting support */
\r
3060 static double A_WIDTH = 5; /* Width of arrow body */
\r
3062 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3063 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3065 static double Sqr( double x )
\r
3070 static int Round( double x )
\r
3072 return (int) (x + 0.5);
\r
3075 /* Draw an arrow between two points using current settings */
\r
3076 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3079 double dx, dy, j, k, x, y;
\r
3081 if( d_x == s_x ) {
\r
3082 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3084 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3087 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3088 arrow[1].y = d_y - h;
\r
3090 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3091 arrow[2].y = d_y - h;
\r
3096 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3097 arrow[5].y = d_y - h;
\r
3099 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3100 arrow[4].y = d_y - h;
\r
3102 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3105 else if( d_y == s_y ) {
\r
3106 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3109 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3111 arrow[1].x = d_x - w;
\r
3112 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3114 arrow[2].x = d_x - w;
\r
3115 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3120 arrow[5].x = d_x - w;
\r
3121 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3123 arrow[4].x = d_x - w;
\r
3124 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3127 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3130 /* [AS] Needed a lot of paper for this! :-) */
\r
3131 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3132 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3134 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3136 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3141 arrow[0].x = Round(x - j);
\r
3142 arrow[0].y = Round(y + j*dx);
\r
3144 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3145 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3148 x = (double) d_x - k;
\r
3149 y = (double) d_y - k*dy;
\r
3152 x = (double) d_x + k;
\r
3153 y = (double) d_y + k*dy;
\r
3156 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3158 arrow[6].x = Round(x - j);
\r
3159 arrow[6].y = Round(y + j*dx);
\r
3161 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3162 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3164 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3165 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3170 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3171 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3174 Polygon( hdc, arrow, 7 );
\r
3177 /* [AS] Draw an arrow between two squares */
\r
3178 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3180 int s_x, s_y, d_x, d_y;
\r