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
225 #if defined(_winmajor)
\r
226 #define oldDialog (_winmajor < 4)
\r
228 #define oldDialog 0
\r
232 #define INTERNATIONAL
\r
234 #ifdef INTERNATIONAL
\r
235 # define _(s) T_(s)
\r
241 # define Translate(x, y)
\r
242 # define LoadLanguageFile(s)
\r
245 #ifdef INTERNATIONAL
\r
247 Boolean barbaric; // flag indicating if translation is needed
\r
249 // list of item numbers used in each dialog (used to alter language at run time)
\r
251 #define ABOUTBOX -1 /* not sure why these are needed */
\r
252 #define ABOUTBOX2 -1
\r
254 int dialogItems[][42] = {
\r
255 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
256 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
257 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
258 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
259 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
260 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
261 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
262 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
263 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
264 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
265 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
266 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
267 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
268 { ABOUTBOX2, IDC_ChessBoard },
\r
269 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
270 OPT_GameListClose, IDC_GameListDoFilter },
\r
271 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
272 { DLG_Error, IDOK },
\r
273 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
274 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
275 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
276 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
277 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
278 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
279 { DLG_IndexNumber, IDC_Index },
\r
280 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
281 { DLG_TypeInName, IDOK, IDCANCEL },
\r
282 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
283 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
284 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
285 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
286 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
287 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
288 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
289 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
290 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
291 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
292 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
293 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
294 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
295 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
296 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
297 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
298 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
299 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
300 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
301 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
302 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
303 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
304 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
305 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
306 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
307 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
308 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
309 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
310 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
311 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
312 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
313 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
314 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
315 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
316 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
317 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
318 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
319 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
320 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
321 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
322 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
323 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
324 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
325 { DLG_MoveHistory },
\r
326 { DLG_EvalGraph },
\r
327 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
328 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
329 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
330 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
331 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
332 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
333 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
334 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
335 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
339 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
340 static int lastChecked;
\r
341 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
342 extern int tinyLayout;
\r
343 extern char * menuBarText[][10];
\r
346 LoadLanguageFile(char *name)
\r
347 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
349 int i=0, j=0, n=0, k;
\r
352 if(!name || name[0] == NULLCHAR) return;
\r
353 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
354 appData.language = oldLanguage;
\r
355 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
356 if((f = fopen(buf, "r")) == NULL) return;
\r
357 while((k = fgetc(f)) != EOF) {
\r
358 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
359 languageBuf[i] = k;
\r
361 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
363 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
364 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
365 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
366 english[j] = languageBuf + n + 1; *p = 0;
\r
367 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
368 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
373 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
375 case 'n': k = '\n'; break;
\r
376 case 'r': k = '\r'; break;
\r
377 case 't': k = '\t'; break;
\r
379 languageBuf[--i] = k;
\r
384 barbaric = (j != 0);
\r
385 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
390 { // return the translation of the given string
\r
391 // efficiency can be improved a lot...
\r
393 static char buf[MSG_SIZ];
\r
394 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
395 if(!barbaric) return s;
\r
396 if(!s) return ""; // sanity
\r
397 while(english[i]) {
\r
398 if(!strcmp(s, english[i])) return foreign[i];
\r
399 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
400 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
409 Translate(HWND hDlg, int dialogID)
\r
410 { // translate all text items in the given dialog
\r
412 char buf[MSG_SIZ], *s;
\r
413 if(!barbaric) return;
\r
414 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
415 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
416 GetWindowText( hDlg, buf, MSG_SIZ );
\r
418 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
419 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
420 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
421 if(strlen(buf) == 0) continue;
\r
423 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
428 TranslateOneMenu(int i, HMENU subMenu)
\r
431 static MENUITEMINFO info;
\r
433 info.cbSize = sizeof(MENUITEMINFO);
\r
434 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
435 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
437 info.dwTypeData = buf;
\r
438 info.cch = sizeof(buf);
\r
439 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
441 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
442 else menuText[i][j] = strdup(buf); // remember original on first change
\r
444 if(buf[0] == NULLCHAR) continue;
\r
445 info.dwTypeData = T_(buf);
\r
446 info.cch = strlen(buf)+1;
\r
447 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
453 TranslateMenus(int addLanguage)
\r
456 WIN32_FIND_DATA fileData;
\r
458 #define IDM_English 1970
\r
460 HMENU mainMenu = GetMenu(hwndMain);
\r
461 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
462 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
463 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
464 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
465 TranslateOneMenu(i, subMenu);
\r
467 DrawMenuBar(hwndMain);
\r
470 if(!addLanguage) return;
\r
471 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
472 HMENU mainMenu = GetMenu(hwndMain);
\r
473 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
474 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
475 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
476 i = 0; lastChecked = IDM_English;
\r
478 char *p, *q = fileData.cFileName;
\r
479 int checkFlag = MF_UNCHECKED;
\r
480 languageFile[i] = strdup(q);
\r
481 if(barbaric && !strcmp(oldLanguage, q)) {
\r
482 checkFlag = MF_CHECKED;
\r
483 lastChecked = IDM_English + i + 1;
\r
484 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
486 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
487 p = strstr(fileData.cFileName, ".lng");
\r
489 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
490 } while(FindNextFile(hFind, &fileData));
\r
497 #define IDM_RecentEngines 3000
\r
500 RecentEngineMenu (char *s)
\r
502 if(appData.icsActive) return;
\r
503 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
504 HMENU mainMenu = GetMenu(hwndMain);
\r
505 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
506 int i=IDM_RecentEngines;
\r
507 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
508 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
510 char *p = strchr(s, '\n');
\r
511 if(p == NULL) return; // malformed!
\r
513 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
527 int cliWidth, cliHeight;
\r
530 SizeInfo sizeInfo[] =
\r
532 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
533 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
534 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
535 { "petite", 33, 1, 1, 1, 0, 0 },
\r
536 { "slim", 37, 2, 1, 0, 0, 0 },
\r
537 { "small", 40, 2, 1, 0, 0, 0 },
\r
538 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
539 { "middling", 49, 2, 0, 0, 0, 0 },
\r
540 { "average", 54, 2, 0, 0, 0, 0 },
\r
541 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
542 { "medium", 64, 3, 0, 0, 0, 0 },
\r
543 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
544 { "large", 80, 3, 0, 0, 0, 0 },
\r
545 { "big", 87, 3, 0, 0, 0, 0 },
\r
546 { "huge", 95, 3, 0, 0, 0, 0 },
\r
547 { "giant", 108, 3, 0, 0, 0, 0 },
\r
548 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
549 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
550 { NULL, 0, 0, 0, 0, 0, 0 }
\r
553 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
554 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
556 { 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
557 { 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
558 { 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
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
576 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
585 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
586 #define N_BUTTONS 5
\r
588 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
590 {"<<", IDM_ToStart, NULL, NULL},
\r
591 {"<", IDM_Backward, NULL, NULL},
\r
592 {"P", IDM_Pause, NULL, NULL},
\r
593 {">", IDM_Forward, NULL, NULL},
\r
594 {">>", IDM_ToEnd, NULL, NULL},
\r
597 int tinyLayout = 0, smallLayout = 0;
\r
598 #define MENU_BAR_ITEMS 9
\r
599 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
600 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
601 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
605 MySound sounds[(int)NSoundClasses];
\r
606 MyTextAttribs textAttribs[(int)NColorClasses];
\r
608 MyColorizeAttribs colorizeAttribs[] = {
\r
609 { (COLORREF)0, 0, N_("Shout Text") },
\r
610 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
611 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
612 { (COLORREF)0, 0, N_("Channel Text") },
\r
613 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
614 { (COLORREF)0, 0, N_("Tell Text") },
\r
615 { (COLORREF)0, 0, N_("Challenge Text") },
\r
616 { (COLORREF)0, 0, N_("Request Text") },
\r
617 { (COLORREF)0, 0, N_("Seek Text") },
\r
618 { (COLORREF)0, 0, N_("Normal Text") },
\r
619 { (COLORREF)0, 0, N_("None") }
\r
624 static char *commentTitle;
\r
625 static char *commentText;
\r
626 static int commentIndex;
\r
627 static Boolean editComment = FALSE;
\r
630 char errorTitle[MSG_SIZ];
\r
631 char errorMessage[2*MSG_SIZ];
\r
632 HWND errorDialog = NULL;
\r
633 BOOLEAN moveErrorMessageUp = FALSE;
\r
634 BOOLEAN consoleEcho = TRUE;
\r
635 CHARFORMAT consoleCF;
\r
636 COLORREF consoleBackgroundColor;
\r
638 char *programVersion;
\r
644 typedef int CPKind;
\r
653 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
656 #define INPUT_SOURCE_BUF_SIZE 4096
\r
658 typedef struct _InputSource {
\r
665 char buf[INPUT_SOURCE_BUF_SIZE];
\r
669 InputCallback func;
\r
670 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
674 InputSource *consoleInputSource;
\r
679 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
680 VOID ConsoleCreate();
\r
682 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
683 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
684 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
685 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
687 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
689 void ParseIcsTextMenu(char *icsTextMenuString);
\r
690 VOID PopUpNameDialog(char firstchar);
\r
691 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
695 int GameListOptions();
\r
697 int dummy; // [HGM] for obsolete args
\r
699 HWND hwndMain = NULL; /* root window*/
\r
700 HWND hwndConsole = NULL;
\r
701 HWND commentDialog = NULL;
\r
702 HWND moveHistoryDialog = NULL;
\r
703 HWND evalGraphDialog = NULL;
\r
704 HWND engineOutputDialog = NULL;
\r
705 HWND gameListDialog = NULL;
\r
706 HWND editTagsDialog = NULL;
\r
708 int commentUp = FALSE;
\r
710 WindowPlacement wpMain;
\r
711 WindowPlacement wpConsole;
\r
712 WindowPlacement wpComment;
\r
713 WindowPlacement wpMoveHistory;
\r
714 WindowPlacement wpEvalGraph;
\r
715 WindowPlacement wpEngineOutput;
\r
716 WindowPlacement wpGameList;
\r
717 WindowPlacement wpTags;
\r
719 VOID EngineOptionsPopup(); // [HGM] settings
\r
721 VOID GothicPopUp(char *title, VariantClass variant);
\r
723 * Setting "frozen" should disable all user input other than deleting
\r
724 * the window. We do this while engines are initializing themselves.
\r
726 static int frozen = 0;
\r
727 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
733 if (frozen) return;
\r
735 hmenu = GetMenu(hwndMain);
\r
736 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
737 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
739 DrawMenuBar(hwndMain);
\r
742 /* Undo a FreezeUI */
\r
748 if (!frozen) return;
\r
750 hmenu = GetMenu(hwndMain);
\r
751 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
752 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
754 DrawMenuBar(hwndMain);
\r
757 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
759 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
765 #define JAWS_ALT_INTERCEPT
\r
766 #define JAWS_KBUP_NAVIGATION
\r
767 #define JAWS_KBDOWN_NAVIGATION
\r
768 #define JAWS_MENU_ITEMS
\r
769 #define JAWS_SILENCE
\r
770 #define JAWS_REPLAY
\r
772 #define JAWS_COPYRIGHT
\r
773 #define JAWS_DELETE(X) X
\r
774 #define SAYMACHINEMOVE()
\r
778 /*---------------------------------------------------------------------------*\
\r
782 \*---------------------------------------------------------------------------*/
\r
785 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
786 LPSTR lpCmdLine, int nCmdShow)
\r
789 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
790 // INITCOMMONCONTROLSEX ex;
\r
794 LoadLibrary("RICHED32.DLL");
\r
795 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
797 if (!InitApplication(hInstance)) {
\r
800 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
807 // InitCommonControlsEx(&ex);
\r
808 InitCommonControls();
\r
810 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
811 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
812 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
814 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
816 while (GetMessage(&msg, /* message structure */
\r
817 NULL, /* handle of window receiving the message */
\r
818 0, /* lowest message to examine */
\r
819 0)) /* highest message to examine */
\r
822 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
823 // [HGM] navigate: switch between all windows with tab
\r
824 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
825 int i, currentElement = 0;
\r
827 // first determine what element of the chain we come from (if any)
\r
828 if(appData.icsActive) {
\r
829 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
830 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
832 if(engineOutputDialog && EngineOutputIsUp()) {
\r
833 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
834 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
836 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
837 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
839 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
840 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
841 if(msg.hwnd == e1) currentElement = 2; else
\r
842 if(msg.hwnd == e2) currentElement = 3; else
\r
843 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
844 if(msg.hwnd == mh) currentElement = 4; else
\r
845 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
846 if(msg.hwnd == hText) currentElement = 5; else
\r
847 if(msg.hwnd == hInput) currentElement = 6; else
\r
848 for (i = 0; i < N_BUTTONS; i++) {
\r
849 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
852 // determine where to go to
\r
853 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
855 currentElement = (currentElement + direction) % 7;
\r
856 switch(currentElement) {
\r
858 h = hwndMain; break; // passing this case always makes the loop exit
\r
860 h = buttonDesc[0].hwnd; break; // could be NULL
\r
862 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
865 if(!EngineOutputIsUp()) continue;
\r
868 if(!MoveHistoryIsUp()) continue;
\r
870 // case 6: // input to eval graph does not seem to get here!
\r
871 // if(!EvalGraphIsUp()) continue;
\r
872 // h = evalGraphDialog; break;
\r
874 if(!appData.icsActive) continue;
\r
878 if(!appData.icsActive) continue;
\r
884 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
885 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
888 continue; // this message now has been processed
\r
892 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
893 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
894 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
895 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
896 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
897 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
898 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
899 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
900 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
901 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
902 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
903 for(i=0; i<MAX_CHAT; i++)
\r
904 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
907 if(done) continue; // [HGM] chat: end patch
\r
908 TranslateMessage(&msg); /* Translates virtual key codes */
\r
909 DispatchMessage(&msg); /* Dispatches message to window */
\r
914 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
917 /*---------------------------------------------------------------------------*\
\r
919 * Initialization functions
\r
921 \*---------------------------------------------------------------------------*/
\r
925 { // update user logo if necessary
\r
926 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
928 if(appData.autoLogo) {
\r
929 curName = UserName();
\r
930 if(strcmp(curName, oldUserName)) {
\r
931 GetCurrentDirectory(MSG_SIZ, dir);
\r
932 SetCurrentDirectory(installDir);
\r
933 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
934 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
935 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
936 if(userLogo == NULL)
\r
937 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
938 SetCurrentDirectory(dir); /* return to prev directory */
\r
944 InitApplication(HINSTANCE hInstance)
\r
948 /* Fill in window class structure with parameters that describe the */
\r
951 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
952 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
953 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
954 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
955 wc.hInstance = hInstance; /* Owner of this class */
\r
956 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
957 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
958 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
959 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
960 wc.lpszClassName = szAppName; /* Name to register as */
\r
962 /* Register the window class and return success/failure code. */
\r
963 if (!RegisterClass(&wc)) return FALSE;
\r
965 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
966 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
968 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
969 wc.hInstance = hInstance;
\r
970 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
971 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
972 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
973 wc.lpszMenuName = NULL;
\r
974 wc.lpszClassName = szConsoleName;
\r
976 if (!RegisterClass(&wc)) return FALSE;
\r
981 /* Set by InitInstance, used by EnsureOnScreen */
\r
982 int screenHeight, screenWidth;
\r
985 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
987 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
988 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
989 if (*x > screenWidth - 32) *x = 0;
\r
990 if (*y > screenHeight - 32) *y = 0;
\r
991 if (*x < minX) *x = minX;
\r
992 if (*y < minY) *y = minY;
\r
996 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
998 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
999 GetCurrentDirectory(MSG_SIZ, dir);
\r
1000 SetCurrentDirectory(installDir);
\r
1001 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1002 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1004 if (cps->programLogo == NULL && appData.debugMode) {
\r
1005 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1007 } else if(appData.autoLogo) {
\r
1008 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1009 char *opponent = "";
\r
1010 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1011 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1012 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1013 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1014 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1015 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1018 if(appData.directory[n] && appData.directory[n][0]) {
\r
1019 SetCurrentDirectory(appData.directory[n]);
\r
1020 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1023 SetCurrentDirectory(dir); /* return to prev directory */
\r
1029 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1030 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1032 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1033 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1034 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1035 liteBackTextureMode = appData.liteBackTextureMode;
\r
1037 if (liteBackTexture == NULL && appData.debugMode) {
\r
1038 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1042 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1043 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1044 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1045 darkBackTextureMode = appData.darkBackTextureMode;
\r
1047 if (darkBackTexture == NULL && appData.debugMode) {
\r
1048 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1054 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1056 HWND hwnd; /* Main window handle. */
\r
1058 WINDOWPLACEMENT wp;
\r
1061 hInst = hInstance; /* Store instance handle in our global variable */
\r
1062 programName = szAppName;
\r
1064 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1065 *filepart = NULLCHAR;
\r
1066 SetCurrentDirectory(installDir);
\r
1068 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1070 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1071 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1072 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1073 /* xboard, and older WinBoards, controlled the move sound with the
\r
1074 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1075 always turn the option on (so that the backend will call us),
\r
1076 then let the user turn the sound off by setting it to silence if
\r
1077 desired. To accommodate old winboard.ini files saved by old
\r
1078 versions of WinBoard, we also turn off the sound if the option
\r
1079 was initially set to false. [HGM] taken out of InitAppData */
\r
1080 if (!appData.ringBellAfterMoves) {
\r
1081 sounds[(int)SoundMove].name = strdup("");
\r
1082 appData.ringBellAfterMoves = TRUE;
\r
1084 if (appData.debugMode) {
\r
1085 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1086 setbuf(debugFP, NULL);
\r
1089 LoadLanguageFile(appData.language);
\r
1093 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1094 // InitEngineUCI( installDir, &second );
\r
1096 /* Create a main window for this application instance. */
\r
1097 hwnd = CreateWindow(szAppName, szTitle,
\r
1098 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1099 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1100 NULL, NULL, hInstance, NULL);
\r
1103 /* If window could not be created, return "failure" */
\r
1108 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1109 LoadLogo(&first, 0, FALSE);
\r
1110 LoadLogo(&second, 1, appData.icsActive);
\r
1114 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1115 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1116 iconCurrent = iconWhite;
\r
1117 InitDrawingColors();
\r
1118 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1119 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1120 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1121 /* Compute window size for each board size, and use the largest
\r
1122 size that fits on this screen as the default. */
\r
1123 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1124 if (boardSize == (BoardSize)-1 &&
\r
1125 winH <= screenHeight
\r
1126 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1127 && winW <= screenWidth) {
\r
1128 boardSize = (BoardSize)ibs;
\r
1132 InitDrawingSizes(boardSize, 0);
\r
1133 RecentEngineMenu(appData.recentEngineList);
\r
1135 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1137 /* [AS] Load textures if specified */
\r
1140 mysrandom( (unsigned) time(NULL) );
\r
1142 /* [AS] Restore layout */
\r
1143 if( wpMoveHistory.visible ) {
\r
1144 MoveHistoryPopUp();
\r
1147 if( wpEvalGraph.visible ) {
\r
1151 if( wpEngineOutput.visible ) {
\r
1152 EngineOutputPopUp();
\r
1155 /* Make the window visible; update its client area; and return "success" */
\r
1156 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1157 wp.length = sizeof(WINDOWPLACEMENT);
\r
1159 wp.showCmd = nCmdShow;
\r
1160 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1161 wp.rcNormalPosition.left = wpMain.x;
\r
1162 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1163 wp.rcNormalPosition.top = wpMain.y;
\r
1164 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1165 SetWindowPlacement(hwndMain, &wp);
\r
1167 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1169 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1170 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1172 if (hwndConsole) {
\r
1174 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1175 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1177 ShowWindow(hwndConsole, nCmdShow);
\r
1178 SetActiveWindow(hwndConsole);
\r
1180 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1181 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1190 HMENU hmenu = GetMenu(hwndMain);
\r
1192 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1193 MF_BYCOMMAND|((appData.icsActive &&
\r
1194 *appData.icsCommPort != NULLCHAR) ?
\r
1195 MF_ENABLED : MF_GRAYED));
\r
1196 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1197 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1198 MF_CHECKED : MF_UNCHECKED));
\r
1201 //---------------------------------------------------------------------------------------------------------
\r
1203 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1204 #define XBOARD FALSE
\r
1206 #define OPTCHAR "/"
\r
1207 #define SEPCHAR "="
\r
1208 #define TOPLEVEL 0
\r
1212 // front-end part of option handling
\r
1215 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1217 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1218 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1221 lf->lfEscapement = 0;
\r
1222 lf->lfOrientation = 0;
\r
1223 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1224 lf->lfItalic = mfp->italic;
\r
1225 lf->lfUnderline = mfp->underline;
\r
1226 lf->lfStrikeOut = mfp->strikeout;
\r
1227 lf->lfCharSet = mfp->charset;
\r
1228 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1229 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1230 lf->lfQuality = DEFAULT_QUALITY;
\r
1231 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1232 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1236 CreateFontInMF(MyFont *mf)
\r
1238 LFfromMFP(&mf->lf, &mf->mfp);
\r
1239 if (mf->hf) DeleteObject(mf->hf);
\r
1240 mf->hf = CreateFontIndirect(&mf->lf);
\r
1243 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1245 colorVariable[] = {
\r
1246 &whitePieceColor,
\r
1247 &blackPieceColor,
\r
1248 &lightSquareColor,
\r
1249 &darkSquareColor,
\r
1250 &highlightSquareColor,
\r
1251 &premoveHighlightColor,
\r
1253 &consoleBackgroundColor,
\r
1254 &appData.fontForeColorWhite,
\r
1255 &appData.fontBackColorWhite,
\r
1256 &appData.fontForeColorBlack,
\r
1257 &appData.fontBackColorBlack,
\r
1258 &appData.evalHistColorWhite,
\r
1259 &appData.evalHistColorBlack,
\r
1260 &appData.highlightArrowColor,
\r
1263 /* Command line font name parser. NULL name means do nothing.
\r
1264 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1265 For backward compatibility, syntax without the colon is also
\r
1266 accepted, but font names with digits in them won't work in that case.
\r
1269 ParseFontName(char *name, MyFontParams *mfp)
\r
1272 if (name == NULL) return;
\r
1274 q = strchr(p, ':');
\r
1276 if (q - p >= sizeof(mfp->faceName))
\r
1277 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1278 memcpy(mfp->faceName, p, q - p);
\r
1279 mfp->faceName[q - p] = NULLCHAR;
\r
1282 q = mfp->faceName;
\r
1284 while (*p && !isdigit(*p)) {
\r
1286 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1287 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1289 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1292 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1293 mfp->pointSize = (float) atof(p);
\r
1294 mfp->bold = (strchr(p, 'b') != NULL);
\r
1295 mfp->italic = (strchr(p, 'i') != NULL);
\r
1296 mfp->underline = (strchr(p, 'u') != NULL);
\r
1297 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1298 mfp->charset = DEFAULT_CHARSET;
\r
1299 q = strchr(p, 'c');
\r
1301 mfp->charset = (BYTE) atoi(q+1);
\r
1305 ParseFont(char *name, int number)
\r
1306 { // wrapper to shield back-end from 'font'
\r
1307 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1312 { // in WB we have a 2D array of fonts; this initializes their description
\r
1314 /* Point font array elements to structures and
\r
1315 parse default font names */
\r
1316 for (i=0; i<NUM_FONTS; i++) {
\r
1317 for (j=0; j<NUM_SIZES; j++) {
\r
1318 font[j][i] = &fontRec[j][i];
\r
1319 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1326 { // here we create the actual fonts from the selected descriptions
\r
1328 for (i=0; i<NUM_FONTS; i++) {
\r
1329 for (j=0; j<NUM_SIZES; j++) {
\r
1330 CreateFontInMF(font[j][i]);
\r
1334 /* Color name parser.
\r
1335 X version accepts X color names, but this one
\r
1336 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1338 ParseColorName(char *name)
\r
1340 int red, green, blue, count;
\r
1341 char buf[MSG_SIZ];
\r
1343 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1345 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1346 &red, &green, &blue);
\r
1349 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1350 DisplayError(buf, 0);
\r
1351 return RGB(0, 0, 0);
\r
1353 return PALETTERGB(red, green, blue);
\r
1357 ParseColor(int n, char *name)
\r
1358 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1359 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1363 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1365 char *e = argValue;
\r
1369 if (*e == 'b') eff |= CFE_BOLD;
\r
1370 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1371 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1372 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1373 else if (*e == '#' || isdigit(*e)) break;
\r
1377 *color = ParseColorName(e);
\r
1381 ParseTextAttribs(ColorClass cc, char *s)
\r
1382 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1383 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1384 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1388 ParseBoardSize(void *addr, char *name)
\r
1389 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1390 BoardSize bs = SizeTiny;
\r
1391 while (sizeInfo[bs].name != NULL) {
\r
1392 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1393 *(BoardSize *)addr = bs;
\r
1398 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1403 { // [HGM] import name from appData first
\r
1406 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1407 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1408 textAttribs[cc].sound.data = NULL;
\r
1409 MyLoadSound(&textAttribs[cc].sound);
\r
1411 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1412 textAttribs[cc].sound.name = strdup("");
\r
1413 textAttribs[cc].sound.data = NULL;
\r
1415 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1416 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1417 sounds[sc].data = NULL;
\r
1418 MyLoadSound(&sounds[sc]);
\r
1423 SetCommPortDefaults()
\r
1425 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1426 dcb.DCBlength = sizeof(DCB);
\r
1427 dcb.BaudRate = 9600;
\r
1428 dcb.fBinary = TRUE;
\r
1429 dcb.fParity = FALSE;
\r
1430 dcb.fOutxCtsFlow = FALSE;
\r
1431 dcb.fOutxDsrFlow = FALSE;
\r
1432 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1433 dcb.fDsrSensitivity = FALSE;
\r
1434 dcb.fTXContinueOnXoff = TRUE;
\r
1435 dcb.fOutX = FALSE;
\r
1437 dcb.fNull = FALSE;
\r
1438 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1439 dcb.fAbortOnError = FALSE;
\r
1441 dcb.Parity = SPACEPARITY;
\r
1442 dcb.StopBits = ONESTOPBIT;
\r
1445 // [HGM] args: these three cases taken out to stay in front-end
\r
1447 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1448 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1449 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1450 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1452 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1453 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1454 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1455 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1456 ad->argName, mfp->faceName, mfp->pointSize,
\r
1457 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1458 mfp->bold ? "b" : "",
\r
1459 mfp->italic ? "i" : "",
\r
1460 mfp->underline ? "u" : "",
\r
1461 mfp->strikeout ? "s" : "",
\r
1462 (int)mfp->charset);
\r
1468 { // [HGM] copy the names from the internal WB variables to appData
\r
1471 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1472 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1473 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1474 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1478 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1479 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1480 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1481 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1482 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1483 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1484 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1485 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1486 (ta->effects) ? " " : "",
\r
1487 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1491 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1492 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1493 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1494 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1495 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1499 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1500 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1501 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1505 ParseCommPortSettings(char *s)
\r
1506 { // wrapper to keep dcb from back-end
\r
1507 ParseCommSettings(s, &dcb);
\r
1512 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1513 GetActualPlacement(hwndMain, &wpMain);
\r
1514 GetActualPlacement(hwndConsole, &wpConsole);
\r
1515 GetActualPlacement(commentDialog, &wpComment);
\r
1516 GetActualPlacement(editTagsDialog, &wpTags);
\r
1517 GetActualPlacement(gameListDialog, &wpGameList);
\r
1518 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1519 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1520 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1524 PrintCommPortSettings(FILE *f, char *name)
\r
1525 { // wrapper to shield back-end from DCB
\r
1526 PrintCommSettings(f, name, &dcb);
\r
1530 MySearchPath(char *installDir, char *name, char *fullname)
\r
1532 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1533 if(name[0]== '%') {
\r
1534 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1535 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1536 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1537 *strchr(buf, '%') = 0;
\r
1538 strcat(fullname, getenv(buf));
\r
1539 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1541 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1542 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1543 return (int) strlen(fullname);
\r
1545 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1549 MyGetFullPathName(char *name, char *fullname)
\r
1552 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1557 { // [HGM] args: allows testing if main window is realized from back-end
\r
1558 return hwndMain != NULL;
\r
1562 PopUpStartupDialog()
\r
1566 LoadLanguageFile(appData.language);
\r
1567 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1568 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1569 FreeProcInstance(lpProc);
\r
1572 /*---------------------------------------------------------------------------*\
\r
1574 * GDI board drawing routines
\r
1576 \*---------------------------------------------------------------------------*/
\r
1578 /* [AS] Draw square using background texture */
\r
1579 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1584 return; /* Should never happen! */
\r
1587 SetGraphicsMode( dst, GM_ADVANCED );
\r
1594 /* X reflection */
\r
1599 x.eDx = (FLOAT) dw + dx - 1;
\r
1602 SetWorldTransform( dst, &x );
\r
1605 /* Y reflection */
\r
1611 x.eDy = (FLOAT) dh + dy - 1;
\r
1613 SetWorldTransform( dst, &x );
\r
1621 x.eDx = (FLOAT) dx;
\r
1622 x.eDy = (FLOAT) dy;
\r
1625 SetWorldTransform( dst, &x );
\r
1629 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1637 SetWorldTransform( dst, &x );
\r
1639 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1642 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1644 PM_WP = (int) WhitePawn,
\r
1645 PM_WN = (int) WhiteKnight,
\r
1646 PM_WB = (int) WhiteBishop,
\r
1647 PM_WR = (int) WhiteRook,
\r
1648 PM_WQ = (int) WhiteQueen,
\r
1649 PM_WF = (int) WhiteFerz,
\r
1650 PM_WW = (int) WhiteWazir,
\r
1651 PM_WE = (int) WhiteAlfil,
\r
1652 PM_WM = (int) WhiteMan,
\r
1653 PM_WO = (int) WhiteCannon,
\r
1654 PM_WU = (int) WhiteUnicorn,
\r
1655 PM_WH = (int) WhiteNightrider,
\r
1656 PM_WA = (int) WhiteAngel,
\r
1657 PM_WC = (int) WhiteMarshall,
\r
1658 PM_WAB = (int) WhiteCardinal,
\r
1659 PM_WD = (int) WhiteDragon,
\r
1660 PM_WL = (int) WhiteLance,
\r
1661 PM_WS = (int) WhiteCobra,
\r
1662 PM_WV = (int) WhiteFalcon,
\r
1663 PM_WSG = (int) WhiteSilver,
\r
1664 PM_WG = (int) WhiteGrasshopper,
\r
1665 PM_WK = (int) WhiteKing,
\r
1666 PM_BP = (int) BlackPawn,
\r
1667 PM_BN = (int) BlackKnight,
\r
1668 PM_BB = (int) BlackBishop,
\r
1669 PM_BR = (int) BlackRook,
\r
1670 PM_BQ = (int) BlackQueen,
\r
1671 PM_BF = (int) BlackFerz,
\r
1672 PM_BW = (int) BlackWazir,
\r
1673 PM_BE = (int) BlackAlfil,
\r
1674 PM_BM = (int) BlackMan,
\r
1675 PM_BO = (int) BlackCannon,
\r
1676 PM_BU = (int) BlackUnicorn,
\r
1677 PM_BH = (int) BlackNightrider,
\r
1678 PM_BA = (int) BlackAngel,
\r
1679 PM_BC = (int) BlackMarshall,
\r
1680 PM_BG = (int) BlackGrasshopper,
\r
1681 PM_BAB = (int) BlackCardinal,
\r
1682 PM_BD = (int) BlackDragon,
\r
1683 PM_BL = (int) BlackLance,
\r
1684 PM_BS = (int) BlackCobra,
\r
1685 PM_BV = (int) BlackFalcon,
\r
1686 PM_BSG = (int) BlackSilver,
\r
1687 PM_BK = (int) BlackKing
\r
1690 static HFONT hPieceFont = NULL;
\r
1691 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1692 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1693 static int fontBitmapSquareSize = 0;
\r
1694 static char pieceToFontChar[(int) EmptySquare] =
\r
1695 { 'p', 'n', 'b', 'r', 'q',
\r
1696 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1697 'k', 'o', 'm', 'v', 't', 'w',
\r
1698 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1701 extern BOOL SetCharTable( char *table, const char * map );
\r
1702 /* [HGM] moved to backend.c */
\r
1704 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1707 BYTE r1 = GetRValue( color );
\r
1708 BYTE g1 = GetGValue( color );
\r
1709 BYTE b1 = GetBValue( color );
\r
1715 /* Create a uniform background first */
\r
1716 hbrush = CreateSolidBrush( color );
\r
1717 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1718 FillRect( hdc, &rc, hbrush );
\r
1719 DeleteObject( hbrush );
\r
1722 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1723 int steps = squareSize / 2;
\r
1726 for( i=0; i<steps; i++ ) {
\r
1727 BYTE r = r1 - (r1-r2) * i / steps;
\r
1728 BYTE g = g1 - (g1-g2) * i / steps;
\r
1729 BYTE b = b1 - (b1-b2) * i / steps;
\r
1731 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1732 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1733 FillRect( hdc, &rc, hbrush );
\r
1734 DeleteObject(hbrush);
\r
1737 else if( mode == 2 ) {
\r
1738 /* Diagonal gradient, good more or less for every piece */
\r
1739 POINT triangle[3];
\r
1740 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1741 HBRUSH hbrush_old;
\r
1742 int steps = squareSize;
\r
1745 triangle[0].x = squareSize - steps;
\r
1746 triangle[0].y = squareSize;
\r
1747 triangle[1].x = squareSize;
\r
1748 triangle[1].y = squareSize;
\r
1749 triangle[2].x = squareSize;
\r
1750 triangle[2].y = squareSize - steps;
\r
1752 for( i=0; i<steps; i++ ) {
\r
1753 BYTE r = r1 - (r1-r2) * i / steps;
\r
1754 BYTE g = g1 - (g1-g2) * i / steps;
\r
1755 BYTE b = b1 - (b1-b2) * i / steps;
\r
1757 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1758 hbrush_old = SelectObject( hdc, hbrush );
\r
1759 Polygon( hdc, triangle, 3 );
\r
1760 SelectObject( hdc, hbrush_old );
\r
1761 DeleteObject(hbrush);
\r
1766 SelectObject( hdc, hpen );
\r
1771 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1772 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1773 piece: follow the steps as explained below.
\r
1775 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1779 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1783 int backColor = whitePieceColor;
\r
1784 int foreColor = blackPieceColor;
\r
1786 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1787 backColor = appData.fontBackColorWhite;
\r
1788 foreColor = appData.fontForeColorWhite;
\r
1790 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1791 backColor = appData.fontBackColorBlack;
\r
1792 foreColor = appData.fontForeColorBlack;
\r
1796 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1798 hbm_old = SelectObject( hdc, hbm );
\r
1802 rc.right = squareSize;
\r
1803 rc.bottom = squareSize;
\r
1805 /* Step 1: background is now black */
\r
1806 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1808 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1810 pt.x = (squareSize - sz.cx) / 2;
\r
1811 pt.y = (squareSize - sz.cy) / 2;
\r
1813 SetBkMode( hdc, TRANSPARENT );
\r
1814 SetTextColor( hdc, chroma );
\r
1815 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1816 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1818 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1819 /* Step 3: the area outside the piece is filled with white */
\r
1820 // FloodFill( hdc, 0, 0, chroma );
\r
1821 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1822 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1823 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1824 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1825 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1827 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1828 but if the start point is not inside the piece we're lost!
\r
1829 There should be a better way to do this... if we could create a region or path
\r
1830 from the fill operation we would be fine for example.
\r
1832 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1833 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1835 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1836 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1837 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1839 SelectObject( dc2, bm2 );
\r
1840 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1841 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1842 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1843 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1844 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1847 DeleteObject( bm2 );
\r
1850 SetTextColor( hdc, 0 );
\r
1852 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1853 draw the piece again in black for safety.
\r
1855 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1857 SelectObject( hdc, hbm_old );
\r
1859 if( hPieceMask[index] != NULL ) {
\r
1860 DeleteObject( hPieceMask[index] );
\r
1863 hPieceMask[index] = hbm;
\r
1866 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1868 SelectObject( hdc, hbm );
\r
1871 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1872 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1873 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1875 SelectObject( dc1, hPieceMask[index] );
\r
1876 SelectObject( dc2, bm2 );
\r
1877 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1878 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1881 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1882 the piece background and deletes (makes transparent) the rest.
\r
1883 Thanks to that mask, we are free to paint the background with the greates
\r
1884 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1885 We use this, to make gradients and give the pieces a "roundish" look.
\r
1887 SetPieceBackground( hdc, backColor, 2 );
\r
1888 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1892 DeleteObject( bm2 );
\r
1895 SetTextColor( hdc, foreColor );
\r
1896 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1898 SelectObject( hdc, hbm_old );
\r
1900 if( hPieceFace[index] != NULL ) {
\r
1901 DeleteObject( hPieceFace[index] );
\r
1904 hPieceFace[index] = hbm;
\r
1907 static int TranslatePieceToFontPiece( int piece )
\r
1937 case BlackMarshall:
\r
1941 case BlackNightrider:
\r
1947 case BlackUnicorn:
\r
1951 case BlackGrasshopper:
\r
1963 case BlackCardinal:
\r
1970 case WhiteMarshall:
\r
1974 case WhiteNightrider:
\r
1980 case WhiteUnicorn:
\r
1984 case WhiteGrasshopper:
\r
1996 case WhiteCardinal:
\r
2005 void CreatePiecesFromFont()
\r
2008 HDC hdc_window = NULL;
\r
2014 if( fontBitmapSquareSize < 0 ) {
\r
2015 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2019 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2020 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2021 fontBitmapSquareSize = -1;
\r
2025 if( fontBitmapSquareSize != squareSize ) {
\r
2026 hdc_window = GetDC( hwndMain );
\r
2027 hdc = CreateCompatibleDC( hdc_window );
\r
2029 if( hPieceFont != NULL ) {
\r
2030 DeleteObject( hPieceFont );
\r
2033 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2034 hPieceMask[i] = NULL;
\r
2035 hPieceFace[i] = NULL;
\r
2041 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2042 fontHeight = appData.fontPieceSize;
\r
2045 fontHeight = (fontHeight * squareSize) / 100;
\r
2047 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2049 lf.lfEscapement = 0;
\r
2050 lf.lfOrientation = 0;
\r
2051 lf.lfWeight = FW_NORMAL;
\r
2053 lf.lfUnderline = 0;
\r
2054 lf.lfStrikeOut = 0;
\r
2055 lf.lfCharSet = DEFAULT_CHARSET;
\r
2056 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2057 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2058 lf.lfQuality = PROOF_QUALITY;
\r
2059 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2060 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2061 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2063 hPieceFont = CreateFontIndirect( &lf );
\r
2065 if( hPieceFont == NULL ) {
\r
2066 fontBitmapSquareSize = -2;
\r
2069 /* Setup font-to-piece character table */
\r
2070 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2071 /* No (or wrong) global settings, try to detect the font */
\r
2072 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2074 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2076 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2077 /* DiagramTT* family */
\r
2078 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2080 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2081 /* Fairy symbols */
\r
2082 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2084 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2085 /* Good Companion (Some characters get warped as literal :-( */
\r
2086 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2087 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2088 SetCharTable(pieceToFontChar, s);
\r
2091 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2092 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2096 /* Create bitmaps */
\r
2097 hfont_old = SelectObject( hdc, hPieceFont );
\r
2098 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2099 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2100 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2102 SelectObject( hdc, hfont_old );
\r
2104 fontBitmapSquareSize = squareSize;
\r
2108 if( hdc != NULL ) {
\r
2112 if( hdc_window != NULL ) {
\r
2113 ReleaseDC( hwndMain, hdc_window );
\r
2118 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2120 char name[128], buf[MSG_SIZ];
\r
2122 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2123 if(appData.pieceDirectory[0]) {
\r
2125 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2126 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2127 if(res) return res;
\r
2129 if (gameInfo.event &&
\r
2130 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2131 strcmp(name, "k80s") == 0) {
\r
2132 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2134 return LoadBitmap(hinst, name);
\r
2138 /* Insert a color into the program's logical palette
\r
2139 structure. This code assumes the given color is
\r
2140 the result of the RGB or PALETTERGB macro, and it
\r
2141 knows how those macros work (which is documented).
\r
2144 InsertInPalette(COLORREF color)
\r
2146 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2148 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2149 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2150 pLogPal->palNumEntries--;
\r
2154 pe->peFlags = (char) 0;
\r
2155 pe->peRed = (char) (0xFF & color);
\r
2156 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2157 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2163 InitDrawingColors()
\r
2165 if (pLogPal == NULL) {
\r
2166 /* Allocate enough memory for a logical palette with
\r
2167 * PALETTESIZE entries and set the size and version fields
\r
2168 * of the logical palette structure.
\r
2170 pLogPal = (NPLOGPALETTE)
\r
2171 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2172 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2173 pLogPal->palVersion = 0x300;
\r
2175 pLogPal->palNumEntries = 0;
\r
2177 InsertInPalette(lightSquareColor);
\r
2178 InsertInPalette(darkSquareColor);
\r
2179 InsertInPalette(whitePieceColor);
\r
2180 InsertInPalette(blackPieceColor);
\r
2181 InsertInPalette(highlightSquareColor);
\r
2182 InsertInPalette(premoveHighlightColor);
\r
2184 /* create a logical color palette according the information
\r
2185 * in the LOGPALETTE structure.
\r
2187 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2189 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2190 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2191 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2192 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2193 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2194 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2195 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2196 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2197 /* [AS] Force rendering of the font-based pieces */
\r
2198 if( fontBitmapSquareSize > 0 ) {
\r
2199 fontBitmapSquareSize = 0;
\r
2205 BoardWidth(int boardSize, int n)
\r
2206 { /* [HGM] argument n added to allow different width and height */
\r
2207 int lineGap = sizeInfo[boardSize].lineGap;
\r
2209 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2210 lineGap = appData.overrideLineGap;
\r
2213 return (n + 1) * lineGap +
\r
2214 n * sizeInfo[boardSize].squareSize;
\r
2217 /* Respond to board resize by dragging edge */
\r
2219 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2221 BoardSize newSize = NUM_SIZES - 1;
\r
2222 static int recurse = 0;
\r
2223 if (IsIconic(hwndMain)) return;
\r
2224 if (recurse > 0) return;
\r
2226 while (newSize > 0) {
\r
2227 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2228 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2229 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2232 boardSize = newSize;
\r
2233 InitDrawingSizes(boardSize, flags);
\r
2238 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2241 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2243 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2244 ChessSquare piece;
\r
2245 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2247 SIZE clockSize, messageSize;
\r
2249 char buf[MSG_SIZ];
\r
2251 HMENU hmenu = GetMenu(hwndMain);
\r
2252 RECT crect, wrect, oldRect;
\r
2254 LOGBRUSH logbrush;
\r
2255 VariantClass v = gameInfo.variant;
\r
2257 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2258 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2260 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2261 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2262 oldBoardSize = boardSize;
\r
2264 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2265 { // correct board size to one where built-in pieces exist
\r
2266 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2267 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2268 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2269 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2270 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {
\r
2271 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2272 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2273 boardSize = SizeMiddling;
\r
2276 if(!appData.useFont && boardSize == SizePetite && (v == VariantShogi || v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2278 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2279 oldRect.top = wpMain.y;
\r
2280 oldRect.right = wpMain.x + wpMain.width;
\r
2281 oldRect.bottom = wpMain.y + wpMain.height;
\r
2283 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2284 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2285 squareSize = sizeInfo[boardSize].squareSize;
\r
2286 lineGap = sizeInfo[boardSize].lineGap;
\r
2287 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2288 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2290 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2291 lineGap = appData.overrideLineGap;
\r
2294 if (tinyLayout != oldTinyLayout) {
\r
2295 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2297 style &= ~WS_SYSMENU;
\r
2298 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2299 "&Minimize\tCtrl+F4");
\r
2301 style |= WS_SYSMENU;
\r
2302 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2304 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2306 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2307 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2308 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2310 DrawMenuBar(hwndMain);
\r
2313 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2314 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2316 /* Get text area sizes */
\r
2317 hdc = GetDC(hwndMain);
\r
2318 if (appData.clockMode) {
\r
2319 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2321 snprintf(buf, MSG_SIZ, _("White"));
\r
2323 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2324 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2325 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2326 str = _("We only care about the height here");
\r
2327 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2328 SelectObject(hdc, oldFont);
\r
2329 ReleaseDC(hwndMain, hdc);
\r
2331 /* Compute where everything goes */
\r
2332 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2333 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2334 logoHeight = 2*clockSize.cy;
\r
2335 leftLogoRect.left = OUTER_MARGIN;
\r
2336 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2337 leftLogoRect.top = OUTER_MARGIN;
\r
2338 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2340 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2341 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2342 rightLogoRect.top = OUTER_MARGIN;
\r
2343 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2346 whiteRect.left = leftLogoRect.right;
\r
2347 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2348 whiteRect.top = OUTER_MARGIN;
\r
2349 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2351 blackRect.right = rightLogoRect.left;
\r
2352 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2353 blackRect.top = whiteRect.top;
\r
2354 blackRect.bottom = whiteRect.bottom;
\r
2356 whiteRect.left = OUTER_MARGIN;
\r
2357 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2358 whiteRect.top = OUTER_MARGIN;
\r
2359 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2361 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2362 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2363 blackRect.top = whiteRect.top;
\r
2364 blackRect.bottom = whiteRect.bottom;
\r
2366 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2369 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2370 if (appData.showButtonBar) {
\r
2371 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2372 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2374 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2376 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2377 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2379 boardRect.left = OUTER_MARGIN;
\r
2380 boardRect.right = boardRect.left + boardWidth;
\r
2381 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2382 boardRect.bottom = boardRect.top + boardHeight;
\r
2384 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2385 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2386 oldTinyLayout = tinyLayout;
\r
2387 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2388 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2389 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2390 winW *= 1 + twoBoards;
\r
2391 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2392 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2393 wpMain.height = winH; // without disturbing window attachments
\r
2394 GetWindowRect(hwndMain, &wrect);
\r
2395 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2396 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2398 // [HGM] placement: let attached windows follow size change.
\r
2399 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2400 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2401 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2402 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2403 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2405 /* compensate if menu bar wrapped */
\r
2406 GetClientRect(hwndMain, &crect);
\r
2407 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2408 wpMain.height += offby;
\r
2410 case WMSZ_TOPLEFT:
\r
2411 SetWindowPos(hwndMain, NULL,
\r
2412 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2413 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2416 case WMSZ_TOPRIGHT:
\r
2418 SetWindowPos(hwndMain, NULL,
\r
2419 wrect.left, wrect.bottom - wpMain.height,
\r
2420 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2423 case WMSZ_BOTTOMLEFT:
\r
2425 SetWindowPos(hwndMain, NULL,
\r
2426 wrect.right - wpMain.width, wrect.top,
\r
2427 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2430 case WMSZ_BOTTOMRIGHT:
\r
2434 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2435 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2440 for (i = 0; i < N_BUTTONS; i++) {
\r
2441 if (buttonDesc[i].hwnd != NULL) {
\r
2442 DestroyWindow(buttonDesc[i].hwnd);
\r
2443 buttonDesc[i].hwnd = NULL;
\r
2445 if (appData.showButtonBar) {
\r
2446 buttonDesc[i].hwnd =
\r
2447 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2448 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2449 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2450 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2451 (HMENU) buttonDesc[i].id,
\r
2452 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2454 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2455 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2456 MAKELPARAM(FALSE, 0));
\r
2458 if (buttonDesc[i].id == IDM_Pause)
\r
2459 hwndPause = buttonDesc[i].hwnd;
\r
2460 buttonDesc[i].wndproc = (WNDPROC)
\r
2461 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2464 if (gridPen != NULL) DeleteObject(gridPen);
\r
2465 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2466 if (premovePen != NULL) DeleteObject(premovePen);
\r
2467 if (lineGap != 0) {
\r
2468 logbrush.lbStyle = BS_SOLID;
\r
2469 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2471 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2472 lineGap, &logbrush, 0, NULL);
\r
2473 logbrush.lbColor = highlightSquareColor;
\r
2475 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2476 lineGap, &logbrush, 0, NULL);
\r
2478 logbrush.lbColor = premoveHighlightColor;
\r
2480 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2481 lineGap, &logbrush, 0, NULL);
\r
2483 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2484 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2485 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2486 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2487 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2488 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2489 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2490 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2492 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2493 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2494 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2495 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2496 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2497 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2498 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2499 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2503 /* [HGM] Licensing requirement */
\r
2505 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2508 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2510 GothicPopUp( "", VariantNormal);
\r
2513 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2515 /* Load piece bitmaps for this board size */
\r
2516 for (i=0; i<=2; i++) {
\r
2517 for (piece = WhitePawn;
\r
2518 (int) piece < (int) BlackPawn;
\r
2519 piece = (ChessSquare) ((int) piece + 1)) {
\r
2520 if (pieceBitmap[i][piece] != NULL)
\r
2521 DeleteObject(pieceBitmap[i][piece]);
\r
2525 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2526 // Orthodox Chess pieces
\r
2527 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2528 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2529 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2530 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2531 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2532 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2533 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2534 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2535 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2536 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2537 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2538 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2539 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2540 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2541 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2542 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2543 // in Shogi, Hijack the unused Queen for Lance
\r
2544 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2545 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2546 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2548 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2549 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2550 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2553 if(squareSize <= 72 && squareSize >= 33) {
\r
2554 /* A & C are available in most sizes now */
\r
2555 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2556 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2557 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2558 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2559 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2560 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2561 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2562 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2563 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2564 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2565 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2566 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2567 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2568 } else { // Smirf-like
\r
2569 if(gameInfo.variant == VariantSChess) {
\r
2570 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2571 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2572 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2574 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2575 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2576 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2579 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2580 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2581 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2582 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2583 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2584 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2585 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2586 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2587 } else { // WinBoard standard
\r
2588 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2589 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2590 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2595 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2596 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2597 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2598 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2599 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2600 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2601 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2602 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2603 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2604 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2605 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2606 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2607 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2608 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2609 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2610 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2611 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2612 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2613 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2614 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2617 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2618 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2619 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2620 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2621 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2622 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2623 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2624 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2625 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2627 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2628 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2629 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2630 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2631 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2632 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2633 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2634 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2635 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2636 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2637 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2638 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2639 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2641 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2642 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2643 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2644 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2647 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2648 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2649 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2650 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2655 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2656 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2657 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2658 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2659 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2660 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2661 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2662 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2663 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2664 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2665 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2666 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2667 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2668 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2669 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2673 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2674 /* special Shogi support in this size */
\r
2675 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2676 for (piece = WhitePawn;
\r
2677 (int) piece < (int) BlackPawn;
\r
2678 piece = (ChessSquare) ((int) piece + 1)) {
\r
2679 if (pieceBitmap[i][piece] != NULL)
\r
2680 DeleteObject(pieceBitmap[i][piece]);
\r
2683 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2684 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2685 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2686 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2687 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2688 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2689 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2690 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2691 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2692 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2693 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2694 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2695 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2696 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2697 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2698 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2699 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2700 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2701 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2702 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2703 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2704 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2705 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2706 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2707 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2708 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2709 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2710 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2711 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2712 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2713 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2714 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2715 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2716 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2717 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2718 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2719 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2720 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2721 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2722 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2723 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2724 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2730 PieceBitmap(ChessSquare p, int kind)
\r
2732 if ((int) p >= (int) BlackPawn)
\r
2733 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2735 return pieceBitmap[kind][(int) p];
\r
2738 /***************************************************************/
\r
2740 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2741 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2743 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2744 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2748 SquareToPos(int row, int column, int * x, int * y)
\r
2751 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2752 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2754 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2755 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2760 DrawCoordsOnDC(HDC hdc)
\r
2762 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2763 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2764 char str[2] = { NULLCHAR, NULLCHAR };
\r
2765 int oldMode, oldAlign, x, y, start, i;
\r
2769 if (!appData.showCoords)
\r
2772 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2774 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2775 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2776 oldAlign = GetTextAlign(hdc);
\r
2777 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2779 y = boardRect.top + lineGap;
\r
2780 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2783 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2784 x += border - lineGap - 4; y += squareSize - 6;
\r
2786 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2787 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2788 str[0] = files[start + i];
\r
2789 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2790 y += squareSize + lineGap;
\r
2793 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2796 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2797 x += -border + 4; y += border - squareSize + 6;
\r
2799 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2800 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2801 str[0] = ranks[start + i];
\r
2802 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2803 x += squareSize + lineGap;
\r
2806 SelectObject(hdc, oldBrush);
\r
2807 SetBkMode(hdc, oldMode);
\r
2808 SetTextAlign(hdc, oldAlign);
\r
2809 SelectObject(hdc, oldFont);
\r
2813 DrawGridOnDC(HDC hdc)
\r
2817 if (lineGap != 0) {
\r
2818 oldPen = SelectObject(hdc, gridPen);
\r
2819 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2820 SelectObject(hdc, oldPen);
\r
2824 #define HIGHLIGHT_PEN 0
\r
2825 #define PREMOVE_PEN 1
\r
2828 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2831 HPEN oldPen, hPen;
\r
2832 if (lineGap == 0) return;
\r
2834 x1 = boardRect.left +
\r
2835 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2836 y1 = boardRect.top +
\r
2837 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2839 x1 = boardRect.left +
\r
2840 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2841 y1 = boardRect.top +
\r
2842 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2844 hPen = pen ? premovePen : highlightPen;
\r
2845 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2846 MoveToEx(hdc, x1, y1, NULL);
\r
2847 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2848 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2849 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2850 LineTo(hdc, x1, y1);
\r
2851 SelectObject(hdc, oldPen);
\r
2855 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2858 for (i=0; i<2; i++) {
\r
2859 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2860 DrawHighlightOnDC(hdc, TRUE,
\r
2861 h->sq[i].x, h->sq[i].y,
\r
2866 /* Note: sqcolor is used only in monoMode */
\r
2867 /* Note that this code is largely duplicated in woptions.c,
\r
2868 function DrawSampleSquare, so that needs to be updated too */
\r
2870 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2872 HBITMAP oldBitmap;
\r
2876 if (appData.blindfold) return;
\r
2878 /* [AS] Use font-based pieces if needed */
\r
2879 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2880 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2881 CreatePiecesFromFont();
\r
2883 if( fontBitmapSquareSize == squareSize ) {
\r
2884 int index = TranslatePieceToFontPiece(piece);
\r
2886 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2888 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2889 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2893 squareSize, squareSize,
\r
2898 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2900 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2901 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2905 squareSize, squareSize,
\r
2914 if (appData.monoMode) {
\r
2915 SelectObject(tmphdc, PieceBitmap(piece,
\r
2916 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2917 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2918 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2920 HBRUSH xBrush = whitePieceBrush;
\r
2921 tmpSize = squareSize;
\r
2922 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2924 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2925 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2926 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2927 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2928 x += (squareSize - minorSize)>>1;
\r
2929 y += squareSize - minorSize - 2;
\r
2930 tmpSize = minorSize;
\r
2932 if (color || appData.allWhite ) {
\r
2933 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2935 oldBrush = SelectObject(hdc, xBrush);
\r
2936 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2937 if(appData.upsideDown && color==flipView)
\r
2938 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2940 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2941 /* Use black for outline of white pieces */
\r
2942 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2943 if(appData.upsideDown && color==flipView)
\r
2944 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2946 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2947 } else if(appData.pieceDirectory[0]) {
\r
2948 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2949 oldBrush = SelectObject(hdc, xBrush);
\r
2950 if(appData.upsideDown && color==flipView)
\r
2951 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2953 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2954 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2955 if(appData.upsideDown && color==flipView)
\r
2956 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2958 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2960 /* Use square color for details of black pieces */
\r
2961 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2962 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2963 if(appData.upsideDown && !flipView)
\r
2964 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2966 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2968 SelectObject(hdc, oldBrush);
\r
2969 SelectObject(tmphdc, oldBitmap);
\r
2973 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2974 int GetBackTextureMode( int algo )
\r
2976 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2980 case BACK_TEXTURE_MODE_PLAIN:
\r
2981 result = 1; /* Always use identity map */
\r
2983 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2984 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2992 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2993 to handle redraws cleanly (as random numbers would always be different).
\r
2995 VOID RebuildTextureSquareInfo()
\r
3005 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3007 if( liteBackTexture != NULL ) {
\r
3008 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3009 lite_w = bi.bmWidth;
\r
3010 lite_h = bi.bmHeight;
\r
3014 if( darkBackTexture != NULL ) {
\r
3015 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3016 dark_w = bi.bmWidth;
\r
3017 dark_h = bi.bmHeight;
\r
3021 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3022 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3023 if( (col + row) & 1 ) {
\r
3025 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3026 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3027 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3029 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3030 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3031 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3033 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3034 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3039 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3040 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3041 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3043 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3044 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3045 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3047 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3048 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3055 /* [AS] Arrow highlighting support */
\r
3057 static double A_WIDTH = 5; /* Width of arrow body */
\r
3059 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3060 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3062 static double Sqr( double x )
\r
3067 static int Round( double x )
\r
3069 return (int) (x + 0.5);
\r
3072 /* Draw an arrow between two points using current settings */
\r
3073 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3076 double dx, dy, j, k, x, y;
\r
3078 if( d_x == s_x ) {
\r
3079 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3081 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3084 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3085 arrow[1].y = d_y - h;
\r
3087 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3088 arrow[2].y = d_y - h;
\r
3093 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3094 arrow[5].y = d_y - h;
\r
3096 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3097 arrow[4].y = d_y - h;
\r
3099 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3102 else if( d_y == s_y ) {
\r
3103 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3106 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3108 arrow[1].x = d_x - w;
\r
3109 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3111 arrow[2].x = d_x - w;
\r
3112 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3117 arrow[5].x = d_x - w;
\r
3118 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3120 arrow[4].x = d_x - w;
\r
3121 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3124 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3127 /* [AS] Needed a lot of paper for this! :-) */
\r
3128 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3129 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3131 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3133 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3138 arrow[0].x = Round(x - j);
\r
3139 arrow[0].y = Round(y + j*dx);
\r
3141 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3142 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3145 x = (double) d_x - k;
\r
3146 y = (double) d_y - k*dy;
\r
3149 x = (double) d_x + k;
\r
3150 y = (double) d_y + k*dy;
\r
3153 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3155 arrow[6].x = Round(x - j);
\r
3156 arrow[6].y = Round(y + j*dx);
\r
3158 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3159 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3161 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3162 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3167 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3168 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3171 Polygon( hdc, arrow, 7 );
\r
3174 /* [AS] Draw an arrow between two squares */
\r
3175 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3177 int s_x, s_y, d_x, d_y;
\r
3184 if( s_col == d_col && s_row == d_row ) {
\r