2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
96 #define DATADIR "~~"
\r
98 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
100 int myrandom(void);
\r
101 void mysrandom(unsigned int seed);
\r
103 extern int whiteFlag, blackFlag;
\r
104 Boolean flipClock = FALSE;
\r
105 extern HANDLE chatHandle[];
\r
106 extern enum ICS_TYPE ics_type;
\r
108 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
109 int MyGetFullPathName P((char *name, char *fullname));
\r
110 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
111 VOID NewVariantPopup(HWND hwnd);
\r
112 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
113 /*char*/int promoChar));
\r
114 void DisplayMove P((int moveNumber));
\r
115 void ChatPopUp P((char *s));
\r
117 ChessSquare piece;
\r
118 POINT pos; /* window coordinates of current pos */
\r
119 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
120 POINT from; /* board coordinates of the piece's orig pos */
\r
121 POINT to; /* board coordinates of the piece's new pos */
\r
124 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
127 POINT start; /* window coordinates of start pos */
\r
128 POINT pos; /* window coordinates of current pos */
\r
129 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
130 POINT from; /* board coordinates of the piece's orig pos */
\r
134 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
137 POINT sq[2]; /* board coordinates of from, to squares */
\r
140 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
145 typedef struct { // [HGM] atomic
\r
146 int fromX, fromY, toX, toY, radius;
\r
149 static ExplodeInfo explodeInfo;
\r
151 /* Window class names */
\r
152 char szAppName[] = "WinBoard";
\r
153 char szConsoleName[] = "WBConsole";
\r
155 /* Title bar text */
\r
156 char szTitle[] = "WinBoard";
\r
157 char szConsoleTitle[] = "I C S Interaction";
\r
160 char *settingsFileName;
\r
161 Boolean saveSettingsOnExit;
\r
162 char installDir[MSG_SIZ];
\r
163 int errorExitStatus;
\r
165 BoardSize boardSize;
\r
166 Boolean chessProgram;
\r
167 //static int boardX, boardY;
\r
168 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
169 int squareSize, lineGap, minorSize, border;
\r
170 static int winW, winH;
\r
171 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
172 static int logoHeight = 0;
\r
173 static char messageText[MESSAGE_TEXT_MAX];
\r
174 static int clockTimerEvent = 0;
\r
175 static int loadGameTimerEvent = 0;
\r
176 static int analysisTimerEvent = 0;
\r
177 static DelayedEventCallback delayedTimerCallback;
\r
178 static int delayedTimerEvent = 0;
\r
179 static int buttonCount = 2;
\r
180 char *icsTextMenuString;
\r
182 char *firstChessProgramNames;
\r
183 char *secondChessProgramNames;
\r
185 #define PALETTESIZE 256
\r
187 HINSTANCE hInst; /* current instance */
\r
188 Boolean alwaysOnTop = FALSE;
\r
190 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
191 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
192 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
194 ColorClass currentColorClass;
\r
196 static HWND savedHwnd;
\r
197 HWND hCommPort = NULL; /* currently open comm port */
\r
198 static HWND hwndPause; /* pause button */
\r
199 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
200 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
201 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
202 explodeBrush, /* [HGM] atomic */
\r
203 markerBrush[8], /* [HGM] markers */
\r
204 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
205 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
206 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
207 static HPEN gridPen = NULL;
\r
208 static HPEN highlightPen = NULL;
\r
209 static HPEN premovePen = NULL;
\r
210 static NPLOGPALETTE pLogPal;
\r
211 static BOOL paletteChanged = FALSE;
\r
212 static HICON iconWhite, iconBlack, iconCurrent;
\r
213 static int doingSizing = FALSE;
\r
214 static int lastSizing = 0;
\r
215 static int prevStderrPort;
\r
216 static HBITMAP userLogo;
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
229 #if defined(_winmajor)
\r
230 #define oldDialog (_winmajor < 4)
\r
232 #define oldDialog 0
\r
236 #define INTERNATIONAL
\r
238 #ifdef INTERNATIONAL
\r
239 # define _(s) T_(s)
\r
245 # define Translate(x, y)
\r
246 # define LoadLanguageFile(s)
\r
249 #ifdef INTERNATIONAL
\r
251 Boolean barbaric; // flag indicating if translation is needed
\r
253 // list of item numbers used in each dialog (used to alter language at run time)
\r
255 #define ABOUTBOX -1 /* not sure why these are needed */
\r
256 #define ABOUTBOX2 -1
\r
258 int dialogItems[][42] = {
\r
259 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
260 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
261 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
262 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
263 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds,
\r
264 OPT_Ranget, IDOK, IDCANCEL },
\r
265 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
266 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
267 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
268 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
269 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
270 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
271 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
272 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
273 { ABOUTBOX2, IDC_ChessBoard },
\r
274 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
275 OPT_GameListClose, IDC_GameListDoFilter },
\r
276 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
277 { DLG_Error, IDOK },
\r
278 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
279 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
280 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
281 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
282 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
283 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
284 { DLG_IndexNumber, IDC_Index },
\r
285 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
286 { DLG_TypeInName, IDOK, IDCANCEL },
\r
287 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
288 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
289 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
290 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
291 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
292 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
293 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
294 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
295 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
296 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
297 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
298 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
299 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
300 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
301 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
302 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
303 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
304 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
305 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
306 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
307 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
308 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
309 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
310 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
311 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
312 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
313 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
314 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
315 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
316 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
317 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
318 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
319 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
320 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
321 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
322 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
323 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
324 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
325 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
326 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
327 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
328 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
329 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
330 { DLG_MoveHistory },
\r
331 { DLG_EvalGraph },
\r
332 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
333 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
334 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
335 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
336 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
337 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
338 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
339 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
340 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
344 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
345 static int lastChecked;
\r
346 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
347 extern int tinyLayout;
\r
348 extern char * menuBarText[][10];
\r
351 LoadLanguageFile(char *name)
\r
352 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
354 int i=0, j=0, n=0, k;
\r
357 if(!name || name[0] == NULLCHAR) return;
\r
358 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
359 appData.language = oldLanguage;
\r
360 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
361 if((f = fopen(buf, "r")) == NULL) return;
\r
362 while((k = fgetc(f)) != EOF) {
\r
363 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
364 languageBuf[i] = k;
\r
366 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
368 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
369 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
370 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
371 english[j] = languageBuf + n + 1; *p = 0;
\r
372 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
373 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
378 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
380 case 'n': k = '\n'; break;
\r
381 case 'r': k = '\r'; break;
\r
382 case 't': k = '\t'; break;
\r
384 languageBuf[--i] = k;
\r
389 barbaric = (j != 0);
\r
390 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
395 { // return the translation of the given string
\r
396 // efficiency can be improved a lot...
\r
398 static char buf[MSG_SIZ];
\r
399 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
400 if(!barbaric) return s;
\r
401 if(!s) return ""; // sanity
\r
402 while(english[i]) {
\r
403 if(!strcmp(s, english[i])) return foreign[i];
\r
404 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
405 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
414 Translate(HWND hDlg, int dialogID)
\r
415 { // translate all text items in the given dialog
\r
417 char buf[MSG_SIZ], *s;
\r
418 if(!barbaric) return;
\r
419 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
420 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
421 GetWindowText( hDlg, buf, MSG_SIZ );
\r
423 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
424 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
425 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
426 if(strlen(buf) == 0) continue;
\r
428 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
433 TranslateOneMenu(int i, HMENU subMenu)
\r
436 static MENUITEMINFO info;
\r
438 info.cbSize = sizeof(MENUITEMINFO);
\r
439 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
440 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
442 info.dwTypeData = buf;
\r
443 info.cch = sizeof(buf);
\r
444 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
446 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
447 else menuText[i][j] = strdup(buf); // remember original on first change
\r
449 if(buf[0] == NULLCHAR) continue;
\r
450 info.dwTypeData = T_(buf);
\r
451 info.cch = strlen(buf)+1;
\r
452 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
458 TranslateMenus(int addLanguage)
\r
461 WIN32_FIND_DATA fileData;
\r
463 #define IDM_English 1970
\r
465 HMENU mainMenu = GetMenu(hwndMain);
\r
466 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
467 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
468 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
469 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
470 TranslateOneMenu(i, subMenu);
\r
472 DrawMenuBar(hwndMain);
\r
475 if(!addLanguage) return;
\r
476 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
477 HMENU mainMenu = GetMenu(hwndMain);
\r
478 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
479 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
480 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
481 i = 0; lastChecked = IDM_English;
\r
483 char *p, *q = fileData.cFileName;
\r
484 int checkFlag = MF_UNCHECKED;
\r
485 languageFile[i] = strdup(q);
\r
486 if(barbaric && !strcmp(oldLanguage, q)) {
\r
487 checkFlag = MF_CHECKED;
\r
488 lastChecked = IDM_English + i + 1;
\r
489 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
491 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
492 p = strstr(fileData.cFileName, ".lng");
\r
494 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
495 } while(FindNextFile(hFind, &fileData));
\r
502 #define IDM_RecentEngines 3000
\r
505 RecentEngineMenu (char *s)
\r
507 if(appData.icsActive) return;
\r
508 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
509 HMENU mainMenu = GetMenu(hwndMain);
\r
510 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
511 int i=IDM_RecentEngines;
\r
512 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
513 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
515 char *p = strchr(s, '\n');
\r
516 if(p == NULL) return; // malformed!
\r
518 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
532 int cliWidth, cliHeight;
\r
535 SizeInfo sizeInfo[] =
\r
537 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
540 { "petite", 33, 1, 1, 1, 0, 0 },
\r
541 { "slim", 37, 2, 1, 0, 0, 0 },
\r
542 { "small", 40, 2, 1, 0, 0, 0 },
\r
543 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
544 { "middling", 49, 2, 0, 0, 0, 0 },
\r
545 { "average", 54, 2, 0, 0, 0, 0 },
\r
546 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
547 { "medium", 64, 3, 0, 0, 0, 0 },
\r
548 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
549 { "large", 80, 3, 0, 0, 0, 0 },
\r
550 { "big", 87, 3, 0, 0, 0, 0 },
\r
551 { "huge", 95, 3, 0, 0, 0, 0 },
\r
552 { "giant", 108, 3, 0, 0, 0, 0 },
\r
553 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
554 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
555 { NULL, 0, 0, 0, 0, 0, 0 }
\r
558 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
559 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
561 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
562 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
578 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
581 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
590 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
591 #define N_BUTTONS 5
\r
593 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
595 {"<<", IDM_ToStart, NULL, NULL},
\r
596 {"<", IDM_Backward, NULL, NULL},
\r
597 {"P", IDM_Pause, NULL, NULL},
\r
598 {">", IDM_Forward, NULL, NULL},
\r
599 {">>", IDM_ToEnd, NULL, NULL},
\r
602 int tinyLayout = 0, smallLayout = 0;
\r
603 #define MENU_BAR_ITEMS 9
\r
604 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
605 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
606 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
610 MySound sounds[(int)NSoundClasses];
\r
611 MyTextAttribs textAttribs[(int)NColorClasses];
\r
613 MyColorizeAttribs colorizeAttribs[] = {
\r
614 { (COLORREF)0, 0, N_("Shout Text") },
\r
615 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
616 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
617 { (COLORREF)0, 0, N_("Channel Text") },
\r
618 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
619 { (COLORREF)0, 0, N_("Tell Text") },
\r
620 { (COLORREF)0, 0, N_("Challenge Text") },
\r
621 { (COLORREF)0, 0, N_("Request Text") },
\r
622 { (COLORREF)0, 0, N_("Seek Text") },
\r
623 { (COLORREF)0, 0, N_("Normal Text") },
\r
624 { (COLORREF)0, 0, N_("None") }
\r
629 static char *commentTitle;
\r
630 static char *commentText;
\r
631 static int commentIndex;
\r
632 static Boolean editComment = FALSE;
\r
635 char errorTitle[MSG_SIZ];
\r
636 char errorMessage[2*MSG_SIZ];
\r
637 HWND errorDialog = NULL;
\r
638 BOOLEAN moveErrorMessageUp = FALSE;
\r
639 BOOLEAN consoleEcho = TRUE;
\r
640 CHARFORMAT consoleCF;
\r
641 COLORREF consoleBackgroundColor;
\r
643 char *programVersion;
\r
649 typedef int CPKind;
\r
658 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
661 #define INPUT_SOURCE_BUF_SIZE 4096
\r
663 typedef struct _InputSource {
\r
670 char buf[INPUT_SOURCE_BUF_SIZE];
\r
674 InputCallback func;
\r
675 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
679 InputSource *consoleInputSource;
\r
684 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
685 VOID ConsoleCreate();
\r
687 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
689 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
690 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
692 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
693 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
694 void ParseIcsTextMenu(char *icsTextMenuString);
\r
695 VOID PopUpNameDialog(char firstchar);
\r
696 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
700 int GameListOptions();
\r
702 int dummy; // [HGM] for obsolete args
\r
704 HWND hwndMain = NULL; /* root window*/
\r
705 HWND hwndConsole = NULL;
\r
706 HWND commentDialog = NULL;
\r
707 HWND moveHistoryDialog = NULL;
\r
708 HWND evalGraphDialog = NULL;
\r
709 HWND engineOutputDialog = NULL;
\r
710 HWND gameListDialog = NULL;
\r
711 HWND editTagsDialog = NULL;
\r
713 int commentUp = FALSE;
\r
715 WindowPlacement wpMain;
\r
716 WindowPlacement wpConsole;
\r
717 WindowPlacement wpComment;
\r
718 WindowPlacement wpMoveHistory;
\r
719 WindowPlacement wpEvalGraph;
\r
720 WindowPlacement wpEngineOutput;
\r
721 WindowPlacement wpGameList;
\r
722 WindowPlacement wpTags;
\r
724 VOID EngineOptionsPopup(); // [HGM] settings
\r
726 VOID GothicPopUp(char *title, VariantClass variant);
\r
728 * Setting "frozen" should disable all user input other than deleting
\r
729 * the window. We do this while engines are initializing themselves.
\r
731 static int frozen = 0;
\r
732 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
738 if (frozen) return;
\r
740 hmenu = GetMenu(hwndMain);
\r
741 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
742 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
744 DrawMenuBar(hwndMain);
\r
747 /* Undo a FreezeUI */
\r
753 if (!frozen) return;
\r
755 hmenu = GetMenu(hwndMain);
\r
756 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
757 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
759 DrawMenuBar(hwndMain);
\r
762 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
764 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
770 #define JAWS_ALT_INTERCEPT
\r
771 #define JAWS_KBUP_NAVIGATION
\r
772 #define JAWS_KBDOWN_NAVIGATION
\r
773 #define JAWS_MENU_ITEMS
\r
774 #define JAWS_SILENCE
\r
775 #define JAWS_REPLAY
\r
777 #define JAWS_COPYRIGHT
\r
778 #define JAWS_DELETE(X) X
\r
779 #define SAYMACHINEMOVE()
\r
783 /*---------------------------------------------------------------------------*\
\r
787 \*---------------------------------------------------------------------------*/
\r
789 static void HandleMessage P((MSG *message));
\r
790 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
793 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
794 LPSTR lpCmdLine, int nCmdShow)
\r
797 // INITCOMMONCONTROLSEX ex;
\r
801 LoadLibrary("RICHED32.DLL");
\r
802 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
804 if (!InitApplication(hInstance)) {
\r
807 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
814 // InitCommonControlsEx(&ex);
\r
815 InitCommonControls();
\r
817 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
818 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
819 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
821 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
823 while (GetMessage(&msg, /* message structure */
\r
824 NULL, /* handle of window receiving the message */
\r
825 0, /* lowest message to examine */
\r
826 0)) /* highest message to examine */
\r
828 HandleMessage(msg);
\r
832 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
836 HandleMessage (MSG *message)
\r
838 MSG msg = *message;
\r
840 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
841 // [HGM] navigate: switch between all windows with tab
\r
842 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
843 int i, currentElement = 0;
\r
845 // first determine what element of the chain we come from (if any)
\r
846 if(appData.icsActive) {
\r
847 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
848 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
850 if(engineOutputDialog && EngineOutputIsUp()) {
\r
851 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
852 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
854 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
855 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
857 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
858 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
859 if(msg.hwnd == e1) currentElement = 2; else
\r
860 if(msg.hwnd == e2) currentElement = 3; else
\r
861 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
862 if(msg.hwnd == mh) currentElement = 4; else
\r
863 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
864 if(msg.hwnd == hText) currentElement = 5; else
\r
865 if(msg.hwnd == hInput) currentElement = 6; else
\r
866 for (i = 0; i < N_BUTTONS; i++) {
\r
867 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
870 // determine where to go to
\r
871 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
873 currentElement = (currentElement + direction) % 7;
\r
874 switch(currentElement) {
\r
876 h = hwndMain; break; // passing this case always makes the loop exit
\r
878 h = buttonDesc[0].hwnd; break; // could be NULL
\r
880 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
883 if(!EngineOutputIsUp()) continue;
\r
886 if(!MoveHistoryIsUp()) continue;
\r
888 // case 6: // input to eval graph does not seem to get here!
\r
889 // if(!EvalGraphIsUp()) continue;
\r
890 // h = evalGraphDialog; break;
\r
892 if(!appData.icsActive) continue;
\r
896 if(!appData.icsActive) continue;
\r
902 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
903 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
906 return; // this message now has been processed
\r
910 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
911 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
912 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
913 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
914 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
915 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
916 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
917 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
918 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
920 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
921 for(i=0; i<MAX_CHAT; i++)
\r
922 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
925 if(done) return; // [HGM] chat: end patch
\r
926 TranslateMessage(&msg); /* Translates virtual key codes */
\r
927 DispatchMessage(&msg); /* Dispatches message to window */
\r
933 { /* Dispatch pending messages */
\r
935 while (PeekMessage(&msg, /* message structure */
\r
936 NULL, /* handle of window receiving the message */
\r
937 0, /* lowest message to examine */
\r
938 0, /* highest message to examine */
\r
941 HandleMessage(msg);
\r
945 /*---------------------------------------------------------------------------*\
\r
947 * Initialization functions
\r
949 \*---------------------------------------------------------------------------*/
\r
953 { // update user logo if necessary
\r
954 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
956 if(appData.autoLogo) {
\r
957 curName = UserName();
\r
958 if(strcmp(curName, oldUserName)) {
\r
959 GetCurrentDirectory(MSG_SIZ, dir);
\r
960 SetCurrentDirectory(installDir);
\r
961 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
962 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
963 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
964 if(userLogo == NULL)
\r
965 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
966 SetCurrentDirectory(dir); /* return to prev directory */
\r
972 InitApplication(HINSTANCE hInstance)
\r
976 /* Fill in window class structure with parameters that describe the */
\r
979 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
980 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
981 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
982 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
983 wc.hInstance = hInstance; /* Owner of this class */
\r
984 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
985 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
986 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
987 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
988 wc.lpszClassName = szAppName; /* Name to register as */
\r
990 /* Register the window class and return success/failure code. */
\r
991 if (!RegisterClass(&wc)) return FALSE;
\r
993 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
994 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
996 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
997 wc.hInstance = hInstance;
\r
998 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
999 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1000 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1001 wc.lpszMenuName = NULL;
\r
1002 wc.lpszClassName = szConsoleName;
\r
1004 if (!RegisterClass(&wc)) return FALSE;
\r
1009 /* Set by InitInstance, used by EnsureOnScreen */
\r
1010 int screenHeight, screenWidth;
\r
1011 RECT screenGeometry;
\r
1014 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1016 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1017 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1018 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1019 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1020 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1021 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1025 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1027 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1028 GetCurrentDirectory(MSG_SIZ, dir);
\r
1029 SetCurrentDirectory(installDir);
\r
1030 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1031 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1033 if (cps->programLogo == NULL && appData.debugMode) {
\r
1034 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1036 } else if(appData.autoLogo) {
\r
1037 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1038 char *opponent = "";
\r
1039 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1040 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1041 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1042 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1043 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1044 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1047 if(appData.directory[n] && appData.directory[n][0]) {
\r
1048 SetCurrentDirectory(appData.directory[n]);
\r
1049 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1052 SetCurrentDirectory(dir); /* return to prev directory */
\r
1058 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1059 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1061 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1062 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1063 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1064 liteBackTextureMode = appData.liteBackTextureMode;
\r
1066 if (liteBackTexture == NULL && appData.debugMode) {
\r
1067 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1071 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1072 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1073 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1074 darkBackTextureMode = appData.darkBackTextureMode;
\r
1076 if (darkBackTexture == NULL && appData.debugMode) {
\r
1077 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1082 #ifndef SM_CXVIRTUALSCREEN
\r
1083 #define SM_CXVIRTUALSCREEN 78
\r
1085 #ifndef SM_CYVIRTUALSCREEN
\r
1086 #define SM_CYVIRTUALSCREEN 79
\r
1088 #ifndef SM_XVIRTUALSCREEN
\r
1089 #define SM_XVIRTUALSCREEN 76
\r
1091 #ifndef SM_YVIRTUALSCREEN
\r
1092 #define SM_YVIRTUALSCREEN 77
\r
1098 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1099 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1100 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1101 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1102 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1103 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1104 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1105 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1109 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1111 HWND hwnd; /* Main window handle. */
\r
1113 WINDOWPLACEMENT wp;
\r
1116 hInst = hInstance; /* Store instance handle in our global variable */
\r
1117 programName = szAppName;
\r
1119 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1120 *filepart = NULLCHAR;
\r
1121 SetCurrentDirectory(installDir);
\r
1123 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1125 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1127 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1128 /* xboard, and older WinBoards, controlled the move sound with the
\r
1129 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1130 always turn the option on (so that the backend will call us),
\r
1131 then let the user turn the sound off by setting it to silence if
\r
1132 desired. To accommodate old winboard.ini files saved by old
\r
1133 versions of WinBoard, we also turn off the sound if the option
\r
1134 was initially set to false. [HGM] taken out of InitAppData */
\r
1135 if (!appData.ringBellAfterMoves) {
\r
1136 sounds[(int)SoundMove].name = strdup("");
\r
1137 appData.ringBellAfterMoves = TRUE;
\r
1139 if (appData.debugMode) {
\r
1140 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1141 setbuf(debugFP, NULL);
\r
1144 LoadLanguageFile(appData.language);
\r
1148 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1149 // InitEngineUCI( installDir, &second );
\r
1151 /* Create a main window for this application instance. */
\r
1152 hwnd = CreateWindow(szAppName, szTitle,
\r
1153 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1154 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1155 NULL, NULL, hInstance, NULL);
\r
1158 /* If window could not be created, return "failure" */
\r
1163 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1164 LoadLogo(&first, 0, FALSE);
\r
1165 LoadLogo(&second, 1, appData.icsActive);
\r
1169 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1170 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1171 iconCurrent = iconWhite;
\r
1172 InitDrawingColors();
\r
1174 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1175 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1176 /* Compute window size for each board size, and use the largest
\r
1177 size that fits on this screen as the default. */
\r
1178 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1179 if (boardSize == (BoardSize)-1 &&
\r
1180 winH <= screenHeight
\r
1181 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1182 && winW <= screenWidth) {
\r
1183 boardSize = (BoardSize)ibs;
\r
1187 InitDrawingSizes(boardSize, 0);
\r
1188 RecentEngineMenu(appData.recentEngineList);
\r
1190 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1192 /* [AS] Load textures if specified */
\r
1195 mysrandom( (unsigned) time(NULL) );
\r
1197 /* [AS] Restore layout */
\r
1198 if( wpMoveHistory.visible ) {
\r
1199 MoveHistoryPopUp();
\r
1202 if( wpEvalGraph.visible ) {
\r
1206 if( wpEngineOutput.visible ) {
\r
1207 EngineOutputPopUp();
\r
1210 /* Make the window visible; update its client area; and return "success" */
\r
1211 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1212 wp.length = sizeof(WINDOWPLACEMENT);
\r
1214 wp.showCmd = nCmdShow;
\r
1215 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1216 wp.rcNormalPosition.left = wpMain.x;
\r
1217 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1218 wp.rcNormalPosition.top = wpMain.y;
\r
1219 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1220 SetWindowPlacement(hwndMain, &wp);
\r
1222 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1224 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1225 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1227 if (hwndConsole) {
\r
1229 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1230 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1232 ShowWindow(hwndConsole, nCmdShow);
\r
1233 SetActiveWindow(hwndConsole);
\r
1235 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1236 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1245 HMENU hmenu = GetMenu(hwndMain);
\r
1247 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1248 MF_BYCOMMAND|((appData.icsActive &&
\r
1249 *appData.icsCommPort != NULLCHAR) ?
\r
1250 MF_ENABLED : MF_GRAYED));
\r
1251 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1252 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1253 MF_CHECKED : MF_UNCHECKED));
\r
1254 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1257 //---------------------------------------------------------------------------------------------------------
\r
1259 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1260 #define XBOARD FALSE
\r
1262 #define OPTCHAR "/"
\r
1263 #define SEPCHAR "="
\r
1264 #define TOPLEVEL 0
\r
1268 // front-end part of option handling
\r
1271 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1273 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1274 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1277 lf->lfEscapement = 0;
\r
1278 lf->lfOrientation = 0;
\r
1279 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1280 lf->lfItalic = mfp->italic;
\r
1281 lf->lfUnderline = mfp->underline;
\r
1282 lf->lfStrikeOut = mfp->strikeout;
\r
1283 lf->lfCharSet = mfp->charset;
\r
1284 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1285 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1286 lf->lfQuality = DEFAULT_QUALITY;
\r
1287 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1288 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1292 CreateFontInMF(MyFont *mf)
\r
1294 LFfromMFP(&mf->lf, &mf->mfp);
\r
1295 if (mf->hf) DeleteObject(mf->hf);
\r
1296 mf->hf = CreateFontIndirect(&mf->lf);
\r
1299 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1301 colorVariable[] = {
\r
1302 &whitePieceColor,
\r
1303 &blackPieceColor,
\r
1304 &lightSquareColor,
\r
1305 &darkSquareColor,
\r
1306 &highlightSquareColor,
\r
1307 &premoveHighlightColor,
\r
1309 &consoleBackgroundColor,
\r
1310 &appData.fontForeColorWhite,
\r
1311 &appData.fontBackColorWhite,
\r
1312 &appData.fontForeColorBlack,
\r
1313 &appData.fontBackColorBlack,
\r
1314 &appData.evalHistColorWhite,
\r
1315 &appData.evalHistColorBlack,
\r
1316 &appData.highlightArrowColor,
\r
1319 /* Command line font name parser. NULL name means do nothing.
\r
1320 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1321 For backward compatibility, syntax without the colon is also
\r
1322 accepted, but font names with digits in them won't work in that case.
\r
1325 ParseFontName(char *name, MyFontParams *mfp)
\r
1328 if (name == NULL) return;
\r
1330 q = strchr(p, ':');
\r
1332 if (q - p >= sizeof(mfp->faceName))
\r
1333 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1334 memcpy(mfp->faceName, p, q - p);
\r
1335 mfp->faceName[q - p] = NULLCHAR;
\r
1338 q = mfp->faceName;
\r
1340 while (*p && !isdigit(*p)) {
\r
1342 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1343 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1345 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1348 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1349 mfp->pointSize = (float) atof(p);
\r
1350 mfp->bold = (strchr(p, 'b') != NULL);
\r
1351 mfp->italic = (strchr(p, 'i') != NULL);
\r
1352 mfp->underline = (strchr(p, 'u') != NULL);
\r
1353 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1354 mfp->charset = DEFAULT_CHARSET;
\r
1355 q = strchr(p, 'c');
\r
1357 mfp->charset = (BYTE) atoi(q+1);
\r
1361 ParseFont(char *name, int number)
\r
1362 { // wrapper to shield back-end from 'font'
\r
1363 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1368 { // in WB we have a 2D array of fonts; this initializes their description
\r
1370 /* Point font array elements to structures and
\r
1371 parse default font names */
\r
1372 for (i=0; i<NUM_FONTS; i++) {
\r
1373 for (j=0; j<NUM_SIZES; j++) {
\r
1374 font[j][i] = &fontRec[j][i];
\r
1375 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1382 { // here we create the actual fonts from the selected descriptions
\r
1384 for (i=0; i<NUM_FONTS; i++) {
\r
1385 for (j=0; j<NUM_SIZES; j++) {
\r
1386 CreateFontInMF(font[j][i]);
\r
1390 /* Color name parser.
\r
1391 X version accepts X color names, but this one
\r
1392 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1394 ParseColorName(char *name)
\r
1396 int red, green, blue, count;
\r
1397 char buf[MSG_SIZ];
\r
1399 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1401 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1402 &red, &green, &blue);
\r
1405 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1406 DisplayError(buf, 0);
\r
1407 return RGB(0, 0, 0);
\r
1409 return PALETTERGB(red, green, blue);
\r
1413 ParseColor(int n, char *name)
\r
1414 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1415 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1419 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1421 char *e = argValue;
\r
1425 if (*e == 'b') eff |= CFE_BOLD;
\r
1426 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1427 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1428 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1429 else if (*e == '#' || isdigit(*e)) break;
\r
1433 *color = ParseColorName(e);
\r
1437 ParseTextAttribs(ColorClass cc, char *s)
\r
1438 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1439 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1440 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1444 ParseBoardSize(void *addr, char *name)
\r
1445 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1446 BoardSize bs = SizeTiny;
\r
1447 while (sizeInfo[bs].name != NULL) {
\r
1448 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1449 *(BoardSize *)addr = bs;
\r
1454 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1459 { // [HGM] import name from appData first
\r
1462 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1463 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1464 textAttribs[cc].sound.data = NULL;
\r
1465 MyLoadSound(&textAttribs[cc].sound);
\r
1467 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1468 textAttribs[cc].sound.name = strdup("");
\r
1469 textAttribs[cc].sound.data = NULL;
\r
1471 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1472 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1473 sounds[sc].data = NULL;
\r
1474 MyLoadSound(&sounds[sc]);
\r
1479 SetCommPortDefaults()
\r
1481 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1482 dcb.DCBlength = sizeof(DCB);
\r
1483 dcb.BaudRate = 9600;
\r
1484 dcb.fBinary = TRUE;
\r
1485 dcb.fParity = FALSE;
\r
1486 dcb.fOutxCtsFlow = FALSE;
\r
1487 dcb.fOutxDsrFlow = FALSE;
\r
1488 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1489 dcb.fDsrSensitivity = FALSE;
\r
1490 dcb.fTXContinueOnXoff = TRUE;
\r
1491 dcb.fOutX = FALSE;
\r
1493 dcb.fNull = FALSE;
\r
1494 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1495 dcb.fAbortOnError = FALSE;
\r
1497 dcb.Parity = SPACEPARITY;
\r
1498 dcb.StopBits = ONESTOPBIT;
\r
1501 // [HGM] args: these three cases taken out to stay in front-end
\r
1503 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1504 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1505 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1506 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1508 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1509 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1510 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1511 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1512 ad->argName, mfp->faceName, mfp->pointSize,
\r
1513 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1514 mfp->bold ? "b" : "",
\r
1515 mfp->italic ? "i" : "",
\r
1516 mfp->underline ? "u" : "",
\r
1517 mfp->strikeout ? "s" : "",
\r
1518 (int)mfp->charset);
\r
1524 { // [HGM] copy the names from the internal WB variables to appData
\r
1527 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1528 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1529 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1530 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1534 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1535 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1536 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1537 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1538 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1539 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1540 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1541 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1542 (ta->effects) ? " " : "",
\r
1543 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1547 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1548 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1549 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1550 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1551 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1555 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1556 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1557 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1561 ParseCommPortSettings(char *s)
\r
1562 { // wrapper to keep dcb from back-end
\r
1563 ParseCommSettings(s, &dcb);
\r
1568 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1569 GetActualPlacement(hwndMain, &wpMain);
\r
1570 GetActualPlacement(hwndConsole, &wpConsole);
\r
1571 GetActualPlacement(commentDialog, &wpComment);
\r
1572 GetActualPlacement(editTagsDialog, &wpTags);
\r
1573 GetActualPlacement(gameListDialog, &wpGameList);
\r
1574 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1575 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1576 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1580 PrintCommPortSettings(FILE *f, char *name)
\r
1581 { // wrapper to shield back-end from DCB
\r
1582 PrintCommSettings(f, name, &dcb);
\r
1586 MySearchPath(char *installDir, char *name, char *fullname)
\r
1588 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1589 if(name[0]== '%') {
\r
1590 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1591 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1592 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1593 *strchr(buf, '%') = 0;
\r
1594 strcat(fullname, getenv(buf));
\r
1595 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1597 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1598 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1599 return (int) strlen(fullname);
\r
1601 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1605 MyGetFullPathName(char *name, char *fullname)
\r
1608 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1613 { // [HGM] args: allows testing if main window is realized from back-end
\r
1614 return hwndMain != NULL;
\r
1618 PopUpStartupDialog()
\r
1622 LoadLanguageFile(appData.language);
\r
1623 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1624 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1625 FreeProcInstance(lpProc);
\r
1628 /*---------------------------------------------------------------------------*\
\r
1630 * GDI board drawing routines
\r
1632 \*---------------------------------------------------------------------------*/
\r
1634 /* [AS] Draw square using background texture */
\r
1635 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1640 return; /* Should never happen! */
\r
1643 SetGraphicsMode( dst, GM_ADVANCED );
\r
1650 /* X reflection */
\r
1655 x.eDx = (FLOAT) dw + dx - 1;
\r
1658 SetWorldTransform( dst, &x );
\r
1661 /* Y reflection */
\r
1667 x.eDy = (FLOAT) dh + dy - 1;
\r
1669 SetWorldTransform( dst, &x );
\r
1677 x.eDx = (FLOAT) dx;
\r
1678 x.eDy = (FLOAT) dy;
\r
1681 SetWorldTransform( dst, &x );
\r
1685 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1693 SetWorldTransform( dst, &x );
\r
1695 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1698 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1700 PM_WP = (int) WhitePawn,
\r
1701 PM_WN = (int) WhiteKnight,
\r
1702 PM_WB = (int) WhiteBishop,
\r
1703 PM_WR = (int) WhiteRook,
\r
1704 PM_WQ = (int) WhiteQueen,
\r
1705 PM_WF = (int) WhiteFerz,
\r
1706 PM_WW = (int) WhiteWazir,
\r
1707 PM_WE = (int) WhiteAlfil,
\r
1708 PM_WM = (int) WhiteMan,
\r
1709 PM_WO = (int) WhiteCannon,
\r
1710 PM_WU = (int) WhiteUnicorn,
\r
1711 PM_WH = (int) WhiteNightrider,
\r
1712 PM_WA = (int) WhiteAngel,
\r
1713 PM_WC = (int) WhiteMarshall,
\r
1714 PM_WAB = (int) WhiteCardinal,
\r
1715 PM_WD = (int) WhiteDragon,
\r
1716 PM_WL = (int) WhiteLance,
\r
1717 PM_WS = (int) WhiteCobra,
\r
1718 PM_WV = (int) WhiteFalcon,
\r
1719 PM_WSG = (int) WhiteSilver,
\r
1720 PM_WG = (int) WhiteGrasshopper,
\r
1721 PM_WK = (int) WhiteKing,
\r
1722 PM_BP = (int) BlackPawn,
\r
1723 PM_BN = (int) BlackKnight,
\r
1724 PM_BB = (int) BlackBishop,
\r
1725 PM_BR = (int) BlackRook,
\r
1726 PM_BQ = (int) BlackQueen,
\r
1727 PM_BF = (int) BlackFerz,
\r
1728 PM_BW = (int) BlackWazir,
\r
1729 PM_BE = (int) BlackAlfil,
\r
1730 PM_BM = (int) BlackMan,
\r
1731 PM_BO = (int) BlackCannon,
\r
1732 PM_BU = (int) BlackUnicorn,
\r
1733 PM_BH = (int) BlackNightrider,
\r
1734 PM_BA = (int) BlackAngel,
\r
1735 PM_BC = (int) BlackMarshall,
\r
1736 PM_BG = (int) BlackGrasshopper,
\r
1737 PM_BAB = (int) BlackCardinal,
\r
1738 PM_BD = (int) BlackDragon,
\r
1739 PM_BL = (int) BlackLance,
\r
1740 PM_BS = (int) BlackCobra,
\r
1741 PM_BV = (int) BlackFalcon,
\r
1742 PM_BSG = (int) BlackSilver,
\r
1743 PM_BK = (int) BlackKing
\r
1746 static HFONT hPieceFont = NULL;
\r
1747 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1748 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1749 static int fontBitmapSquareSize = 0;
\r
1750 static char pieceToFontChar[(int) EmptySquare] =
\r
1751 { 'p', 'n', 'b', 'r', 'q',
\r
1752 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1753 'k', 'o', 'm', 'v', 't', 'w',
\r
1754 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1757 extern BOOL SetCharTable( char *table, const char * map );
\r
1758 /* [HGM] moved to backend.c */
\r
1760 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1763 BYTE r1 = GetRValue( color );
\r
1764 BYTE g1 = GetGValue( color );
\r
1765 BYTE b1 = GetBValue( color );
\r
1771 /* Create a uniform background first */
\r
1772 hbrush = CreateSolidBrush( color );
\r
1773 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1774 FillRect( hdc, &rc, hbrush );
\r
1775 DeleteObject( hbrush );
\r
1778 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1779 int steps = squareSize / 2;
\r
1782 for( i=0; i<steps; i++ ) {
\r
1783 BYTE r = r1 - (r1-r2) * i / steps;
\r
1784 BYTE g = g1 - (g1-g2) * i / steps;
\r
1785 BYTE b = b1 - (b1-b2) * i / steps;
\r
1787 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1788 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1789 FillRect( hdc, &rc, hbrush );
\r
1790 DeleteObject(hbrush);
\r
1793 else if( mode == 2 ) {
\r
1794 /* Diagonal gradient, good more or less for every piece */
\r
1795 POINT triangle[3];
\r
1796 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1797 HBRUSH hbrush_old;
\r
1798 int steps = squareSize;
\r
1801 triangle[0].x = squareSize - steps;
\r
1802 triangle[0].y = squareSize;
\r
1803 triangle[1].x = squareSize;
\r
1804 triangle[1].y = squareSize;
\r
1805 triangle[2].x = squareSize;
\r
1806 triangle[2].y = squareSize - steps;
\r
1808 for( i=0; i<steps; i++ ) {
\r
1809 BYTE r = r1 - (r1-r2) * i / steps;
\r
1810 BYTE g = g1 - (g1-g2) * i / steps;
\r
1811 BYTE b = b1 - (b1-b2) * i / steps;
\r
1813 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1814 hbrush_old = SelectObject( hdc, hbrush );
\r
1815 Polygon( hdc, triangle, 3 );
\r
1816 SelectObject( hdc, hbrush_old );
\r
1817 DeleteObject(hbrush);
\r
1822 SelectObject( hdc, hpen );
\r
1827 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1828 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1829 piece: follow the steps as explained below.
\r
1831 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1835 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1841 int backColor = whitePieceColor;
\r
1842 int foreColor = blackPieceColor;
\r
1844 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1845 backColor = appData.fontBackColorWhite;
\r
1846 foreColor = appData.fontForeColorWhite;
\r
1848 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1849 backColor = appData.fontBackColorBlack;
\r
1850 foreColor = appData.fontForeColorBlack;
\r
1854 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1856 hbm_old = SelectObject( hdc, hbm );
\r
1860 rc.right = squareSize;
\r
1861 rc.bottom = squareSize;
\r
1863 /* Step 1: background is now black */
\r
1864 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1866 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1868 pt.x = (squareSize - sz.cx) / 2;
\r
1869 pt.y = (squareSize - sz.cy) / 2;
\r
1871 SetBkMode( hdc, TRANSPARENT );
\r
1872 SetTextColor( hdc, chroma );
\r
1873 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1874 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1876 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1877 /* Step 3: the area outside the piece is filled with white */
\r
1878 // FloodFill( hdc, 0, 0, chroma );
\r
1879 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1880 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1881 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1882 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1883 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1885 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1886 but if the start point is not inside the piece we're lost!
\r
1887 There should be a better way to do this... if we could create a region or path
\r
1888 from the fill operation we would be fine for example.
\r
1890 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1891 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1893 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1894 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1895 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1897 SelectObject( dc2, bm2 );
\r
1898 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1899 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1900 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1901 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1902 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1905 DeleteObject( bm2 );
\r
1908 SetTextColor( hdc, 0 );
\r
1910 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1911 draw the piece again in black for safety.
\r
1913 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1915 SelectObject( hdc, hbm_old );
\r
1917 if( hPieceMask[index] != NULL ) {
\r
1918 DeleteObject( hPieceMask[index] );
\r
1921 hPieceMask[index] = hbm;
\r
1924 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1926 SelectObject( hdc, hbm );
\r
1929 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1930 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1931 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1933 SelectObject( dc1, hPieceMask[index] );
\r
1934 SelectObject( dc2, bm2 );
\r
1935 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1936 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1939 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1940 the piece background and deletes (makes transparent) the rest.
\r
1941 Thanks to that mask, we are free to paint the background with the greates
\r
1942 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1943 We use this, to make gradients and give the pieces a "roundish" look.
\r
1945 SetPieceBackground( hdc, backColor, 2 );
\r
1946 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1950 DeleteObject( bm2 );
\r
1953 SetTextColor( hdc, foreColor );
\r
1954 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1956 SelectObject( hdc, hbm_old );
\r
1958 if( hPieceFace[index] != NULL ) {
\r
1959 DeleteObject( hPieceFace[index] );
\r
1962 hPieceFace[index] = hbm;
\r
1965 static int TranslatePieceToFontPiece( int piece )
\r
1995 case BlackMarshall:
\r
1999 case BlackNightrider:
\r
2005 case BlackUnicorn:
\r
2009 case BlackGrasshopper:
\r
2021 case BlackCardinal:
\r
2028 case WhiteMarshall:
\r
2032 case WhiteNightrider:
\r
2038 case WhiteUnicorn:
\r
2042 case WhiteGrasshopper:
\r
2054 case WhiteCardinal:
\r
2063 void CreatePiecesFromFont()
\r
2066 HDC hdc_window = NULL;
\r
2072 if( fontBitmapSquareSize < 0 ) {
\r
2073 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2077 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2078 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2079 fontBitmapSquareSize = -1;
\r
2083 if( fontBitmapSquareSize != squareSize ) {
\r
2084 hdc_window = GetDC( hwndMain );
\r
2085 hdc = CreateCompatibleDC( hdc_window );
\r
2087 if( hPieceFont != NULL ) {
\r
2088 DeleteObject( hPieceFont );
\r
2091 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2092 hPieceMask[i] = NULL;
\r
2093 hPieceFace[i] = NULL;
\r
2099 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2100 fontHeight = appData.fontPieceSize;
\r
2103 fontHeight = (fontHeight * squareSize) / 100;
\r
2105 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2107 lf.lfEscapement = 0;
\r
2108 lf.lfOrientation = 0;
\r
2109 lf.lfWeight = FW_NORMAL;
\r
2111 lf.lfUnderline = 0;
\r
2112 lf.lfStrikeOut = 0;
\r
2113 lf.lfCharSet = DEFAULT_CHARSET;
\r
2114 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2115 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2116 lf.lfQuality = PROOF_QUALITY;
\r
2117 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2118 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2119 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2121 hPieceFont = CreateFontIndirect( &lf );
\r
2123 if( hPieceFont == NULL ) {
\r
2124 fontBitmapSquareSize = -2;
\r
2127 /* Setup font-to-piece character table */
\r
2128 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2129 /* No (or wrong) global settings, try to detect the font */
\r
2130 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2132 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2134 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2135 /* DiagramTT* family */
\r
2136 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2138 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2139 /* Fairy symbols */
\r
2140 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2142 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2143 /* Good Companion (Some characters get warped as literal :-( */
\r
2144 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2145 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2146 SetCharTable(pieceToFontChar, s);
\r
2149 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2150 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2154 /* Create bitmaps */
\r
2155 hfont_old = SelectObject( hdc, hPieceFont );
\r
2156 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2157 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2158 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2160 SelectObject( hdc, hfont_old );
\r
2162 fontBitmapSquareSize = squareSize;
\r
2166 if( hdc != NULL ) {
\r
2170 if( hdc_window != NULL ) {
\r
2171 ReleaseDC( hwndMain, hdc_window );
\r
2176 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2178 char name[128], buf[MSG_SIZ];
\r
2180 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2181 if(appData.pieceDirectory[0]) {
\r
2183 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2184 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2185 if(res) return res;
\r
2187 if (gameInfo.event &&
\r
2188 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2189 strcmp(name, "k80s") == 0) {
\r
2190 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2192 return LoadBitmap(hinst, name);
\r
2196 /* Insert a color into the program's logical palette
\r
2197 structure. This code assumes the given color is
\r
2198 the result of the RGB or PALETTERGB macro, and it
\r
2199 knows how those macros work (which is documented).
\r
2202 InsertInPalette(COLORREF color)
\r
2204 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2206 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2207 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2208 pLogPal->palNumEntries--;
\r
2212 pe->peFlags = (char) 0;
\r
2213 pe->peRed = (char) (0xFF & color);
\r
2214 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2215 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2221 InitDrawingColors()
\r
2224 if (pLogPal == NULL) {
\r
2225 /* Allocate enough memory for a logical palette with
\r
2226 * PALETTESIZE entries and set the size and version fields
\r
2227 * of the logical palette structure.
\r
2229 pLogPal = (NPLOGPALETTE)
\r
2230 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2231 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2232 pLogPal->palVersion = 0x300;
\r
2234 pLogPal->palNumEntries = 0;
\r
2236 InsertInPalette(lightSquareColor);
\r
2237 InsertInPalette(darkSquareColor);
\r
2238 InsertInPalette(whitePieceColor);
\r
2239 InsertInPalette(blackPieceColor);
\r
2240 InsertInPalette(highlightSquareColor);
\r
2241 InsertInPalette(premoveHighlightColor);
\r
2243 /* create a logical color palette according the information
\r
2244 * in the LOGPALETTE structure.
\r
2246 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2248 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2249 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2250 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2251 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2252 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2253 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2254 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2255 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2257 /* [AS] Force rendering of the font-based pieces */
\r
2258 if( fontBitmapSquareSize > 0 ) {
\r
2259 fontBitmapSquareSize = 0;
\r
2265 BoardWidth(int boardSize, int n)
\r
2266 { /* [HGM] argument n added to allow different width and height */
\r
2267 int lineGap = sizeInfo[boardSize].lineGap;
\r
2269 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2270 lineGap = appData.overrideLineGap;
\r
2273 return (n + 1) * lineGap +
\r
2274 n * sizeInfo[boardSize].squareSize;
\r
2277 /* Respond to board resize by dragging edge */
\r
2279 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2281 BoardSize newSize = NUM_SIZES - 1;
\r
2282 static int recurse = 0;
\r
2283 if (IsIconic(hwndMain)) return;
\r
2284 if (recurse > 0) return;
\r
2286 while (newSize > 0) {
\r
2287 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2288 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2289 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2292 boardSize = newSize;
\r
2293 InitDrawingSizes(boardSize, flags);
\r
2298 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2301 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2303 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2304 ChessSquare piece;
\r
2305 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2307 SIZE clockSize, messageSize;
\r
2309 char buf[MSG_SIZ];
\r
2311 HMENU hmenu = GetMenu(hwndMain);
\r
2312 RECT crect, wrect, oldRect;
\r
2314 LOGBRUSH logbrush;
\r
2315 VariantClass v = gameInfo.variant;
\r
2317 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2318 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2320 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2321 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2322 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2323 oldBoardSize = boardSize;
\r
2325 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2326 { // correct board size to one where built-in pieces exist
\r
2327 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2328 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2330 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2331 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2332 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2333 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2334 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2335 boardSize = SizeMiddling;
\r
2338 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2340 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2341 oldRect.top = wpMain.y;
\r
2342 oldRect.right = wpMain.x + wpMain.width;
\r
2343 oldRect.bottom = wpMain.y + wpMain.height;
\r
2345 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2346 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2347 squareSize = sizeInfo[boardSize].squareSize;
\r
2348 lineGap = sizeInfo[boardSize].lineGap;
\r
2349 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2350 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2352 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2353 lineGap = appData.overrideLineGap;
\r
2356 if (tinyLayout != oldTinyLayout) {
\r
2357 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2359 style &= ~WS_SYSMENU;
\r
2360 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2361 "&Minimize\tCtrl+F4");
\r
2363 style |= WS_SYSMENU;
\r
2364 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2366 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2368 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2369 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2370 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2372 DrawMenuBar(hwndMain);
\r
2375 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2376 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2378 /* Get text area sizes */
\r
2379 hdc = GetDC(hwndMain);
\r
2380 if (appData.clockMode) {
\r
2381 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2383 snprintf(buf, MSG_SIZ, _("White"));
\r
2385 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2386 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2387 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2388 str = _("We only care about the height here");
\r
2389 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2390 SelectObject(hdc, oldFont);
\r
2391 ReleaseDC(hwndMain, hdc);
\r
2393 /* Compute where everything goes */
\r
2394 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2395 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2396 logoHeight = 2*clockSize.cy;
\r
2397 leftLogoRect.left = OUTER_MARGIN;
\r
2398 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2399 leftLogoRect.top = OUTER_MARGIN;
\r
2400 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2402 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2403 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2404 rightLogoRect.top = OUTER_MARGIN;
\r
2405 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2408 whiteRect.left = leftLogoRect.right;
\r
2409 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2410 whiteRect.top = OUTER_MARGIN;
\r
2411 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2413 blackRect.right = rightLogoRect.left;
\r
2414 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2415 blackRect.top = whiteRect.top;
\r
2416 blackRect.bottom = whiteRect.bottom;
\r
2418 whiteRect.left = OUTER_MARGIN;
\r
2419 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2420 whiteRect.top = OUTER_MARGIN;
\r
2421 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2423 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2424 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2425 blackRect.top = whiteRect.top;
\r
2426 blackRect.bottom = whiteRect.bottom;
\r
2428 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2431 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2432 if (appData.showButtonBar) {
\r
2433 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2434 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2436 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2438 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2439 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2441 boardRect.left = OUTER_MARGIN;
\r
2442 boardRect.right = boardRect.left + boardWidth;
\r
2443 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2444 boardRect.bottom = boardRect.top + boardHeight;
\r
2446 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2447 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2448 oldTinyLayout = tinyLayout;
\r
2449 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2450 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2451 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2452 winW *= 1 + twoBoards;
\r
2453 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2454 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2455 wpMain.height = winH; // without disturbing window attachments
\r
2456 GetWindowRect(hwndMain, &wrect);
\r
2457 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2458 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2460 // [HGM] placement: let attached windows follow size change.
\r
2461 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2462 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2463 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2464 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2465 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2467 /* compensate if menu bar wrapped */
\r
2468 GetClientRect(hwndMain, &crect);
\r
2469 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2470 wpMain.height += offby;
\r
2472 case WMSZ_TOPLEFT:
\r
2473 SetWindowPos(hwndMain, NULL,
\r
2474 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2475 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2478 case WMSZ_TOPRIGHT:
\r
2480 SetWindowPos(hwndMain, NULL,
\r
2481 wrect.left, wrect.bottom - wpMain.height,
\r
2482 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2485 case WMSZ_BOTTOMLEFT:
\r
2487 SetWindowPos(hwndMain, NULL,
\r
2488 wrect.right - wpMain.width, wrect.top,
\r
2489 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2492 case WMSZ_BOTTOMRIGHT:
\r
2496 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2497 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2502 for (i = 0; i < N_BUTTONS; i++) {
\r
2503 if (buttonDesc[i].hwnd != NULL) {
\r
2504 DestroyWindow(buttonDesc[i].hwnd);
\r
2505 buttonDesc[i].hwnd = NULL;
\r
2507 if (appData.showButtonBar) {
\r
2508 buttonDesc[i].hwnd =
\r
2509 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2510 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2511 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2512 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2513 (HMENU) buttonDesc[i].id,
\r
2514 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2516 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2517 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2518 MAKELPARAM(FALSE, 0));
\r
2520 if (buttonDesc[i].id == IDM_Pause)
\r
2521 hwndPause = buttonDesc[i].hwnd;
\r
2522 buttonDesc[i].wndproc = (WNDPROC)
\r
2523 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2526 if (gridPen != NULL) DeleteObject(gridPen);
\r
2527 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2528 if (premovePen != NULL) DeleteObject(premovePen);
\r
2529 if (lineGap != 0) {
\r
2530 logbrush.lbStyle = BS_SOLID;
\r
2531 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2533 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2534 lineGap, &logbrush, 0, NULL);
\r
2535 logbrush.lbColor = highlightSquareColor;
\r
2537 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2538 lineGap, &logbrush, 0, NULL);
\r
2540 logbrush.lbColor = premoveHighlightColor;
\r
2542 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2543 lineGap, &logbrush, 0, NULL);
\r
2545 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2546 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2547 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2548 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2549 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2550 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2551 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2552 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2554 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2555 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2556 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2557 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2558 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2559 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2560 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2561 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2565 /* [HGM] Licensing requirement */
\r
2567 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2570 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2572 GothicPopUp( "", VariantNormal);
\r
2575 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2577 /* Load piece bitmaps for this board size */
\r
2578 for (i=0; i<=2; i++) {
\r
2579 for (piece = WhitePawn;
\r
2580 (int) piece < (int) BlackPawn;
\r
2581 piece = (ChessSquare) ((int) piece + 1)) {
\r
2582 if (pieceBitmap[i][piece] != NULL)
\r
2583 DeleteObject(pieceBitmap[i][piece]);
\r
2587 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2588 // Orthodox Chess pieces
\r
2589 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2590 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2591 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2592 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2593 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2594 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2595 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2596 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2597 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2598 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2599 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2600 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2601 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2602 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2603 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2604 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2605 // in Shogi, Hijack the unused Queen for Lance
\r
2606 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2607 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2608 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2610 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2611 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2612 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2615 if(squareSize <= 72 && squareSize >= 33) {
\r
2616 /* A & C are available in most sizes now */
\r
2617 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2618 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2621 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2622 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2623 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2624 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2625 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2626 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", 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 } else { // Smirf-like
\r
2631 if(gameInfo.variant == VariantSChess) {
\r
2632 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2633 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2634 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2636 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2637 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2638 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2641 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2642 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2645 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2646 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2647 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2648 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2649 } else { // WinBoard standard
\r
2650 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2657 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2658 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2659 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2660 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2661 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2662 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2663 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2664 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2665 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2666 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2667 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2668 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2669 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2670 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2671 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2672 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2673 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2674 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2675 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2676 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2677 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2678 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2679 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2680 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2681 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2682 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2683 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2684 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2685 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2686 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2687 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2688 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2689 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2690 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2692 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2693 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2694 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2695 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2696 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2697 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2698 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2699 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2700 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2701 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2702 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2703 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2704 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2706 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2707 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2708 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2709 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2710 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2711 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2712 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2713 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2714 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2715 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2716 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2717 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2720 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2721 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2722 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2723 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2724 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2725 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2726 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2727 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2728 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2729 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2730 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2731 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2732 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2733 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2734 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2738 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2739 /* special Shogi support in this size */
\r
2740 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2741 for (piece = WhitePawn;
\r
2742 (int) piece < (int) BlackPawn;
\r
2743 piece = (ChessSquare) ((int) piece + 1)) {
\r
2744 if (pieceBitmap[i][piece] != NULL)
\r
2745 DeleteObject(pieceBitmap[i][piece]);
\r
2748 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2749 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2750 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2751 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2752 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2753 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2754 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2755 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2756 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2757 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2758 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2762 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2763 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2764 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2765 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2766 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2767 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2768 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2769 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2770 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2771 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2772 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2776 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2777 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2778 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2779 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2780 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2781 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2782 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2783 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2784 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2785 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2786 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2795 PieceBitmap(ChessSquare p, int kind)
\r
2797 if ((int) p >= (int) BlackPawn)
\r
2798 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2800 return pieceBitmap[kind][(int) p];
\r
2803 /***************************************************************/
\r
2805 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2806 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2808 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2809 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2813 SquareToPos(int row, int column, int * x, int * y)
\r
2816 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2817 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2819 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2820 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2825 DrawCoordsOnDC(HDC hdc)
\r
2827 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2828 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2829 char str[2] = { NULLCHAR, NULLCHAR };
\r
2830 int oldMode, oldAlign, x, y, start, i;
\r
2834 if (!appData.showCoords)
\r
2837 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2839 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2840 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2841 oldAlign = GetTextAlign(hdc);
\r
2842 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2844 y = boardRect.top + lineGap;
\r
2845 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2848 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2849 x += border - lineGap - 4; y += squareSize - 6;
\r
2851 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2852 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2853 str[0] = files[start + i];
\r
2854 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2855 y += squareSize + lineGap;
\r
2858 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2861 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2862 x += -border + 4; y += border - squareSize + 6;
\r
2864 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2865 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2866 str[0] = ranks[start + i];
\r
2867 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2868 x += squareSize + lineGap;
\r
2871 SelectObject(hdc, oldBrush);
\r
2872 SetBkMode(hdc, oldMode);
\r
2873 SetTextAlign(hdc, oldAlign);
\r
2874 SelectObject(hdc, oldFont);
\r
2878 DrawGridOnDC(HDC hdc)
\r
2882 if (lineGap != 0) {
\r
2883 oldPen = SelectObject(hdc, gridPen);
\r
2884 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2885 SelectObject(hdc, oldPen);
\r
2889 #define HIGHLIGHT_PEN 0
\r
2890 #define PREMOVE_PEN 1
\r
2893 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2896 HPEN oldPen, hPen;
\r
2897 if (lineGap == 0) return;
\r
2899 x1 = boardRect.left +
\r
2900 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2901 y1 = boardRect.top +
\r
2902 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2904 x1 = boardRect.left +
\r
2905 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2906 y1 = boardRect.top +
\r
2907 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2909 hPen = pen ? premovePen : highlightPen;
\r
2910 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2911 MoveToEx(hdc, x1, y1, NULL);
\r
2912 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2913 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2914 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2915 LineTo(hdc, x1, y1);
\r
2916 SelectObject(hdc, oldPen);
\r
2920 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2923 for (i=0; i<2; i++) {
\r
2924 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2925 DrawHighlightOnDC(hdc, TRUE,
\r
2926 h->sq[i].x, h->sq[i].y,
\r
2931 /* Note: sqcolor is used only in monoMode */
\r
2932 /* Note that this code is largely duplicated in woptions.c,
\r
2933 function DrawSampleSquare, so that needs to be updated too */
\r
2935 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2937 HBITMAP oldBitmap;
\r
2941 if (appData.blindfold) return;
\r
2943 /* [AS] Use font-based pieces if needed */
\r
2944 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2945 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2946 CreatePiecesFromFont();
\r
2948 if( fontBitmapSquareSize == squareSize ) {
\r
2949 int index = TranslatePieceToFontPiece(piece);
\r
2951 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2953 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2954 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2958 squareSize, squareSize,
\r
2963 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2965 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2966 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2970 squareSize, squareSize,
\r
2979 if (appData.monoMode) {
\r
2980 SelectObject(tmphdc, PieceBitmap(piece,
\r
2981 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2982 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2983 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2985 HBRUSH xBrush = whitePieceBrush;
\r
2986 tmpSize = squareSize;
\r
2987 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2989 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2990 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2991 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2992 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2993 x += (squareSize - minorSize)>>1;
\r
2994 y += squareSize - minorSize - 2;
\r
2995 tmpSize = minorSize;
\r
2997 if (color || appData.allWhite ) {
\r
2998 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3000 oldBrush = SelectObject(hdc, xBrush);
\r
3001 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3002 if(appData.upsideDown && color==flipView)
\r
3003 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3005 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3006 /* Use black for outline of white pieces */
\r
3007 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3008 if(appData.upsideDown && color==flipView)
\r
3009 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3011 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3012 } else if(appData.pieceDirectory[0]) {
\r
3013 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3014 oldBrush = SelectObject(hdc, xBrush);
\r
3015 if(appData.upsideDown && color==flipView)
\r
3016 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3018 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3019 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3020 if(appData.upsideDown && color==flipView)
\r
3021 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3023 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3025 /* Use square color for details of black pieces */
\r
3026 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3027 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3028 if(appData.upsideDown && !flipView)
\r
3029 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3031 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3033 SelectObject(hdc, oldBrush);
\r
3034 SelectObject(tmphdc, oldBitmap);
\r
3038 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3039 int GetBackTextureMode( int algo )
\r
3041 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3045 case BACK_TEXTURE_MODE_PLAIN:
\r
3046 result = 1; /* Always use identity map */
\r
3048 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3049 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3057 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3058 to handle redraws cleanly (as random numbers would always be different).
\r
3060 VOID RebuildTextureSquareInfo()
\r
3070 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3072 if( liteBackTexture != NULL ) {
\r
3073 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3074 lite_w = bi.bmWidth;
\r
3075 lite_h = bi.bmHeight;
\r
3079 if( darkBackTexture != NULL ) {
\r
3080 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3081 dark_w = bi.bmWidth;
\r
3082 dark_h = bi.bmHeight;
\r
3086 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3087 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3088 if( (col + row) & 1 ) {
\r
3090 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3091 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3092 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3094 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3095 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3096 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3098 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3099 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3104 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3105 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3106 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3108 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3109 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3110 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3112 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3113 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3120 /* [AS] Arrow highlighting support */
\r
3122 static double A_WIDTH = 5; /* Width of arrow body */
\r
3124 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3125 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3127 static double Sqr( double x )
\r
3132 static int Round( double x )
\r
3134 return (int) (x + 0.5);
\r
3137 /* Draw an arrow between two points using current settings */
\r
3138 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3141 double dx, dy, j, k, x, y;
\r
3143 if( d_x == s_x ) {
\r
3144 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3146 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3149 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3150 arrow[1].y = d_y - h;
\r
3152 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3153 arrow[2].y = d_y - h;
\r
3158 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3159 arrow[5].y = d_y - h;
\r
3161 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3162 arrow[4].y = d_y - h;
\r
3164 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3167 else if( d_y == s_y ) {
\r
3168 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3171 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3173 arrow[1].x = d_x - w;
\r
3174 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3176 arrow[2].x = d_x - w;
\r
3177 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3182 arrow[5].x = d_x - w;
\r
3183 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3185 arrow[4].x = d_x - w;
\r
3186 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3189 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r