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, 2015 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;
\r
170 static int winW, winH;
\r
171 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
172 static int logoHeight = 0;
\r
173 static char messageText[MESSAGE_TEXT_MAX];
\r
174 static int clockTimerEvent = 0;
\r
175 static int loadGameTimerEvent = 0;
\r
176 static int analysisTimerEvent = 0;
\r
177 static DelayedEventCallback delayedTimerCallback;
\r
178 static int delayedTimerEvent = 0;
\r
179 static int buttonCount = 2;
\r
180 char *icsTextMenuString;
\r
182 char *firstChessProgramNames;
\r
183 char *secondChessProgramNames;
\r
185 #define PALETTESIZE 256
\r
187 HINSTANCE hInst; /* current instance */
\r
188 Boolean alwaysOnTop = FALSE;
\r
190 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
191 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
192 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
194 ColorClass currentColorClass;
\r
196 static HWND savedHwnd;
\r
197 HWND hCommPort = NULL; /* currently open comm port */
\r
198 static HWND hwndPause; /* pause button */
\r
199 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
200 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
201 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
202 explodeBrush, /* [HGM] atomic */
\r
203 markerBrush[8], /* [HGM] markers */
\r
204 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
205 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
206 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
207 static HPEN gridPen = NULL;
\r
208 static HPEN highlightPen = NULL;
\r
209 static HPEN premovePen = NULL;
\r
210 static NPLOGPALETTE pLogPal;
\r
211 static BOOL paletteChanged = FALSE;
\r
212 static HICON iconWhite, iconBlack, iconCurrent;
\r
213 static int doingSizing = FALSE;
\r
214 static int lastSizing = 0;
\r
215 static int prevStderrPort;
\r
216 static HBITMAP userLogo;
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
229 #if defined(_winmajor)
\r
230 #define oldDialog (_winmajor < 4)
\r
232 #define oldDialog 0
\r
236 #define INTERNATIONAL
\r
238 #ifdef INTERNATIONAL
\r
239 # define _(s) T_(s)
\r
245 # define Translate(x, y)
\r
246 # define LoadLanguageFile(s)
\r
249 #ifdef INTERNATIONAL
\r
251 Boolean barbaric; // flag indicating if translation is needed
\r
253 // list of item numbers used in each dialog (used to alter language at run time)
\r
255 #define ABOUTBOX -1 /* not sure why these are needed */
\r
256 #define ABOUTBOX2 -1
\r
258 int dialogItems[][42] = {
\r
259 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
260 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
261 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
262 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
263 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds,
\r
264 OPT_Ranget, IDOK, IDCANCEL },
\r
265 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
266 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
267 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
268 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
269 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
270 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
271 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
272 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
273 { ABOUTBOX2, IDC_ChessBoard },
\r
274 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
275 OPT_GameListClose, IDC_GameListDoFilter },
\r
276 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
277 { DLG_Error, IDOK },
\r
278 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
279 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
280 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
281 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
282 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
283 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
284 { DLG_IndexNumber, IDC_Index },
\r
285 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
286 { DLG_TypeInName, IDOK, IDCANCEL },
\r
287 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
288 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
289 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
290 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
291 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
292 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
293 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
294 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
295 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
296 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
297 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
298 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
299 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
300 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
301 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
302 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
303 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
304 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
305 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
306 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
307 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
308 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
309 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
310 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
311 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
312 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
313 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
314 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
315 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
316 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
317 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
318 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
319 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
320 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
321 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
322 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
323 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
324 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
325 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
326 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
327 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
328 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
329 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
330 { DLG_MoveHistory },
\r
331 { DLG_EvalGraph },
\r
332 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
333 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
334 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
335 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
336 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
337 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
338 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
339 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
340 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
344 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
345 static int lastChecked;
\r
346 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
347 extern int tinyLayout;
\r
348 extern char * menuBarText[][10];
\r
351 LoadLanguageFile(char *name)
\r
352 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
354 int i=0, j=0, n=0, k;
\r
357 if(!name || name[0] == NULLCHAR) return;
\r
358 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
359 appData.language = oldLanguage;
\r
360 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
361 if((f = fopen(buf, "r")) == NULL) return;
\r
362 while((k = fgetc(f)) != EOF) {
\r
363 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
364 languageBuf[i] = k;
\r
366 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
368 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
369 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
370 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
371 english[j] = languageBuf + n + 1; *p = 0;
\r
372 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
373 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
378 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
380 case 'n': k = '\n'; break;
\r
381 case 'r': k = '\r'; break;
\r
382 case 't': k = '\t'; break;
\r
384 languageBuf[--i] = k;
\r
389 barbaric = (j != 0);
\r
390 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
395 { // return the translation of the given string
\r
396 // efficiency can be improved a lot...
\r
398 static char buf[MSG_SIZ];
\r
399 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
400 if(!barbaric) return s;
\r
401 if(!s) return ""; // sanity
\r
402 while(english[i]) {
\r
403 if(!strcmp(s, english[i])) return foreign[i];
\r
404 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
405 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
414 Translate(HWND hDlg, int dialogID)
\r
415 { // translate all text items in the given dialog
\r
417 char buf[MSG_SIZ], *s;
\r
418 if(!barbaric) return;
\r
419 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
420 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
421 GetWindowText( hDlg, buf, MSG_SIZ );
\r
423 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
424 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
425 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
426 if(strlen(buf) == 0) continue;
\r
428 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
433 TranslateOneMenu(int i, HMENU subMenu)
\r
436 static MENUITEMINFO info;
\r
438 info.cbSize = sizeof(MENUITEMINFO);
\r
439 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
440 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
442 info.dwTypeData = buf;
\r
443 info.cch = sizeof(buf);
\r
444 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
446 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
447 else menuText[i][j] = strdup(buf); // remember original on first change
\r
449 if(buf[0] == NULLCHAR) continue;
\r
450 info.dwTypeData = T_(buf);
\r
451 info.cch = strlen(buf)+1;
\r
452 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
458 TranslateMenus(int addLanguage)
\r
461 WIN32_FIND_DATA fileData;
\r
463 #define IDM_English 1970
\r
465 HMENU mainMenu = GetMenu(hwndMain);
\r
466 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
467 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
468 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
469 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
470 TranslateOneMenu(i, subMenu);
\r
472 DrawMenuBar(hwndMain);
\r
475 if(!addLanguage) return;
\r
476 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
477 HMENU mainMenu = GetMenu(hwndMain);
\r
478 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
479 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
480 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
481 i = 0; lastChecked = IDM_English;
\r
483 char *p, *q = fileData.cFileName;
\r
484 int checkFlag = MF_UNCHECKED;
\r
485 languageFile[i] = strdup(q);
\r
486 if(barbaric && !strcmp(oldLanguage, q)) {
\r
487 checkFlag = MF_CHECKED;
\r
488 lastChecked = IDM_English + i + 1;
\r
489 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
491 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
492 p = strstr(fileData.cFileName, ".lng");
\r
494 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
495 } while(FindNextFile(hFind, &fileData));
\r
502 #define IDM_RecentEngines 3000
\r
505 RecentEngineMenu (char *s)
\r
507 if(appData.icsActive) return;
\r
508 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
509 HMENU mainMenu = GetMenu(hwndMain);
\r
510 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
511 int i=IDM_RecentEngines;
\r
512 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
513 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
515 char *p = strchr(s, '\n');
\r
516 if(p == NULL) return; // malformed!
\r
518 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
532 int cliWidth, cliHeight;
\r
535 SizeInfo sizeInfo[] =
\r
537 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
540 { "petite", 33, 1, 1, 1, 0, 0 },
\r
541 { "slim", 37, 2, 1, 0, 0, 0 },
\r
542 { "small", 40, 2, 1, 0, 0, 0 },
\r
543 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
544 { "middling", 49, 2, 0, 0, 0, 0 },
\r
545 { "average", 54, 2, 0, 0, 0, 0 },
\r
546 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
547 { "medium", 64, 3, 0, 0, 0, 0 },
\r
548 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
549 { "large", 80, 3, 0, 0, 0, 0 },
\r
550 { "big", 87, 3, 0, 0, 0, 0 },
\r
551 { "huge", 95, 3, 0, 0, 0, 0 },
\r
552 { "giant", 108, 3, 0, 0, 0, 0 },
\r
553 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
554 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
555 { NULL, 0, 0, 0, 0, 0, 0 }
\r
558 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
559 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
561 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
562 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
578 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
581 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
590 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
591 #define N_BUTTONS 5
\r
593 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
595 {"<<", IDM_ToStart, NULL, NULL},
\r
596 {"<", IDM_Backward, NULL, NULL},
\r
597 {"P", IDM_Pause, NULL, NULL},
\r
598 {">", IDM_Forward, NULL, NULL},
\r
599 {">>", IDM_ToEnd, NULL, NULL},
\r
602 int tinyLayout = 0, smallLayout = 0;
\r
603 #define MENU_BAR_ITEMS 9
\r
604 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
605 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
606 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
610 MySound sounds[(int)NSoundClasses];
\r
611 MyTextAttribs textAttribs[(int)NColorClasses];
\r
613 MyColorizeAttribs colorizeAttribs[] = {
\r
614 { (COLORREF)0, 0, N_("Shout Text") },
\r
615 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
616 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
617 { (COLORREF)0, 0, N_("Channel Text") },
\r
618 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
619 { (COLORREF)0, 0, N_("Tell Text") },
\r
620 { (COLORREF)0, 0, N_("Challenge Text") },
\r
621 { (COLORREF)0, 0, N_("Request Text") },
\r
622 { (COLORREF)0, 0, N_("Seek Text") },
\r
623 { (COLORREF)0, 0, N_("Normal Text") },
\r
624 { (COLORREF)0, 0, N_("None") }
\r
629 static char *commentTitle;
\r
630 static char *commentText;
\r
631 static int commentIndex;
\r
632 static Boolean editComment = FALSE;
\r
635 char errorTitle[MSG_SIZ];
\r
636 char errorMessage[2*MSG_SIZ];
\r
637 HWND errorDialog = NULL;
\r
638 BOOLEAN moveErrorMessageUp = FALSE;
\r
639 BOOLEAN consoleEcho = TRUE;
\r
640 CHARFORMAT consoleCF;
\r
641 COLORREF consoleBackgroundColor;
\r
643 char *programVersion;
\r
649 typedef int CPKind;
\r
658 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
661 #define INPUT_SOURCE_BUF_SIZE 4096
\r
663 typedef struct _InputSource {
\r
670 char buf[INPUT_SOURCE_BUF_SIZE];
\r
674 InputCallback func;
\r
675 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
679 InputSource *consoleInputSource;
\r
684 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
685 VOID ConsoleCreate();
\r
687 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
689 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
690 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
692 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
693 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
694 void ParseIcsTextMenu(char *icsTextMenuString);
\r
695 VOID PopUpNameDialog(char firstchar);
\r
696 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
700 int GameListOptions();
\r
702 int dummy; // [HGM] for obsolete args
\r
704 HWND hwndMain = NULL; /* root window*/
\r
705 HWND hwndConsole = NULL;
\r
706 HWND commentDialog = NULL;
\r
707 HWND moveHistoryDialog = NULL;
\r
708 HWND evalGraphDialog = NULL;
\r
709 HWND engineOutputDialog = NULL;
\r
710 HWND gameListDialog = NULL;
\r
711 HWND editTagsDialog = NULL;
\r
713 int commentUp = FALSE;
\r
715 WindowPlacement wpMain;
\r
716 WindowPlacement wpConsole;
\r
717 WindowPlacement wpComment;
\r
718 WindowPlacement wpMoveHistory;
\r
719 WindowPlacement wpEvalGraph;
\r
720 WindowPlacement wpEngineOutput;
\r
721 WindowPlacement wpGameList;
\r
722 WindowPlacement wpTags;
\r
724 VOID EngineOptionsPopup(); // [HGM] settings
\r
726 VOID GothicPopUp(char *title, VariantClass variant);
\r
728 * Setting "frozen" should disable all user input other than deleting
\r
729 * the window. We do this while engines are initializing themselves.
\r
731 static int frozen = 0;
\r
732 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
738 if (frozen) return;
\r
740 hmenu = GetMenu(hwndMain);
\r
741 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
742 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
744 DrawMenuBar(hwndMain);
\r
747 /* Undo a FreezeUI */
\r
753 if (!frozen) return;
\r
755 hmenu = GetMenu(hwndMain);
\r
756 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
757 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
759 DrawMenuBar(hwndMain);
\r
762 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
764 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
770 #define JAWS_ALT_INTERCEPT
\r
771 #define JAWS_KBUP_NAVIGATION
\r
772 #define JAWS_KBDOWN_NAVIGATION
\r
773 #define JAWS_MENU_ITEMS
\r
774 #define JAWS_SILENCE
\r
775 #define JAWS_REPLAY
\r
777 #define JAWS_COPYRIGHT
\r
778 #define JAWS_DELETE(X) X
\r
779 #define SAYMACHINEMOVE()
\r
783 /*---------------------------------------------------------------------------*\
\r
787 \*---------------------------------------------------------------------------*/
\r
789 static void HandleMessage P((MSG *message));
\r
790 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
793 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
794 LPSTR lpCmdLine, int nCmdShow)
\r
797 // INITCOMMONCONTROLSEX ex;
\r
801 LoadLibrary("RICHED32.DLL");
\r
802 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
804 if (!InitApplication(hInstance)) {
\r
807 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
814 // InitCommonControlsEx(&ex);
\r
815 InitCommonControls();
\r
817 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
818 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
819 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
821 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
823 while (GetMessage(&msg, /* message structure */
\r
824 NULL, /* handle of window receiving the message */
\r
825 0, /* lowest message to examine */
\r
826 0)) /* highest message to examine */
\r
828 HandleMessage(&msg);
\r
832 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
836 HandleMessage (MSG *message)
\r
838 MSG msg = *message;
\r
840 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
841 // [HGM] navigate: switch between all windows with tab
\r
842 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
843 int i, currentElement = 0;
\r
845 // first determine what element of the chain we come from (if any)
\r
846 if(appData.icsActive) {
\r
847 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
848 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
850 if(engineOutputDialog && EngineOutputIsUp()) {
\r
851 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
852 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
854 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
855 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
857 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
858 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
859 if(msg.hwnd == e1) currentElement = 2; else
\r
860 if(msg.hwnd == e2) currentElement = 3; else
\r
861 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
862 if(msg.hwnd == mh) currentElement = 4; else
\r
863 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
864 if(msg.hwnd == hText) currentElement = 5; else
\r
865 if(msg.hwnd == hInput) currentElement = 6; else
\r
866 for (i = 0; i < N_BUTTONS; i++) {
\r
867 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
870 // determine where to go to
\r
871 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
873 currentElement = (currentElement + direction) % 7;
\r
874 switch(currentElement) {
\r
876 h = hwndMain; break; // passing this case always makes the loop exit
\r
878 h = buttonDesc[0].hwnd; break; // could be NULL
\r
880 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
883 if(!EngineOutputIsUp()) continue;
\r
886 if(!MoveHistoryIsUp()) continue;
\r
888 // case 6: // input to eval graph does not seem to get here!
\r
889 // if(!EvalGraphIsUp()) continue;
\r
890 // h = evalGraphDialog; break;
\r
892 if(!appData.icsActive) continue;
\r
896 if(!appData.icsActive) continue;
\r
902 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
903 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
906 return; // this message now has been processed
\r
910 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
911 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
912 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
913 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
914 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
915 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
916 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
917 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
918 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
920 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
921 for(i=0; i<MAX_CHAT; i++)
\r
922 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
925 if(done) return; // [HGM] chat: end patch
\r
926 TranslateMessage(&msg); /* Translates virtual key codes */
\r
927 DispatchMessage(&msg); /* Dispatches message to window */
\r
933 { /* Dispatch pending messages */
\r
935 while (PeekMessage(&msg, /* message structure */
\r
936 NULL, /* handle of window receiving the message */
\r
937 0, /* lowest message to examine */
\r
938 0, /* highest message to examine */
\r
941 HandleMessage(&msg);
\r
945 /*---------------------------------------------------------------------------*\
\r
947 * Initialization functions
\r
949 \*---------------------------------------------------------------------------*/
\r
953 { // update user logo if necessary
\r
954 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
956 if(appData.autoLogo) {
\r
957 curName = UserName();
\r
958 if(strcmp(curName, oldUserName)) {
\r
959 GetCurrentDirectory(MSG_SIZ, dir);
\r
960 SetCurrentDirectory(installDir);
\r
961 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
962 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
963 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
964 if(userLogo == NULL)
\r
965 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
966 SetCurrentDirectory(dir); /* return to prev directory */
\r
972 InitApplication(HINSTANCE hInstance)
\r
976 /* Fill in window class structure with parameters that describe the */
\r
979 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
980 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
981 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
982 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
983 wc.hInstance = hInstance; /* Owner of this class */
\r
984 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
985 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
986 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
987 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
988 wc.lpszClassName = szAppName; /* Name to register as */
\r
990 /* Register the window class and return success/failure code. */
\r
991 if (!RegisterClass(&wc)) return FALSE;
\r
993 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
994 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
996 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
997 wc.hInstance = hInstance;
\r
998 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
999 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1000 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1001 wc.lpszMenuName = NULL;
\r
1002 wc.lpszClassName = szConsoleName;
\r
1004 if (!RegisterClass(&wc)) return FALSE;
\r
1009 /* Set by InitInstance, used by EnsureOnScreen */
\r
1010 int screenHeight, screenWidth;
\r
1011 RECT screenGeometry;
\r
1014 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1016 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1017 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1018 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1019 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1020 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1021 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1025 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1027 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1028 GetCurrentDirectory(MSG_SIZ, dir);
\r
1029 SetCurrentDirectory(installDir);
\r
1030 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1031 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1033 if (cps->programLogo == NULL && appData.debugMode) {
\r
1034 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1036 } else if(appData.autoLogo) {
\r
1037 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1038 char *opponent = "";
\r
1039 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1040 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1041 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1042 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1043 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1044 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1047 if(appData.directory[n] && appData.directory[n][0]) {
\r
1048 SetCurrentDirectory(appData.directory[n]);
\r
1049 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1052 SetCurrentDirectory(dir); /* return to prev directory */
\r
1058 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1059 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1061 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1062 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1063 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1064 liteBackTextureMode = appData.liteBackTextureMode;
\r
1066 if (liteBackTexture == NULL && appData.debugMode) {
\r
1067 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1071 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1072 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1073 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1074 darkBackTextureMode = appData.darkBackTextureMode;
\r
1076 if (darkBackTexture == NULL && appData.debugMode) {
\r
1077 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1082 #ifndef SM_CXVIRTUALSCREEN
\r
1083 #define SM_CXVIRTUALSCREEN 78
\r
1085 #ifndef SM_CYVIRTUALSCREEN
\r
1086 #define SM_CYVIRTUALSCREEN 79
\r
1088 #ifndef SM_XVIRTUALSCREEN
\r
1089 #define SM_XVIRTUALSCREEN 76
\r
1091 #ifndef SM_YVIRTUALSCREEN
\r
1092 #define SM_YVIRTUALSCREEN 77
\r
1098 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1099 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1100 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1101 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1102 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1103 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1104 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1105 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1109 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1111 HWND hwnd; /* Main window handle. */
\r
1113 WINDOWPLACEMENT wp;
\r
1116 hInst = hInstance; /* Store instance handle in our global variable */
\r
1117 programName = szAppName;
\r
1119 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1120 *filepart = NULLCHAR;
\r
1121 SetCurrentDirectory(installDir);
\r
1123 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1125 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1127 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1128 /* xboard, and older WinBoards, controlled the move sound with the
\r
1129 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1130 always turn the option on (so that the backend will call us),
\r
1131 then let the user turn the sound off by setting it to silence if
\r
1132 desired. To accommodate old winboard.ini files saved by old
\r
1133 versions of WinBoard, we also turn off the sound if the option
\r
1134 was initially set to false. [HGM] taken out of InitAppData */
\r
1135 if (!appData.ringBellAfterMoves) {
\r
1136 sounds[(int)SoundMove].name = strdup("");
\r
1137 appData.ringBellAfterMoves = TRUE;
\r
1139 if (appData.debugMode) {
\r
1140 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1141 setbuf(debugFP, NULL);
\r
1144 LoadLanguageFile(appData.language);
\r
1148 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1149 // InitEngineUCI( installDir, &second );
\r
1151 /* Create a main window for this application instance. */
\r
1152 hwnd = CreateWindow(szAppName, szTitle,
\r
1153 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1154 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1155 NULL, NULL, hInstance, NULL);
\r
1158 /* If window could not be created, return "failure" */
\r
1163 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1164 LoadLogo(&first, 0, FALSE);
\r
1165 LoadLogo(&second, 1, appData.icsActive);
\r
1169 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1170 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1171 iconCurrent = iconWhite;
\r
1172 InitDrawingColors();
\r
1174 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1175 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1176 /* Compute window size for each board size, and use the largest
\r
1177 size that fits on this screen as the default. */
\r
1178 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1179 if (boardSize == (BoardSize)-1 &&
\r
1180 winH <= screenHeight
\r
1181 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1182 && winW <= screenWidth) {
\r
1183 boardSize = (BoardSize)ibs;
\r
1187 InitDrawingSizes(boardSize, 0);
\r
1188 RecentEngineMenu(appData.recentEngineList);
\r
1190 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1192 /* [AS] Load textures if specified */
\r
1195 mysrandom( (unsigned) time(NULL) );
\r
1197 /* [AS] Restore layout */
\r
1198 if( wpMoveHistory.visible ) {
\r
1199 MoveHistoryPopUp();
\r
1202 if( wpEvalGraph.visible ) {
\r
1206 if( wpEngineOutput.visible ) {
\r
1207 EngineOutputPopUp();
\r
1210 /* Make the window visible; update its client area; and return "success" */
\r
1211 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1212 wp.length = sizeof(WINDOWPLACEMENT);
\r
1214 wp.showCmd = nCmdShow;
\r
1215 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1216 wp.rcNormalPosition.left = wpMain.x;
\r
1217 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1218 wp.rcNormalPosition.top = wpMain.y;
\r
1219 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1220 SetWindowPlacement(hwndMain, &wp);
\r
1222 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1224 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1225 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1227 if (hwndConsole) {
\r
1229 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1230 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1232 ShowWindow(hwndConsole, nCmdShow);
\r
1233 SetActiveWindow(hwndConsole);
\r
1235 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1236 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1245 HMENU hmenu = GetMenu(hwndMain);
\r
1247 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1248 MF_BYCOMMAND|((appData.icsActive &&
\r
1249 *appData.icsCommPort != NULLCHAR) ?
\r
1250 MF_ENABLED : MF_GRAYED));
\r
1251 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1252 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1253 MF_CHECKED : MF_UNCHECKED));
\r
1254 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1257 //---------------------------------------------------------------------------------------------------------
\r
1259 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1260 #define XBOARD FALSE
\r
1262 #define OPTCHAR "/"
\r
1263 #define SEPCHAR "="
\r
1264 #define TOPLEVEL 0
\r
1268 // front-end part of option handling
\r
1271 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1273 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1274 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1277 lf->lfEscapement = 0;
\r
1278 lf->lfOrientation = 0;
\r
1279 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1280 lf->lfItalic = mfp->italic;
\r
1281 lf->lfUnderline = mfp->underline;
\r
1282 lf->lfStrikeOut = mfp->strikeout;
\r
1283 lf->lfCharSet = mfp->charset;
\r
1284 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1287 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1288 lf->lfQuality = DEFAULT_QUALITY;
\r
1289 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1290 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1294 CreateFontInMF(MyFont *mf)
\r
1296 LFfromMFP(&mf->lf, &mf->mfp);
\r
1297 if (mf->hf) DeleteObject(mf->hf);
\r
1298 mf->hf = CreateFontIndirect(&mf->lf);
\r
1301 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1303 colorVariable[] = {
\r
1304 &whitePieceColor,
\r
1305 &blackPieceColor,
\r
1306 &lightSquareColor,
\r
1307 &darkSquareColor,
\r
1308 &highlightSquareColor,
\r
1309 &premoveHighlightColor,
\r
1311 &consoleBackgroundColor,
\r
1312 &appData.fontForeColorWhite,
\r
1313 &appData.fontBackColorWhite,
\r
1314 &appData.fontForeColorBlack,
\r
1315 &appData.fontBackColorBlack,
\r
1316 &appData.evalHistColorWhite,
\r
1317 &appData.evalHistColorBlack,
\r
1318 &appData.highlightArrowColor,
\r
1321 /* Command line font name parser. NULL name means do nothing.
\r
1322 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1323 For backward compatibility, syntax without the colon is also
\r
1324 accepted, but font names with digits in them won't work in that case.
\r
1327 ParseFontName(char *name, MyFontParams *mfp)
\r
1330 if (name == NULL) return;
\r
1332 q = strchr(p, ':');
\r
1334 if (q - p >= sizeof(mfp->faceName))
\r
1335 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1336 memcpy(mfp->faceName, p, q - p);
\r
1337 mfp->faceName[q - p] = NULLCHAR;
\r
1340 q = mfp->faceName;
\r
1342 while (*p && !isdigit(*p)) {
\r
1344 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1345 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1347 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1350 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1351 mfp->pointSize = (float) atof(p);
\r
1352 mfp->bold = (strchr(p, 'b') != NULL);
\r
1353 mfp->italic = (strchr(p, 'i') != NULL);
\r
1354 mfp->underline = (strchr(p, 'u') != NULL);
\r
1355 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1356 mfp->charset = DEFAULT_CHARSET;
\r
1357 q = strchr(p, 'c');
\r
1359 mfp->charset = (BYTE) atoi(q+1);
\r
1363 ParseFont(char *name, int number)
\r
1364 { // wrapper to shield back-end from 'font'
\r
1365 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1370 { // in WB we have a 2D array of fonts; this initializes their description
\r
1372 /* Point font array elements to structures and
\r
1373 parse default font names */
\r
1374 for (i=0; i<NUM_FONTS; i++) {
\r
1375 for (j=0; j<NUM_SIZES; j++) {
\r
1376 font[j][i] = &fontRec[j][i];
\r
1377 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1384 { // here we create the actual fonts from the selected descriptions
\r
1386 for (i=0; i<NUM_FONTS; i++) {
\r
1387 for (j=0; j<NUM_SIZES; j++) {
\r
1388 CreateFontInMF(font[j][i]);
\r
1392 /* Color name parser.
\r
1393 X version accepts X color names, but this one
\r
1394 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1396 ParseColorName(char *name)
\r
1398 int red, green, blue, count;
\r
1399 char buf[MSG_SIZ];
\r
1401 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1403 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1404 &red, &green, &blue);
\r
1407 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1408 DisplayError(buf, 0);
\r
1409 return RGB(0, 0, 0);
\r
1411 return PALETTERGB(red, green, blue);
\r
1415 ParseColor(int n, char *name)
\r
1416 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1417 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1421 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1423 char *e = argValue;
\r
1427 if (*e == 'b') eff |= CFE_BOLD;
\r
1428 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1429 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1430 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1431 else if (*e == '#' || isdigit(*e)) break;
\r
1435 *color = ParseColorName(e);
\r
1439 ParseTextAttribs(ColorClass cc, char *s)
\r
1440 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1441 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1442 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1446 ParseBoardSize(void *addr, char *name)
\r
1447 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1448 BoardSize bs = SizeTiny;
\r
1449 while (sizeInfo[bs].name != NULL) {
\r
1450 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1451 *(BoardSize *)addr = bs;
\r
1456 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1461 { // [HGM] import name from appData first
\r
1464 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1465 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1466 textAttribs[cc].sound.data = NULL;
\r
1467 MyLoadSound(&textAttribs[cc].sound);
\r
1469 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1470 textAttribs[cc].sound.name = strdup("");
\r
1471 textAttribs[cc].sound.data = NULL;
\r
1473 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1474 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1475 sounds[sc].data = NULL;
\r
1476 MyLoadSound(&sounds[sc]);
\r
1481 SetCommPortDefaults()
\r
1483 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1484 dcb.DCBlength = sizeof(DCB);
\r
1485 dcb.BaudRate = 9600;
\r
1486 dcb.fBinary = TRUE;
\r
1487 dcb.fParity = FALSE;
\r
1488 dcb.fOutxCtsFlow = FALSE;
\r
1489 dcb.fOutxDsrFlow = FALSE;
\r
1490 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1491 dcb.fDsrSensitivity = FALSE;
\r
1492 dcb.fTXContinueOnXoff = TRUE;
\r
1493 dcb.fOutX = FALSE;
\r
1495 dcb.fNull = FALSE;
\r
1496 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1497 dcb.fAbortOnError = FALSE;
\r
1499 dcb.Parity = SPACEPARITY;
\r
1500 dcb.StopBits = ONESTOPBIT;
\r
1503 // [HGM] args: these three cases taken out to stay in front-end
\r
1505 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1506 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1507 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1508 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1510 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1511 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1512 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1513 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1514 ad->argName, mfp->faceName, mfp->pointSize,
\r
1515 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1516 mfp->bold ? "b" : "",
\r
1517 mfp->italic ? "i" : "",
\r
1518 mfp->underline ? "u" : "",
\r
1519 mfp->strikeout ? "s" : "",
\r
1520 (int)mfp->charset);
\r
1526 { // [HGM] copy the names from the internal WB variables to appData
\r
1529 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1530 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1531 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1532 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1536 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1537 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1538 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1539 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1540 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1541 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1542 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1543 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1544 (ta->effects) ? " " : "",
\r
1545 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1549 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1550 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1551 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1552 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1553 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1557 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1558 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1559 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1563 ParseCommPortSettings(char *s)
\r
1564 { // wrapper to keep dcb from back-end
\r
1565 ParseCommSettings(s, &dcb);
\r
1570 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1571 GetActualPlacement(hwndMain, &wpMain);
\r
1572 GetActualPlacement(hwndConsole, &wpConsole);
\r
1573 GetActualPlacement(commentDialog, &wpComment);
\r
1574 GetActualPlacement(editTagsDialog, &wpTags);
\r
1575 GetActualPlacement(gameListDialog, &wpGameList);
\r
1576 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1577 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1578 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1582 PrintCommPortSettings(FILE *f, char *name)
\r
1583 { // wrapper to shield back-end from DCB
\r
1584 PrintCommSettings(f, name, &dcb);
\r
1588 MySearchPath(char *installDir, char *name, char *fullname)
\r
1590 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1591 if(name[0]== '%') {
\r
1592 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1593 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1594 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1595 *strchr(buf, '%') = 0;
\r
1596 strcat(fullname, getenv(buf));
\r
1597 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1599 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1600 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1601 return (int) strlen(fullname);
\r
1603 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1607 MyGetFullPathName(char *name, char *fullname)
\r
1610 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1615 { // [HGM] args: allows testing if main window is realized from back-end
\r
1616 return hwndMain != NULL;
\r
1620 PopUpStartupDialog()
\r
1624 LoadLanguageFile(appData.language);
\r
1625 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1626 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1627 FreeProcInstance(lpProc);
\r
1630 /*---------------------------------------------------------------------------*\
\r
1632 * GDI board drawing routines
\r
1634 \*---------------------------------------------------------------------------*/
\r
1636 /* [AS] Draw square using background texture */
\r
1637 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1642 return; /* Should never happen! */
\r
1645 SetGraphicsMode( dst, GM_ADVANCED );
\r
1652 /* X reflection */
\r
1657 x.eDx = (FLOAT) dw + dx - 1;
\r
1660 SetWorldTransform( dst, &x );
\r
1663 /* Y reflection */
\r
1669 x.eDy = (FLOAT) dh + dy - 1;
\r
1671 SetWorldTransform( dst, &x );
\r
1679 x.eDx = (FLOAT) dx;
\r
1680 x.eDy = (FLOAT) dy;
\r
1683 SetWorldTransform( dst, &x );
\r
1687 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1695 SetWorldTransform( dst, &x );
\r
1697 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1700 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1702 PM_WP = (int) WhitePawn,
\r
1703 PM_WN = (int) WhiteKnight,
\r
1704 PM_WB = (int) WhiteBishop,
\r
1705 PM_WR = (int) WhiteRook,
\r
1706 PM_WQ = (int) WhiteQueen,
\r
1707 PM_WF = (int) WhiteFerz,
\r
1708 PM_WW = (int) WhiteWazir,
\r
1709 PM_WE = (int) WhiteAlfil,
\r
1710 PM_WM = (int) WhiteMan,
\r
1711 PM_WO = (int) WhiteCannon,
\r
1712 PM_WU = (int) WhiteUnicorn,
\r
1713 PM_WH = (int) WhiteNightrider,
\r
1714 PM_WA = (int) WhiteAngel,
\r
1715 PM_WC = (int) WhiteMarshall,
\r
1716 PM_WAB = (int) WhiteCardinal,
\r
1717 PM_WD = (int) WhiteDragon,
\r
1718 PM_WL = (int) WhiteLance,
\r
1719 PM_WS = (int) WhiteCobra,
\r
1720 PM_WV = (int) WhiteFalcon,
\r
1721 PM_WSG = (int) WhiteSilver,
\r
1722 PM_WG = (int) WhiteGrasshopper,
\r
1723 PM_WK = (int) WhiteKing,
\r
1724 PM_BP = (int) BlackPawn,
\r
1725 PM_BN = (int) BlackKnight,
\r
1726 PM_BB = (int) BlackBishop,
\r
1727 PM_BR = (int) BlackRook,
\r
1728 PM_BQ = (int) BlackQueen,
\r
1729 PM_BF = (int) BlackFerz,
\r
1730 PM_BW = (int) BlackWazir,
\r
1731 PM_BE = (int) BlackAlfil,
\r
1732 PM_BM = (int) BlackMan,
\r
1733 PM_BO = (int) BlackCannon,
\r
1734 PM_BU = (int) BlackUnicorn,
\r
1735 PM_BH = (int) BlackNightrider,
\r
1736 PM_BA = (int) BlackAngel,
\r
1737 PM_BC = (int) BlackMarshall,
\r
1738 PM_BG = (int) BlackGrasshopper,
\r
1739 PM_BAB = (int) BlackCardinal,
\r
1740 PM_BD = (int) BlackDragon,
\r
1741 PM_BL = (int) BlackLance,
\r
1742 PM_BS = (int) BlackCobra,
\r
1743 PM_BV = (int) BlackFalcon,
\r
1744 PM_BSG = (int) BlackSilver,
\r
1745 PM_BK = (int) BlackKing
\r
1748 static HFONT hPieceFont = NULL;
\r
1749 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1750 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1751 static int fontBitmapSquareSize = 0;
\r
1752 static char pieceToFontChar[(int) EmptySquare] =
\r
1753 { 'p', 'n', 'b', 'r', 'q',
\r
1754 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1755 'k', 'o', 'm', 'v', 't', 'w',
\r
1756 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1759 extern BOOL SetCharTable( char *table, const char * map );
\r
1760 /* [HGM] moved to backend.c */
\r
1762 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1765 BYTE r1 = GetRValue( color );
\r
1766 BYTE g1 = GetGValue( color );
\r
1767 BYTE b1 = GetBValue( color );
\r
1773 /* Create a uniform background first */
\r
1774 hbrush = CreateSolidBrush( color );
\r
1775 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1776 FillRect( hdc, &rc, hbrush );
\r
1777 DeleteObject( hbrush );
\r
1780 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1781 int steps = squareSize / 2;
\r
1784 for( i=0; i<steps; i++ ) {
\r
1785 BYTE r = r1 - (r1-r2) * i / steps;
\r
1786 BYTE g = g1 - (g1-g2) * i / steps;
\r
1787 BYTE b = b1 - (b1-b2) * i / steps;
\r
1789 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1790 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1791 FillRect( hdc, &rc, hbrush );
\r
1792 DeleteObject(hbrush);
\r
1795 else if( mode == 2 ) {
\r
1796 /* Diagonal gradient, good more or less for every piece */
\r
1797 POINT triangle[3];
\r
1798 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1799 HBRUSH hbrush_old;
\r
1800 int steps = squareSize;
\r
1803 triangle[0].x = squareSize - steps;
\r
1804 triangle[0].y = squareSize;
\r
1805 triangle[1].x = squareSize;
\r
1806 triangle[1].y = squareSize;
\r
1807 triangle[2].x = squareSize;
\r
1808 triangle[2].y = squareSize - steps;
\r
1810 for( i=0; i<steps; i++ ) {
\r
1811 BYTE r = r1 - (r1-r2) * i / steps;
\r
1812 BYTE g = g1 - (g1-g2) * i / steps;
\r
1813 BYTE b = b1 - (b1-b2) * i / steps;
\r
1815 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1816 hbrush_old = SelectObject( hdc, hbrush );
\r
1817 Polygon( hdc, triangle, 3 );
\r
1818 SelectObject( hdc, hbrush_old );
\r
1819 DeleteObject(hbrush);
\r
1824 SelectObject( hdc, hpen );
\r
1829 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1830 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1831 piece: follow the steps as explained below.
\r
1833 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1837 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1843 int backColor = whitePieceColor;
\r
1844 int foreColor = blackPieceColor;
\r
1846 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1847 backColor = appData.fontBackColorWhite;
\r
1848 foreColor = appData.fontForeColorWhite;
\r
1850 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1851 backColor = appData.fontBackColorBlack;
\r
1852 foreColor = appData.fontForeColorBlack;
\r
1856 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1858 hbm_old = SelectObject( hdc, hbm );
\r
1862 rc.right = squareSize;
\r
1863 rc.bottom = squareSize;
\r
1865 /* Step 1: background is now black */
\r
1866 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1868 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1870 pt.x = (squareSize - sz.cx) / 2;
\r
1871 pt.y = (squareSize - sz.cy) / 2;
\r
1873 SetBkMode( hdc, TRANSPARENT );
\r
1874 SetTextColor( hdc, chroma );
\r
1875 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1876 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1878 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1879 /* Step 3: the area outside the piece is filled with white */
\r
1880 // FloodFill( hdc, 0, 0, chroma );
\r
1881 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1882 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1883 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1884 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1885 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1887 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1888 but if the start point is not inside the piece we're lost!
\r
1889 There should be a better way to do this... if we could create a region or path
\r
1890 from the fill operation we would be fine for example.
\r
1892 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1893 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1895 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1896 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1897 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1899 SelectObject( dc2, bm2 );
\r
1900 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1901 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1902 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1903 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1904 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1907 DeleteObject( bm2 );
\r
1910 SetTextColor( hdc, 0 );
\r
1912 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1913 draw the piece again in black for safety.
\r
1915 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1917 SelectObject( hdc, hbm_old );
\r
1919 if( hPieceMask[index] != NULL ) {
\r
1920 DeleteObject( hPieceMask[index] );
\r
1923 hPieceMask[index] = hbm;
\r
1926 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1928 SelectObject( hdc, hbm );
\r
1931 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1932 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1933 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1935 SelectObject( dc1, hPieceMask[index] );
\r
1936 SelectObject( dc2, bm2 );
\r
1937 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1938 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1941 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1942 the piece background and deletes (makes transparent) the rest.
\r
1943 Thanks to that mask, we are free to paint the background with the greates
\r
1944 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1945 We use this, to make gradients and give the pieces a "roundish" look.
\r
1947 SetPieceBackground( hdc, backColor, 2 );
\r
1948 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1952 DeleteObject( bm2 );
\r
1955 SetTextColor( hdc, foreColor );
\r
1956 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1958 SelectObject( hdc, hbm_old );
\r
1960 if( hPieceFace[index] != NULL ) {
\r
1961 DeleteObject( hPieceFace[index] );
\r
1964 hPieceFace[index] = hbm;
\r
1967 static int TranslatePieceToFontPiece( int piece )
\r
1997 case BlackMarshall:
\r
2001 case BlackNightrider:
\r
2007 case BlackUnicorn:
\r
2011 case BlackGrasshopper:
\r
2023 case BlackCardinal:
\r
2030 case WhiteMarshall:
\r
2034 case WhiteNightrider:
\r
2040 case WhiteUnicorn:
\r
2044 case WhiteGrasshopper:
\r
2056 case WhiteCardinal:
\r
2065 void CreatePiecesFromFont()
\r
2068 HDC hdc_window = NULL;
\r
2074 if( fontBitmapSquareSize < 0 ) {
\r
2075 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2079 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2080 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2081 fontBitmapSquareSize = -1;
\r
2085 if( fontBitmapSquareSize != squareSize ) {
\r
2086 hdc_window = GetDC( hwndMain );
\r
2087 hdc = CreateCompatibleDC( hdc_window );
\r
2089 if( hPieceFont != NULL ) {
\r
2090 DeleteObject( hPieceFont );
\r
2093 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2094 hPieceMask[i] = NULL;
\r
2095 hPieceFace[i] = NULL;
\r
2101 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2102 fontHeight = appData.fontPieceSize;
\r
2105 fontHeight = (fontHeight * squareSize) / 100;
\r
2107 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2109 lf.lfEscapement = 0;
\r
2110 lf.lfOrientation = 0;
\r
2111 lf.lfWeight = FW_NORMAL;
\r
2113 lf.lfUnderline = 0;
\r
2114 lf.lfStrikeOut = 0;
\r
2115 lf.lfCharSet = DEFAULT_CHARSET;
\r
2116 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2117 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2118 lf.lfQuality = PROOF_QUALITY;
\r
2119 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2120 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2121 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2123 hPieceFont = CreateFontIndirect( &lf );
\r
2125 if( hPieceFont == NULL ) {
\r
2126 fontBitmapSquareSize = -2;
\r
2129 /* Setup font-to-piece character table */
\r
2130 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2131 /* No (or wrong) global settings, try to detect the font */
\r
2132 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2134 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2136 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2137 /* DiagramTT* family */
\r
2138 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2140 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2141 /* Fairy symbols */
\r
2142 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2144 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2145 /* Good Companion (Some characters get warped as literal :-( */
\r
2146 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2147 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2148 SetCharTable(pieceToFontChar, s);
\r
2151 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2152 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2156 /* Create bitmaps */
\r
2157 hfont_old = SelectObject( hdc, hPieceFont );
\r
2158 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2159 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2160 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2162 SelectObject( hdc, hfont_old );
\r
2164 fontBitmapSquareSize = squareSize;
\r
2168 if( hdc != NULL ) {
\r
2172 if( hdc_window != NULL ) {
\r
2173 ReleaseDC( hwndMain, hdc_window );
\r
2178 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2180 char name[128], buf[MSG_SIZ];
\r
2182 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2183 if(appData.pieceDirectory[0]) {
\r
2185 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2186 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2187 if(res) return res;
\r
2189 if (gameInfo.event &&
\r
2190 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2191 strcmp(name, "k80s") == 0) {
\r
2192 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2194 return LoadBitmap(hinst, name);
\r
2198 /* Insert a color into the program's logical palette
\r
2199 structure. This code assumes the given color is
\r
2200 the result of the RGB or PALETTERGB macro, and it
\r
2201 knows how those macros work (which is documented).
\r
2204 InsertInPalette(COLORREF color)
\r
2206 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2208 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2209 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2210 pLogPal->palNumEntries--;
\r
2214 pe->peFlags = (char) 0;
\r
2215 pe->peRed = (char) (0xFF & color);
\r
2216 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2217 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2223 InitDrawingColors()
\r
2226 if (pLogPal == NULL) {
\r
2227 /* Allocate enough memory for a logical palette with
\r
2228 * PALETTESIZE entries and set the size and version fields
\r
2229 * of the logical palette structure.
\r
2231 pLogPal = (NPLOGPALETTE)
\r
2232 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2233 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2234 pLogPal->palVersion = 0x300;
\r
2236 pLogPal->palNumEntries = 0;
\r
2238 InsertInPalette(lightSquareColor);
\r
2239 InsertInPalette(darkSquareColor);
\r
2240 InsertInPalette(whitePieceColor);
\r
2241 InsertInPalette(blackPieceColor);
\r
2242 InsertInPalette(highlightSquareColor);
\r
2243 InsertInPalette(premoveHighlightColor);
\r
2245 /* create a logical color palette according the information
\r
2246 * in the LOGPALETTE structure.
\r
2248 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2250 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2251 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2252 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2253 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2254 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2255 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2256 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2257 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2259 /* [AS] Force rendering of the font-based pieces */
\r
2260 if( fontBitmapSquareSize > 0 ) {
\r
2261 fontBitmapSquareSize = 0;
\r
2267 BoardWidth(int boardSize, int n)
\r
2268 { /* [HGM] argument n added to allow different width and height */
\r
2269 int lineGap = sizeInfo[boardSize].lineGap;
\r
2271 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2272 lineGap = appData.overrideLineGap;
\r
2275 return (n + 1) * lineGap +
\r
2276 n * sizeInfo[boardSize].squareSize;
\r
2279 /* Respond to board resize by dragging edge */
\r
2281 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2283 BoardSize newSize = NUM_SIZES - 1;
\r
2284 static int recurse = 0;
\r
2285 if (IsIconic(hwndMain)) return;
\r
2286 if (recurse > 0) return;
\r
2288 while (newSize > 0) {
\r
2289 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2290 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2291 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2294 boardSize = newSize;
\r
2295 InitDrawingSizes(boardSize, flags);
\r
2300 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2303 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2305 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2306 ChessSquare piece;
\r
2307 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2309 SIZE clockSize, messageSize;
\r
2311 char buf[MSG_SIZ];
\r
2313 HMENU hmenu = GetMenu(hwndMain);
\r
2314 RECT crect, wrect, oldRect;
\r
2316 LOGBRUSH logbrush;
\r
2317 VariantClass v = gameInfo.variant;
\r
2319 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2320 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2322 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2323 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2324 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2325 oldBoardSize = boardSize;
\r
2327 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2328 { // correct board size to one where built-in pieces exist
\r
2329 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2330 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2332 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2333 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2334 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2335 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2336 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2337 boardSize = SizeMiddling;
\r
2340 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2342 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2343 oldRect.top = wpMain.y;
\r
2344 oldRect.right = wpMain.x + wpMain.width;
\r
2345 oldRect.bottom = wpMain.y + wpMain.height;
\r
2347 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2348 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2349 squareSize = sizeInfo[boardSize].squareSize;
\r
2350 lineGap = sizeInfo[boardSize].lineGap;
\r
2351 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2352 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2354 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2355 lineGap = appData.overrideLineGap;
\r
2358 if (tinyLayout != oldTinyLayout) {
\r
2359 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2361 style &= ~WS_SYSMENU;
\r
2362 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2363 "&Minimize\tCtrl+F4");
\r
2365 style |= WS_SYSMENU;
\r
2366 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2368 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2370 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2371 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2372 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2374 DrawMenuBar(hwndMain);
\r
2377 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2378 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2380 /* Get text area sizes */
\r
2381 hdc = GetDC(hwndMain);
\r
2382 if (appData.clockMode) {
\r
2383 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2385 snprintf(buf, MSG_SIZ, _("White"));
\r
2387 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2388 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2389 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2390 str = _("We only care about the height here");
\r
2391 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2392 SelectObject(hdc, oldFont);
\r
2393 ReleaseDC(hwndMain, hdc);
\r
2395 /* Compute where everything goes */
\r
2396 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2397 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2398 logoHeight = 2*clockSize.cy;
\r
2399 leftLogoRect.left = OUTER_MARGIN;
\r
2400 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2401 leftLogoRect.top = OUTER_MARGIN;
\r
2402 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2404 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2405 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2406 rightLogoRect.top = OUTER_MARGIN;
\r
2407 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2410 whiteRect.left = leftLogoRect.right;
\r
2411 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2412 whiteRect.top = OUTER_MARGIN;
\r
2413 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2415 blackRect.right = rightLogoRect.left;
\r
2416 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2417 blackRect.top = whiteRect.top;
\r
2418 blackRect.bottom = whiteRect.bottom;
\r
2420 whiteRect.left = OUTER_MARGIN;
\r
2421 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2422 whiteRect.top = OUTER_MARGIN;
\r
2423 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2425 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2426 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2427 blackRect.top = whiteRect.top;
\r
2428 blackRect.bottom = whiteRect.bottom;
\r
2430 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2433 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2434 if (appData.showButtonBar) {
\r
2435 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2436 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2438 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2440 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2441 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2443 boardRect.left = OUTER_MARGIN;
\r
2444 boardRect.right = boardRect.left + boardWidth;
\r
2445 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2446 boardRect.bottom = boardRect.top + boardHeight;
\r
2448 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2449 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2450 oldTinyLayout = tinyLayout;
\r
2451 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2452 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2453 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2454 winW *= 1 + twoBoards;
\r
2455 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2456 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2457 wpMain.height = winH; // without disturbing window attachments
\r
2458 GetWindowRect(hwndMain, &wrect);
\r
2459 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2460 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2462 // [HGM] placement: let attached windows follow size change.
\r
2463 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2464 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2465 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2466 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2467 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2469 /* compensate if menu bar wrapped */
\r
2470 GetClientRect(hwndMain, &crect);
\r
2471 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2472 wpMain.height += offby;
\r
2474 case WMSZ_TOPLEFT:
\r
2475 SetWindowPos(hwndMain, NULL,
\r
2476 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2477 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2480 case WMSZ_TOPRIGHT:
\r
2482 SetWindowPos(hwndMain, NULL,
\r
2483 wrect.left, wrect.bottom - wpMain.height,
\r
2484 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2487 case WMSZ_BOTTOMLEFT:
\r
2489 SetWindowPos(hwndMain, NULL,
\r
2490 wrect.right - wpMain.width, wrect.top,
\r
2491 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2494 case WMSZ_BOTTOMRIGHT:
\r
2498 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2499 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2504 for (i = 0; i < N_BUTTONS; i++) {
\r
2505 if (buttonDesc[i].hwnd != NULL) {
\r
2506 DestroyWindow(buttonDesc[i].hwnd);
\r
2507 buttonDesc[i].hwnd = NULL;
\r
2509 if (appData.showButtonBar) {
\r
2510 buttonDesc[i].hwnd =
\r
2511 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2512 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2513 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2514 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2515 (HMENU) buttonDesc[i].id,
\r
2516 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2518 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2519 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2520 MAKELPARAM(FALSE, 0));
\r
2522 if (buttonDesc[i].id == IDM_Pause)
\r
2523 hwndPause = buttonDesc[i].hwnd;
\r
2524 buttonDesc[i].wndproc = (WNDPROC)
\r
2525 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2528 if (gridPen != NULL) DeleteObject(gridPen);
\r
2529 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2530 if (premovePen != NULL) DeleteObject(premovePen);
\r
2531 if (lineGap != 0) {
\r
2532 logbrush.lbStyle = BS_SOLID;
\r
2533 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2535 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2536 lineGap, &logbrush, 0, NULL);
\r
2537 logbrush.lbColor = highlightSquareColor;
\r
2539 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2540 lineGap, &logbrush, 0, NULL);
\r
2542 logbrush.lbColor = premoveHighlightColor;
\r
2544 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2545 lineGap, &logbrush, 0, NULL);
\r
2547 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2548 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2549 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2550 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2551 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2552 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2553 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2554 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2556 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2557 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2558 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2559 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2560 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2561 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2562 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2563 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2567 /* [HGM] Licensing requirement */
\r
2569 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2572 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2574 GothicPopUp( "", VariantNormal);
\r
2577 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2579 /* Load piece bitmaps for this board size */
\r
2580 for (i=0; i<=2; i++) {
\r
2581 for (piece = WhitePawn;
\r
2582 (int) piece < (int) BlackPawn;
\r
2583 piece = (ChessSquare) ((int) piece + 1)) {
\r
2584 if (pieceBitmap[i][piece] != NULL)
\r
2585 DeleteObject(pieceBitmap[i][piece]);
\r
2589 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2590 // Orthodox Chess pieces
\r
2591 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2592 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2593 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2594 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2595 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2596 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2597 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2598 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2599 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2600 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2601 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2602 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2603 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2604 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2605 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2606 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2607 // in Shogi, Hijack the unused Queen for Lance
\r
2608 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2609 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2610 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2612 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2613 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2614 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2617 if(squareSize <= 72 && squareSize >= 33) {
\r
2618 /* A & C are available in most sizes now */
\r
2619 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2620 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2621 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2622 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2623 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2624 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2625 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2626 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2627 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2628 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2629 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2630 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2631 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2632 } else { // Smirf-like
\r
2633 if(gameInfo.variant == VariantSChess) {
\r
2634 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2635 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2636 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2638 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2639 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2640 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2643 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2644 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2647 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2648 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2651 } else { // WinBoard standard
\r
2652 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2653 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2654 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2659 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2660 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2663 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2664 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2665 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2666 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2667 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2668 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2669 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2670 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2671 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2672 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2673 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2674 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2675 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2676 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2677 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2678 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2679 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2680 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2681 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2682 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2683 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2684 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2685 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2686 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2687 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2688 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2689 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2690 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2691 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2692 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2694 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2695 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2696 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2697 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2698 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2699 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2700 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2701 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2702 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2703 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2704 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2705 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2706 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2708 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2709 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2710 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2711 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2712 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2713 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2714 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2715 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2716 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2717 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2718 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2719 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2722 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2723 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2724 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2725 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2726 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2727 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2728 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2729 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2730 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2731 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2732 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2733 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2734 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2735 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2736 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2740 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2741 /* special Shogi support in this size */
\r
2742 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2743 for (piece = WhitePawn;
\r
2744 (int) piece < (int) BlackPawn;
\r
2745 piece = (ChessSquare) ((int) piece + 1)) {
\r
2746 if (pieceBitmap[i][piece] != NULL)
\r
2747 DeleteObject(pieceBitmap[i][piece]);
\r
2750 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2751 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2752 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2753 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2754 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2755 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2756 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2757 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2758 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2762 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2763 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2764 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2765 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2766 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2767 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2768 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2769 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2770 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2771 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2772 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2776 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2777 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2778 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2779 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2780 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2781 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2782 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2783 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2784 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2785 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2786 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2790 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2791 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2797 PieceBitmap(ChessSquare p, int kind)
\r
2799 if ((int) p >= (int) BlackPawn)
\r
2800 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2802 return pieceBitmap[kind][(int) p];
\r
2805 /***************************************************************/
\r
2807 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2808 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2810 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2811 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2815 SquareToPos(int row, int column, int * x, int * y)
\r
2818 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2819 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2821 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2822 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2827 DrawCoordsOnDC(HDC hdc)
\r
2829 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2830 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2831 char str[2] = { NULLCHAR, NULLCHAR };
\r
2832 int oldMode, oldAlign, x, y, start, i;
\r
2836 if (!appData.showCoords)
\r
2839 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2841 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2842 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2843 oldAlign = GetTextAlign(hdc);
\r
2844 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2846 y = boardRect.top + lineGap;
\r
2847 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2850 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2851 x += border - lineGap - 4; y += squareSize - 6;
\r
2853 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2854 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2855 str[0] = files[start + i];
\r
2856 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2857 y += squareSize + lineGap;
\r
2860 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2863 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2864 x += -border + 4; y += border - squareSize + 6;
\r
2866 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2867 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2868 str[0] = ranks[start + i];
\r
2869 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2870 x += squareSize + lineGap;
\r
2873 SelectObject(hdc, oldBrush);
\r
2874 SetBkMode(hdc, oldMode);
\r
2875 SetTextAlign(hdc, oldAlign);
\r
2876 SelectObject(hdc, oldFont);
\r
2880 DrawGridOnDC(HDC hdc)
\r
2884 if (lineGap != 0) {
\r
2885 oldPen = SelectObject(hdc, gridPen);
\r
2886 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2887 SelectObject(hdc, oldPen);
\r
2891 #define HIGHLIGHT_PEN 0
\r
2892 #define PREMOVE_PEN 1
\r
2895 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2898 HPEN oldPen, hPen;
\r
2899 if (lineGap == 0) return;
\r
2901 x1 = boardRect.left +
\r
2902 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2903 y1 = boardRect.top +
\r
2904 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2906 x1 = boardRect.left +
\r
2907 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2908 y1 = boardRect.top +
\r
2909 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2911 hPen = pen ? premovePen : highlightPen;
\r
2912 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2913 MoveToEx(hdc, x1, y1, NULL);
\r
2914 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2915 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2916 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2917 LineTo(hdc, x1, y1);
\r
2918 SelectObject(hdc, oldPen);
\r
2922 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2925 for (i=0; i<2; i++) {
\r
2926 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2927 DrawHighlightOnDC(hdc, TRUE,
\r
2928 h->sq[i].x, h->sq[i].y,
\r
2933 /* Note: sqcolor is used only in monoMode */
\r
2934 /* Note that this code is largely duplicated in woptions.c,
\r
2935 function DrawSampleSquare, so that needs to be updated too */
\r
2937 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2939 HBITMAP oldBitmap;
\r
2943 if (appData.blindfold) return;
\r
2945 /* [AS] Use font-based pieces if needed */
\r
2946 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2947 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2948 CreatePiecesFromFont();
\r
2950 if( fontBitmapSquareSize == squareSize ) {
\r
2951 int index = TranslatePieceToFontPiece(piece);
\r
2953 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2955 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2956 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2960 squareSize, squareSize,
\r
2965 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2967 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2968 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2972 squareSize, squareSize,
\r
2981 if (appData.monoMode) {
\r
2982 SelectObject(tmphdc, PieceBitmap(piece,
\r
2983 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2984 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2985 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2987 HBRUSH xBrush = whitePieceBrush;
\r
2988 tmpSize = squareSize;
\r
2989 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2991 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2992 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2993 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2994 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2995 x += (squareSize - minorSize)>>1;
\r
2996 y += squareSize - minorSize - 2;
\r
2997 tmpSize = minorSize;
\r
2999 if (color || appData.allWhite ) {
\r
3000 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3002 oldBrush = SelectObject(hdc, xBrush);
\r
3003 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3004 if(appData.upsideDown && color==flipView)
\r
3005 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3007 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3008 /* Use black for outline of white pieces */
\r
3009 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3010 if(appData.upsideDown && color==flipView)
\r
3011 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3013 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3014 } else if(appData.pieceDirectory[0]) {
\r
3015 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3016 oldBrush = SelectObject(hdc, xBrush);
\r
3017 if(appData.upsideDown && color==flipView)
\r
3018 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3020 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3021 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3022 if(appData.upsideDown && color==flipView)
\r
3023 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3025 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3027 /* Use square color for details of black pieces */
\r
3028 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3029 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3030 if(appData.upsideDown && !flipView)
\r
3031 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3033 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3035 SelectObject(hdc, oldBrush);
\r
3036 SelectObject(tmphdc, oldBitmap);
\r
3040 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3041 int GetBackTextureMode( int algo )
\r
3043 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3047 case BACK_TEXTURE_MODE_PLAIN:
\r
3048 result = 1; /* Always use identity map */
\r
3050 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3051 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3059 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3060 to handle redraws cleanly (as random numbers would always be different).
\r
3062 VOID RebuildTextureSquareInfo()
\r
3072 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3074 if( liteBackTexture != NULL ) {
\r
3075 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3076 lite_w = bi.bmWidth;
\r
3077 lite_h = bi.bmHeight;
\r
3081 if( darkBackTexture != NULL ) {
\r
3082 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3083 dark_w = bi.bmWidth;
\r
3084 dark_h = bi.bmHeight;
\r
3088 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3089 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3090 if( (col + row) & 1 ) {
\r
3092 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3093 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3094 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3096 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3097 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3098 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3100 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3101 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3106 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3107 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3108 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3110 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3111 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3112 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3114 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3115 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3122 /* [AS] Arrow highlighting support */
\r
3124 static double A_WIDTH = 5; /* Width of arrow body */
\r
3126 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3127 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3129 static double Sqr( double x )
\r
3134 static int Round( double x )
\r
3136 return (int) (x + 0.5);
\r
3139 /* Draw an arrow between two points using current settings */
\r
3140 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3143 double dx, dy, j, k, x, y;
\r
3145 if( d_x == s_x ) {
\r
3146 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3148 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3151 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3152 arrow[1].y = d_y - h;
\r
3154 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3155 arrow[2].y = d_y - h;
\r
3160 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3161 arrow[5].y = d_y - h;
\r
3163 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3164 arrow[4].y = d_y - h;
\r
3166 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3169 else if( d_y == s_y ) {
\r
3170 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3173 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3175 arrow[1].x = d_x - w;
\r
3176 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3178 arrow[2].x = d_x - w;
\r
3179 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3184 arrow[5].x = d_x - w;
\r
3185 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3187 arrow[4].x = d_x - w;
\r
3188 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3191 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3194 /* [AS] Needed a lot of paper for this! :-) */
\r
3195 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3196 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3198 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3200 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3205 arrow[0].x = Round(x - j);
\r
3206 arrow[0].y = Round(y + j*dx);
\r
3208 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3209 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3212 x = (double) d_x - k;
\r
3213 y = (double) d_y - k*dy;
\r
3216 x = (double) d_x + k;
\r
3217 y = (double) d_y + k*dy;
\r
3220 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3222 arrow[6].x = Round(x - j);
\r
3223 arrow[6].y = Round(y + j*dx);
\r
3225 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3226 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3228 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3229 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3234 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3235 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3238 Polygon( hdc, arrow, 7 );
\r
3241 /* [AS] Draw an arrow between two squares */
\r
3242 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3244 int s_x, s_y, d_x, d_y;
\r
3251 if( s_col == d_col && s_row == d_row ) {
\r
3255 /* Get source and destination points */
\r
3256 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3257 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3260 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3262 else if( d_y < s_y ) {
\r
3263 d_y += squareSize / 2 + squareSize / 4;
\r
3266 d_y += squareSize / 2;
\r
3270 d_x += squareSize / 2 - squareSize / 4;
\r
3272 else if( d_x < s_x ) {
\r
3273 d_x += squareSize / 2 + squareSize / 4;
\r
3276 d_x += squareSize / 2;
\r
3279 s_x += squareSize / 2;
\r
3280 s_y += squareSize / 2;
\r
3282 /* Adjust width */
\r
3283 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3286 stLB.lbStyle = BS_SOLID;
\r
3287 stLB.lbColor = appData.highlightArrowColor;
\r
3290 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3291 holdpen = SelectObject( hdc, hpen );
\r
3292 hbrush = CreateBrushIndirect( &stLB );
\r
3293 holdbrush = SelectObject( hdc, hbrush );
\r
3295 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3297 SelectObject( hdc, holdpen );
\r
3298 SelectObject( hdc, holdbrush );
\r
3299 DeleteObject( hpen );
\r
3300 DeleteObject( hbrush );
\r
3303 BOOL HasHighlightInfo()
\r
3305 BOOL result = FALSE;
\r
3307 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3308 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3319 BOOL IsDrawArrowEnabled()
\r
3321 BOOL result = FALSE;
\r
3323 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3330 VOID DrawArrowHighlight( HDC hdc )
\r
3332 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3333 DrawArrowBetweenSquares( hdc,
\r
3334 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3335 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3339 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3341 HRGN result = NULL;
\r
3343 if( HasHighlightInfo() ) {
\r
3344 int x1, y1, x2, y2;
\r
3345 int sx, sy, dx, dy;
\r
3347 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3348 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3350 sx = MIN( x1, x2 );
\r
3351 sy = MIN( y1, y2 );
\r
3352 dx = MAX( x1, x2 ) + squareSize;
\r
3353 dy = MAX( y1, y2 ) + squareSize;
\r
3355 result = CreateRectRgn( sx, sy, dx, dy );
\r
3362 Warning: this function modifies the behavior of several other functions.
\r
3364 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3365 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3366 repaint is scattered all over the place, which is not good for features such as
\r
3367 "arrow highlighting" that require a full repaint of the board.
\r
3369 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3370 user interaction, when speed is not so important) but especially to avoid errors
\r
3371 in the displayed graphics.
\r
3373 In such patched places, I always try refer to this function so there is a single
\r
3374 place to maintain knowledge.
\r
3376 To restore the original behavior, just return FALSE unconditionally.
\r
3378 BOOL IsFullRepaintPreferrable()
\r
3380 BOOL result = FALSE;
\r
3382 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3383 /* Arrow may appear on the board */
\r
3391 This function is called by DrawPosition to know whether a full repaint must
\r
3394 Only DrawPosition may directly call this function, which makes use of
\r
3395 some state information. Other function should call DrawPosition specifying
\r
3396 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3398 BOOL DrawPositionNeedsFullRepaint()
\r
3400 BOOL result = FALSE;
\r
3403 Probably a slightly better policy would be to trigger a full repaint
\r
3404 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3405 but animation is fast enough that it's difficult to notice.
\r
3407 if( animInfo.piece == EmptySquare ) {
\r
3408 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3416 static HBITMAP borderBitmap;
\r
3419 DrawBackgroundOnDC(HDC hdc)
\r
3425 static char oldBorder[MSG_SIZ];
\r
3426 int w = 600, h = 600, mode;
\r
3428 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3429 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3430 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3432 if(borderBitmap == NULL) { // loading failed, use white
\r
3433 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3436 tmphdc = CreateCompatibleDC(hdc);
\r
3437 hbm = SelectObject(tmphdc, borderBitmap);
\r
3438 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3442 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3443 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3444 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3445 SetStretchBltMode(hdc, mode);
\r
3446 SelectObject(tmphdc, hbm);
\r
3451 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3453 int row, column, x, y, square_color, piece_color;
\r
3454 ChessSquare piece;
\r
3456 HDC texture_hdc = NULL;
\r
3458 /* [AS] Initialize background textures if needed */
\r
3459 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3460 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3461 if( backTextureSquareSize != squareSize
\r
3462 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3463 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3464 backTextureSquareSize = squareSize;
\r
3465 RebuildTextureSquareInfo();
\r
3468 texture_hdc = CreateCompatibleDC( hdc );
\r
3471 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3472 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3474 SquareToPos(row, column, &x, &y);
\r
3476 piece = board[row][column];
\r
3478 square_color = ((column + row) % 2) == 1;
\r
3479 if( gameInfo.variant == VariantXiangqi ) {
\r
3480 square_color = !InPalace(row, column);
\r
3481 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3482 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3484 piece_color = (int) piece < (int) BlackPawn;
\r
3487 /* [HGM] holdings file: light square or black */
\r
3488 if(column == BOARD_LEFT-2) {
\r
3489 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3492 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3496 if(column == BOARD_RGHT + 1 ) {
\r
3497 if( row < gameInfo.holdingsSize )
\r
3500 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3504 if(column == BOARD_LEFT-1 ) /* left align */
\r
3505 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3506 else if( column == BOARD_RGHT) /* right align */
\r
3507 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3508 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3510 if (appData.monoMode) {
\r
3511 if (piece == EmptySquare) {
\r
3512 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3513 square_color ? WHITENESS : BLACKNESS);
\r
3515 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3518 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3519 /* [AS] Draw the square using a texture bitmap */
\r
3520 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3521 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3522 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3525 squareSize, squareSize,
\r
3528 backTextureSquareInfo[r][c].mode,
\r
3529 backTextureSquareInfo[r][c].x,
\r
3530 backTextureSquareInfo[r][c].y );
\r
3532 SelectObject( texture_hdc, hbm );
\r
3534 if (piece != EmptySquare) {
\r
3535 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3539 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3541 oldBrush = SelectObject(hdc, brush );
\r
3542 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3543 SelectObject(hdc, oldBrush);
\r
3544 if (piece != EmptySquare)
\r
3545 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3550 if( texture_hdc != NULL ) {
\r
3551 DeleteDC( texture_hdc );
\r
3555 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3556 void fputDW(FILE *f, int x)
\r
3558 fputc(x & 255, f);
\r
3559 fputc(x>>8 & 255, f);
\r
3560 fputc(x>>16 & 255, f);
\r
3561 fputc(x>>24 & 255, f);
\r
3564 #define MAX_CLIPS 200 /* more than enough */
\r
3567 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3569 // HBITMAP bufferBitmap;
\r
3574 int w = 100, h = 50;
\r
3576 if(logo == NULL) {
\r
3577 if(!logoHeight) return;
\r
3578 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3580 // GetClientRect(hwndMain, &Rect);
\r
3581 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3582 // Rect.bottom-Rect.top+1);
\r
3583 tmphdc = CreateCompatibleDC(hdc);
\r
3584 hbm = SelectObject(tmphdc, logo);
\r
3585 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3589 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3590 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3591 SelectObject(tmphdc, hbm);
\r
3599 HDC hdc = GetDC(hwndMain);
\r
3600 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3601 if(appData.autoLogo) {
\r
3603 switch(gameMode) { // pick logos based on game mode
\r
3604 case IcsObserving:
\r
3605 whiteLogo = second.programLogo; // ICS logo
\r
3606 blackLogo = second.programLogo;
\r
3609 case IcsPlayingWhite:
\r
3610 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3611 blackLogo = second.programLogo; // ICS logo
\r
3613 case IcsPlayingBlack:
\r
3614 whiteLogo = second.programLogo; // ICS logo
\r
3615 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3617 case TwoMachinesPlay:
\r
3618 if(first.twoMachinesColor[0] == 'b') {
\r
3619 whiteLogo = second.programLogo;
\r
3620 blackLogo = first.programLogo;
\r
3623 case MachinePlaysWhite:
\r
3624 blackLogo = userLogo;
\r
3626 case MachinePlaysBlack:
\r
3627 whiteLogo = userLogo;
\r
3628 blackLogo = first.programLogo;
\r
3631 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3632 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3633 ReleaseDC(hwndMain, hdc);
\r
3638 UpdateLogos(int display)
\r
3639 { // called after loading new engine(s), in tourney or from menu
\r
3640 LoadLogo(&first, 0, FALSE);
\r
3641 LoadLogo(&second, 1, appData.icsActive);
\r
3642 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3643 if(display) DisplayLogos();
\r
3646 static HDC hdcSeek;
\r
3648 // [HGM] seekgraph
\r
3649 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3652 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3653 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3654 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3655 SelectObject( hdcSeek, hp );
\r
3658 // front-end wrapper for drawing functions to do rectangles
\r
3659 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3664 if (hdcSeek == NULL) {
\r
3665 hdcSeek = GetDC(hwndMain);
\r
3666 if (!appData.monoMode) {
\r
3667 SelectPalette(hdcSeek, hPal, FALSE);
\r
3668 RealizePalette(hdcSeek);
\r
3671 hp = SelectObject( hdcSeek, gridPen );
\r
3672 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3673 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3674 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3675 SelectObject( hdcSeek, hp );
\r
3678 // front-end wrapper for putting text in graph
\r
3679 void DrawSeekText(char *buf, int x, int y)
\r
3682 SetBkMode( hdcSeek, TRANSPARENT );
\r
3683 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3684 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3687 void DrawSeekDot(int x, int y, int color)
\r
3689 int square = color & 0x80;
\r
3690 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3691 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3694 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3695 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r