2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
97 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
100 void mysrandom(unsigned int seed);
\r
102 extern int whiteFlag, blackFlag;
\r
103 Boolean flipClock = FALSE;
\r
104 extern HANDLE chatHandle[];
\r
105 extern enum ICS_TYPE ics_type;
\r
107 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
108 int MyGetFullPathName P((char *name, char *fullname));
\r
109 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
110 VOID NewVariantPopup(HWND hwnd);
\r
111 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
112 /*char*/int promoChar));
\r
113 void DisplayMove P((int moveNumber));
\r
114 void ChatPopUp P((char *s));
\r
116 ChessSquare piece;
\r
117 POINT pos; /* window coordinates of current pos */
\r
118 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
119 POINT from; /* board coordinates of the piece's orig pos */
\r
120 POINT to; /* board coordinates of the piece's new pos */
\r
123 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
126 POINT start; /* window coordinates of start pos */
\r
127 POINT pos; /* window coordinates of current pos */
\r
128 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
129 POINT from; /* board coordinates of the piece's orig pos */
\r
133 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
136 POINT sq[2]; /* board coordinates of from, to squares */
\r
139 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
144 typedef struct { // [HGM] atomic
\r
145 int fromX, fromY, toX, toY, radius;
\r
148 static ExplodeInfo explodeInfo;
\r
150 /* Window class names */
\r
151 char szAppName[] = "WinBoard";
\r
152 char szConsoleName[] = "WBConsole";
\r
154 /* Title bar text */
\r
155 char szTitle[] = "WinBoard";
\r
156 char szConsoleTitle[] = "I C S Interaction";
\r
159 char *settingsFileName;
\r
160 Boolean saveSettingsOnExit;
\r
161 char installDir[MSG_SIZ];
\r
162 int errorExitStatus;
\r
164 BoardSize boardSize;
\r
165 Boolean chessProgram;
\r
166 //static int boardX, boardY;
\r
167 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
168 int squareSize, lineGap, minorSize, border;
\r
169 static int winW, winH;
\r
170 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
171 static int logoHeight = 0;
\r
172 static char messageText[MESSAGE_TEXT_MAX];
\r
173 static int clockTimerEvent = 0;
\r
174 static int loadGameTimerEvent = 0;
\r
175 static int analysisTimerEvent = 0;
\r
176 static DelayedEventCallback delayedTimerCallback;
\r
177 static int delayedTimerEvent = 0;
\r
178 static int buttonCount = 2;
\r
179 char *icsTextMenuString;
\r
181 char *firstChessProgramNames;
\r
182 char *secondChessProgramNames;
\r
184 #define PALETTESIZE 256
\r
186 HINSTANCE hInst; /* current instance */
\r
187 Boolean alwaysOnTop = FALSE;
\r
189 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
190 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
193 ColorClass currentColorClass;
\r
195 static HWND savedHwnd;
\r
196 HWND hCommPort = NULL; /* currently open comm port */
\r
197 static HWND hwndPause; /* pause button */
\r
198 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
199 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
200 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
201 explodeBrush, /* [HGM] atomic */
\r
202 markerBrush[8], /* [HGM] markers */
\r
203 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
204 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
205 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
206 static HPEN gridPen = NULL;
\r
207 static HPEN highlightPen = NULL;
\r
208 static HPEN premovePen = NULL;
\r
209 static NPLOGPALETTE pLogPal;
\r
210 static BOOL paletteChanged = FALSE;
\r
211 static HICON iconWhite, iconBlack, iconCurrent;
\r
212 static int doingSizing = FALSE;
\r
213 static int lastSizing = 0;
\r
214 static int prevStderrPort;
\r
215 static HBITMAP userLogo;
\r
217 static HBITMAP liteBackTexture = NULL;
\r
218 static HBITMAP darkBackTexture = NULL;
\r
219 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
220 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int backTextureSquareSize = 0;
\r
222 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
224 #if __GNUC__ && !defined(_winmajor)
\r
225 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 #define INTERNATIONAL
\r
237 #ifdef INTERNATIONAL
\r
238 # define _(s) T_(s)
\r
244 # define Translate(x, y)
\r
245 # define LoadLanguageFile(s)
\r
248 #ifdef INTERNATIONAL
\r
250 Boolean barbaric; // flag indicating if translation is needed
\r
252 // list of item numbers used in each dialog (used to alter language at run time)
\r
254 #define ABOUTBOX -1 /* not sure why these are needed */
\r
255 #define ABOUTBOX2 -1
\r
257 int dialogItems[][42] = {
\r
258 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
259 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
260 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
261 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
262 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
263 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
264 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
265 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
266 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
267 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
268 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
269 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
270 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
271 { ABOUTBOX2, IDC_ChessBoard },
\r
272 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
273 OPT_GameListClose, IDC_GameListDoFilter },
\r
274 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
275 { DLG_Error, IDOK },
\r
276 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
277 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
278 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
279 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
280 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
281 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
282 { DLG_IndexNumber, IDC_Index },
\r
283 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
284 { DLG_TypeInName, IDOK, IDCANCEL },
\r
285 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
286 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
287 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
288 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
289 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
290 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
291 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
292 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
293 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
294 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
295 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
296 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
297 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
298 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
299 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
300 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
301 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
302 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
303 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
304 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
305 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
306 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
307 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
308 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
309 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
310 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
311 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
312 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
313 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
314 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
315 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
316 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
317 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
318 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
319 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
320 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
321 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
322 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
323 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
324 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
325 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
326 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
327 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
328 { DLG_MoveHistory },
\r
329 { DLG_EvalGraph },
\r
330 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
331 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
332 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
333 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
334 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
335 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
336 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
337 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
338 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
342 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
343 static int lastChecked;
\r
344 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
345 extern int tinyLayout;
\r
346 extern char * menuBarText[][10];
\r
349 LoadLanguageFile(char *name)
\r
350 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
352 int i=0, j=0, n=0, k;
\r
355 if(!name || name[0] == NULLCHAR) return;
\r
356 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
357 appData.language = oldLanguage;
\r
358 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
359 if((f = fopen(buf, "r")) == NULL) return;
\r
360 while((k = fgetc(f)) != EOF) {
\r
361 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
362 languageBuf[i] = k;
\r
364 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
366 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
367 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
368 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
369 english[j] = languageBuf + n + 1; *p = 0;
\r
370 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
371 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
376 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
378 case 'n': k = '\n'; break;
\r
379 case 'r': k = '\r'; break;
\r
380 case 't': k = '\t'; break;
\r
382 languageBuf[--i] = k;
\r
387 barbaric = (j != 0);
\r
388 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
393 { // return the translation of the given string
\r
394 // efficiency can be improved a lot...
\r
396 static char buf[MSG_SIZ];
\r
397 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
398 if(!barbaric) return s;
\r
399 if(!s) return ""; // sanity
\r
400 while(english[i]) {
\r
401 if(!strcmp(s, english[i])) return foreign[i];
\r
402 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
403 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
412 Translate(HWND hDlg, int dialogID)
\r
413 { // translate all text items in the given dialog
\r
415 char buf[MSG_SIZ], *s;
\r
416 if(!barbaric) return;
\r
417 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
418 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
419 GetWindowText( hDlg, buf, MSG_SIZ );
\r
421 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
422 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
423 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
424 if(strlen(buf) == 0) continue;
\r
426 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
431 TranslateOneMenu(int i, HMENU subMenu)
\r
434 static MENUITEMINFO info;
\r
436 info.cbSize = sizeof(MENUITEMINFO);
\r
437 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
438 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
440 info.dwTypeData = buf;
\r
441 info.cch = sizeof(buf);
\r
442 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
444 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
445 else menuText[i][j] = strdup(buf); // remember original on first change
\r
447 if(buf[0] == NULLCHAR) continue;
\r
448 info.dwTypeData = T_(buf);
\r
449 info.cch = strlen(buf)+1;
\r
450 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
456 TranslateMenus(int addLanguage)
\r
459 WIN32_FIND_DATA fileData;
\r
461 #define IDM_English 1970
\r
463 HMENU mainMenu = GetMenu(hwndMain);
\r
464 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
465 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
466 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
467 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
468 TranslateOneMenu(i, subMenu);
\r
470 DrawMenuBar(hwndMain);
\r
473 if(!addLanguage) return;
\r
474 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
475 HMENU mainMenu = GetMenu(hwndMain);
\r
476 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
477 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
478 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
479 i = 0; lastChecked = IDM_English;
\r
481 char *p, *q = fileData.cFileName;
\r
482 int checkFlag = MF_UNCHECKED;
\r
483 languageFile[i] = strdup(q);
\r
484 if(barbaric && !strcmp(oldLanguage, q)) {
\r
485 checkFlag = MF_CHECKED;
\r
486 lastChecked = IDM_English + i + 1;
\r
487 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
489 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
490 p = strstr(fileData.cFileName, ".lng");
\r
492 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
493 } while(FindNextFile(hFind, &fileData));
\r
500 #define IDM_RecentEngines 3000
\r
503 RecentEngineMenu (char *s)
\r
505 if(appData.icsActive) return;
\r
506 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
507 HMENU mainMenu = GetMenu(hwndMain);
\r
508 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
509 int i=IDM_RecentEngines;
\r
510 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
511 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
513 char *p = strchr(s, '\n');
\r
514 if(p == NULL) return; // malformed!
\r
516 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
530 int cliWidth, cliHeight;
\r
533 SizeInfo sizeInfo[] =
\r
535 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
536 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
537 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
538 { "petite", 33, 1, 1, 1, 0, 0 },
\r
539 { "slim", 37, 2, 1, 0, 0, 0 },
\r
540 { "small", 40, 2, 1, 0, 0, 0 },
\r
541 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
542 { "middling", 49, 2, 0, 0, 0, 0 },
\r
543 { "average", 54, 2, 0, 0, 0, 0 },
\r
544 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
545 { "medium", 64, 3, 0, 0, 0, 0 },
\r
546 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
547 { "large", 80, 3, 0, 0, 0, 0 },
\r
548 { "big", 87, 3, 0, 0, 0, 0 },
\r
549 { "huge", 95, 3, 0, 0, 0, 0 },
\r
550 { "giant", 108, 3, 0, 0, 0, 0 },
\r
551 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
552 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
553 { NULL, 0, 0, 0, 0, 0, 0 }
\r
556 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
557 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
575 { 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
576 { 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
579 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
588 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
589 #define N_BUTTONS 5
\r
591 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
593 {"<<", IDM_ToStart, NULL, NULL},
\r
594 {"<", IDM_Backward, NULL, NULL},
\r
595 {"P", IDM_Pause, NULL, NULL},
\r
596 {">", IDM_Forward, NULL, NULL},
\r
597 {">>", IDM_ToEnd, NULL, NULL},
\r
600 int tinyLayout = 0, smallLayout = 0;
\r
601 #define MENU_BAR_ITEMS 9
\r
602 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
603 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
604 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
608 MySound sounds[(int)NSoundClasses];
\r
609 MyTextAttribs textAttribs[(int)NColorClasses];
\r
611 MyColorizeAttribs colorizeAttribs[] = {
\r
612 { (COLORREF)0, 0, N_("Shout Text") },
\r
613 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
614 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
615 { (COLORREF)0, 0, N_("Channel Text") },
\r
616 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
617 { (COLORREF)0, 0, N_("Tell Text") },
\r
618 { (COLORREF)0, 0, N_("Challenge Text") },
\r
619 { (COLORREF)0, 0, N_("Request Text") },
\r
620 { (COLORREF)0, 0, N_("Seek Text") },
\r
621 { (COLORREF)0, 0, N_("Normal Text") },
\r
622 { (COLORREF)0, 0, N_("None") }
\r
627 static char *commentTitle;
\r
628 static char *commentText;
\r
629 static int commentIndex;
\r
630 static Boolean editComment = FALSE;
\r
633 char errorTitle[MSG_SIZ];
\r
634 char errorMessage[2*MSG_SIZ];
\r
635 HWND errorDialog = NULL;
\r
636 BOOLEAN moveErrorMessageUp = FALSE;
\r
637 BOOLEAN consoleEcho = TRUE;
\r
638 CHARFORMAT consoleCF;
\r
639 COLORREF consoleBackgroundColor;
\r
641 char *programVersion;
\r
647 typedef int CPKind;
\r
656 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
659 #define INPUT_SOURCE_BUF_SIZE 4096
\r
661 typedef struct _InputSource {
\r
668 char buf[INPUT_SOURCE_BUF_SIZE];
\r
672 InputCallback func;
\r
673 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
677 InputSource *consoleInputSource;
\r
682 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
683 VOID ConsoleCreate();
\r
685 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
686 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
687 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
688 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
690 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
691 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
692 void ParseIcsTextMenu(char *icsTextMenuString);
\r
693 VOID PopUpNameDialog(char firstchar);
\r
694 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
698 int GameListOptions();
\r
700 int dummy; // [HGM] for obsolete args
\r
702 HWND hwndMain = NULL; /* root window*/
\r
703 HWND hwndConsole = NULL;
\r
704 HWND commentDialog = NULL;
\r
705 HWND moveHistoryDialog = NULL;
\r
706 HWND evalGraphDialog = NULL;
\r
707 HWND engineOutputDialog = NULL;
\r
708 HWND gameListDialog = NULL;
\r
709 HWND editTagsDialog = NULL;
\r
711 int commentUp = FALSE;
\r
713 WindowPlacement wpMain;
\r
714 WindowPlacement wpConsole;
\r
715 WindowPlacement wpComment;
\r
716 WindowPlacement wpMoveHistory;
\r
717 WindowPlacement wpEvalGraph;
\r
718 WindowPlacement wpEngineOutput;
\r
719 WindowPlacement wpGameList;
\r
720 WindowPlacement wpTags;
\r
722 VOID EngineOptionsPopup(); // [HGM] settings
\r
724 VOID GothicPopUp(char *title, VariantClass variant);
\r
726 * Setting "frozen" should disable all user input other than deleting
\r
727 * the window. We do this while engines are initializing themselves.
\r
729 static int frozen = 0;
\r
730 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
736 if (frozen) return;
\r
738 hmenu = GetMenu(hwndMain);
\r
739 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
740 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
742 DrawMenuBar(hwndMain);
\r
745 /* Undo a FreezeUI */
\r
751 if (!frozen) return;
\r
753 hmenu = GetMenu(hwndMain);
\r
754 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
755 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
757 DrawMenuBar(hwndMain);
\r
760 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
762 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
768 #define JAWS_ALT_INTERCEPT
\r
769 #define JAWS_KBUP_NAVIGATION
\r
770 #define JAWS_KBDOWN_NAVIGATION
\r
771 #define JAWS_MENU_ITEMS
\r
772 #define JAWS_SILENCE
\r
773 #define JAWS_REPLAY
\r
775 #define JAWS_COPYRIGHT
\r
776 #define JAWS_DELETE(X) X
\r
777 #define SAYMACHINEMOVE()
\r
781 /*---------------------------------------------------------------------------*\
\r
785 \*---------------------------------------------------------------------------*/
\r
788 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
789 LPSTR lpCmdLine, int nCmdShow)
\r
792 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
793 // INITCOMMONCONTROLSEX ex;
\r
797 LoadLibrary("RICHED32.DLL");
\r
798 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
800 if (!InitApplication(hInstance)) {
\r
803 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
810 // InitCommonControlsEx(&ex);
\r
811 InitCommonControls();
\r
813 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
814 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
815 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
817 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
819 while (GetMessage(&msg, /* message structure */
\r
820 NULL, /* handle of window receiving the message */
\r
821 0, /* lowest message to examine */
\r
822 0)) /* highest message to examine */
\r
825 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
826 // [HGM] navigate: switch between all windows with tab
\r
827 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
828 int i, currentElement = 0;
\r
830 // first determine what element of the chain we come from (if any)
\r
831 if(appData.icsActive) {
\r
832 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
833 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
835 if(engineOutputDialog && EngineOutputIsUp()) {
\r
836 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
837 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
839 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
840 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
842 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
843 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
844 if(msg.hwnd == e1) currentElement = 2; else
\r
845 if(msg.hwnd == e2) currentElement = 3; else
\r
846 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
847 if(msg.hwnd == mh) currentElement = 4; else
\r
848 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
849 if(msg.hwnd == hText) currentElement = 5; else
\r
850 if(msg.hwnd == hInput) currentElement = 6; else
\r
851 for (i = 0; i < N_BUTTONS; i++) {
\r
852 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
855 // determine where to go to
\r
856 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
858 currentElement = (currentElement + direction) % 7;
\r
859 switch(currentElement) {
\r
861 h = hwndMain; break; // passing this case always makes the loop exit
\r
863 h = buttonDesc[0].hwnd; break; // could be NULL
\r
865 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
868 if(!EngineOutputIsUp()) continue;
\r
871 if(!MoveHistoryIsUp()) continue;
\r
873 // case 6: // input to eval graph does not seem to get here!
\r
874 // if(!EvalGraphIsUp()) continue;
\r
875 // h = evalGraphDialog; break;
\r
877 if(!appData.icsActive) continue;
\r
881 if(!appData.icsActive) continue;
\r
887 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
888 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
891 continue; // this message now has been processed
\r
895 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
896 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
897 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
898 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
899 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
900 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
901 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
902 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
903 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
904 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
905 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
906 for(i=0; i<MAX_CHAT; i++)
\r
907 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
910 if(done) continue; // [HGM] chat: end patch
\r
911 TranslateMessage(&msg); /* Translates virtual key codes */
\r
912 DispatchMessage(&msg); /* Dispatches message to window */
\r
917 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
920 /*---------------------------------------------------------------------------*\
\r
922 * Initialization functions
\r
924 \*---------------------------------------------------------------------------*/
\r
928 { // update user logo if necessary
\r
929 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
931 if(appData.autoLogo) {
\r
932 curName = UserName();
\r
933 if(strcmp(curName, oldUserName)) {
\r
934 GetCurrentDirectory(MSG_SIZ, dir);
\r
935 SetCurrentDirectory(installDir);
\r
936 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
937 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
938 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
939 if(userLogo == NULL)
\r
940 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
941 SetCurrentDirectory(dir); /* return to prev directory */
\r
947 InitApplication(HINSTANCE hInstance)
\r
951 /* Fill in window class structure with parameters that describe the */
\r
954 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
955 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
956 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
957 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
958 wc.hInstance = hInstance; /* Owner of this class */
\r
959 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
960 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
961 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
962 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
963 wc.lpszClassName = szAppName; /* Name to register as */
\r
965 /* Register the window class and return success/failure code. */
\r
966 if (!RegisterClass(&wc)) return FALSE;
\r
968 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
969 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
971 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
972 wc.hInstance = hInstance;
\r
973 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
974 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
975 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
976 wc.lpszMenuName = NULL;
\r
977 wc.lpszClassName = szConsoleName;
\r
979 if (!RegisterClass(&wc)) return FALSE;
\r
984 /* Set by InitInstance, used by EnsureOnScreen */
\r
985 int screenHeight, screenWidth;
\r
988 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
990 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
991 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
992 if (*x > screenWidth - 32) *x = 0;
\r
993 if (*y > screenHeight - 32) *y = 0;
\r
994 if (*x < minX) *x = minX;
\r
995 if (*y < minY) *y = minY;
\r
999 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1001 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1002 GetCurrentDirectory(MSG_SIZ, dir);
\r
1003 SetCurrentDirectory(installDir);
\r
1004 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1005 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1007 if (cps->programLogo == NULL && appData.debugMode) {
\r
1008 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1010 } else if(appData.autoLogo) {
\r
1011 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1012 char *opponent = "";
\r
1013 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1014 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1015 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1016 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1017 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1018 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1021 if(appData.directory[n] && appData.directory[n][0]) {
\r
1022 SetCurrentDirectory(appData.directory[n]);
\r
1023 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1026 SetCurrentDirectory(dir); /* return to prev directory */
\r
1032 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1033 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1035 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1036 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1037 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1038 liteBackTextureMode = appData.liteBackTextureMode;
\r
1040 if (liteBackTexture == NULL && appData.debugMode) {
\r
1041 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1045 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1046 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1047 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1048 darkBackTextureMode = appData.darkBackTextureMode;
\r
1050 if (darkBackTexture == NULL && appData.debugMode) {
\r
1051 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1057 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1059 HWND hwnd; /* Main window handle. */
\r
1061 WINDOWPLACEMENT wp;
\r
1064 hInst = hInstance; /* Store instance handle in our global variable */
\r
1065 programName = szAppName;
\r
1067 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1068 *filepart = NULLCHAR;
\r
1069 SetCurrentDirectory(installDir);
\r
1071 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1073 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1074 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1075 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1076 /* xboard, and older WinBoards, controlled the move sound with the
\r
1077 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1078 always turn the option on (so that the backend will call us),
\r
1079 then let the user turn the sound off by setting it to silence if
\r
1080 desired. To accommodate old winboard.ini files saved by old
\r
1081 versions of WinBoard, we also turn off the sound if the option
\r
1082 was initially set to false. [HGM] taken out of InitAppData */
\r
1083 if (!appData.ringBellAfterMoves) {
\r
1084 sounds[(int)SoundMove].name = strdup("");
\r
1085 appData.ringBellAfterMoves = TRUE;
\r
1087 if (appData.debugMode) {
\r
1088 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1089 setbuf(debugFP, NULL);
\r
1092 LoadLanguageFile(appData.language);
\r
1096 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1097 // InitEngineUCI( installDir, &second );
\r
1099 /* Create a main window for this application instance. */
\r
1100 hwnd = CreateWindow(szAppName, szTitle,
\r
1101 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1102 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1103 NULL, NULL, hInstance, NULL);
\r
1106 /* If window could not be created, return "failure" */
\r
1111 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1112 LoadLogo(&first, 0, FALSE);
\r
1113 LoadLogo(&second, 1, appData.icsActive);
\r
1117 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1118 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1119 iconCurrent = iconWhite;
\r
1120 InitDrawingColors();
\r
1121 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1122 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1123 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1124 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1125 /* Compute window size for each board size, and use the largest
\r
1126 size that fits on this screen as the default. */
\r
1127 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1128 if (boardSize == (BoardSize)-1 &&
\r
1129 winH <= screenHeight
\r
1130 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1131 && winW <= screenWidth) {
\r
1132 boardSize = (BoardSize)ibs;
\r
1136 InitDrawingSizes(boardSize, 0);
\r
1137 RecentEngineMenu(appData.recentEngineList);
\r
1139 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1141 /* [AS] Load textures if specified */
\r
1144 mysrandom( (unsigned) time(NULL) );
\r
1146 /* [AS] Restore layout */
\r
1147 if( wpMoveHistory.visible ) {
\r
1148 MoveHistoryPopUp();
\r
1151 if( wpEvalGraph.visible ) {
\r
1155 if( wpEngineOutput.visible ) {
\r
1156 EngineOutputPopUp();
\r
1159 /* Make the window visible; update its client area; and return "success" */
\r
1160 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1161 wp.length = sizeof(WINDOWPLACEMENT);
\r
1163 wp.showCmd = nCmdShow;
\r
1164 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1165 wp.rcNormalPosition.left = wpMain.x;
\r
1166 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1167 wp.rcNormalPosition.top = wpMain.y;
\r
1168 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1169 SetWindowPlacement(hwndMain, &wp);
\r
1171 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1173 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1174 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1176 if (hwndConsole) {
\r
1178 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1179 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1181 ShowWindow(hwndConsole, nCmdShow);
\r
1182 SetActiveWindow(hwndConsole);
\r
1184 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1185 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1194 HMENU hmenu = GetMenu(hwndMain);
\r
1196 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1197 MF_BYCOMMAND|((appData.icsActive &&
\r
1198 *appData.icsCommPort != NULLCHAR) ?
\r
1199 MF_ENABLED : MF_GRAYED));
\r
1200 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1201 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1202 MF_CHECKED : MF_UNCHECKED));
\r
1205 //---------------------------------------------------------------------------------------------------------
\r
1207 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1208 #define XBOARD FALSE
\r
1210 #define OPTCHAR "/"
\r
1211 #define SEPCHAR "="
\r
1212 #define TOPLEVEL 0
\r
1216 // front-end part of option handling
\r
1219 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1221 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1222 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1225 lf->lfEscapement = 0;
\r
1226 lf->lfOrientation = 0;
\r
1227 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1228 lf->lfItalic = mfp->italic;
\r
1229 lf->lfUnderline = mfp->underline;
\r
1230 lf->lfStrikeOut = mfp->strikeout;
\r
1231 lf->lfCharSet = mfp->charset;
\r
1232 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1233 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1234 lf->lfQuality = DEFAULT_QUALITY;
\r
1235 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1236 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1240 CreateFontInMF(MyFont *mf)
\r
1242 LFfromMFP(&mf->lf, &mf->mfp);
\r
1243 if (mf->hf) DeleteObject(mf->hf);
\r
1244 mf->hf = CreateFontIndirect(&mf->lf);
\r
1247 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1249 colorVariable[] = {
\r
1250 &whitePieceColor,
\r
1251 &blackPieceColor,
\r
1252 &lightSquareColor,
\r
1253 &darkSquareColor,
\r
1254 &highlightSquareColor,
\r
1255 &premoveHighlightColor,
\r
1257 &consoleBackgroundColor,
\r
1258 &appData.fontForeColorWhite,
\r
1259 &appData.fontBackColorWhite,
\r
1260 &appData.fontForeColorBlack,
\r
1261 &appData.fontBackColorBlack,
\r
1262 &appData.evalHistColorWhite,
\r
1263 &appData.evalHistColorBlack,
\r
1264 &appData.highlightArrowColor,
\r
1267 /* Command line font name parser. NULL name means do nothing.
\r
1268 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1269 For backward compatibility, syntax without the colon is also
\r
1270 accepted, but font names with digits in them won't work in that case.
\r
1273 ParseFontName(char *name, MyFontParams *mfp)
\r
1276 if (name == NULL) return;
\r
1278 q = strchr(p, ':');
\r
1280 if (q - p >= sizeof(mfp->faceName))
\r
1281 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1282 memcpy(mfp->faceName, p, q - p);
\r
1283 mfp->faceName[q - p] = NULLCHAR;
\r
1286 q = mfp->faceName;
\r
1288 while (*p && !isdigit(*p)) {
\r
1290 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1291 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1293 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1296 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1297 mfp->pointSize = (float) atof(p);
\r
1298 mfp->bold = (strchr(p, 'b') != NULL);
\r
1299 mfp->italic = (strchr(p, 'i') != NULL);
\r
1300 mfp->underline = (strchr(p, 'u') != NULL);
\r
1301 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1302 mfp->charset = DEFAULT_CHARSET;
\r
1303 q = strchr(p, 'c');
\r
1305 mfp->charset = (BYTE) atoi(q+1);
\r
1309 ParseFont(char *name, int number)
\r
1310 { // wrapper to shield back-end from 'font'
\r
1311 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1316 { // in WB we have a 2D array of fonts; this initializes their description
\r
1318 /* Point font array elements to structures and
\r
1319 parse default font names */
\r
1320 for (i=0; i<NUM_FONTS; i++) {
\r
1321 for (j=0; j<NUM_SIZES; j++) {
\r
1322 font[j][i] = &fontRec[j][i];
\r
1323 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1330 { // here we create the actual fonts from the selected descriptions
\r
1332 for (i=0; i<NUM_FONTS; i++) {
\r
1333 for (j=0; j<NUM_SIZES; j++) {
\r
1334 CreateFontInMF(font[j][i]);
\r
1338 /* Color name parser.
\r
1339 X version accepts X color names, but this one
\r
1340 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1342 ParseColorName(char *name)
\r
1344 int red, green, blue, count;
\r
1345 char buf[MSG_SIZ];
\r
1347 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1349 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1350 &red, &green, &blue);
\r
1353 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1354 DisplayError(buf, 0);
\r
1355 return RGB(0, 0, 0);
\r
1357 return PALETTERGB(red, green, blue);
\r
1361 ParseColor(int n, char *name)
\r
1362 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1363 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1367 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1369 char *e = argValue;
\r
1373 if (*e == 'b') eff |= CFE_BOLD;
\r
1374 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1375 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1376 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1377 else if (*e == '#' || isdigit(*e)) break;
\r
1381 *color = ParseColorName(e);
\r
1385 ParseTextAttribs(ColorClass cc, char *s)
\r
1386 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1387 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1388 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1392 ParseBoardSize(void *addr, char *name)
\r
1393 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1394 BoardSize bs = SizeTiny;
\r
1395 while (sizeInfo[bs].name != NULL) {
\r
1396 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1397 *(BoardSize *)addr = bs;
\r
1402 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1407 { // [HGM] import name from appData first
\r
1410 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1411 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1412 textAttribs[cc].sound.data = NULL;
\r
1413 MyLoadSound(&textAttribs[cc].sound);
\r
1415 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1416 textAttribs[cc].sound.name = strdup("");
\r
1417 textAttribs[cc].sound.data = NULL;
\r
1419 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1420 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1421 sounds[sc].data = NULL;
\r
1422 MyLoadSound(&sounds[sc]);
\r
1427 SetCommPortDefaults()
\r
1429 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1430 dcb.DCBlength = sizeof(DCB);
\r
1431 dcb.BaudRate = 9600;
\r
1432 dcb.fBinary = TRUE;
\r
1433 dcb.fParity = FALSE;
\r
1434 dcb.fOutxCtsFlow = FALSE;
\r
1435 dcb.fOutxDsrFlow = FALSE;
\r
1436 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1437 dcb.fDsrSensitivity = FALSE;
\r
1438 dcb.fTXContinueOnXoff = TRUE;
\r
1439 dcb.fOutX = FALSE;
\r
1441 dcb.fNull = FALSE;
\r
1442 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1443 dcb.fAbortOnError = FALSE;
\r
1445 dcb.Parity = SPACEPARITY;
\r
1446 dcb.StopBits = ONESTOPBIT;
\r
1449 // [HGM] args: these three cases taken out to stay in front-end
\r
1451 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1452 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1453 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1454 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1456 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1457 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1458 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1459 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1460 ad->argName, mfp->faceName, mfp->pointSize,
\r
1461 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1462 mfp->bold ? "b" : "",
\r
1463 mfp->italic ? "i" : "",
\r
1464 mfp->underline ? "u" : "",
\r
1465 mfp->strikeout ? "s" : "",
\r
1466 (int)mfp->charset);
\r
1472 { // [HGM] copy the names from the internal WB variables to appData
\r
1475 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1476 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1477 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1478 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1482 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1483 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1484 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1485 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1486 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1487 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1488 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1489 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1490 (ta->effects) ? " " : "",
\r
1491 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1495 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1496 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1497 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1498 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1499 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1503 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1504 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1505 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1509 ParseCommPortSettings(char *s)
\r
1510 { // wrapper to keep dcb from back-end
\r
1511 ParseCommSettings(s, &dcb);
\r
1516 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1517 GetActualPlacement(hwndMain, &wpMain);
\r
1518 GetActualPlacement(hwndConsole, &wpConsole);
\r
1519 GetActualPlacement(commentDialog, &wpComment);
\r
1520 GetActualPlacement(editTagsDialog, &wpTags);
\r
1521 GetActualPlacement(gameListDialog, &wpGameList);
\r
1522 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1523 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1524 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1528 PrintCommPortSettings(FILE *f, char *name)
\r
1529 { // wrapper to shield back-end from DCB
\r
1530 PrintCommSettings(f, name, &dcb);
\r
1534 MySearchPath(char *installDir, char *name, char *fullname)
\r
1536 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1537 if(name[0]== '%') {
\r
1538 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1539 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1540 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1541 *strchr(buf, '%') = 0;
\r
1542 strcat(fullname, getenv(buf));
\r
1543 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1545 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1546 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1547 return (int) strlen(fullname);
\r
1549 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1553 MyGetFullPathName(char *name, char *fullname)
\r
1556 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1561 { // [HGM] args: allows testing if main window is realized from back-end
\r
1562 return hwndMain != NULL;
\r
1566 PopUpStartupDialog()
\r
1570 LoadLanguageFile(appData.language);
\r
1571 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1572 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1573 FreeProcInstance(lpProc);
\r
1576 /*---------------------------------------------------------------------------*\
\r
1578 * GDI board drawing routines
\r
1580 \*---------------------------------------------------------------------------*/
\r
1582 /* [AS] Draw square using background texture */
\r
1583 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1588 return; /* Should never happen! */
\r
1591 SetGraphicsMode( dst, GM_ADVANCED );
\r
1598 /* X reflection */
\r
1603 x.eDx = (FLOAT) dw + dx - 1;
\r
1606 SetWorldTransform( dst, &x );
\r
1609 /* Y reflection */
\r
1615 x.eDy = (FLOAT) dh + dy - 1;
\r
1617 SetWorldTransform( dst, &x );
\r
1625 x.eDx = (FLOAT) dx;
\r
1626 x.eDy = (FLOAT) dy;
\r
1629 SetWorldTransform( dst, &x );
\r
1633 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1641 SetWorldTransform( dst, &x );
\r
1643 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1646 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1648 PM_WP = (int) WhitePawn,
\r
1649 PM_WN = (int) WhiteKnight,
\r
1650 PM_WB = (int) WhiteBishop,
\r
1651 PM_WR = (int) WhiteRook,
\r
1652 PM_WQ = (int) WhiteQueen,
\r
1653 PM_WF = (int) WhiteFerz,
\r
1654 PM_WW = (int) WhiteWazir,
\r
1655 PM_WE = (int) WhiteAlfil,
\r
1656 PM_WM = (int) WhiteMan,
\r
1657 PM_WO = (int) WhiteCannon,
\r
1658 PM_WU = (int) WhiteUnicorn,
\r
1659 PM_WH = (int) WhiteNightrider,
\r
1660 PM_WA = (int) WhiteAngel,
\r
1661 PM_WC = (int) WhiteMarshall,
\r
1662 PM_WAB = (int) WhiteCardinal,
\r
1663 PM_WD = (int) WhiteDragon,
\r
1664 PM_WL = (int) WhiteLance,
\r
1665 PM_WS = (int) WhiteCobra,
\r
1666 PM_WV = (int) WhiteFalcon,
\r
1667 PM_WSG = (int) WhiteSilver,
\r
1668 PM_WG = (int) WhiteGrasshopper,
\r
1669 PM_WK = (int) WhiteKing,
\r
1670 PM_BP = (int) BlackPawn,
\r
1671 PM_BN = (int) BlackKnight,
\r
1672 PM_BB = (int) BlackBishop,
\r
1673 PM_BR = (int) BlackRook,
\r
1674 PM_BQ = (int) BlackQueen,
\r
1675 PM_BF = (int) BlackFerz,
\r
1676 PM_BW = (int) BlackWazir,
\r
1677 PM_BE = (int) BlackAlfil,
\r
1678 PM_BM = (int) BlackMan,
\r
1679 PM_BO = (int) BlackCannon,
\r
1680 PM_BU = (int) BlackUnicorn,
\r
1681 PM_BH = (int) BlackNightrider,
\r
1682 PM_BA = (int) BlackAngel,
\r
1683 PM_BC = (int) BlackMarshall,
\r
1684 PM_BG = (int) BlackGrasshopper,
\r
1685 PM_BAB = (int) BlackCardinal,
\r
1686 PM_BD = (int) BlackDragon,
\r
1687 PM_BL = (int) BlackLance,
\r
1688 PM_BS = (int) BlackCobra,
\r
1689 PM_BV = (int) BlackFalcon,
\r
1690 PM_BSG = (int) BlackSilver,
\r
1691 PM_BK = (int) BlackKing
\r
1694 static HFONT hPieceFont = NULL;
\r
1695 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1696 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1697 static int fontBitmapSquareSize = 0;
\r
1698 static char pieceToFontChar[(int) EmptySquare] =
\r
1699 { 'p', 'n', 'b', 'r', 'q',
\r
1700 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1701 'k', 'o', 'm', 'v', 't', 'w',
\r
1702 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1705 extern BOOL SetCharTable( char *table, const char * map );
\r
1706 /* [HGM] moved to backend.c */
\r
1708 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1711 BYTE r1 = GetRValue( color );
\r
1712 BYTE g1 = GetGValue( color );
\r
1713 BYTE b1 = GetBValue( color );
\r
1719 /* Create a uniform background first */
\r
1720 hbrush = CreateSolidBrush( color );
\r
1721 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1722 FillRect( hdc, &rc, hbrush );
\r
1723 DeleteObject( hbrush );
\r
1726 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1727 int steps = squareSize / 2;
\r
1730 for( i=0; i<steps; i++ ) {
\r
1731 BYTE r = r1 - (r1-r2) * i / steps;
\r
1732 BYTE g = g1 - (g1-g2) * i / steps;
\r
1733 BYTE b = b1 - (b1-b2) * i / steps;
\r
1735 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1736 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1737 FillRect( hdc, &rc, hbrush );
\r
1738 DeleteObject(hbrush);
\r
1741 else if( mode == 2 ) {
\r
1742 /* Diagonal gradient, good more or less for every piece */
\r
1743 POINT triangle[3];
\r
1744 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1745 HBRUSH hbrush_old;
\r
1746 int steps = squareSize;
\r
1749 triangle[0].x = squareSize - steps;
\r
1750 triangle[0].y = squareSize;
\r
1751 triangle[1].x = squareSize;
\r
1752 triangle[1].y = squareSize;
\r
1753 triangle[2].x = squareSize;
\r
1754 triangle[2].y = squareSize - steps;
\r
1756 for( i=0; i<steps; i++ ) {
\r
1757 BYTE r = r1 - (r1-r2) * i / steps;
\r
1758 BYTE g = g1 - (g1-g2) * i / steps;
\r
1759 BYTE b = b1 - (b1-b2) * i / steps;
\r
1761 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1762 hbrush_old = SelectObject( hdc, hbrush );
\r
1763 Polygon( hdc, triangle, 3 );
\r
1764 SelectObject( hdc, hbrush_old );
\r
1765 DeleteObject(hbrush);
\r
1770 SelectObject( hdc, hpen );
\r
1775 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1776 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1777 piece: follow the steps as explained below.
\r
1779 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1783 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1787 int backColor = whitePieceColor;
\r
1788 int foreColor = blackPieceColor;
\r
1790 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1791 backColor = appData.fontBackColorWhite;
\r
1792 foreColor = appData.fontForeColorWhite;
\r
1794 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1795 backColor = appData.fontBackColorBlack;
\r
1796 foreColor = appData.fontForeColorBlack;
\r
1800 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1802 hbm_old = SelectObject( hdc, hbm );
\r
1806 rc.right = squareSize;
\r
1807 rc.bottom = squareSize;
\r
1809 /* Step 1: background is now black */
\r
1810 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1812 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1814 pt.x = (squareSize - sz.cx) / 2;
\r
1815 pt.y = (squareSize - sz.cy) / 2;
\r
1817 SetBkMode( hdc, TRANSPARENT );
\r
1818 SetTextColor( hdc, chroma );
\r
1819 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1820 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1822 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1823 /* Step 3: the area outside the piece is filled with white */
\r
1824 // FloodFill( hdc, 0, 0, chroma );
\r
1825 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1826 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1827 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1828 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1829 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1831 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1832 but if the start point is not inside the piece we're lost!
\r
1833 There should be a better way to do this... if we could create a region or path
\r
1834 from the fill operation we would be fine for example.
\r
1836 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1837 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1839 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1840 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1841 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1843 SelectObject( dc2, bm2 );
\r
1844 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1845 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1846 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1847 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1848 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1851 DeleteObject( bm2 );
\r
1854 SetTextColor( hdc, 0 );
\r
1856 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1857 draw the piece again in black for safety.
\r
1859 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1861 SelectObject( hdc, hbm_old );
\r
1863 if( hPieceMask[index] != NULL ) {
\r
1864 DeleteObject( hPieceMask[index] );
\r
1867 hPieceMask[index] = hbm;
\r
1870 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1872 SelectObject( hdc, hbm );
\r
1875 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1876 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1877 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1879 SelectObject( dc1, hPieceMask[index] );
\r
1880 SelectObject( dc2, bm2 );
\r
1881 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1882 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1885 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1886 the piece background and deletes (makes transparent) the rest.
\r
1887 Thanks to that mask, we are free to paint the background with the greates
\r
1888 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1889 We use this, to make gradients and give the pieces a "roundish" look.
\r
1891 SetPieceBackground( hdc, backColor, 2 );
\r
1892 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1896 DeleteObject( bm2 );
\r
1899 SetTextColor( hdc, foreColor );
\r
1900 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1902 SelectObject( hdc, hbm_old );
\r
1904 if( hPieceFace[index] != NULL ) {
\r
1905 DeleteObject( hPieceFace[index] );
\r
1908 hPieceFace[index] = hbm;
\r
1911 static int TranslatePieceToFontPiece( int piece )
\r
1941 case BlackMarshall:
\r
1945 case BlackNightrider:
\r
1951 case BlackUnicorn:
\r
1955 case BlackGrasshopper:
\r
1967 case BlackCardinal:
\r
1974 case WhiteMarshall:
\r
1978 case WhiteNightrider:
\r
1984 case WhiteUnicorn:
\r
1988 case WhiteGrasshopper:
\r
2000 case WhiteCardinal:
\r
2009 void CreatePiecesFromFont()
\r
2012 HDC hdc_window = NULL;
\r
2018 if( fontBitmapSquareSize < 0 ) {
\r
2019 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2023 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2024 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2025 fontBitmapSquareSize = -1;
\r
2029 if( fontBitmapSquareSize != squareSize ) {
\r
2030 hdc_window = GetDC( hwndMain );
\r
2031 hdc = CreateCompatibleDC( hdc_window );
\r
2033 if( hPieceFont != NULL ) {
\r
2034 DeleteObject( hPieceFont );
\r
2037 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2038 hPieceMask[i] = NULL;
\r
2039 hPieceFace[i] = NULL;
\r
2045 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2046 fontHeight = appData.fontPieceSize;
\r
2049 fontHeight = (fontHeight * squareSize) / 100;
\r
2051 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2053 lf.lfEscapement = 0;
\r
2054 lf.lfOrientation = 0;
\r
2055 lf.lfWeight = FW_NORMAL;
\r
2057 lf.lfUnderline = 0;
\r
2058 lf.lfStrikeOut = 0;
\r
2059 lf.lfCharSet = DEFAULT_CHARSET;
\r
2060 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2061 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2062 lf.lfQuality = PROOF_QUALITY;
\r
2063 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2064 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2065 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2067 hPieceFont = CreateFontIndirect( &lf );
\r
2069 if( hPieceFont == NULL ) {
\r
2070 fontBitmapSquareSize = -2;
\r
2073 /* Setup font-to-piece character table */
\r
2074 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2075 /* No (or wrong) global settings, try to detect the font */
\r
2076 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2078 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2080 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2081 /* DiagramTT* family */
\r
2082 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2084 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2085 /* Fairy symbols */
\r
2086 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2088 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2089 /* Good Companion (Some characters get warped as literal :-( */
\r
2090 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2091 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2092 SetCharTable(pieceToFontChar, s);
\r
2095 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2096 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2100 /* Create bitmaps */
\r
2101 hfont_old = SelectObject( hdc, hPieceFont );
\r
2102 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2103 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2104 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2106 SelectObject( hdc, hfont_old );
\r
2108 fontBitmapSquareSize = squareSize;
\r
2112 if( hdc != NULL ) {
\r
2116 if( hdc_window != NULL ) {
\r
2117 ReleaseDC( hwndMain, hdc_window );
\r
2122 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2124 char name[128], buf[MSG_SIZ];
\r
2126 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2127 if(appData.pieceDirectory[0]) {
\r
2129 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2130 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2131 if(res) return res;
\r
2133 if (gameInfo.event &&
\r
2134 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2135 strcmp(name, "k80s") == 0) {
\r
2136 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2138 return LoadBitmap(hinst, name);
\r
2142 /* Insert a color into the program's logical palette
\r
2143 structure. This code assumes the given color is
\r
2144 the result of the RGB or PALETTERGB macro, and it
\r
2145 knows how those macros work (which is documented).
\r
2148 InsertInPalette(COLORREF color)
\r
2150 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2152 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2153 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2154 pLogPal->palNumEntries--;
\r
2158 pe->peFlags = (char) 0;
\r
2159 pe->peRed = (char) (0xFF & color);
\r
2160 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2161 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2167 InitDrawingColors()
\r
2170 if (pLogPal == NULL) {
\r
2171 /* Allocate enough memory for a logical palette with
\r
2172 * PALETTESIZE entries and set the size and version fields
\r
2173 * of the logical palette structure.
\r
2175 pLogPal = (NPLOGPALETTE)
\r
2176 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2177 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2178 pLogPal->palVersion = 0x300;
\r
2180 pLogPal->palNumEntries = 0;
\r
2182 InsertInPalette(lightSquareColor);
\r
2183 InsertInPalette(darkSquareColor);
\r
2184 InsertInPalette(whitePieceColor);
\r
2185 InsertInPalette(blackPieceColor);
\r
2186 InsertInPalette(highlightSquareColor);
\r
2187 InsertInPalette(premoveHighlightColor);
\r
2189 /* create a logical color palette according the information
\r
2190 * in the LOGPALETTE structure.
\r
2192 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2194 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2195 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2196 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2197 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2198 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2199 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2200 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2201 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2203 /* [AS] Force rendering of the font-based pieces */
\r
2204 if( fontBitmapSquareSize > 0 ) {
\r
2205 fontBitmapSquareSize = 0;
\r
2211 BoardWidth(int boardSize, int n)
\r
2212 { /* [HGM] argument n added to allow different width and height */
\r
2213 int lineGap = sizeInfo[boardSize].lineGap;
\r
2215 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2216 lineGap = appData.overrideLineGap;
\r
2219 return (n + 1) * lineGap +
\r
2220 n * sizeInfo[boardSize].squareSize;
\r
2223 /* Respond to board resize by dragging edge */
\r
2225 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2227 BoardSize newSize = NUM_SIZES - 1;
\r
2228 static int recurse = 0;
\r
2229 if (IsIconic(hwndMain)) return;
\r
2230 if (recurse > 0) return;
\r
2232 while (newSize > 0) {
\r
2233 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2234 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2235 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2238 boardSize = newSize;
\r
2239 InitDrawingSizes(boardSize, flags);
\r
2244 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2247 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2249 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2250 ChessSquare piece;
\r
2251 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2253 SIZE clockSize, messageSize;
\r
2255 char buf[MSG_SIZ];
\r
2257 HMENU hmenu = GetMenu(hwndMain);
\r
2258 RECT crect, wrect, oldRect;
\r
2260 LOGBRUSH logbrush;
\r
2261 VariantClass v = gameInfo.variant;
\r
2263 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2264 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2266 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2267 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2268 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2269 oldBoardSize = boardSize;
\r
2271 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2272 { // correct board size to one where built-in pieces exist
\r
2273 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2274 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2275 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2276 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2277 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2278 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2279 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2280 boardSize = SizeMiddling;
\r
2283 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2285 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2286 oldRect.top = wpMain.y;
\r
2287 oldRect.right = wpMain.x + wpMain.width;
\r
2288 oldRect.bottom = wpMain.y + wpMain.height;
\r
2290 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2291 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2292 squareSize = sizeInfo[boardSize].squareSize;
\r
2293 lineGap = sizeInfo[boardSize].lineGap;
\r
2294 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2295 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2297 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2298 lineGap = appData.overrideLineGap;
\r
2301 if (tinyLayout != oldTinyLayout) {
\r
2302 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2304 style &= ~WS_SYSMENU;
\r
2305 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2306 "&Minimize\tCtrl+F4");
\r
2308 style |= WS_SYSMENU;
\r
2309 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2311 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2313 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2314 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2315 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2317 DrawMenuBar(hwndMain);
\r
2320 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2321 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2323 /* Get text area sizes */
\r
2324 hdc = GetDC(hwndMain);
\r
2325 if (appData.clockMode) {
\r
2326 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2328 snprintf(buf, MSG_SIZ, _("White"));
\r
2330 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2331 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2332 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2333 str = _("We only care about the height here");
\r
2334 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2335 SelectObject(hdc, oldFont);
\r
2336 ReleaseDC(hwndMain, hdc);
\r
2338 /* Compute where everything goes */
\r
2339 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2340 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2341 logoHeight = 2*clockSize.cy;
\r
2342 leftLogoRect.left = OUTER_MARGIN;
\r
2343 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2344 leftLogoRect.top = OUTER_MARGIN;
\r
2345 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2347 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2348 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2349 rightLogoRect.top = OUTER_MARGIN;
\r
2350 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2353 whiteRect.left = leftLogoRect.right;
\r
2354 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2355 whiteRect.top = OUTER_MARGIN;
\r
2356 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2358 blackRect.right = rightLogoRect.left;
\r
2359 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2360 blackRect.top = whiteRect.top;
\r
2361 blackRect.bottom = whiteRect.bottom;
\r
2363 whiteRect.left = OUTER_MARGIN;
\r
2364 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2365 whiteRect.top = OUTER_MARGIN;
\r
2366 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2368 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2369 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2370 blackRect.top = whiteRect.top;
\r
2371 blackRect.bottom = whiteRect.bottom;
\r
2373 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2376 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2377 if (appData.showButtonBar) {
\r
2378 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2379 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2381 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2383 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2384 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2386 boardRect.left = OUTER_MARGIN;
\r
2387 boardRect.right = boardRect.left + boardWidth;
\r
2388 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2389 boardRect.bottom = boardRect.top + boardHeight;
\r
2391 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2392 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2393 oldTinyLayout = tinyLayout;
\r
2394 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2395 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2396 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2397 winW *= 1 + twoBoards;
\r
2398 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2399 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2400 wpMain.height = winH; // without disturbing window attachments
\r
2401 GetWindowRect(hwndMain, &wrect);
\r
2402 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2403 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2405 // [HGM] placement: let attached windows follow size change.
\r
2406 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2407 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2408 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2409 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2410 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2412 /* compensate if menu bar wrapped */
\r
2413 GetClientRect(hwndMain, &crect);
\r
2414 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2415 wpMain.height += offby;
\r
2417 case WMSZ_TOPLEFT:
\r
2418 SetWindowPos(hwndMain, NULL,
\r
2419 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2420 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2423 case WMSZ_TOPRIGHT:
\r
2425 SetWindowPos(hwndMain, NULL,
\r
2426 wrect.left, wrect.bottom - wpMain.height,
\r
2427 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2430 case WMSZ_BOTTOMLEFT:
\r
2432 SetWindowPos(hwndMain, NULL,
\r
2433 wrect.right - wpMain.width, wrect.top,
\r
2434 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2437 case WMSZ_BOTTOMRIGHT:
\r
2441 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2442 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2447 for (i = 0; i < N_BUTTONS; i++) {
\r
2448 if (buttonDesc[i].hwnd != NULL) {
\r
2449 DestroyWindow(buttonDesc[i].hwnd);
\r
2450 buttonDesc[i].hwnd = NULL;
\r
2452 if (appData.showButtonBar) {
\r
2453 buttonDesc[i].hwnd =
\r
2454 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2455 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2456 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2457 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2458 (HMENU) buttonDesc[i].id,
\r
2459 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2461 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2462 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2463 MAKELPARAM(FALSE, 0));
\r
2465 if (buttonDesc[i].id == IDM_Pause)
\r
2466 hwndPause = buttonDesc[i].hwnd;
\r
2467 buttonDesc[i].wndproc = (WNDPROC)
\r
2468 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2471 if (gridPen != NULL) DeleteObject(gridPen);
\r
2472 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2473 if (premovePen != NULL) DeleteObject(premovePen);
\r
2474 if (lineGap != 0) {
\r
2475 logbrush.lbStyle = BS_SOLID;
\r
2476 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2478 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2479 lineGap, &logbrush, 0, NULL);
\r
2480 logbrush.lbColor = highlightSquareColor;
\r
2482 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2483 lineGap, &logbrush, 0, NULL);
\r
2485 logbrush.lbColor = premoveHighlightColor;
\r
2487 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2488 lineGap, &logbrush, 0, NULL);
\r
2490 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2491 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2492 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2493 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2494 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2495 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2496 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2497 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2499 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2500 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2501 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2502 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2503 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2504 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2505 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2506 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2510 /* [HGM] Licensing requirement */
\r
2512 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2515 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2517 GothicPopUp( "", VariantNormal);
\r
2520 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2522 /* Load piece bitmaps for this board size */
\r
2523 for (i=0; i<=2; i++) {
\r
2524 for (piece = WhitePawn;
\r
2525 (int) piece < (int) BlackPawn;
\r
2526 piece = (ChessSquare) ((int) piece + 1)) {
\r
2527 if (pieceBitmap[i][piece] != NULL)
\r
2528 DeleteObject(pieceBitmap[i][piece]);
\r
2532 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2533 // Orthodox Chess pieces
\r
2534 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2535 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2536 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2537 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2538 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2539 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2540 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2541 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2542 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2543 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2544 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2545 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2546 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2547 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2548 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2549 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2550 // in Shogi, Hijack the unused Queen for Lance
\r
2551 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2552 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2553 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2555 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2556 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2557 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2560 if(squareSize <= 72 && squareSize >= 33) {
\r
2561 /* A & C are available in most sizes now */
\r
2562 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2563 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2564 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2565 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2566 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2567 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2568 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2569 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2570 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2571 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2572 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2573 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2574 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2575 } else { // Smirf-like
\r
2576 if(gameInfo.variant == VariantSChess) {
\r
2577 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2578 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2579 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2581 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2582 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2583 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2586 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2587 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2588 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2589 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2590 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2591 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2592 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2593 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2594 } else { // WinBoard standard
\r
2595 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2596 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2597 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2602 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2603 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2604 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2605 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2606 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2607 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2608 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2609 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2610 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2611 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2612 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2613 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2614 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2615 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2616 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2617 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2618 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2621 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2622 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2623 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2624 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2625 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2626 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2627 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2628 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2629 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2630 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2631 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2632 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2633 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2634 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2635 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2637 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2638 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2639 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2640 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2641 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2642 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2643 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2644 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2647 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2648 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2649 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2651 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2652 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2653 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2654 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2655 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2656 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2657 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2658 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2659 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2660 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2665 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2666 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2667 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2668 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2669 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2670 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2671 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2672 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2673 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2674 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2675 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2676 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2677 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2678 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2679 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2683 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2684 /* special Shogi support in this size */
\r
2685 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2686 for (piece = WhitePawn;
\r
2687 (int) piece < (int) BlackPawn;
\r
2688 piece = (ChessSquare) ((int) piece + 1)) {
\r
2689 if (pieceBitmap[i][piece] != NULL)
\r
2690 DeleteObject(pieceBitmap[i][piece]);
\r
2693 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2694 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2695 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2696 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2697 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2698 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2699 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2700 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2701 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2702 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2703 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2704 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2705 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2706 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2707 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2708 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2709 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2710 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2711 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2712 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2713 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2714 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2715 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2716 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2717 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2718 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2719 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2720 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2721 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2722 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2723 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2724 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2725 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2726 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2727 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2728 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2729 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2730 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2731 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2732 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2733 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2734 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2740 PieceBitmap(ChessSquare p, int kind)
\r
2742 if ((int) p >= (int) BlackPawn)
\r
2743 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2745 return pieceBitmap[kind][(int) p];
\r
2748 /***************************************************************/
\r
2750 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2751 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2753 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2754 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2758 SquareToPos(int row, int column, int * x, int * y)
\r
2761 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2762 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2764 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2765 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2770 DrawCoordsOnDC(HDC hdc)
\r
2772 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2773 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2774 char str[2] = { NULLCHAR, NULLCHAR };
\r
2775 int oldMode, oldAlign, x, y, start, i;
\r
2779 if (!appData.showCoords)
\r
2782 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2784 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2785 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2786 oldAlign = GetTextAlign(hdc);
\r
2787 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2789 y = boardRect.top + lineGap;
\r
2790 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2793 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2794 x += border - lineGap - 4; y += squareSize - 6;
\r
2796 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2797 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2798 str[0] = files[start + i];
\r
2799 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2800 y += squareSize + lineGap;
\r
2803 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2806 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2807 x += -border + 4; y += border - squareSize + 6;
\r
2809 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2810 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2811 str[0] = ranks[start + i];
\r
2812 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2813 x += squareSize + lineGap;
\r
2816 SelectObject(hdc, oldBrush);
\r
2817 SetBkMode(hdc, oldMode);
\r
2818 SetTextAlign(hdc, oldAlign);
\r
2819 SelectObject(hdc, oldFont);
\r
2823 DrawGridOnDC(HDC hdc)
\r
2827 if (lineGap != 0) {
\r
2828 oldPen = SelectObject(hdc, gridPen);
\r
2829 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2830 SelectObject(hdc, oldPen);
\r
2834 #define HIGHLIGHT_PEN 0
\r
2835 #define PREMOVE_PEN 1
\r
2838 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2841 HPEN oldPen, hPen;
\r
2842 if (lineGap == 0) return;
\r
2844 x1 = boardRect.left +
\r
2845 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2846 y1 = boardRect.top +
\r
2847 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2849 x1 = boardRect.left +
\r
2850 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2851 y1 = boardRect.top +
\r
2852 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2854 hPen = pen ? premovePen : highlightPen;
\r
2855 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2856 MoveToEx(hdc, x1, y1, NULL);
\r
2857 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2858 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2859 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2860 LineTo(hdc, x1, y1);
\r
2861 SelectObject(hdc, oldPen);
\r
2865 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2868 for (i=0; i<2; i++) {
\r
2869 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2870 DrawHighlightOnDC(hdc, TRUE,
\r
2871 h->sq[i].x, h->sq[i].y,
\r
2876 /* Note: sqcolor is used only in monoMode */
\r
2877 /* Note that this code is largely duplicated in woptions.c,
\r
2878 function DrawSampleSquare, so that needs to be updated too */
\r
2880 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2882 HBITMAP oldBitmap;
\r
2886 if (appData.blindfold) return;
\r
2888 /* [AS] Use font-based pieces if needed */
\r
2889 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2890 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2891 CreatePiecesFromFont();
\r
2893 if( fontBitmapSquareSize == squareSize ) {
\r
2894 int index = TranslatePieceToFontPiece(piece);
\r
2896 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2898 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2899 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2903 squareSize, squareSize,
\r
2908 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2910 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2911 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2915 squareSize, squareSize,
\r
2924 if (appData.monoMode) {
\r
2925 SelectObject(tmphdc, PieceBitmap(piece,
\r
2926 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2927 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2928 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2930 HBRUSH xBrush = whitePieceBrush;
\r
2931 tmpSize = squareSize;
\r
2932 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2934 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2935 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2936 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2937 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2938 x += (squareSize - minorSize)>>1;
\r
2939 y += squareSize - minorSize - 2;
\r
2940 tmpSize = minorSize;
\r
2942 if (color || appData.allWhite ) {
\r
2943 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2945 oldBrush = SelectObject(hdc, xBrush);
\r
2946 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2947 if(appData.upsideDown && color==flipView)
\r
2948 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2950 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2951 /* Use black for outline of white pieces */
\r
2952 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2953 if(appData.upsideDown && color==flipView)
\r
2954 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2956 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2957 } else if(appData.pieceDirectory[0]) {
\r
2958 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2959 oldBrush = SelectObject(hdc, xBrush);
\r
2960 if(appData.upsideDown && color==flipView)
\r
2961 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2963 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2964 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2965 if(appData.upsideDown && color==flipView)
\r
2966 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2968 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2970 /* Use square color for details of black pieces */
\r
2971 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2972 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2973 if(appData.upsideDown && !flipView)
\r
2974 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2976 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2978 SelectObject(hdc, oldBrush);
\r
2979 SelectObject(tmphdc, oldBitmap);
\r
2983 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2984 int GetBackTextureMode( int algo )
\r
2986 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2990 case BACK_TEXTURE_MODE_PLAIN:
\r
2991 result = 1; /* Always use identity map */
\r
2993 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2994 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3002 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3003 to handle redraws cleanly (as random numbers would always be different).
\r
3005 VOID RebuildTextureSquareInfo()
\r
3015 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3017 if( liteBackTexture != NULL ) {
\r
3018 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3019 lite_w = bi.bmWidth;
\r
3020 lite_h = bi.bmHeight;
\r
3024 if( darkBackTexture != NULL ) {
\r
3025 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3026 dark_w = bi.bmWidth;
\r
3027 dark_h = bi.bmHeight;
\r
3031 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3032 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3033 if( (col + row) & 1 ) {
\r
3035 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3036 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3037 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3039 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3040 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3041 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3043 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3044 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3049 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3050 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3051 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3053 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3054 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3055 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3057 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3058 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3065 /* [AS] Arrow highlighting support */
\r
3067 static double A_WIDTH = 5; /* Width of arrow body */
\r
3069 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3070 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3072 static double Sqr( double x )
\r
3077 static int Round( double x )
\r
3079 return (int) (x + 0.5);
\r
3082 /* Draw an arrow between two points using current settings */
\r
3083 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3086 double dx, dy, j, k, x, y;
\r
3088 if( d_x == s_x ) {
\r
3089 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3091 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3094 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3095 arrow[1].y = d_y - h;
\r
3097 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3098 arrow[2].y = d_y - h;
\r
3103 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3104 arrow[5].y = d_y - h;
\r
3106 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3107 arrow[4].y = d_y - h;
\r
3109 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3112 else if( d_y == s_y ) {
\r
3113 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3116 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3118 arrow[1].x = d_x - w;
\r
3119 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3121 arrow[2].x = d_x - w;
\r
3122 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3127 arrow[5].x = d_x - w;
\r
3128 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3130 arrow[4].x = d_x - w;
\r
3131 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3134 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3137 /* [AS] Needed a lot of paper for this! :-) */
\r
3138 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3139 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3141 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3143 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3148 arrow[0].x = Round(x - j);
\r
3149 arrow[0].y = Round(y + j*dx);
\r
3151 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3152 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3155 x = (double) d_x - k;
\r
3156 y = (double) d_y - k*dy;
\r
3159 x = (double) d_x + k;
\r
3160 y = (double) d_y + k*dy;
\r
3163 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3165 arrow[6].x = Round(x - j);
\r
3166 arrow[6].y = Round(y + j*dx);
\r
3168 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3169 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3171 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3172 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3177 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3178 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3181 Polygon( hdc, arrow, 7 );
\r
3184 /* [AS] Draw an arrow between two squares */
\r