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, IDOK, IDCANCEL },
\r
264 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
265 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
266 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
267 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
268 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
269 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
270 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
271 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
272 { ABOUTBOX2, IDC_ChessBoard },
\r
273 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
274 OPT_GameListClose, IDC_GameListDoFilter },
\r
275 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
276 { DLG_Error, IDOK },
\r
277 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
278 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
279 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
280 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
281 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
282 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
283 { DLG_IndexNumber, IDC_Index },
\r
284 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
285 { DLG_TypeInName, IDOK, IDCANCEL },
\r
286 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
287 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
288 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
289 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
290 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
291 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
292 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
293 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
294 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
295 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
296 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
297 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
298 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
299 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
300 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
301 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
302 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
303 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
304 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
305 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
306 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
307 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
308 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
309 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
310 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
311 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
312 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
313 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
314 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
315 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
316 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
317 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
318 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
319 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
320 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
321 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
322 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
323 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
324 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
325 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
326 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
327 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
328 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
329 { DLG_MoveHistory },
\r
330 { DLG_EvalGraph },
\r
331 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
332 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
333 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
334 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
335 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
336 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
337 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
338 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
339 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
343 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
344 static int lastChecked;
\r
345 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
346 extern int tinyLayout;
\r
347 extern char * menuBarText[][10];
\r
350 LoadLanguageFile(char *name)
\r
351 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
353 int i=0, j=0, n=0, k;
\r
356 if(!name || name[0] == NULLCHAR) return;
\r
357 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
358 appData.language = oldLanguage;
\r
359 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
360 if((f = fopen(buf, "r")) == NULL) return;
\r
361 while((k = fgetc(f)) != EOF) {
\r
362 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
363 languageBuf[i] = k;
\r
365 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
367 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
368 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
369 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
370 english[j] = languageBuf + n + 1; *p = 0;
\r
371 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
372 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
377 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
379 case 'n': k = '\n'; break;
\r
380 case 'r': k = '\r'; break;
\r
381 case 't': k = '\t'; break;
\r
383 languageBuf[--i] = k;
\r
388 barbaric = (j != 0);
\r
389 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
394 { // return the translation of the given string
\r
395 // efficiency can be improved a lot...
\r
397 static char buf[MSG_SIZ];
\r
398 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
399 if(!barbaric) return s;
\r
400 if(!s) return ""; // sanity
\r
401 while(english[i]) {
\r
402 if(!strcmp(s, english[i])) return foreign[i];
\r
403 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
404 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
413 Translate(HWND hDlg, int dialogID)
\r
414 { // translate all text items in the given dialog
\r
416 char buf[MSG_SIZ], *s;
\r
417 if(!barbaric) return;
\r
418 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
419 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
420 GetWindowText( hDlg, buf, MSG_SIZ );
\r
422 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
423 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
424 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
425 if(strlen(buf) == 0) continue;
\r
427 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
432 TranslateOneMenu(int i, HMENU subMenu)
\r
435 static MENUITEMINFO info;
\r
437 info.cbSize = sizeof(MENUITEMINFO);
\r
438 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
439 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
441 info.dwTypeData = buf;
\r
442 info.cch = sizeof(buf);
\r
443 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
445 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
446 else menuText[i][j] = strdup(buf); // remember original on first change
\r
448 if(buf[0] == NULLCHAR) continue;
\r
449 info.dwTypeData = T_(buf);
\r
450 info.cch = strlen(buf)+1;
\r
451 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
457 TranslateMenus(int addLanguage)
\r
460 WIN32_FIND_DATA fileData;
\r
462 #define IDM_English 1970
\r
464 HMENU mainMenu = GetMenu(hwndMain);
\r
465 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
466 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
467 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
468 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
469 TranslateOneMenu(i, subMenu);
\r
471 DrawMenuBar(hwndMain);
\r
474 if(!addLanguage) return;
\r
475 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
476 HMENU mainMenu = GetMenu(hwndMain);
\r
477 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
478 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
479 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
480 i = 0; lastChecked = IDM_English;
\r
482 char *p, *q = fileData.cFileName;
\r
483 int checkFlag = MF_UNCHECKED;
\r
484 languageFile[i] = strdup(q);
\r
485 if(barbaric && !strcmp(oldLanguage, q)) {
\r
486 checkFlag = MF_CHECKED;
\r
487 lastChecked = IDM_English + i + 1;
\r
488 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
490 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
491 p = strstr(fileData.cFileName, ".lng");
\r
493 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
494 } while(FindNextFile(hFind, &fileData));
\r
501 #define IDM_RecentEngines 3000
\r
504 RecentEngineMenu (char *s)
\r
506 if(appData.icsActive) return;
\r
507 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
508 HMENU mainMenu = GetMenu(hwndMain);
\r
509 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
510 int i=IDM_RecentEngines;
\r
511 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
512 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
514 char *p = strchr(s, '\n');
\r
515 if(p == NULL) return; // malformed!
\r
517 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
531 int cliWidth, cliHeight;
\r
534 SizeInfo sizeInfo[] =
\r
536 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
537 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
538 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
539 { "petite", 33, 1, 1, 1, 0, 0 },
\r
540 { "slim", 37, 2, 1, 0, 0, 0 },
\r
541 { "small", 40, 2, 1, 0, 0, 0 },
\r
542 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
543 { "middling", 49, 2, 0, 0, 0, 0 },
\r
544 { "average", 54, 2, 0, 0, 0, 0 },
\r
545 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
546 { "medium", 64, 3, 0, 0, 0, 0 },
\r
547 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
548 { "large", 80, 3, 0, 0, 0, 0 },
\r
549 { "big", 87, 3, 0, 0, 0, 0 },
\r
550 { "huge", 95, 3, 0, 0, 0, 0 },
\r
551 { "giant", 108, 3, 0, 0, 0, 0 },
\r
552 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
553 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
554 { NULL, 0, 0, 0, 0, 0, 0 }
\r
557 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
558 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
575 { 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
576 { 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
577 { 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
580 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
589 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
590 #define N_BUTTONS 5
\r
592 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
594 {"<<", IDM_ToStart, NULL, NULL},
\r
595 {"<", IDM_Backward, NULL, NULL},
\r
596 {"P", IDM_Pause, NULL, NULL},
\r
597 {">", IDM_Forward, NULL, NULL},
\r
598 {">>", IDM_ToEnd, NULL, NULL},
\r
601 int tinyLayout = 0, smallLayout = 0;
\r
602 #define MENU_BAR_ITEMS 9
\r
603 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
604 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
605 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
609 MySound sounds[(int)NSoundClasses];
\r
610 MyTextAttribs textAttribs[(int)NColorClasses];
\r
612 MyColorizeAttribs colorizeAttribs[] = {
\r
613 { (COLORREF)0, 0, N_("Shout Text") },
\r
614 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
615 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
616 { (COLORREF)0, 0, N_("Channel Text") },
\r
617 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
618 { (COLORREF)0, 0, N_("Tell Text") },
\r
619 { (COLORREF)0, 0, N_("Challenge Text") },
\r
620 { (COLORREF)0, 0, N_("Request Text") },
\r
621 { (COLORREF)0, 0, N_("Seek Text") },
\r
622 { (COLORREF)0, 0, N_("Normal Text") },
\r
623 { (COLORREF)0, 0, N_("None") }
\r
628 static char *commentTitle;
\r
629 static char *commentText;
\r
630 static int commentIndex;
\r
631 static Boolean editComment = FALSE;
\r
634 char errorTitle[MSG_SIZ];
\r
635 char errorMessage[2*MSG_SIZ];
\r
636 HWND errorDialog = NULL;
\r
637 BOOLEAN moveErrorMessageUp = FALSE;
\r
638 BOOLEAN consoleEcho = TRUE;
\r
639 CHARFORMAT consoleCF;
\r
640 COLORREF consoleBackgroundColor;
\r
642 char *programVersion;
\r
648 typedef int CPKind;
\r
657 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
660 #define INPUT_SOURCE_BUF_SIZE 4096
\r
662 typedef struct _InputSource {
\r
669 char buf[INPUT_SOURCE_BUF_SIZE];
\r
673 InputCallback func;
\r
674 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
678 InputSource *consoleInputSource;
\r
683 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
684 VOID ConsoleCreate();
\r
686 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
687 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
688 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
689 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
691 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
692 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
693 void ParseIcsTextMenu(char *icsTextMenuString);
\r
694 VOID PopUpNameDialog(char firstchar);
\r
695 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
699 int GameListOptions();
\r
701 int dummy; // [HGM] for obsolete args
\r
703 HWND hwndMain = NULL; /* root window*/
\r
704 HWND hwndConsole = NULL;
\r
705 HWND commentDialog = NULL;
\r
706 HWND moveHistoryDialog = NULL;
\r
707 HWND evalGraphDialog = NULL;
\r
708 HWND engineOutputDialog = NULL;
\r
709 HWND gameListDialog = NULL;
\r
710 HWND editTagsDialog = NULL;
\r
712 int commentUp = FALSE;
\r
714 WindowPlacement wpMain;
\r
715 WindowPlacement wpConsole;
\r
716 WindowPlacement wpComment;
\r
717 WindowPlacement wpMoveHistory;
\r
718 WindowPlacement wpEvalGraph;
\r
719 WindowPlacement wpEngineOutput;
\r
720 WindowPlacement wpGameList;
\r
721 WindowPlacement wpTags;
\r
723 VOID EngineOptionsPopup(); // [HGM] settings
\r
725 VOID GothicPopUp(char *title, VariantClass variant);
\r
727 * Setting "frozen" should disable all user input other than deleting
\r
728 * the window. We do this while engines are initializing themselves.
\r
730 static int frozen = 0;
\r
731 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
737 if (frozen) return;
\r
739 hmenu = GetMenu(hwndMain);
\r
740 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
741 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
743 DrawMenuBar(hwndMain);
\r
746 /* Undo a FreezeUI */
\r
752 if (!frozen) return;
\r
754 hmenu = GetMenu(hwndMain);
\r
755 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
756 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
758 DrawMenuBar(hwndMain);
\r
761 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
763 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
769 #define JAWS_ALT_INTERCEPT
\r
770 #define JAWS_KBUP_NAVIGATION
\r
771 #define JAWS_KBDOWN_NAVIGATION
\r
772 #define JAWS_MENU_ITEMS
\r
773 #define JAWS_SILENCE
\r
774 #define JAWS_REPLAY
\r
776 #define JAWS_COPYRIGHT
\r
777 #define JAWS_DELETE(X) X
\r
778 #define SAYMACHINEMOVE()
\r
782 /*---------------------------------------------------------------------------*\
\r
786 \*---------------------------------------------------------------------------*/
\r
789 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
790 LPSTR lpCmdLine, int nCmdShow)
\r
793 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
794 // INITCOMMONCONTROLSEX ex;
\r
798 LoadLibrary("RICHED32.DLL");
\r
799 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
801 if (!InitApplication(hInstance)) {
\r
804 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
811 // InitCommonControlsEx(&ex);
\r
812 InitCommonControls();
\r
814 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
815 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
816 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
818 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
820 while (GetMessage(&msg, /* message structure */
\r
821 NULL, /* handle of window receiving the message */
\r
822 0, /* lowest message to examine */
\r
823 0)) /* highest message to examine */
\r
826 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
827 // [HGM] navigate: switch between all windows with tab
\r
828 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
829 int i, currentElement = 0;
\r
831 // first determine what element of the chain we come from (if any)
\r
832 if(appData.icsActive) {
\r
833 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
834 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
836 if(engineOutputDialog && EngineOutputIsUp()) {
\r
837 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
838 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
840 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
841 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
843 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
844 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
845 if(msg.hwnd == e1) currentElement = 2; else
\r
846 if(msg.hwnd == e2) currentElement = 3; else
\r
847 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
848 if(msg.hwnd == mh) currentElement = 4; else
\r
849 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
850 if(msg.hwnd == hText) currentElement = 5; else
\r
851 if(msg.hwnd == hInput) currentElement = 6; else
\r
852 for (i = 0; i < N_BUTTONS; i++) {
\r
853 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
856 // determine where to go to
\r
857 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
859 currentElement = (currentElement + direction) % 7;
\r
860 switch(currentElement) {
\r
862 h = hwndMain; break; // passing this case always makes the loop exit
\r
864 h = buttonDesc[0].hwnd; break; // could be NULL
\r
866 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
869 if(!EngineOutputIsUp()) continue;
\r
872 if(!MoveHistoryIsUp()) continue;
\r
874 // case 6: // input to eval graph does not seem to get here!
\r
875 // if(!EvalGraphIsUp()) continue;
\r
876 // h = evalGraphDialog; break;
\r
878 if(!appData.icsActive) continue;
\r
882 if(!appData.icsActive) continue;
\r
888 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
889 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
892 continue; // this message now has been processed
\r
896 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
897 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
898 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
899 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
900 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
901 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
902 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
903 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
904 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
905 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
906 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
907 for(i=0; i<MAX_CHAT; i++)
\r
908 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
911 if(done) continue; // [HGM] chat: end patch
\r
912 TranslateMessage(&msg); /* Translates virtual key codes */
\r
913 DispatchMessage(&msg); /* Dispatches message to window */
\r
918 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
921 /*---------------------------------------------------------------------------*\
\r
923 * Initialization functions
\r
925 \*---------------------------------------------------------------------------*/
\r
929 { // update user logo if necessary
\r
930 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
932 if(appData.autoLogo) {
\r
933 curName = UserName();
\r
934 if(strcmp(curName, oldUserName)) {
\r
935 GetCurrentDirectory(MSG_SIZ, dir);
\r
936 SetCurrentDirectory(installDir);
\r
937 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
938 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
939 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
940 if(userLogo == NULL)
\r
941 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
942 SetCurrentDirectory(dir); /* return to prev directory */
\r
948 InitApplication(HINSTANCE hInstance)
\r
952 /* Fill in window class structure with parameters that describe the */
\r
955 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
956 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
957 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
958 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
959 wc.hInstance = hInstance; /* Owner of this class */
\r
960 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
961 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
962 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
963 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
964 wc.lpszClassName = szAppName; /* Name to register as */
\r
966 /* Register the window class and return success/failure code. */
\r
967 if (!RegisterClass(&wc)) return FALSE;
\r
969 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
970 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
972 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
973 wc.hInstance = hInstance;
\r
974 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
975 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
976 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
977 wc.lpszMenuName = NULL;
\r
978 wc.lpszClassName = szConsoleName;
\r
980 if (!RegisterClass(&wc)) return FALSE;
\r
985 /* Set by InitInstance, used by EnsureOnScreen */
\r
986 int screenHeight, screenWidth;
\r
987 RECT screenGeometry;
\r
990 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
992 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
993 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
994 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
995 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
996 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
997 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1001 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1003 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1004 GetCurrentDirectory(MSG_SIZ, dir);
\r
1005 SetCurrentDirectory(installDir);
\r
1006 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1007 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1009 if (cps->programLogo == NULL && appData.debugMode) {
\r
1010 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1012 } else if(appData.autoLogo) {
\r
1013 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1014 char *opponent = "";
\r
1015 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1016 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1017 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1018 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1019 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1020 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1023 if(appData.directory[n] && appData.directory[n][0]) {
\r
1024 SetCurrentDirectory(appData.directory[n]);
\r
1025 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1028 SetCurrentDirectory(dir); /* return to prev directory */
\r
1034 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1035 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1037 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1038 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1039 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1040 liteBackTextureMode = appData.liteBackTextureMode;
\r
1042 if (liteBackTexture == NULL && appData.debugMode) {
\r
1043 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1047 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1048 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1049 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1050 darkBackTextureMode = appData.darkBackTextureMode;
\r
1052 if (darkBackTexture == NULL && appData.debugMode) {
\r
1053 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1058 #ifndef SM_CXVIRTUALSCREEN
\r
1059 #define SM_CXVIRTUALSCREEN 78
\r
1061 #ifndef SM_CYVIRTUALSCREEN
\r
1062 #define SM_CYVIRTUALSCREEN 79
\r
1064 #ifndef SM_XVIRTUALSCREEN
\r
1065 #define SM_XVIRTUALSCREEN 76
\r
1067 #ifndef SM_YVIRTUALSCREEN
\r
1068 #define SM_YVIRTUALSCREEN 77
\r
1074 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1075 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1076 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1077 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1078 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1079 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1080 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1081 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1085 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1087 HWND hwnd; /* Main window handle. */
\r
1089 WINDOWPLACEMENT wp;
\r
1092 hInst = hInstance; /* Store instance handle in our global variable */
\r
1093 programName = szAppName;
\r
1095 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1096 *filepart = NULLCHAR;
\r
1097 SetCurrentDirectory(installDir);
\r
1099 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1101 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1103 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1104 /* xboard, and older WinBoards, controlled the move sound with the
\r
1105 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1106 always turn the option on (so that the backend will call us),
\r
1107 then let the user turn the sound off by setting it to silence if
\r
1108 desired. To accommodate old winboard.ini files saved by old
\r
1109 versions of WinBoard, we also turn off the sound if the option
\r
1110 was initially set to false. [HGM] taken out of InitAppData */
\r
1111 if (!appData.ringBellAfterMoves) {
\r
1112 sounds[(int)SoundMove].name = strdup("");
\r
1113 appData.ringBellAfterMoves = TRUE;
\r
1115 if (appData.debugMode) {
\r
1116 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1117 setbuf(debugFP, NULL);
\r
1120 LoadLanguageFile(appData.language);
\r
1124 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1125 // InitEngineUCI( installDir, &second );
\r
1127 /* Create a main window for this application instance. */
\r
1128 hwnd = CreateWindow(szAppName, szTitle,
\r
1129 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1130 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1131 NULL, NULL, hInstance, NULL);
\r
1134 /* If window could not be created, return "failure" */
\r
1139 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1140 LoadLogo(&first, 0, FALSE);
\r
1141 LoadLogo(&second, 1, appData.icsActive);
\r
1145 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1146 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1147 iconCurrent = iconWhite;
\r
1148 InitDrawingColors();
\r
1150 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1151 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1152 /* Compute window size for each board size, and use the largest
\r
1153 size that fits on this screen as the default. */
\r
1154 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1155 if (boardSize == (BoardSize)-1 &&
\r
1156 winH <= screenHeight
\r
1157 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1158 && winW <= screenWidth) {
\r
1159 boardSize = (BoardSize)ibs;
\r
1163 InitDrawingSizes(boardSize, 0);
\r
1164 RecentEngineMenu(appData.recentEngineList);
\r
1166 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1168 /* [AS] Load textures if specified */
\r
1171 mysrandom( (unsigned) time(NULL) );
\r
1173 /* [AS] Restore layout */
\r
1174 if( wpMoveHistory.visible ) {
\r
1175 MoveHistoryPopUp();
\r
1178 if( wpEvalGraph.visible ) {
\r
1182 if( wpEngineOutput.visible ) {
\r
1183 EngineOutputPopUp();
\r
1186 /* Make the window visible; update its client area; and return "success" */
\r
1187 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1188 wp.length = sizeof(WINDOWPLACEMENT);
\r
1190 wp.showCmd = nCmdShow;
\r
1191 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1192 wp.rcNormalPosition.left = wpMain.x;
\r
1193 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1194 wp.rcNormalPosition.top = wpMain.y;
\r
1195 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1196 SetWindowPlacement(hwndMain, &wp);
\r
1198 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1200 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1201 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1203 if (hwndConsole) {
\r
1205 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1206 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1208 ShowWindow(hwndConsole, nCmdShow);
\r
1209 SetActiveWindow(hwndConsole);
\r
1211 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1212 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1221 HMENU hmenu = GetMenu(hwndMain);
\r
1223 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1224 MF_BYCOMMAND|((appData.icsActive &&
\r
1225 *appData.icsCommPort != NULLCHAR) ?
\r
1226 MF_ENABLED : MF_GRAYED));
\r
1227 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1228 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1229 MF_CHECKED : MF_UNCHECKED));
\r
1232 //---------------------------------------------------------------------------------------------------------
\r
1234 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1235 #define XBOARD FALSE
\r
1237 #define OPTCHAR "/"
\r
1238 #define SEPCHAR "="
\r
1239 #define TOPLEVEL 0
\r
1243 // front-end part of option handling
\r
1246 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1248 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1249 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1252 lf->lfEscapement = 0;
\r
1253 lf->lfOrientation = 0;
\r
1254 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1255 lf->lfItalic = mfp->italic;
\r
1256 lf->lfUnderline = mfp->underline;
\r
1257 lf->lfStrikeOut = mfp->strikeout;
\r
1258 lf->lfCharSet = mfp->charset;
\r
1259 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1260 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1261 lf->lfQuality = DEFAULT_QUALITY;
\r
1262 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1263 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1267 CreateFontInMF(MyFont *mf)
\r
1269 LFfromMFP(&mf->lf, &mf->mfp);
\r
1270 if (mf->hf) DeleteObject(mf->hf);
\r
1271 mf->hf = CreateFontIndirect(&mf->lf);
\r
1274 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1276 colorVariable[] = {
\r
1277 &whitePieceColor,
\r
1278 &blackPieceColor,
\r
1279 &lightSquareColor,
\r
1280 &darkSquareColor,
\r
1281 &highlightSquareColor,
\r
1282 &premoveHighlightColor,
\r
1284 &consoleBackgroundColor,
\r
1285 &appData.fontForeColorWhite,
\r
1286 &appData.fontBackColorWhite,
\r
1287 &appData.fontForeColorBlack,
\r
1288 &appData.fontBackColorBlack,
\r
1289 &appData.evalHistColorWhite,
\r
1290 &appData.evalHistColorBlack,
\r
1291 &appData.highlightArrowColor,
\r
1294 /* Command line font name parser. NULL name means do nothing.
\r
1295 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1296 For backward compatibility, syntax without the colon is also
\r
1297 accepted, but font names with digits in them won't work in that case.
\r
1300 ParseFontName(char *name, MyFontParams *mfp)
\r
1303 if (name == NULL) return;
\r
1305 q = strchr(p, ':');
\r
1307 if (q - p >= sizeof(mfp->faceName))
\r
1308 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1309 memcpy(mfp->faceName, p, q - p);
\r
1310 mfp->faceName[q - p] = NULLCHAR;
\r
1313 q = mfp->faceName;
\r
1315 while (*p && !isdigit(*p)) {
\r
1317 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1318 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1320 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1323 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1324 mfp->pointSize = (float) atof(p);
\r
1325 mfp->bold = (strchr(p, 'b') != NULL);
\r
1326 mfp->italic = (strchr(p, 'i') != NULL);
\r
1327 mfp->underline = (strchr(p, 'u') != NULL);
\r
1328 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1329 mfp->charset = DEFAULT_CHARSET;
\r
1330 q = strchr(p, 'c');
\r
1332 mfp->charset = (BYTE) atoi(q+1);
\r
1336 ParseFont(char *name, int number)
\r
1337 { // wrapper to shield back-end from 'font'
\r
1338 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1343 { // in WB we have a 2D array of fonts; this initializes their description
\r
1345 /* Point font array elements to structures and
\r
1346 parse default font names */
\r
1347 for (i=0; i<NUM_FONTS; i++) {
\r
1348 for (j=0; j<NUM_SIZES; j++) {
\r
1349 font[j][i] = &fontRec[j][i];
\r
1350 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1357 { // here we create the actual fonts from the selected descriptions
\r
1359 for (i=0; i<NUM_FONTS; i++) {
\r
1360 for (j=0; j<NUM_SIZES; j++) {
\r
1361 CreateFontInMF(font[j][i]);
\r
1365 /* Color name parser.
\r
1366 X version accepts X color names, but this one
\r
1367 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1369 ParseColorName(char *name)
\r
1371 int red, green, blue, count;
\r
1372 char buf[MSG_SIZ];
\r
1374 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1376 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1377 &red, &green, &blue);
\r
1380 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1381 DisplayError(buf, 0);
\r
1382 return RGB(0, 0, 0);
\r
1384 return PALETTERGB(red, green, blue);
\r
1388 ParseColor(int n, char *name)
\r
1389 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1390 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1394 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1396 char *e = argValue;
\r
1400 if (*e == 'b') eff |= CFE_BOLD;
\r
1401 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1402 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1403 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1404 else if (*e == '#' || isdigit(*e)) break;
\r
1408 *color = ParseColorName(e);
\r
1412 ParseTextAttribs(ColorClass cc, char *s)
\r
1413 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1414 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1415 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1419 ParseBoardSize(void *addr, char *name)
\r
1420 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1421 BoardSize bs = SizeTiny;
\r
1422 while (sizeInfo[bs].name != NULL) {
\r
1423 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1424 *(BoardSize *)addr = bs;
\r
1429 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1434 { // [HGM] import name from appData first
\r
1437 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1438 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1439 textAttribs[cc].sound.data = NULL;
\r
1440 MyLoadSound(&textAttribs[cc].sound);
\r
1442 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1443 textAttribs[cc].sound.name = strdup("");
\r
1444 textAttribs[cc].sound.data = NULL;
\r
1446 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1447 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1448 sounds[sc].data = NULL;
\r
1449 MyLoadSound(&sounds[sc]);
\r
1454 SetCommPortDefaults()
\r
1456 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1457 dcb.DCBlength = sizeof(DCB);
\r
1458 dcb.BaudRate = 9600;
\r
1459 dcb.fBinary = TRUE;
\r
1460 dcb.fParity = FALSE;
\r
1461 dcb.fOutxCtsFlow = FALSE;
\r
1462 dcb.fOutxDsrFlow = FALSE;
\r
1463 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1464 dcb.fDsrSensitivity = FALSE;
\r
1465 dcb.fTXContinueOnXoff = TRUE;
\r
1466 dcb.fOutX = FALSE;
\r
1468 dcb.fNull = FALSE;
\r
1469 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1470 dcb.fAbortOnError = FALSE;
\r
1472 dcb.Parity = SPACEPARITY;
\r
1473 dcb.StopBits = ONESTOPBIT;
\r
1476 // [HGM] args: these three cases taken out to stay in front-end
\r
1478 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1479 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1480 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1481 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1483 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1484 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1485 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1486 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1487 ad->argName, mfp->faceName, mfp->pointSize,
\r
1488 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1489 mfp->bold ? "b" : "",
\r
1490 mfp->italic ? "i" : "",
\r
1491 mfp->underline ? "u" : "",
\r
1492 mfp->strikeout ? "s" : "",
\r
1493 (int)mfp->charset);
\r
1499 { // [HGM] copy the names from the internal WB variables to appData
\r
1502 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1503 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1504 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1505 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1509 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1510 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1511 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1512 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1513 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1514 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1515 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1516 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1517 (ta->effects) ? " " : "",
\r
1518 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1522 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1523 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1524 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1525 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1526 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1530 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1531 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1532 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1536 ParseCommPortSettings(char *s)
\r
1537 { // wrapper to keep dcb from back-end
\r
1538 ParseCommSettings(s, &dcb);
\r
1543 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1544 GetActualPlacement(hwndMain, &wpMain);
\r
1545 GetActualPlacement(hwndConsole, &wpConsole);
\r
1546 GetActualPlacement(commentDialog, &wpComment);
\r
1547 GetActualPlacement(editTagsDialog, &wpTags);
\r
1548 GetActualPlacement(gameListDialog, &wpGameList);
\r
1549 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1550 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1551 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1555 PrintCommPortSettings(FILE *f, char *name)
\r
1556 { // wrapper to shield back-end from DCB
\r
1557 PrintCommSettings(f, name, &dcb);
\r
1561 MySearchPath(char *installDir, char *name, char *fullname)
\r
1563 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1564 if(name[0]== '%') {
\r
1565 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1566 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1567 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1568 *strchr(buf, '%') = 0;
\r
1569 strcat(fullname, getenv(buf));
\r
1570 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1572 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1573 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1574 return (int) strlen(fullname);
\r
1576 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1580 MyGetFullPathName(char *name, char *fullname)
\r
1583 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1588 { // [HGM] args: allows testing if main window is realized from back-end
\r
1589 return hwndMain != NULL;
\r
1593 PopUpStartupDialog()
\r
1597 LoadLanguageFile(appData.language);
\r
1598 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1599 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1600 FreeProcInstance(lpProc);
\r
1603 /*---------------------------------------------------------------------------*\
\r
1605 * GDI board drawing routines
\r
1607 \*---------------------------------------------------------------------------*/
\r
1609 /* [AS] Draw square using background texture */
\r
1610 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1615 return; /* Should never happen! */
\r
1618 SetGraphicsMode( dst, GM_ADVANCED );
\r
1625 /* X reflection */
\r
1630 x.eDx = (FLOAT) dw + dx - 1;
\r
1633 SetWorldTransform( dst, &x );
\r
1636 /* Y reflection */
\r
1642 x.eDy = (FLOAT) dh + dy - 1;
\r
1644 SetWorldTransform( dst, &x );
\r
1652 x.eDx = (FLOAT) dx;
\r
1653 x.eDy = (FLOAT) dy;
\r
1656 SetWorldTransform( dst, &x );
\r
1660 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1668 SetWorldTransform( dst, &x );
\r
1670 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1673 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1675 PM_WP = (int) WhitePawn,
\r
1676 PM_WN = (int) WhiteKnight,
\r
1677 PM_WB = (int) WhiteBishop,
\r
1678 PM_WR = (int) WhiteRook,
\r
1679 PM_WQ = (int) WhiteQueen,
\r
1680 PM_WF = (int) WhiteFerz,
\r
1681 PM_WW = (int) WhiteWazir,
\r
1682 PM_WE = (int) WhiteAlfil,
\r
1683 PM_WM = (int) WhiteMan,
\r
1684 PM_WO = (int) WhiteCannon,
\r
1685 PM_WU = (int) WhiteUnicorn,
\r
1686 PM_WH = (int) WhiteNightrider,
\r
1687 PM_WA = (int) WhiteAngel,
\r
1688 PM_WC = (int) WhiteMarshall,
\r
1689 PM_WAB = (int) WhiteCardinal,
\r
1690 PM_WD = (int) WhiteDragon,
\r
1691 PM_WL = (int) WhiteLance,
\r
1692 PM_WS = (int) WhiteCobra,
\r
1693 PM_WV = (int) WhiteFalcon,
\r
1694 PM_WSG = (int) WhiteSilver,
\r
1695 PM_WG = (int) WhiteGrasshopper,
\r
1696 PM_WK = (int) WhiteKing,
\r
1697 PM_BP = (int) BlackPawn,
\r
1698 PM_BN = (int) BlackKnight,
\r
1699 PM_BB = (int) BlackBishop,
\r
1700 PM_BR = (int) BlackRook,
\r
1701 PM_BQ = (int) BlackQueen,
\r
1702 PM_BF = (int) BlackFerz,
\r
1703 PM_BW = (int) BlackWazir,
\r
1704 PM_BE = (int) BlackAlfil,
\r
1705 PM_BM = (int) BlackMan,
\r
1706 PM_BO = (int) BlackCannon,
\r
1707 PM_BU = (int) BlackUnicorn,
\r
1708 PM_BH = (int) BlackNightrider,
\r
1709 PM_BA = (int) BlackAngel,
\r
1710 PM_BC = (int) BlackMarshall,
\r
1711 PM_BG = (int) BlackGrasshopper,
\r
1712 PM_BAB = (int) BlackCardinal,
\r
1713 PM_BD = (int) BlackDragon,
\r
1714 PM_BL = (int) BlackLance,
\r
1715 PM_BS = (int) BlackCobra,
\r
1716 PM_BV = (int) BlackFalcon,
\r
1717 PM_BSG = (int) BlackSilver,
\r
1718 PM_BK = (int) BlackKing
\r
1721 static HFONT hPieceFont = NULL;
\r
1722 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1723 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1724 static int fontBitmapSquareSize = 0;
\r
1725 static char pieceToFontChar[(int) EmptySquare] =
\r
1726 { 'p', 'n', 'b', 'r', 'q',
\r
1727 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1728 'k', 'o', 'm', 'v', 't', 'w',
\r
1729 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1732 extern BOOL SetCharTable( char *table, const char * map );
\r
1733 /* [HGM] moved to backend.c */
\r
1735 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1738 BYTE r1 = GetRValue( color );
\r
1739 BYTE g1 = GetGValue( color );
\r
1740 BYTE b1 = GetBValue( color );
\r
1746 /* Create a uniform background first */
\r
1747 hbrush = CreateSolidBrush( color );
\r
1748 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1749 FillRect( hdc, &rc, hbrush );
\r
1750 DeleteObject( hbrush );
\r
1753 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1754 int steps = squareSize / 2;
\r
1757 for( i=0; i<steps; i++ ) {
\r
1758 BYTE r = r1 - (r1-r2) * i / steps;
\r
1759 BYTE g = g1 - (g1-g2) * i / steps;
\r
1760 BYTE b = b1 - (b1-b2) * i / steps;
\r
1762 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1763 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1764 FillRect( hdc, &rc, hbrush );
\r
1765 DeleteObject(hbrush);
\r
1768 else if( mode == 2 ) {
\r
1769 /* Diagonal gradient, good more or less for every piece */
\r
1770 POINT triangle[3];
\r
1771 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1772 HBRUSH hbrush_old;
\r
1773 int steps = squareSize;
\r
1776 triangle[0].x = squareSize - steps;
\r
1777 triangle[0].y = squareSize;
\r
1778 triangle[1].x = squareSize;
\r
1779 triangle[1].y = squareSize;
\r
1780 triangle[2].x = squareSize;
\r
1781 triangle[2].y = squareSize - steps;
\r
1783 for( i=0; i<steps; i++ ) {
\r
1784 BYTE r = r1 - (r1-r2) * i / steps;
\r
1785 BYTE g = g1 - (g1-g2) * i / steps;
\r
1786 BYTE b = b1 - (b1-b2) * i / steps;
\r
1788 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1789 hbrush_old = SelectObject( hdc, hbrush );
\r
1790 Polygon( hdc, triangle, 3 );
\r
1791 SelectObject( hdc, hbrush_old );
\r
1792 DeleteObject(hbrush);
\r
1797 SelectObject( hdc, hpen );
\r
1802 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1803 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1804 piece: follow the steps as explained below.
\r
1806 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1810 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1814 int backColor = whitePieceColor;
\r
1815 int foreColor = blackPieceColor;
\r
1817 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1818 backColor = appData.fontBackColorWhite;
\r
1819 foreColor = appData.fontForeColorWhite;
\r
1821 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1822 backColor = appData.fontBackColorBlack;
\r
1823 foreColor = appData.fontForeColorBlack;
\r
1827 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1829 hbm_old = SelectObject( hdc, hbm );
\r
1833 rc.right = squareSize;
\r
1834 rc.bottom = squareSize;
\r
1836 /* Step 1: background is now black */
\r
1837 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1839 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1841 pt.x = (squareSize - sz.cx) / 2;
\r
1842 pt.y = (squareSize - sz.cy) / 2;
\r
1844 SetBkMode( hdc, TRANSPARENT );
\r
1845 SetTextColor( hdc, chroma );
\r
1846 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1847 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1849 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1850 /* Step 3: the area outside the piece is filled with white */
\r
1851 // FloodFill( hdc, 0, 0, chroma );
\r
1852 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1853 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1854 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1855 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1856 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1858 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1859 but if the start point is not inside the piece we're lost!
\r
1860 There should be a better way to do this... if we could create a region or path
\r
1861 from the fill operation we would be fine for example.
\r
1863 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1864 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1866 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1867 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1868 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1870 SelectObject( dc2, bm2 );
\r
1871 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1872 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1873 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1874 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1875 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1878 DeleteObject( bm2 );
\r
1881 SetTextColor( hdc, 0 );
\r
1883 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1884 draw the piece again in black for safety.
\r
1886 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1888 SelectObject( hdc, hbm_old );
\r
1890 if( hPieceMask[index] != NULL ) {
\r
1891 DeleteObject( hPieceMask[index] );
\r
1894 hPieceMask[index] = hbm;
\r
1897 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1899 SelectObject( hdc, hbm );
\r
1902 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1903 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1904 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1906 SelectObject( dc1, hPieceMask[index] );
\r
1907 SelectObject( dc2, bm2 );
\r
1908 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1909 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1912 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1913 the piece background and deletes (makes transparent) the rest.
\r
1914 Thanks to that mask, we are free to paint the background with the greates
\r
1915 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1916 We use this, to make gradients and give the pieces a "roundish" look.
\r
1918 SetPieceBackground( hdc, backColor, 2 );
\r
1919 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1923 DeleteObject( bm2 );
\r
1926 SetTextColor( hdc, foreColor );
\r
1927 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1929 SelectObject( hdc, hbm_old );
\r
1931 if( hPieceFace[index] != NULL ) {
\r
1932 DeleteObject( hPieceFace[index] );
\r
1935 hPieceFace[index] = hbm;
\r
1938 static int TranslatePieceToFontPiece( int piece )
\r
1968 case BlackMarshall:
\r
1972 case BlackNightrider:
\r
1978 case BlackUnicorn:
\r
1982 case BlackGrasshopper:
\r
1994 case BlackCardinal:
\r
2001 case WhiteMarshall:
\r
2005 case WhiteNightrider:
\r
2011 case WhiteUnicorn:
\r
2015 case WhiteGrasshopper:
\r
2027 case WhiteCardinal:
\r
2036 void CreatePiecesFromFont()
\r
2039 HDC hdc_window = NULL;
\r
2045 if( fontBitmapSquareSize < 0 ) {
\r
2046 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2050 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2051 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2052 fontBitmapSquareSize = -1;
\r
2056 if( fontBitmapSquareSize != squareSize ) {
\r
2057 hdc_window = GetDC( hwndMain );
\r
2058 hdc = CreateCompatibleDC( hdc_window );
\r
2060 if( hPieceFont != NULL ) {
\r
2061 DeleteObject( hPieceFont );
\r
2064 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2065 hPieceMask[i] = NULL;
\r
2066 hPieceFace[i] = NULL;
\r
2072 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2073 fontHeight = appData.fontPieceSize;
\r
2076 fontHeight = (fontHeight * squareSize) / 100;
\r
2078 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2080 lf.lfEscapement = 0;
\r
2081 lf.lfOrientation = 0;
\r
2082 lf.lfWeight = FW_NORMAL;
\r
2084 lf.lfUnderline = 0;
\r
2085 lf.lfStrikeOut = 0;
\r
2086 lf.lfCharSet = DEFAULT_CHARSET;
\r
2087 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2088 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2089 lf.lfQuality = PROOF_QUALITY;
\r
2090 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2091 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2092 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2094 hPieceFont = CreateFontIndirect( &lf );
\r
2096 if( hPieceFont == NULL ) {
\r
2097 fontBitmapSquareSize = -2;
\r
2100 /* Setup font-to-piece character table */
\r
2101 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2102 /* No (or wrong) global settings, try to detect the font */
\r
2103 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2105 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2107 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2108 /* DiagramTT* family */
\r
2109 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2111 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2112 /* Fairy symbols */
\r
2113 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2115 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2116 /* Good Companion (Some characters get warped as literal :-( */
\r
2117 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2118 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2119 SetCharTable(pieceToFontChar, s);
\r
2122 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2123 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2127 /* Create bitmaps */
\r
2128 hfont_old = SelectObject( hdc, hPieceFont );
\r
2129 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2130 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2131 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2133 SelectObject( hdc, hfont_old );
\r
2135 fontBitmapSquareSize = squareSize;
\r
2139 if( hdc != NULL ) {
\r
2143 if( hdc_window != NULL ) {
\r
2144 ReleaseDC( hwndMain, hdc_window );
\r
2149 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2151 char name[128], buf[MSG_SIZ];
\r
2153 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2154 if(appData.pieceDirectory[0]) {
\r
2156 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2157 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2158 if(res) return res;
\r
2160 if (gameInfo.event &&
\r
2161 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2162 strcmp(name, "k80s") == 0) {
\r
2163 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2165 return LoadBitmap(hinst, name);
\r
2169 /* Insert a color into the program's logical palette
\r
2170 structure. This code assumes the given color is
\r
2171 the result of the RGB or PALETTERGB macro, and it
\r
2172 knows how those macros work (which is documented).
\r
2175 InsertInPalette(COLORREF color)
\r
2177 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2179 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2180 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2181 pLogPal->palNumEntries--;
\r
2185 pe->peFlags = (char) 0;
\r
2186 pe->peRed = (char) (0xFF & color);
\r
2187 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2188 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2194 InitDrawingColors()
\r
2197 if (pLogPal == NULL) {
\r
2198 /* Allocate enough memory for a logical palette with
\r
2199 * PALETTESIZE entries and set the size and version fields
\r
2200 * of the logical palette structure.
\r
2202 pLogPal = (NPLOGPALETTE)
\r
2203 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2204 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2205 pLogPal->palVersion = 0x300;
\r
2207 pLogPal->palNumEntries = 0;
\r
2209 InsertInPalette(lightSquareColor);
\r
2210 InsertInPalette(darkSquareColor);
\r
2211 InsertInPalette(whitePieceColor);
\r
2212 InsertInPalette(blackPieceColor);
\r
2213 InsertInPalette(highlightSquareColor);
\r
2214 InsertInPalette(premoveHighlightColor);
\r
2216 /* create a logical color palette according the information
\r
2217 * in the LOGPALETTE structure.
\r
2219 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2221 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2222 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2223 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2224 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2225 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2226 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2227 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2228 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2230 /* [AS] Force rendering of the font-based pieces */
\r
2231 if( fontBitmapSquareSize > 0 ) {
\r
2232 fontBitmapSquareSize = 0;
\r
2238 BoardWidth(int boardSize, int n)
\r
2239 { /* [HGM] argument n added to allow different width and height */
\r
2240 int lineGap = sizeInfo[boardSize].lineGap;
\r
2242 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2243 lineGap = appData.overrideLineGap;
\r
2246 return (n + 1) * lineGap +
\r
2247 n * sizeInfo[boardSize].squareSize;
\r
2250 /* Respond to board resize by dragging edge */
\r
2252 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2254 BoardSize newSize = NUM_SIZES - 1;
\r
2255 static int recurse = 0;
\r
2256 if (IsIconic(hwndMain)) return;
\r
2257 if (recurse > 0) return;
\r
2259 while (newSize > 0) {
\r
2260 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2261 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2262 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2265 boardSize = newSize;
\r
2266 InitDrawingSizes(boardSize, flags);
\r
2271 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2274 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2276 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2277 ChessSquare piece;
\r
2278 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2280 SIZE clockSize, messageSize;
\r
2282 char buf[MSG_SIZ];
\r
2284 HMENU hmenu = GetMenu(hwndMain);
\r
2285 RECT crect, wrect, oldRect;
\r
2287 LOGBRUSH logbrush;
\r
2288 VariantClass v = gameInfo.variant;
\r
2290 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2291 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2293 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2294 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2295 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2296 oldBoardSize = boardSize;
\r
2298 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2299 { // correct board size to one where built-in pieces exist
\r
2300 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2301 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2302 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2303 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2304 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2305 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2306 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2307 boardSize = SizeMiddling;
\r
2310 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2312 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2313 oldRect.top = wpMain.y;
\r
2314 oldRect.right = wpMain.x + wpMain.width;
\r
2315 oldRect.bottom = wpMain.y + wpMain.height;
\r
2317 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2318 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2319 squareSize = sizeInfo[boardSize].squareSize;
\r
2320 lineGap = sizeInfo[boardSize].lineGap;
\r
2321 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2322 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2324 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2325 lineGap = appData.overrideLineGap;
\r
2328 if (tinyLayout != oldTinyLayout) {
\r
2329 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2331 style &= ~WS_SYSMENU;
\r
2332 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2333 "&Minimize\tCtrl+F4");
\r
2335 style |= WS_SYSMENU;
\r
2336 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2338 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2340 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2341 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2342 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2344 DrawMenuBar(hwndMain);
\r
2347 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2348 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2350 /* Get text area sizes */
\r
2351 hdc = GetDC(hwndMain);
\r
2352 if (appData.clockMode) {
\r
2353 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2355 snprintf(buf, MSG_SIZ, _("White"));
\r
2357 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2358 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2359 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2360 str = _("We only care about the height here");
\r
2361 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2362 SelectObject(hdc, oldFont);
\r
2363 ReleaseDC(hwndMain, hdc);
\r
2365 /* Compute where everything goes */
\r
2366 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2367 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2368 logoHeight = 2*clockSize.cy;
\r
2369 leftLogoRect.left = OUTER_MARGIN;
\r
2370 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2371 leftLogoRect.top = OUTER_MARGIN;
\r
2372 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2374 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2375 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2376 rightLogoRect.top = OUTER_MARGIN;
\r
2377 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2380 whiteRect.left = leftLogoRect.right;
\r
2381 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2382 whiteRect.top = OUTER_MARGIN;
\r
2383 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2385 blackRect.right = rightLogoRect.left;
\r
2386 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2387 blackRect.top = whiteRect.top;
\r
2388 blackRect.bottom = whiteRect.bottom;
\r
2390 whiteRect.left = OUTER_MARGIN;
\r
2391 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2392 whiteRect.top = OUTER_MARGIN;
\r
2393 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2395 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2396 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2397 blackRect.top = whiteRect.top;
\r
2398 blackRect.bottom = whiteRect.bottom;
\r
2400 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2403 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2404 if (appData.showButtonBar) {
\r
2405 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2406 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2408 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2410 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2411 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2413 boardRect.left = OUTER_MARGIN;
\r
2414 boardRect.right = boardRect.left + boardWidth;
\r
2415 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2416 boardRect.bottom = boardRect.top + boardHeight;
\r
2418 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2419 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2420 oldTinyLayout = tinyLayout;
\r
2421 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2422 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2423 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2424 winW *= 1 + twoBoards;
\r
2425 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2426 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2427 wpMain.height = winH; // without disturbing window attachments
\r
2428 GetWindowRect(hwndMain, &wrect);
\r
2429 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2430 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2432 // [HGM] placement: let attached windows follow size change.
\r
2433 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2434 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2435 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2436 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2437 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2439 /* compensate if menu bar wrapped */
\r
2440 GetClientRect(hwndMain, &crect);
\r
2441 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2442 wpMain.height += offby;
\r
2444 case WMSZ_TOPLEFT:
\r
2445 SetWindowPos(hwndMain, NULL,
\r
2446 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2447 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2450 case WMSZ_TOPRIGHT:
\r
2452 SetWindowPos(hwndMain, NULL,
\r
2453 wrect.left, wrect.bottom - wpMain.height,
\r
2454 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2457 case WMSZ_BOTTOMLEFT:
\r
2459 SetWindowPos(hwndMain, NULL,
\r
2460 wrect.right - wpMain.width, wrect.top,
\r
2461 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2464 case WMSZ_BOTTOMRIGHT:
\r
2468 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2469 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2474 for (i = 0; i < N_BUTTONS; i++) {
\r
2475 if (buttonDesc[i].hwnd != NULL) {
\r
2476 DestroyWindow(buttonDesc[i].hwnd);
\r
2477 buttonDesc[i].hwnd = NULL;
\r
2479 if (appData.showButtonBar) {
\r
2480 buttonDesc[i].hwnd =
\r
2481 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2482 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2483 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2484 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2485 (HMENU) buttonDesc[i].id,
\r
2486 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2488 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2489 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2490 MAKELPARAM(FALSE, 0));
\r
2492 if (buttonDesc[i].id == IDM_Pause)
\r
2493 hwndPause = buttonDesc[i].hwnd;
\r
2494 buttonDesc[i].wndproc = (WNDPROC)
\r
2495 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2498 if (gridPen != NULL) DeleteObject(gridPen);
\r
2499 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2500 if (premovePen != NULL) DeleteObject(premovePen);
\r
2501 if (lineGap != 0) {
\r
2502 logbrush.lbStyle = BS_SOLID;
\r
2503 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2505 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2506 lineGap, &logbrush, 0, NULL);
\r
2507 logbrush.lbColor = highlightSquareColor;
\r
2509 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2510 lineGap, &logbrush, 0, NULL);
\r
2512 logbrush.lbColor = premoveHighlightColor;
\r
2514 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2515 lineGap, &logbrush, 0, NULL);
\r
2517 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2518 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2519 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2520 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2521 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2522 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2523 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2524 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2526 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2527 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2528 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2529 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2530 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2531 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2532 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2533 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2537 /* [HGM] Licensing requirement */
\r
2539 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2542 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2544 GothicPopUp( "", VariantNormal);
\r
2547 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2549 /* Load piece bitmaps for this board size */
\r
2550 for (i=0; i<=2; i++) {
\r
2551 for (piece = WhitePawn;
\r
2552 (int) piece < (int) BlackPawn;
\r
2553 piece = (ChessSquare) ((int) piece + 1)) {
\r
2554 if (pieceBitmap[i][piece] != NULL)
\r
2555 DeleteObject(pieceBitmap[i][piece]);
\r
2559 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2560 // Orthodox Chess pieces
\r
2561 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2562 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2563 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2564 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2565 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2566 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2567 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2568 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2569 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2570 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2571 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2572 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2573 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2574 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2575 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2576 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2577 // in Shogi, Hijack the unused Queen for Lance
\r
2578 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2579 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2580 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2582 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2583 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2584 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2587 if(squareSize <= 72 && squareSize >= 33) {
\r
2588 /* A & C are available in most sizes now */
\r
2589 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2590 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2591 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2592 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2593 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2594 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2595 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2596 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2597 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2598 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2599 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2600 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2601 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2602 } else { // Smirf-like
\r
2603 if(gameInfo.variant == VariantSChess) {
\r
2604 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2605 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2606 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2608 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2609 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2610 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2613 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2614 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2617 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2618 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2621 } else { // WinBoard standard
\r
2622 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2623 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2624 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2629 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2630 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2631 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2632 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2633 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2634 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2635 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2636 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2637 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2638 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2639 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2640 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2641 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2642 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2645 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2646 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2647 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2648 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2651 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2652 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2653 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2654 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2655 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2656 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2657 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2658 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2659 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2660 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2664 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2665 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2666 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2667 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2668 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2669 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2670 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2671 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2672 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2673 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2674 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2678 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2679 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2680 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2681 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2682 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2683 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2684 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2685 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2686 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2687 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2688 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2689 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2692 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2693 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2694 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2695 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2696 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2697 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2698 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2699 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2700 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2701 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2702 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2703 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2704 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2705 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2706 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2710 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2711 /* special Shogi support in this size */
\r
2712 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2713 for (piece = WhitePawn;
\r
2714 (int) piece < (int) BlackPawn;
\r
2715 piece = (ChessSquare) ((int) piece + 1)) {
\r
2716 if (pieceBitmap[i][piece] != NULL)
\r
2717 DeleteObject(pieceBitmap[i][piece]);
\r
2720 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2721 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2722 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2723 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2724 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2725 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2726 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2727 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2728 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2729 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2730 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2731 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2732 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2733 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2734 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2735 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2736 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2737 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2738 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2739 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2740 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2741 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2742 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2743 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2744 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2745 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2746 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2747 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2748 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2749 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2750 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2751 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2752 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2753 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2754 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2755 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2756 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2757 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2758 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2759 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2760 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2761 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2767 PieceBitmap(ChessSquare p, int kind)
\r
2769 if ((int) p >= (int) BlackPawn)
\r
2770 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2772 return pieceBitmap[kind][(int) p];
\r
2775 /***************************************************************/
\r
2777 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2778 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2780 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2781 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2785 SquareToPos(int row, int column, int * x, int * y)
\r
2788 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2789 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2791 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2792 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2797 DrawCoordsOnDC(HDC hdc)
\r
2799 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2800 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2801 char str[2] = { NULLCHAR, NULLCHAR };
\r
2802 int oldMode, oldAlign, x, y, start, i;
\r
2806 if (!appData.showCoords)
\r
2809 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2811 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2812 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2813 oldAlign = GetTextAlign(hdc);
\r
2814 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2816 y = boardRect.top + lineGap;
\r
2817 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2820 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2821 x += border - lineGap - 4; y += squareSize - 6;
\r
2823 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2824 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2825 str[0] = files[start + i];
\r
2826 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2827 y += squareSize + lineGap;
\r
2830 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2833 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2834 x += -border + 4; y += border - squareSize + 6;
\r
2836 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2837 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2838 str[0] = ranks[start + i];
\r
2839 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2840 x += squareSize + lineGap;
\r
2843 SelectObject(hdc, oldBrush);
\r
2844 SetBkMode(hdc, oldMode);
\r
2845 SetTextAlign(hdc, oldAlign);
\r
2846 SelectObject(hdc, oldFont);
\r
2850 DrawGridOnDC(HDC hdc)
\r
2854 if (lineGap != 0) {
\r
2855 oldPen = SelectObject(hdc, gridPen);
\r
2856 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2857 SelectObject(hdc, oldPen);
\r
2861 #define HIGHLIGHT_PEN 0
\r
2862 #define PREMOVE_PEN 1
\r
2865 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2868 HPEN oldPen, hPen;
\r
2869 if (lineGap == 0) return;
\r
2871 x1 = boardRect.left +
\r
2872 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2873 y1 = boardRect.top +
\r
2874 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2876 x1 = boardRect.left +
\r
2877 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2878 y1 = boardRect.top +
\r
2879 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2881 hPen = pen ? premovePen : highlightPen;
\r
2882 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2883 MoveToEx(hdc, x1, y1, NULL);
\r
2884 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2885 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2886 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2887 LineTo(hdc, x1, y1);
\r
2888 SelectObject(hdc, oldPen);
\r
2892 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2895 for (i=0; i<2; i++) {
\r
2896 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2897 DrawHighlightOnDC(hdc, TRUE,
\r
2898 h->sq[i].x, h->sq[i].y,
\r
2903 /* Note: sqcolor is used only in monoMode */
\r
2904 /* Note that this code is largely duplicated in woptions.c,
\r
2905 function DrawSampleSquare, so that needs to be updated too */
\r
2907 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2909 HBITMAP oldBitmap;
\r
2913 if (appData.blindfold) return;
\r
2915 /* [AS] Use font-based pieces if needed */
\r
2916 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2917 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2918 CreatePiecesFromFont();
\r
2920 if( fontBitmapSquareSize == squareSize ) {
\r
2921 int index = TranslatePieceToFontPiece(piece);
\r
2923 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2925 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2926 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2930 squareSize, squareSize,
\r
2935 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2937 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2938 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2942 squareSize, squareSize,
\r
2951 if (appData.monoMode) {
\r
2952 SelectObject(tmphdc, PieceBitmap(piece,
\r
2953 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2954 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2955 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2957 HBRUSH xBrush = whitePieceBrush;
\r
2958 tmpSize = squareSize;
\r
2959 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2961 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2962 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2963 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2964 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2965 x += (squareSize - minorSize)>>1;
\r
2966 y += squareSize - minorSize - 2;
\r
2967 tmpSize = minorSize;
\r
2969 if (color || appData.allWhite ) {
\r
2970 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2972 oldBrush = SelectObject(hdc, xBrush);
\r
2973 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2974 if(appData.upsideDown && color==flipView)
\r
2975 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2977 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2978 /* Use black for outline of white pieces */
\r
2979 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2980 if(appData.upsideDown && color==flipView)
\r
2981 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2983 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2984 } else if(appData.pieceDirectory[0]) {
\r
2985 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2986 oldBrush = SelectObject(hdc, xBrush);
\r
2987 if(appData.upsideDown && color==flipView)
\r
2988 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2990 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2991 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2992 if(appData.upsideDown && color==flipView)
\r
2993 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2995 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2997 /* Use square color for details of black pieces */
\r
2998 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2999 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3000 if(appData.upsideDown && !flipView)
\r
3001 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3003 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3005 SelectObject(hdc, oldBrush);
\r
3006 SelectObject(tmphdc, oldBitmap);
\r
3010 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3011 int GetBackTextureMode( int algo )
\r
3013 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3017 case BACK_TEXTURE_MODE_PLAIN:
\r
3018 result = 1; /* Always use identity map */
\r
3020 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3021 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3029 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3030 to handle redraws cleanly (as random numbers would always be different).
\r
3032 VOID RebuildTextureSquareInfo()
\r
3042 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3044 if( liteBackTexture != NULL ) {
\r
3045 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3046 lite_w = bi.bmWidth;
\r
3047 lite_h = bi.bmHeight;
\r
3051 if( darkBackTexture != NULL ) {
\r
3052 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3053 dark_w = bi.bmWidth;
\r
3054 dark_h = bi.bmHeight;
\r
3058 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3059 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3060 if( (col + row) & 1 ) {
\r
3062 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3063 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3064 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3066 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3067 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3068 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3070 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3071 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3076 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3077 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3078 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3080 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3081 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3082 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3084 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3085 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3092 /* [AS] Arrow highlighting support */
\r
3094 static double A_WIDTH = 5; /* Width of arrow body */
\r
3096 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3097 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3099 static double Sqr( double x )
\r
3104 static int Round( double x )
\r
3106 return (int) (x + 0.5);
\r
3109 /* Draw an arrow between two points using current settings */
\r
3110 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3113 double dx, dy, j, k, x, y;
\r
3115 if( d_x == s_x ) {
\r
3116 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3118 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3121 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3122 arrow[1].y = d_y - h;
\r
3124 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3125 arrow[2].y = d_y - h;
\r
3130 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3131 arrow[5].y = d_y - h;
\r
3133 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3134 arrow[4].y = d_y - h;
\r
3136 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3139 else if( d_y == s_y ) {
\r
3140 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3143 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3145 arrow[1].x = d_x - w;
\r
3146 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3148 arrow[2].x = d_x - w;
\r
3149 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3154 arrow[5].x = d_x - w;
\r
3155 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3157 arrow[4].x = d_x - w;
\r
3158 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3161 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3164 /* [AS] Needed a lot of paper for this! :-) */
\r
3165 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3166 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3168 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3170 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3175 arrow[0].x = Round(x - j);
\r
3176 arrow[0].y = Round(y + j*dx);
\r
3178 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3179 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3182 x = (double) d_x - k;
\r
3183 y = (double) d_y - k*dy;
\r
3186 x = (double) d_x + k;
\r