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 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
95 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
98 void mysrandom(unsigned int seed);
\r
100 extern int whiteFlag, blackFlag;
\r
101 Boolean flipClock = FALSE;
\r
102 extern HANDLE chatHandle[];
\r
103 extern int ics_type;
\r
105 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
106 VOID NewVariantPopup(HWND hwnd);
\r
107 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
108 /*char*/int promoChar));
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
111 void ChatPopUp P((char *s));
\r
113 ChessSquare piece;
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
117 POINT to; /* board coordinates of the piece's new pos */
\r
120 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT start; /* window coordinates of start pos */
\r
124 POINT pos; /* window coordinates of current pos */
\r
125 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
126 POINT from; /* board coordinates of the piece's orig pos */
\r
130 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
133 POINT sq[2]; /* board coordinates of from, to squares */
\r
136 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
137 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
139 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
141 typedef struct { // [HGM] atomic
\r
142 int fromX, fromY, toX, toY, radius;
\r
145 static ExplodeInfo explodeInfo;
\r
147 /* Window class names */
\r
148 char szAppName[] = "WinBoard";
\r
149 char szConsoleName[] = "WBConsole";
\r
151 /* Title bar text */
\r
152 char szTitle[] = "WinBoard";
\r
153 char szConsoleTitle[] = "I C S Interaction";
\r
156 char *settingsFileName;
\r
157 Boolean saveSettingsOnExit;
\r
158 char installDir[MSG_SIZ];
\r
159 int errorExitStatus;
\r
161 BoardSize boardSize;
\r
162 Boolean chessProgram;
\r
163 //static int boardX, boardY;
\r
164 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
165 int squareSize, lineGap, minorSize;
\r
166 static int winW, winH;
\r
167 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
168 static int logoHeight = 0;
\r
169 static char messageText[MESSAGE_TEXT_MAX];
\r
170 static int clockTimerEvent = 0;
\r
171 static int loadGameTimerEvent = 0;
\r
172 static int analysisTimerEvent = 0;
\r
173 static DelayedEventCallback delayedTimerCallback;
\r
174 static int delayedTimerEvent = 0;
\r
175 static int buttonCount = 2;
\r
176 char *icsTextMenuString;
\r
178 char *firstChessProgramNames;
\r
179 char *secondChessProgramNames;
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 Boolean alwaysOnTop = FALSE;
\r
186 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
187 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
189 ColorClass currentColorClass;
\r
191 static HWND savedHwnd;
\r
192 HWND hCommPort = NULL; /* currently open comm port */
\r
193 static HWND hwndPause; /* pause button */
\r
194 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
195 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
196 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
197 explodeBrush, /* [HGM] atomic */
\r
198 markerBrush, /* [HGM] markers */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
201 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 static HBITMAP liteBackTexture = NULL;
\r
214 static HBITMAP darkBackTexture = NULL;
\r
215 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
216 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
217 static int backTextureSquareSize = 0;
\r
218 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
220 #if __GNUC__ && !defined(_winmajor)
\r
221 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
223 #if defined(_winmajor)
\r
224 #define oldDialog (_winmajor < 4)
\r
226 #define oldDialog 0
\r
230 #define INTERNATIONAL
\r
232 #ifdef INTERNATIONAL
\r
233 # define _(s) T_(s)
\r
239 # define Translate(x, y)
\r
240 # define LoadLanguageFile(s)
\r
243 #ifdef INTERNATIONAL
\r
245 Boolean barbaric; // flag indicating if translation is needed
\r
247 // list of item numbers used in each dialog (used to alter language at run time)
\r
249 #define ABOUTBOX -1 /* not sure why these are needed */
\r
250 #define ABOUTBOX2 -1
\r
252 int dialogItems[][42] = {
\r
253 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
254 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
255 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
256 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
257 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
258 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
259 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
260 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
261 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
262 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
263 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
264 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
265 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
266 { ABOUTBOX2, IDC_ChessBoard },
\r
267 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
268 OPT_GameListClose, IDC_GameListDoFilter },
\r
269 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
270 { DLG_Error, IDOK },
\r
271 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
272 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
273 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
274 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
275 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
276 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
277 { DLG_IndexNumber, IDC_Index },
\r
278 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
279 { DLG_TypeInName, IDOK, IDCANCEL },
\r
280 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
281 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
282 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
283 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
284 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
285 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
286 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
287 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
288 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
289 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
290 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
291 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
292 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
293 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
294 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
295 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
296 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
297 GPB_General, GPB_Alarm },
\r
298 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
299 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
300 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
301 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
302 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
303 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
304 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
305 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
306 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
307 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
308 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
309 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
310 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
311 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
312 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
313 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
314 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
315 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
316 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
317 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
318 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
319 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
320 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
321 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
322 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
323 { DLG_MoveHistory },
\r
324 { DLG_EvalGraph },
\r
325 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
326 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
327 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
328 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
329 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
330 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
331 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
332 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
333 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
337 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
338 static int lastChecked;
\r
339 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
340 extern int tinyLayout;
\r
341 extern char * menuBarText[][10];
\r
344 LoadLanguageFile(char *name)
\r
345 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
347 int i=0, j=0, n=0, k;
\r
350 if(!name || name[0] == NULLCHAR) return;
\r
351 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
352 appData.language = oldLanguage;
\r
353 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
354 if((f = fopen(buf, "r")) == NULL) return;
\r
355 while((k = fgetc(f)) != EOF) {
\r
356 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
357 languageBuf[i] = k;
\r
359 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
361 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
362 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
363 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
364 english[j] = languageBuf + n + 1; *p = 0;
\r
365 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
366 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
371 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
373 case 'n': k = '\n'; break;
\r
374 case 'r': k = '\r'; break;
\r
375 case 't': k = '\t'; break;
\r
377 languageBuf[--i] = k;
\r
382 barbaric = (j != 0);
\r
383 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
388 { // return the translation of the given string
\r
389 // efficiency can be improved a lot...
\r
391 static char buf[MSG_SIZ];
\r
392 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
393 if(!barbaric) return s;
\r
394 if(!s) return ""; // sanity
\r
395 while(english[i]) {
\r
396 if(!strcmp(s, english[i])) return foreign[i];
\r
397 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
398 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
407 Translate(HWND hDlg, int dialogID)
\r
408 { // translate all text items in the given dialog
\r
410 char buf[MSG_SIZ], *s;
\r
411 if(!barbaric) return;
\r
412 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
413 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
414 GetWindowText( hDlg, buf, MSG_SIZ );
\r
416 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
417 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
418 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
419 if(strlen(buf) == 0) continue;
\r
421 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
426 TranslateOneMenu(int i, HMENU subMenu)
\r
429 static MENUITEMINFO info;
\r
431 info.cbSize = sizeof(MENUITEMINFO);
\r
432 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
433 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
435 info.dwTypeData = buf;
\r
436 info.cch = sizeof(buf);
\r
437 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
439 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
440 else menuText[i][j] = strdup(buf); // remember original on first change
\r
442 if(buf[0] == NULLCHAR) continue;
\r
443 info.dwTypeData = T_(buf);
\r
444 info.cch = strlen(buf)+1;
\r
445 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
451 TranslateMenus(int addLanguage)
\r
454 WIN32_FIND_DATA fileData;
\r
456 #define IDM_English 1970
\r
458 HMENU mainMenu = GetMenu(hwndMain);
\r
459 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
460 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
461 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
462 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
463 TranslateOneMenu(i, subMenu);
\r
465 DrawMenuBar(hwndMain);
\r
468 if(!addLanguage) return;
\r
469 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
470 HMENU mainMenu = GetMenu(hwndMain);
\r
471 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
472 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
473 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
474 i = 0; lastChecked = IDM_English;
\r
476 char *p, *q = fileData.cFileName;
\r
477 int checkFlag = MF_UNCHECKED;
\r
478 languageFile[i] = strdup(q);
\r
479 if(barbaric && !strcmp(oldLanguage, q)) {
\r
480 checkFlag = MF_CHECKED;
\r
481 lastChecked = IDM_English + i + 1;
\r
482 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
484 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
485 p = strstr(fileData.cFileName, ".lng");
\r
487 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
488 } while(FindNextFile(hFind, &fileData));
\r
495 #define IDM_RecentEngines 3000
\r
498 RecentEngineMenu (char *s)
\r
500 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
501 HMENU mainMenu = GetMenu(hwndMain);
\r
502 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
503 int i=IDM_RecentEngines;
\r
504 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
505 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
507 char *p = strchr(s, '\n');
\r
508 if(p == NULL) return; // malformed!
\r
510 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
524 int cliWidth, cliHeight;
\r
527 SizeInfo sizeInfo[] =
\r
529 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
530 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
531 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
532 { "petite", 33, 1, 1, 1, 0, 0 },
\r
533 { "slim", 37, 2, 1, 0, 0, 0 },
\r
534 { "small", 40, 2, 1, 0, 0, 0 },
\r
535 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
536 { "middling", 49, 2, 0, 0, 0, 0 },
\r
537 { "average", 54, 2, 0, 0, 0, 0 },
\r
538 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
539 { "medium", 64, 3, 0, 0, 0, 0 },
\r
540 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
541 { "large", 80, 3, 0, 0, 0, 0 },
\r
542 { "big", 87, 3, 0, 0, 0, 0 },
\r
543 { "huge", 95, 3, 0, 0, 0, 0 },
\r
544 { "giant", 108, 3, 0, 0, 0, 0 },
\r
545 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
546 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
547 { NULL, 0, 0, 0, 0, 0, 0 }
\r
550 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
551 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
553 { 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
554 { 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
555 { 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
556 { 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
557 { 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
558 { 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
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
573 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
582 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
583 #define N_BUTTONS 5
\r
585 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
587 {"<<", IDM_ToStart, NULL, NULL},
\r
588 {"<", IDM_Backward, NULL, NULL},
\r
589 {"P", IDM_Pause, NULL, NULL},
\r
590 {">", IDM_Forward, NULL, NULL},
\r
591 {">>", IDM_ToEnd, NULL, NULL},
\r
594 int tinyLayout = 0, smallLayout = 0;
\r
595 #define MENU_BAR_ITEMS 9
\r
596 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
597 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
598 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
602 MySound sounds[(int)NSoundClasses];
\r
603 MyTextAttribs textAttribs[(int)NColorClasses];
\r
605 MyColorizeAttribs colorizeAttribs[] = {
\r
606 { (COLORREF)0, 0, N_("Shout Text") },
\r
607 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
608 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
609 { (COLORREF)0, 0, N_("Channel Text") },
\r
610 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
611 { (COLORREF)0, 0, N_("Tell Text") },
\r
612 { (COLORREF)0, 0, N_("Challenge Text") },
\r
613 { (COLORREF)0, 0, N_("Request Text") },
\r
614 { (COLORREF)0, 0, N_("Seek Text") },
\r
615 { (COLORREF)0, 0, N_("Normal Text") },
\r
616 { (COLORREF)0, 0, N_("None") }
\r
621 static char *commentTitle;
\r
622 static char *commentText;
\r
623 static int commentIndex;
\r
624 static Boolean editComment = FALSE;
\r
627 char errorTitle[MSG_SIZ];
\r
628 char errorMessage[2*MSG_SIZ];
\r
629 HWND errorDialog = NULL;
\r
630 BOOLEAN moveErrorMessageUp = FALSE;
\r
631 BOOLEAN consoleEcho = TRUE;
\r
632 CHARFORMAT consoleCF;
\r
633 COLORREF consoleBackgroundColor;
\r
635 char *programVersion;
\r
641 typedef int CPKind;
\r
650 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
653 #define INPUT_SOURCE_BUF_SIZE 4096
\r
655 typedef struct _InputSource {
\r
662 char buf[INPUT_SOURCE_BUF_SIZE];
\r
666 InputCallback func;
\r
667 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
671 InputSource *consoleInputSource;
\r
676 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
677 VOID ConsoleCreate();
\r
679 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
680 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
681 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
682 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
684 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
685 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
686 void ParseIcsTextMenu(char *icsTextMenuString);
\r
687 VOID PopUpNameDialog(char firstchar);
\r
688 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
692 int GameListOptions();
\r
694 int dummy; // [HGM] for obsolete args
\r
696 HWND hwndMain = NULL; /* root window*/
\r
697 HWND hwndConsole = NULL;
\r
698 HWND commentDialog = NULL;
\r
699 HWND moveHistoryDialog = NULL;
\r
700 HWND evalGraphDialog = NULL;
\r
701 HWND engineOutputDialog = NULL;
\r
702 HWND gameListDialog = NULL;
\r
703 HWND editTagsDialog = NULL;
\r
705 int commentUp = FALSE;
\r
707 WindowPlacement wpMain;
\r
708 WindowPlacement wpConsole;
\r
709 WindowPlacement wpComment;
\r
710 WindowPlacement wpMoveHistory;
\r
711 WindowPlacement wpEvalGraph;
\r
712 WindowPlacement wpEngineOutput;
\r
713 WindowPlacement wpGameList;
\r
714 WindowPlacement wpTags;
\r
716 VOID EngineOptionsPopup(); // [HGM] settings
\r
718 VOID GothicPopUp(char *title, VariantClass variant);
\r
720 * Setting "frozen" should disable all user input other than deleting
\r
721 * the window. We do this while engines are initializing themselves.
\r
723 static int frozen = 0;
\r
724 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
730 if (frozen) return;
\r
732 hmenu = GetMenu(hwndMain);
\r
733 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
734 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
736 DrawMenuBar(hwndMain);
\r
739 /* Undo a FreezeUI */
\r
745 if (!frozen) return;
\r
747 hmenu = GetMenu(hwndMain);
\r
748 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
749 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
751 DrawMenuBar(hwndMain);
\r
754 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
756 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
762 #define JAWS_ALT_INTERCEPT
\r
763 #define JAWS_KBUP_NAVIGATION
\r
764 #define JAWS_KBDOWN_NAVIGATION
\r
765 #define JAWS_MENU_ITEMS
\r
766 #define JAWS_SILENCE
\r
767 #define JAWS_REPLAY
\r
769 #define JAWS_COPYRIGHT
\r
770 #define JAWS_DELETE(X) X
\r
771 #define SAYMACHINEMOVE()
\r
775 /*---------------------------------------------------------------------------*\
\r
779 \*---------------------------------------------------------------------------*/
\r
782 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
783 LPSTR lpCmdLine, int nCmdShow)
\r
786 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
787 // INITCOMMONCONTROLSEX ex;
\r
791 LoadLibrary("RICHED32.DLL");
\r
792 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
794 if (!InitApplication(hInstance)) {
\r
797 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
804 // InitCommonControlsEx(&ex);
\r
805 InitCommonControls();
\r
807 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
808 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
809 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
811 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
813 while (GetMessage(&msg, /* message structure */
\r
814 NULL, /* handle of window receiving the message */
\r
815 0, /* lowest message to examine */
\r
816 0)) /* highest message to examine */
\r
819 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
820 // [HGM] navigate: switch between all windows with tab
\r
821 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
822 int i, currentElement = 0;
\r
824 // first determine what element of the chain we come from (if any)
\r
825 if(appData.icsActive) {
\r
826 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
827 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
829 if(engineOutputDialog && EngineOutputIsUp()) {
\r
830 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
831 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
833 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
834 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
836 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
837 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
838 if(msg.hwnd == e1) currentElement = 2; else
\r
839 if(msg.hwnd == e2) currentElement = 3; else
\r
840 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
841 if(msg.hwnd == mh) currentElement = 4; else
\r
842 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
843 if(msg.hwnd == hText) currentElement = 5; else
\r
844 if(msg.hwnd == hInput) currentElement = 6; else
\r
845 for (i = 0; i < N_BUTTONS; i++) {
\r
846 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
849 // determine where to go to
\r
850 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
852 currentElement = (currentElement + direction) % 7;
\r
853 switch(currentElement) {
\r
855 h = hwndMain; break; // passing this case always makes the loop exit
\r
857 h = buttonDesc[0].hwnd; break; // could be NULL
\r
859 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
862 if(!EngineOutputIsUp()) continue;
\r
865 if(!MoveHistoryIsUp()) continue;
\r
867 // case 6: // input to eval graph does not seem to get here!
\r
868 // if(!EvalGraphIsUp()) continue;
\r
869 // h = evalGraphDialog; break;
\r
871 if(!appData.icsActive) continue;
\r
875 if(!appData.icsActive) continue;
\r
881 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
882 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
885 continue; // this message now has been processed
\r
889 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
890 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
891 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
892 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
893 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
894 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
895 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
896 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
897 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
898 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
899 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
900 for(i=0; i<MAX_CHAT; i++)
\r
901 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
904 if(done) continue; // [HGM] chat: end patch
\r
905 TranslateMessage(&msg); /* Translates virtual key codes */
\r
906 DispatchMessage(&msg); /* Dispatches message to window */
\r
911 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
914 /*---------------------------------------------------------------------------*\
\r
916 * Initialization functions
\r
918 \*---------------------------------------------------------------------------*/
\r
922 { // update user logo if necessary
\r
923 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
925 if(appData.autoLogo) {
\r
926 curName = UserName();
\r
927 if(strcmp(curName, oldUserName)) {
\r
928 GetCurrentDirectory(MSG_SIZ, dir);
\r
929 SetCurrentDirectory(installDir);
\r
930 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
931 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
932 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
933 if(userLogo == NULL)
\r
934 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
935 SetCurrentDirectory(dir); /* return to prev directory */
\r
941 InitApplication(HINSTANCE hInstance)
\r
945 /* Fill in window class structure with parameters that describe the */
\r
948 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
949 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
950 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
951 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
952 wc.hInstance = hInstance; /* Owner of this class */
\r
953 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
954 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
955 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
956 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
957 wc.lpszClassName = szAppName; /* Name to register as */
\r
959 /* Register the window class and return success/failure code. */
\r
960 if (!RegisterClass(&wc)) return FALSE;
\r
962 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
963 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
965 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
966 wc.hInstance = hInstance;
\r
967 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
968 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
969 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
970 wc.lpszMenuName = NULL;
\r
971 wc.lpszClassName = szConsoleName;
\r
973 if (!RegisterClass(&wc)) return FALSE;
\r
978 /* Set by InitInstance, used by EnsureOnScreen */
\r
979 int screenHeight, screenWidth;
\r
982 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
984 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
985 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
986 if (*x > screenWidth - 32) *x = 0;
\r
987 if (*y > screenHeight - 32) *y = 0;
\r
988 if (*x < minX) *x = minX;
\r
989 if (*y < minY) *y = minY;
\r
993 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
995 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
996 GetCurrentDirectory(MSG_SIZ, dir);
\r
997 SetCurrentDirectory(installDir);
\r
998 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
999 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1001 if (cps->programLogo == NULL && appData.debugMode) {
\r
1002 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1004 } else if(appData.autoLogo) {
\r
1005 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1006 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1007 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1009 if(appData.directory[n] && appData.directory[n][0]) {
\r
1010 SetCurrentDirectory(appData.directory[n]);
\r
1011 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1014 SetCurrentDirectory(dir); /* return to prev directory */
\r
1020 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1021 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1023 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1024 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1025 liteBackTextureMode = appData.liteBackTextureMode;
\r
1027 if (liteBackTexture == NULL && appData.debugMode) {
\r
1028 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1032 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1033 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1034 darkBackTextureMode = appData.darkBackTextureMode;
\r
1036 if (darkBackTexture == NULL && appData.debugMode) {
\r
1037 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1043 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1045 HWND hwnd; /* Main window handle. */
\r
1047 WINDOWPLACEMENT wp;
\r
1050 hInst = hInstance; /* Store instance handle in our global variable */
\r
1051 programName = szAppName;
\r
1053 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1054 *filepart = NULLCHAR;
\r
1056 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1058 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1059 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1060 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1061 /* xboard, and older WinBoards, controlled the move sound with the
\r
1062 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1063 always turn the option on (so that the backend will call us),
\r
1064 then let the user turn the sound off by setting it to silence if
\r
1065 desired. To accommodate old winboard.ini files saved by old
\r
1066 versions of WinBoard, we also turn off the sound if the option
\r
1067 was initially set to false. [HGM] taken out of InitAppData */
\r
1068 if (!appData.ringBellAfterMoves) {
\r
1069 sounds[(int)SoundMove].name = strdup("");
\r
1070 appData.ringBellAfterMoves = TRUE;
\r
1072 if (appData.debugMode) {
\r
1073 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1074 setbuf(debugFP, NULL);
\r
1077 LoadLanguageFile(appData.language);
\r
1081 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1082 // InitEngineUCI( installDir, &second );
\r
1084 /* Create a main window for this application instance. */
\r
1085 hwnd = CreateWindow(szAppName, szTitle,
\r
1086 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1087 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1088 NULL, NULL, hInstance, NULL);
\r
1091 /* If window could not be created, return "failure" */
\r
1096 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1097 LoadLogo(&first, 0, FALSE);
\r
1098 LoadLogo(&second, 1, appData.icsActive);
\r
1102 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1103 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1104 iconCurrent = iconWhite;
\r
1105 InitDrawingColors();
\r
1106 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1107 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1108 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1109 /* Compute window size for each board size, and use the largest
\r
1110 size that fits on this screen as the default. */
\r
1111 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1112 if (boardSize == (BoardSize)-1 &&
\r
1113 winH <= screenHeight
\r
1114 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1115 && winW <= screenWidth) {
\r
1116 boardSize = (BoardSize)ibs;
\r
1120 InitDrawingSizes(boardSize, 0);
\r
1121 RecentEngineMenu(appData.recentEngineList);
\r
1123 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1125 /* [AS] Load textures if specified */
\r
1128 mysrandom( (unsigned) time(NULL) );
\r
1130 /* [AS] Restore layout */
\r
1131 if( wpMoveHistory.visible ) {
\r
1132 MoveHistoryPopUp();
\r
1135 if( wpEvalGraph.visible ) {
\r
1139 if( wpEngineOutput.visible ) {
\r
1140 EngineOutputPopUp();
\r
1143 /* Make the window visible; update its client area; and return "success" */
\r
1144 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1145 wp.length = sizeof(WINDOWPLACEMENT);
\r
1147 wp.showCmd = nCmdShow;
\r
1148 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1149 wp.rcNormalPosition.left = wpMain.x;
\r
1150 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1151 wp.rcNormalPosition.top = wpMain.y;
\r
1152 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1153 SetWindowPlacement(hwndMain, &wp);
\r
1155 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1157 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1158 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1160 if (hwndConsole) {
\r
1162 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1163 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1165 ShowWindow(hwndConsole, nCmdShow);
\r
1166 SetActiveWindow(hwndConsole);
\r
1168 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1169 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1178 HMENU hmenu = GetMenu(hwndMain);
\r
1180 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1181 MF_BYCOMMAND|((appData.icsActive &&
\r
1182 *appData.icsCommPort != NULLCHAR) ?
\r
1183 MF_ENABLED : MF_GRAYED));
\r
1184 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1185 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1186 MF_CHECKED : MF_UNCHECKED));
\r
1189 //---------------------------------------------------------------------------------------------------------
\r
1191 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1192 #define XBOARD FALSE
\r
1194 #define OPTCHAR "/"
\r
1195 #define SEPCHAR "="
\r
1199 // front-end part of option handling
\r
1202 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1204 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1205 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1208 lf->lfEscapement = 0;
\r
1209 lf->lfOrientation = 0;
\r
1210 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1211 lf->lfItalic = mfp->italic;
\r
1212 lf->lfUnderline = mfp->underline;
\r
1213 lf->lfStrikeOut = mfp->strikeout;
\r
1214 lf->lfCharSet = mfp->charset;
\r
1215 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1216 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1217 lf->lfQuality = DEFAULT_QUALITY;
\r
1218 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1219 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1223 CreateFontInMF(MyFont *mf)
\r
1225 LFfromMFP(&mf->lf, &mf->mfp);
\r
1226 if (mf->hf) DeleteObject(mf->hf);
\r
1227 mf->hf = CreateFontIndirect(&mf->lf);
\r
1230 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1232 colorVariable[] = {
\r
1233 &whitePieceColor,
\r
1234 &blackPieceColor,
\r
1235 &lightSquareColor,
\r
1236 &darkSquareColor,
\r
1237 &highlightSquareColor,
\r
1238 &premoveHighlightColor,
\r
1240 &consoleBackgroundColor,
\r
1241 &appData.fontForeColorWhite,
\r
1242 &appData.fontBackColorWhite,
\r
1243 &appData.fontForeColorBlack,
\r
1244 &appData.fontBackColorBlack,
\r
1245 &appData.evalHistColorWhite,
\r
1246 &appData.evalHistColorBlack,
\r
1247 &appData.highlightArrowColor,
\r
1250 /* Command line font name parser. NULL name means do nothing.
\r
1251 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1252 For backward compatibility, syntax without the colon is also
\r
1253 accepted, but font names with digits in them won't work in that case.
\r
1256 ParseFontName(char *name, MyFontParams *mfp)
\r
1259 if (name == NULL) return;
\r
1261 q = strchr(p, ':');
\r
1263 if (q - p >= sizeof(mfp->faceName))
\r
1264 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1265 memcpy(mfp->faceName, p, q - p);
\r
1266 mfp->faceName[q - p] = NULLCHAR;
\r
1269 q = mfp->faceName;
\r
1270 while (*p && !isdigit(*p)) {
\r
1272 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1273 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1275 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1278 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1279 mfp->pointSize = (float) atof(p);
\r
1280 mfp->bold = (strchr(p, 'b') != NULL);
\r
1281 mfp->italic = (strchr(p, 'i') != NULL);
\r
1282 mfp->underline = (strchr(p, 'u') != NULL);
\r
1283 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1284 mfp->charset = DEFAULT_CHARSET;
\r
1285 q = strchr(p, 'c');
\r
1287 mfp->charset = (BYTE) atoi(q+1);
\r
1291 ParseFont(char *name, int number)
\r
1292 { // wrapper to shield back-end from 'font'
\r
1293 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1298 { // in WB we have a 2D array of fonts; this initializes their description
\r
1300 /* Point font array elements to structures and
\r
1301 parse default font names */
\r
1302 for (i=0; i<NUM_FONTS; i++) {
\r
1303 for (j=0; j<NUM_SIZES; j++) {
\r
1304 font[j][i] = &fontRec[j][i];
\r
1305 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1312 { // here we create the actual fonts from the selected descriptions
\r
1314 for (i=0; i<NUM_FONTS; i++) {
\r
1315 for (j=0; j<NUM_SIZES; j++) {
\r
1316 CreateFontInMF(font[j][i]);
\r
1320 /* Color name parser.
\r
1321 X version accepts X color names, but this one
\r
1322 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1324 ParseColorName(char *name)
\r
1326 int red, green, blue, count;
\r
1327 char buf[MSG_SIZ];
\r
1329 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1331 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1332 &red, &green, &blue);
\r
1335 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1336 DisplayError(buf, 0);
\r
1337 return RGB(0, 0, 0);
\r
1339 return PALETTERGB(red, green, blue);
\r
1343 ParseColor(int n, char *name)
\r
1344 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1345 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1349 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1351 char *e = argValue;
\r
1355 if (*e == 'b') eff |= CFE_BOLD;
\r
1356 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1357 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1358 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1359 else if (*e == '#' || isdigit(*e)) break;
\r
1363 *color = ParseColorName(e);
\r
1367 ParseTextAttribs(ColorClass cc, char *s)
\r
1368 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1369 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1370 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1374 ParseBoardSize(void *addr, char *name)
\r
1375 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1376 BoardSize bs = SizeTiny;
\r
1377 while (sizeInfo[bs].name != NULL) {
\r
1378 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1379 *(BoardSize *)addr = bs;
\r
1384 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1389 { // [HGM] import name from appData first
\r
1392 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1393 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1394 textAttribs[cc].sound.data = NULL;
\r
1395 MyLoadSound(&textAttribs[cc].sound);
\r
1397 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1398 textAttribs[cc].sound.name = strdup("");
\r
1399 textAttribs[cc].sound.data = NULL;
\r
1401 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1402 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1403 sounds[sc].data = NULL;
\r
1404 MyLoadSound(&sounds[sc]);
\r
1409 SetCommPortDefaults()
\r
1411 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1412 dcb.DCBlength = sizeof(DCB);
\r
1413 dcb.BaudRate = 9600;
\r
1414 dcb.fBinary = TRUE;
\r
1415 dcb.fParity = FALSE;
\r
1416 dcb.fOutxCtsFlow = FALSE;
\r
1417 dcb.fOutxDsrFlow = FALSE;
\r
1418 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1419 dcb.fDsrSensitivity = FALSE;
\r
1420 dcb.fTXContinueOnXoff = TRUE;
\r
1421 dcb.fOutX = FALSE;
\r
1423 dcb.fNull = FALSE;
\r
1424 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1425 dcb.fAbortOnError = FALSE;
\r
1427 dcb.Parity = SPACEPARITY;
\r
1428 dcb.StopBits = ONESTOPBIT;
\r
1431 // [HGM] args: these three cases taken out to stay in front-end
\r
1433 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1434 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1435 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1436 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1438 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1439 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1440 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1441 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1442 ad->argName, mfp->faceName, mfp->pointSize,
\r
1443 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1444 mfp->bold ? "b" : "",
\r
1445 mfp->italic ? "i" : "",
\r
1446 mfp->underline ? "u" : "",
\r
1447 mfp->strikeout ? "s" : "",
\r
1448 (int)mfp->charset);
\r
1454 { // [HGM] copy the names from the internal WB variables to appData
\r
1457 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1458 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1459 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1460 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1464 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1465 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1466 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1467 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1468 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1469 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1470 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1471 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1472 (ta->effects) ? " " : "",
\r
1473 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1477 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1478 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1479 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1480 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1481 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1485 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1486 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1487 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1491 ParseCommPortSettings(char *s)
\r
1492 { // wrapper to keep dcb from back-end
\r
1493 ParseCommSettings(s, &dcb);
\r
1498 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1499 GetActualPlacement(hwndMain, &wpMain);
\r
1500 GetActualPlacement(hwndConsole, &wpConsole);
\r
1501 GetActualPlacement(commentDialog, &wpComment);
\r
1502 GetActualPlacement(editTagsDialog, &wpTags);
\r
1503 GetActualPlacement(gameListDialog, &wpGameList);
\r
1504 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1505 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1506 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1510 PrintCommPortSettings(FILE *f, char *name)
\r
1511 { // wrapper to shield back-end from DCB
\r
1512 PrintCommSettings(f, name, &dcb);
\r
1516 MySearchPath(char *installDir, char *name, char *fullname)
\r
1518 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1519 if(name[0]== '%') {
\r
1520 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1521 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1522 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1523 *strchr(buf, '%') = 0;
\r
1524 strcat(fullname, getenv(buf));
\r
1525 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1527 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1528 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1529 return (int) strlen(fullname);
\r
1531 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1535 MyGetFullPathName(char *name, char *fullname)
\r
1538 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1543 { // [HGM] args: allows testing if main window is realized from back-end
\r
1544 return hwndMain != NULL;
\r
1548 PopUpStartupDialog()
\r
1552 LoadLanguageFile(appData.language);
\r
1553 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1554 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1555 FreeProcInstance(lpProc);
\r
1558 /*---------------------------------------------------------------------------*\
\r
1560 * GDI board drawing routines
\r
1562 \*---------------------------------------------------------------------------*/
\r
1564 /* [AS] Draw square using background texture */
\r
1565 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1570 return; /* Should never happen! */
\r
1573 SetGraphicsMode( dst, GM_ADVANCED );
\r
1580 /* X reflection */
\r
1585 x.eDx = (FLOAT) dw + dx - 1;
\r
1588 SetWorldTransform( dst, &x );
\r
1591 /* Y reflection */
\r
1597 x.eDy = (FLOAT) dh + dy - 1;
\r
1599 SetWorldTransform( dst, &x );
\r
1607 x.eDx = (FLOAT) dx;
\r
1608 x.eDy = (FLOAT) dy;
\r
1611 SetWorldTransform( dst, &x );
\r
1615 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1623 SetWorldTransform( dst, &x );
\r
1625 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1628 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1630 PM_WP = (int) WhitePawn,
\r
1631 PM_WN = (int) WhiteKnight,
\r
1632 PM_WB = (int) WhiteBishop,
\r
1633 PM_WR = (int) WhiteRook,
\r
1634 PM_WQ = (int) WhiteQueen,
\r
1635 PM_WF = (int) WhiteFerz,
\r
1636 PM_WW = (int) WhiteWazir,
\r
1637 PM_WE = (int) WhiteAlfil,
\r
1638 PM_WM = (int) WhiteMan,
\r
1639 PM_WO = (int) WhiteCannon,
\r
1640 PM_WU = (int) WhiteUnicorn,
\r
1641 PM_WH = (int) WhiteNightrider,
\r
1642 PM_WA = (int) WhiteAngel,
\r
1643 PM_WC = (int) WhiteMarshall,
\r
1644 PM_WAB = (int) WhiteCardinal,
\r
1645 PM_WD = (int) WhiteDragon,
\r
1646 PM_WL = (int) WhiteLance,
\r
1647 PM_WS = (int) WhiteCobra,
\r
1648 PM_WV = (int) WhiteFalcon,
\r
1649 PM_WSG = (int) WhiteSilver,
\r
1650 PM_WG = (int) WhiteGrasshopper,
\r
1651 PM_WK = (int) WhiteKing,
\r
1652 PM_BP = (int) BlackPawn,
\r
1653 PM_BN = (int) BlackKnight,
\r
1654 PM_BB = (int) BlackBishop,
\r
1655 PM_BR = (int) BlackRook,
\r
1656 PM_BQ = (int) BlackQueen,
\r
1657 PM_BF = (int) BlackFerz,
\r
1658 PM_BW = (int) BlackWazir,
\r
1659 PM_BE = (int) BlackAlfil,
\r
1660 PM_BM = (int) BlackMan,
\r
1661 PM_BO = (int) BlackCannon,
\r
1662 PM_BU = (int) BlackUnicorn,
\r
1663 PM_BH = (int) BlackNightrider,
\r
1664 PM_BA = (int) BlackAngel,
\r
1665 PM_BC = (int) BlackMarshall,
\r
1666 PM_BG = (int) BlackGrasshopper,
\r
1667 PM_BAB = (int) BlackCardinal,
\r
1668 PM_BD = (int) BlackDragon,
\r
1669 PM_BL = (int) BlackLance,
\r
1670 PM_BS = (int) BlackCobra,
\r
1671 PM_BV = (int) BlackFalcon,
\r
1672 PM_BSG = (int) BlackSilver,
\r
1673 PM_BK = (int) BlackKing
\r
1676 static HFONT hPieceFont = NULL;
\r
1677 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1678 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1679 static int fontBitmapSquareSize = 0;
\r
1680 static char pieceToFontChar[(int) EmptySquare] =
\r
1681 { 'p', 'n', 'b', 'r', 'q',
\r
1682 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1683 'k', 'o', 'm', 'v', 't', 'w',
\r
1684 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1687 extern BOOL SetCharTable( char *table, const char * map );
\r
1688 /* [HGM] moved to backend.c */
\r
1690 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1693 BYTE r1 = GetRValue( color );
\r
1694 BYTE g1 = GetGValue( color );
\r
1695 BYTE b1 = GetBValue( color );
\r
1701 /* Create a uniform background first */
\r
1702 hbrush = CreateSolidBrush( color );
\r
1703 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1704 FillRect( hdc, &rc, hbrush );
\r
1705 DeleteObject( hbrush );
\r
1708 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1709 int steps = squareSize / 2;
\r
1712 for( i=0; i<steps; i++ ) {
\r
1713 BYTE r = r1 - (r1-r2) * i / steps;
\r
1714 BYTE g = g1 - (g1-g2) * i / steps;
\r
1715 BYTE b = b1 - (b1-b2) * i / steps;
\r
1717 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1718 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1719 FillRect( hdc, &rc, hbrush );
\r
1720 DeleteObject(hbrush);
\r
1723 else if( mode == 2 ) {
\r
1724 /* Diagonal gradient, good more or less for every piece */
\r
1725 POINT triangle[3];
\r
1726 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1727 HBRUSH hbrush_old;
\r
1728 int steps = squareSize;
\r
1731 triangle[0].x = squareSize - steps;
\r
1732 triangle[0].y = squareSize;
\r
1733 triangle[1].x = squareSize;
\r
1734 triangle[1].y = squareSize;
\r
1735 triangle[2].x = squareSize;
\r
1736 triangle[2].y = squareSize - steps;
\r
1738 for( i=0; i<steps; i++ ) {
\r
1739 BYTE r = r1 - (r1-r2) * i / steps;
\r
1740 BYTE g = g1 - (g1-g2) * i / steps;
\r
1741 BYTE b = b1 - (b1-b2) * i / steps;
\r
1743 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1744 hbrush_old = SelectObject( hdc, hbrush );
\r
1745 Polygon( hdc, triangle, 3 );
\r
1746 SelectObject( hdc, hbrush_old );
\r
1747 DeleteObject(hbrush);
\r
1752 SelectObject( hdc, hpen );
\r
1757 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1758 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1759 piece: follow the steps as explained below.
\r
1761 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1765 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1769 int backColor = whitePieceColor;
\r
1770 int foreColor = blackPieceColor;
\r
1772 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1773 backColor = appData.fontBackColorWhite;
\r
1774 foreColor = appData.fontForeColorWhite;
\r
1776 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1777 backColor = appData.fontBackColorBlack;
\r
1778 foreColor = appData.fontForeColorBlack;
\r
1782 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1784 hbm_old = SelectObject( hdc, hbm );
\r
1788 rc.right = squareSize;
\r
1789 rc.bottom = squareSize;
\r
1791 /* Step 1: background is now black */
\r
1792 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1794 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1796 pt.x = (squareSize - sz.cx) / 2;
\r
1797 pt.y = (squareSize - sz.cy) / 2;
\r
1799 SetBkMode( hdc, TRANSPARENT );
\r
1800 SetTextColor( hdc, chroma );
\r
1801 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1802 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1804 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1805 /* Step 3: the area outside the piece is filled with white */
\r
1806 // FloodFill( hdc, 0, 0, chroma );
\r
1807 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1808 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1809 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1810 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1811 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1813 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1814 but if the start point is not inside the piece we're lost!
\r
1815 There should be a better way to do this... if we could create a region or path
\r
1816 from the fill operation we would be fine for example.
\r
1818 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1819 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1821 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1822 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1823 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1825 SelectObject( dc2, bm2 );
\r
1826 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1827 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1828 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1829 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1830 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1833 DeleteObject( bm2 );
\r
1836 SetTextColor( hdc, 0 );
\r
1838 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1839 draw the piece again in black for safety.
\r
1841 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1843 SelectObject( hdc, hbm_old );
\r
1845 if( hPieceMask[index] != NULL ) {
\r
1846 DeleteObject( hPieceMask[index] );
\r
1849 hPieceMask[index] = hbm;
\r
1852 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1854 SelectObject( hdc, hbm );
\r
1857 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1858 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1859 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1861 SelectObject( dc1, hPieceMask[index] );
\r
1862 SelectObject( dc2, bm2 );
\r
1863 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1864 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1867 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1868 the piece background and deletes (makes transparent) the rest.
\r
1869 Thanks to that mask, we are free to paint the background with the greates
\r
1870 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1871 We use this, to make gradients and give the pieces a "roundish" look.
\r
1873 SetPieceBackground( hdc, backColor, 2 );
\r
1874 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1878 DeleteObject( bm2 );
\r
1881 SetTextColor( hdc, foreColor );
\r
1882 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1884 SelectObject( hdc, hbm_old );
\r
1886 if( hPieceFace[index] != NULL ) {
\r
1887 DeleteObject( hPieceFace[index] );
\r
1890 hPieceFace[index] = hbm;
\r
1893 static int TranslatePieceToFontPiece( int piece )
\r
1923 case BlackMarshall:
\r
1927 case BlackNightrider:
\r
1933 case BlackUnicorn:
\r
1937 case BlackGrasshopper:
\r
1949 case BlackCardinal:
\r
1956 case WhiteMarshall:
\r
1960 case WhiteNightrider:
\r
1966 case WhiteUnicorn:
\r
1970 case WhiteGrasshopper:
\r
1982 case WhiteCardinal:
\r
1991 void CreatePiecesFromFont()
\r
1994 HDC hdc_window = NULL;
\r
2000 if( fontBitmapSquareSize < 0 ) {
\r
2001 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2005 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2006 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2007 fontBitmapSquareSize = -1;
\r
2011 if( fontBitmapSquareSize != squareSize ) {
\r
2012 hdc_window = GetDC( hwndMain );
\r
2013 hdc = CreateCompatibleDC( hdc_window );
\r
2015 if( hPieceFont != NULL ) {
\r
2016 DeleteObject( hPieceFont );
\r
2019 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2020 hPieceMask[i] = NULL;
\r
2021 hPieceFace[i] = NULL;
\r
2027 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2028 fontHeight = appData.fontPieceSize;
\r
2031 fontHeight = (fontHeight * squareSize) / 100;
\r
2033 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2035 lf.lfEscapement = 0;
\r
2036 lf.lfOrientation = 0;
\r
2037 lf.lfWeight = FW_NORMAL;
\r
2039 lf.lfUnderline = 0;
\r
2040 lf.lfStrikeOut = 0;
\r
2041 lf.lfCharSet = DEFAULT_CHARSET;
\r
2042 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2043 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2044 lf.lfQuality = PROOF_QUALITY;
\r
2045 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2046 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2047 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2049 hPieceFont = CreateFontIndirect( &lf );
\r
2051 if( hPieceFont == NULL ) {
\r
2052 fontBitmapSquareSize = -2;
\r
2055 /* Setup font-to-piece character table */
\r
2056 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2057 /* No (or wrong) global settings, try to detect the font */
\r
2058 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2060 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2062 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2063 /* DiagramTT* family */
\r
2064 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2066 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2067 /* Fairy symbols */
\r
2068 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2070 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2071 /* Good Companion (Some characters get warped as literal :-( */
\r
2072 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2073 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2074 SetCharTable(pieceToFontChar, s);
\r
2077 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2078 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2082 /* Create bitmaps */
\r
2083 hfont_old = SelectObject( hdc, hPieceFont );
\r
2084 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2085 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2086 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2088 SelectObject( hdc, hfont_old );
\r
2090 fontBitmapSquareSize = squareSize;
\r
2094 if( hdc != NULL ) {
\r
2098 if( hdc_window != NULL ) {
\r
2099 ReleaseDC( hwndMain, hdc_window );
\r
2104 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2108 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2109 if (gameInfo.event &&
\r
2110 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2111 strcmp(name, "k80s") == 0) {
\r
2112 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2114 return LoadBitmap(hinst, name);
\r
2118 /* Insert a color into the program's logical palette
\r
2119 structure. This code assumes the given color is
\r
2120 the result of the RGB or PALETTERGB macro, and it
\r
2121 knows how those macros work (which is documented).
\r
2124 InsertInPalette(COLORREF color)
\r
2126 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2128 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2129 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2130 pLogPal->palNumEntries--;
\r
2134 pe->peFlags = (char) 0;
\r
2135 pe->peRed = (char) (0xFF & color);
\r
2136 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2137 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2143 InitDrawingColors()
\r
2145 if (pLogPal == NULL) {
\r
2146 /* Allocate enough memory for a logical palette with
\r
2147 * PALETTESIZE entries and set the size and version fields
\r
2148 * of the logical palette structure.
\r
2150 pLogPal = (NPLOGPALETTE)
\r
2151 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2152 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2153 pLogPal->palVersion = 0x300;
\r
2155 pLogPal->palNumEntries = 0;
\r
2157 InsertInPalette(lightSquareColor);
\r
2158 InsertInPalette(darkSquareColor);
\r
2159 InsertInPalette(whitePieceColor);
\r
2160 InsertInPalette(blackPieceColor);
\r
2161 InsertInPalette(highlightSquareColor);
\r
2162 InsertInPalette(premoveHighlightColor);
\r
2164 /* create a logical color palette according the information
\r
2165 * in the LOGPALETTE structure.
\r
2167 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2169 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2170 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2171 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2172 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2173 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2174 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2175 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2176 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2177 /* [AS] Force rendering of the font-based pieces */
\r
2178 if( fontBitmapSquareSize > 0 ) {
\r
2179 fontBitmapSquareSize = 0;
\r
2185 BoardWidth(int boardSize, int n)
\r
2186 { /* [HGM] argument n added to allow different width and height */
\r
2187 int lineGap = sizeInfo[boardSize].lineGap;
\r
2189 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2190 lineGap = appData.overrideLineGap;
\r
2193 return (n + 1) * lineGap +
\r
2194 n * sizeInfo[boardSize].squareSize;
\r
2197 /* Respond to board resize by dragging edge */
\r
2199 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2201 BoardSize newSize = NUM_SIZES - 1;
\r
2202 static int recurse = 0;
\r
2203 if (IsIconic(hwndMain)) return;
\r
2204 if (recurse > 0) return;
\r
2206 while (newSize > 0) {
\r
2207 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2208 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2209 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2212 boardSize = newSize;
\r
2213 InitDrawingSizes(boardSize, flags);
\r
2218 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2221 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2223 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2224 ChessSquare piece;
\r
2225 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2227 SIZE clockSize, messageSize;
\r
2229 char buf[MSG_SIZ];
\r
2231 HMENU hmenu = GetMenu(hwndMain);
\r
2232 RECT crect, wrect, oldRect;
\r
2234 LOGBRUSH logbrush;
\r
2236 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2237 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2239 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2240 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2242 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2243 oldRect.top = wpMain.y;
\r
2244 oldRect.right = wpMain.x + wpMain.width;
\r
2245 oldRect.bottom = wpMain.y + wpMain.height;
\r
2247 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2248 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2249 squareSize = sizeInfo[boardSize].squareSize;
\r
2250 lineGap = sizeInfo[boardSize].lineGap;
\r
2251 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2253 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2254 lineGap = appData.overrideLineGap;
\r
2257 if (tinyLayout != oldTinyLayout) {
\r
2258 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2260 style &= ~WS_SYSMENU;
\r
2261 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2262 "&Minimize\tCtrl+F4");
\r
2264 style |= WS_SYSMENU;
\r
2265 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2267 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2269 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2270 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2271 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2273 DrawMenuBar(hwndMain);
\r
2276 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2277 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2279 /* Get text area sizes */
\r
2280 hdc = GetDC(hwndMain);
\r
2281 if (appData.clockMode) {
\r
2282 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2284 snprintf(buf, MSG_SIZ, _("White"));
\r
2286 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2287 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2288 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2289 str = _("We only care about the height here");
\r
2290 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2291 SelectObject(hdc, oldFont);
\r
2292 ReleaseDC(hwndMain, hdc);
\r
2294 /* Compute where everything goes */
\r
2295 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2296 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2297 logoHeight = 2*clockSize.cy;
\r
2298 leftLogoRect.left = OUTER_MARGIN;
\r
2299 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2300 leftLogoRect.top = OUTER_MARGIN;
\r
2301 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2303 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2304 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2305 rightLogoRect.top = OUTER_MARGIN;
\r
2306 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2309 whiteRect.left = leftLogoRect.right;
\r
2310 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2311 whiteRect.top = OUTER_MARGIN;
\r
2312 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2314 blackRect.right = rightLogoRect.left;
\r
2315 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2316 blackRect.top = whiteRect.top;
\r
2317 blackRect.bottom = whiteRect.bottom;
\r
2319 whiteRect.left = OUTER_MARGIN;
\r
2320 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2321 whiteRect.top = OUTER_MARGIN;
\r
2322 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2324 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2325 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2326 blackRect.top = whiteRect.top;
\r
2327 blackRect.bottom = whiteRect.bottom;
\r
2329 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2332 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2333 if (appData.showButtonBar) {
\r
2334 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2335 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2337 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2339 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2340 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2342 boardRect.left = OUTER_MARGIN;
\r
2343 boardRect.right = boardRect.left + boardWidth;
\r
2344 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2345 boardRect.bottom = boardRect.top + boardHeight;
\r
2347 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2348 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2349 oldBoardSize = boardSize;
\r
2350 oldTinyLayout = tinyLayout;
\r
2351 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2352 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2353 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2354 winW *= 1 + twoBoards;
\r
2355 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2356 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2357 wpMain.height = winH; // without disturbing window attachments
\r
2358 GetWindowRect(hwndMain, &wrect);
\r
2359 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2360 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2362 // [HGM] placement: let attached windows follow size change.
\r
2363 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2364 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2365 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2366 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2367 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2369 /* compensate if menu bar wrapped */
\r
2370 GetClientRect(hwndMain, &crect);
\r
2371 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2372 wpMain.height += offby;
\r
2374 case WMSZ_TOPLEFT:
\r
2375 SetWindowPos(hwndMain, NULL,
\r
2376 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2377 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2380 case WMSZ_TOPRIGHT:
\r
2382 SetWindowPos(hwndMain, NULL,
\r
2383 wrect.left, wrect.bottom - wpMain.height,
\r
2384 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2387 case WMSZ_BOTTOMLEFT:
\r
2389 SetWindowPos(hwndMain, NULL,
\r
2390 wrect.right - wpMain.width, wrect.top,
\r
2391 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2394 case WMSZ_BOTTOMRIGHT:
\r
2398 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2399 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2404 for (i = 0; i < N_BUTTONS; i++) {
\r
2405 if (buttonDesc[i].hwnd != NULL) {
\r
2406 DestroyWindow(buttonDesc[i].hwnd);
\r
2407 buttonDesc[i].hwnd = NULL;
\r
2409 if (appData.showButtonBar) {
\r
2410 buttonDesc[i].hwnd =
\r
2411 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2412 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2413 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2414 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2415 (HMENU) buttonDesc[i].id,
\r
2416 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2418 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2419 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2420 MAKELPARAM(FALSE, 0));
\r
2422 if (buttonDesc[i].id == IDM_Pause)
\r
2423 hwndPause = buttonDesc[i].hwnd;
\r
2424 buttonDesc[i].wndproc = (WNDPROC)
\r
2425 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2428 if (gridPen != NULL) DeleteObject(gridPen);
\r
2429 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2430 if (premovePen != NULL) DeleteObject(premovePen);
\r
2431 if (lineGap != 0) {
\r
2432 logbrush.lbStyle = BS_SOLID;
\r
2433 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2435 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2436 lineGap, &logbrush, 0, NULL);
\r
2437 logbrush.lbColor = highlightSquareColor;
\r
2439 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2440 lineGap, &logbrush, 0, NULL);
\r
2442 logbrush.lbColor = premoveHighlightColor;
\r
2444 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2445 lineGap, &logbrush, 0, NULL);
\r
2447 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2448 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2449 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2450 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2451 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2452 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2453 BOARD_WIDTH * (squareSize + lineGap);
\r
2454 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2456 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2457 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2458 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2459 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2460 lineGap / 2 + (i * (squareSize + lineGap));
\r
2461 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2462 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2463 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2467 /* [HGM] Licensing requirement */
\r
2469 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2472 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2474 GothicPopUp( "", VariantNormal);
\r
2477 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2479 /* Load piece bitmaps for this board size */
\r
2480 for (i=0; i<=2; i++) {
\r
2481 for (piece = WhitePawn;
\r
2482 (int) piece < (int) BlackPawn;
\r
2483 piece = (ChessSquare) ((int) piece + 1)) {
\r
2484 if (pieceBitmap[i][piece] != NULL)
\r
2485 DeleteObject(pieceBitmap[i][piece]);
\r
2489 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2490 // Orthodox Chess pieces
\r
2491 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2492 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2493 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2494 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2495 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2496 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2497 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2498 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2499 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2500 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2501 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2502 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2503 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2504 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2505 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2506 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2507 // in Shogi, Hijack the unused Queen for Lance
\r
2508 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2509 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2510 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2512 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2513 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2514 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2517 if(squareSize <= 72 && squareSize >= 33) {
\r
2518 /* A & C are available in most sizes now */
\r
2519 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2520 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2521 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2522 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2523 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2524 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2525 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2526 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2527 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2528 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2529 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2530 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2531 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2532 } else { // Smirf-like
\r
2533 if(gameInfo.variant == VariantSChess) {
\r
2534 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2535 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2536 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2538 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2539 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2540 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2543 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2544 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2545 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2546 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2547 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2548 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2549 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2550 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2551 } else { // WinBoard standard
\r
2552 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2553 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2554 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2559 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2560 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2561 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2562 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2563 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2564 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2565 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2566 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2567 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2568 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2569 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2570 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2571 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2572 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2573 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2574 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2575 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2576 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2577 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2578 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2579 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2580 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2581 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2582 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2583 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2584 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2585 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2586 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2587 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2588 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2589 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2591 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2592 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2593 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2594 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2595 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2596 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2597 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2598 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2599 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2600 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2601 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2602 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2603 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2605 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2606 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2607 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2608 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2609 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2610 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2611 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2612 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2613 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2614 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2619 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2620 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2621 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2622 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2623 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2624 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2625 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2626 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2627 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2628 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2629 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2630 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2631 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2632 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2633 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2637 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2638 /* special Shogi support in this size */
\r
2639 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2640 for (piece = WhitePawn;
\r
2641 (int) piece < (int) BlackPawn;
\r
2642 piece = (ChessSquare) ((int) piece + 1)) {
\r
2643 if (pieceBitmap[i][piece] != NULL)
\r
2644 DeleteObject(pieceBitmap[i][piece]);
\r
2647 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2648 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2649 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2650 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2651 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2652 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2653 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2654 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2655 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2656 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2657 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2658 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2659 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2660 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2661 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2662 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2663 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2664 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2665 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2666 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2667 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2668 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2669 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2670 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2671 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2672 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2673 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2674 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2675 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2676 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2677 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2678 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2679 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2680 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2681 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2682 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2683 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2684 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2685 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2686 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2687 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2688 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2694 PieceBitmap(ChessSquare p, int kind)
\r
2696 if ((int) p >= (int) BlackPawn)
\r
2697 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2699 return pieceBitmap[kind][(int) p];
\r
2702 /***************************************************************/
\r
2704 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2705 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2707 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2708 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2712 SquareToPos(int row, int column, int * x, int * y)
\r
2715 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2716 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2718 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2719 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2724 DrawCoordsOnDC(HDC hdc)
\r
2726 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2727 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2728 char str[2] = { NULLCHAR, NULLCHAR };
\r
2729 int oldMode, oldAlign, x, y, start, i;
\r
2733 if (!appData.showCoords)
\r
2736 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2738 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2739 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2740 oldAlign = GetTextAlign(hdc);
\r
2741 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2743 y = boardRect.top + lineGap;
\r
2744 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2746 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2747 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2748 str[0] = files[start + i];
\r
2749 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2750 y += squareSize + lineGap;
\r
2753 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2755 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2756 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2757 str[0] = ranks[start + i];
\r
2758 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2759 x += squareSize + lineGap;
\r
2762 SelectObject(hdc, oldBrush);
\r
2763 SetBkMode(hdc, oldMode);
\r
2764 SetTextAlign(hdc, oldAlign);
\r
2765 SelectObject(hdc, oldFont);
\r
2769 DrawGridOnDC(HDC hdc)
\r
2773 if (lineGap != 0) {
\r
2774 oldPen = SelectObject(hdc, gridPen);
\r
2775 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2776 SelectObject(hdc, oldPen);
\r
2780 #define HIGHLIGHT_PEN 0
\r
2781 #define PREMOVE_PEN 1
\r
2784 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2787 HPEN oldPen, hPen;
\r
2788 if (lineGap == 0) return;
\r
2790 x1 = boardRect.left +
\r
2791 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2792 y1 = boardRect.top +
\r
2793 lineGap/2 + y * (squareSize + lineGap);
\r
2795 x1 = boardRect.left +
\r
2796 lineGap/2 + x * (squareSize + lineGap);
\r
2797 y1 = boardRect.top +
\r
2798 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2800 hPen = pen ? premovePen : highlightPen;
\r
2801 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2802 MoveToEx(hdc, x1, y1, NULL);
\r
2803 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2804 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2805 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2806 LineTo(hdc, x1, y1);
\r
2807 SelectObject(hdc, oldPen);
\r
2811 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2814 for (i=0; i<2; i++) {
\r
2815 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2816 DrawHighlightOnDC(hdc, TRUE,
\r
2817 h->sq[i].x, h->sq[i].y,
\r
2822 /* Note: sqcolor is used only in monoMode */
\r
2823 /* Note that this code is largely duplicated in woptions.c,
\r
2824 function DrawSampleSquare, so that needs to be updated too */
\r
2826 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2828 HBITMAP oldBitmap;
\r
2832 if (appData.blindfold) return;
\r
2834 /* [AS] Use font-based pieces if needed */
\r
2835 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2836 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2837 CreatePiecesFromFont();
\r
2839 if( fontBitmapSquareSize == squareSize ) {
\r
2840 int index = TranslatePieceToFontPiece(piece);
\r
2842 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2844 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2845 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2849 squareSize, squareSize,
\r
2854 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2856 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2857 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2861 squareSize, squareSize,
\r
2870 if (appData.monoMode) {
\r
2871 SelectObject(tmphdc, PieceBitmap(piece,
\r
2872 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2873 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2874 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2876 tmpSize = squareSize;
\r
2878 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2879 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2880 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2881 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2882 x += (squareSize - minorSize)>>1;
\r
2883 y += squareSize - minorSize - 2;
\r
2884 tmpSize = minorSize;
\r
2886 if (color || appData.allWhite ) {
\r
2887 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2889 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2890 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2891 if(appData.upsideDown && color==flipView)
\r
2892 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2894 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2895 /* Use black for outline of white pieces */
\r
2896 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2897 if(appData.upsideDown && color==flipView)
\r
2898 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2900 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2902 /* Use square color for details of black pieces */
\r
2903 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2904 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2905 if(appData.upsideDown && !flipView)
\r
2906 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2908 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2910 SelectObject(hdc, oldBrush);
\r
2911 SelectObject(tmphdc, oldBitmap);
\r
2915 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2916 int GetBackTextureMode( int algo )
\r
2918 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2922 case BACK_TEXTURE_MODE_PLAIN:
\r
2923 result = 1; /* Always use identity map */
\r
2925 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2926 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2934 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2935 to handle redraws cleanly (as random numbers would always be different).
\r
2937 VOID RebuildTextureSquareInfo()
\r
2947 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2949 if( liteBackTexture != NULL ) {
\r
2950 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2951 lite_w = bi.bmWidth;
\r
2952 lite_h = bi.bmHeight;
\r
2956 if( darkBackTexture != NULL ) {
\r
2957 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2958 dark_w = bi.bmWidth;
\r
2959 dark_h = bi.bmHeight;
\r
2963 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2964 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2965 if( (col + row) & 1 ) {
\r
2967 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2968 if( lite_w >= squareSize*BOARD_WIDTH )
\r
2969 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
2971 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2972 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
2973 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
2975 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2976 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2981 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2982 if( dark_w >= squareSize*BOARD_WIDTH )
\r
2983 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
2985 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2986 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
2987 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
2989 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2990 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
2997 /* [AS] Arrow highlighting support */
\r
2999 static double A_WIDTH = 5; /* Width of arrow body */
\r
3001 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3002 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3004 static double Sqr( double x )
\r
3009 static int Round( double x )
\r
3011 return (int) (x + 0.5);
\r
3014 /* Draw an arrow between two points using current settings */
\r
3015 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3018 double dx, dy, j, k, x, y;
\r
3020 if( d_x == s_x ) {
\r
3021 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3023 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3026 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3027 arrow[1].y = d_y - h;
\r
3029 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3030 arrow[2].y = d_y - h;
\r
3035 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3036 arrow[5].y = d_y - h;
\r
3038 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3039 arrow[4].y = d_y - h;
\r
3041 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3044 else if( d_y == s_y ) {
\r
3045 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3048 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3050 arrow[1].x = d_x - w;
\r
3051 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3053 arrow[2].x = d_x - w;
\r
3054 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3059 arrow[5].x = d_x - w;
\r
3060 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3062 arrow[4].x = d_x - w;
\r
3063 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3066 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3069 /* [AS] Needed a lot of paper for this! :-) */
\r
3070 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3071 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3073 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3075 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3080 arrow[0].x = Round(x - j);
\r
3081 arrow[0].y = Round(y + j*dx);
\r
3083 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3084 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3087 x = (double) d_x - k;
\r
3088 y = (double) d_y - k*dy;
\r
3091 x = (double) d_x + k;
\r
3092 y = (double) d_y + k*dy;
\r
3095 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3097 arrow[6].x = Round(x - j);
\r
3098 arrow[6].y = Round(y + j*dx);
\r
3100 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3101 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3103 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3104 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3109 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3110 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3113 Polygon( hdc, arrow, 7 );
\r
3116 /* [AS] Draw an arrow between two squares */
\r
3117 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3119 int s_x, s_y, d_x, d_y;
\r
3126 if( s_col == d_col && s_row == d_row ) {
\r
3130 /* Get source and destination points */
\r
3131 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3132 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3135 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3137 else if( d_y < s_y ) {
\r
3138 d_y += squareSize / 2 + squareSize / 4;
\r
3141 d_y += squareSize / 2;
\r
3145 d_x += squareSize / 2 - squareSize / 4;
\r
3147 else if( d_x < s_x ) {
\r
3148 d_x += squareSize / 2 + squareSize / 4;
\r
3151 d_x += squareSize / 2;
\r
3154 s_x += squareSize / 2;
\r
3155 s_y += squareSize / 2;
\r
3157 /* Adjust width */
\r
3158 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3161 stLB.lbStyle = BS_SOLID;
\r
3162 stLB.lbColor = appData.highlightArrowColor;
\r
3165 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3166 holdpen = SelectObject( hdc, hpen );
\r
3167 hbrush = CreateBrushIndirect( &stLB );
\r
3168 holdbrush = SelectObject( hdc, hbrush );
\r
3170 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3172 SelectObject( hdc, holdpen );
\r
3173 SelectObject( hdc, holdbrush );
\r
3174 DeleteObject( hpen );
\r
3175 DeleteObject( hbrush );
\r
3178 BOOL HasHighlightInfo()
\r
3180 BOOL result = FALSE;
\r
3182 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3183 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3191 BOOL IsDrawArrowEnabled()
\r
3193 BOOL result = FALSE;
\r
3195 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r