2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
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 enum ICS_TYPE ics_type;
\r
105 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
106 int MyGetFullPathName P((char *name, char *fullname));
\r
107 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
108 VOID NewVariantPopup(HWND hwnd);
\r
109 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
110 /*char*/int promoChar));
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P((char *s));
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
132 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
135 POINT sq[2]; /* board coordinates of from, to squares */
\r
138 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
139 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
143 typedef struct { // [HGM] atomic
\r
144 int fromX, fromY, toX, toY, radius;
\r
147 static ExplodeInfo explodeInfo;
\r
149 /* Window class names */
\r
150 char szAppName[] = "WinBoard";
\r
151 char szConsoleName[] = "WBConsole";
\r
153 /* Title bar text */
\r
154 char szTitle[] = "WinBoard";
\r
155 char szConsoleTitle[] = "I C S Interaction";
\r
158 char *settingsFileName;
\r
159 Boolean saveSettingsOnExit;
\r
160 char installDir[MSG_SIZ];
\r
161 int errorExitStatus;
\r
163 BoardSize boardSize;
\r
164 Boolean chessProgram;
\r
165 //static int boardX, boardY;
\r
166 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
167 int squareSize, lineGap, minorSize, border;
\r
168 static int winW, winH;
\r
169 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
170 static int logoHeight = 0;
\r
171 static char messageText[MESSAGE_TEXT_MAX];
\r
172 static int clockTimerEvent = 0;
\r
173 static int loadGameTimerEvent = 0;
\r
174 static int analysisTimerEvent = 0;
\r
175 static DelayedEventCallback delayedTimerCallback;
\r
176 static int delayedTimerEvent = 0;
\r
177 static int buttonCount = 2;
\r
178 char *icsTextMenuString;
\r
180 char *firstChessProgramNames;
\r
181 char *secondChessProgramNames;
\r
183 #define PALETTESIZE 256
\r
185 HINSTANCE hInst; /* current instance */
\r
186 Boolean alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 static HWND savedHwnd;
\r
194 HWND hCommPort = NULL; /* currently open comm port */
\r
195 static HWND hwndPause; /* pause button */
\r
196 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
197 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
198 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
199 explodeBrush, /* [HGM] atomic */
\r
200 markerBrush, /* [HGM] markers */
\r
201 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
202 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
203 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
204 static HPEN gridPen = NULL;
\r
205 static HPEN highlightPen = NULL;
\r
206 static HPEN premovePen = NULL;
\r
207 static NPLOGPALETTE pLogPal;
\r
208 static BOOL paletteChanged = FALSE;
\r
209 static HICON iconWhite, iconBlack, iconCurrent;
\r
210 static int doingSizing = FALSE;
\r
211 static int lastSizing = 0;
\r
212 static int prevStderrPort;
\r
213 static HBITMAP userLogo;
\r
215 static HBITMAP liteBackTexture = NULL;
\r
216 static HBITMAP darkBackTexture = NULL;
\r
217 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
219 static int backTextureSquareSize = 0;
\r
220 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
222 #if __GNUC__ && !defined(_winmajor)
\r
223 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
227 #if defined(_winmajor)
\r
228 #define oldDialog (_winmajor < 4)
\r
230 #define oldDialog 0
\r
234 #define INTERNATIONAL
\r
236 #ifdef INTERNATIONAL
\r
237 # define _(s) T_(s)
\r
243 # define Translate(x, y)
\r
244 # define LoadLanguageFile(s)
\r
247 #ifdef INTERNATIONAL
\r
249 Boolean barbaric; // flag indicating if translation is needed
\r
251 // list of item numbers used in each dialog (used to alter language at run time)
\r
253 #define ABOUTBOX -1 /* not sure why these are needed */
\r
254 #define ABOUTBOX2 -1
\r
256 int dialogItems[][42] = {
\r
257 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
258 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
259 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
260 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
261 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
262 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
263 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
264 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
265 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
266 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
267 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
268 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
269 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
270 { ABOUTBOX2, IDC_ChessBoard },
\r
271 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
272 OPT_GameListClose, IDC_GameListDoFilter },
\r
273 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
274 { DLG_Error, IDOK },
\r
275 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
276 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
277 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
278 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
279 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
280 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
281 { DLG_IndexNumber, IDC_Index },
\r
282 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
283 { DLG_TypeInName, IDOK, IDCANCEL },
\r
284 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
285 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
286 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
287 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
288 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
289 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
290 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
291 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
292 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
293 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
294 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
295 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
296 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
297 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
298 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
299 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
300 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
301 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
302 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
303 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
304 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
305 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
306 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
307 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
308 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
309 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
310 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
311 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
312 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
313 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
314 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
315 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
316 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
317 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
318 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
319 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
320 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
321 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
322 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
323 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
324 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
325 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
326 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
327 { DLG_MoveHistory },
\r
328 { DLG_EvalGraph },
\r
329 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
330 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
331 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
332 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
333 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
334 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
335 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
336 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
337 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
341 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
342 static int lastChecked;
\r
343 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
344 extern int tinyLayout;
\r
345 extern char * menuBarText[][10];
\r
348 LoadLanguageFile(char *name)
\r
349 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
351 int i=0, j=0, n=0, k;
\r
354 if(!name || name[0] == NULLCHAR) return;
\r
355 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
356 appData.language = oldLanguage;
\r
357 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
358 if((f = fopen(buf, "r")) == NULL) return;
\r
359 while((k = fgetc(f)) != EOF) {
\r
360 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
361 languageBuf[i] = k;
\r
363 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
365 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
366 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
367 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
368 english[j] = languageBuf + n + 1; *p = 0;
\r
369 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
370 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
375 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
377 case 'n': k = '\n'; break;
\r
378 case 'r': k = '\r'; break;
\r
379 case 't': k = '\t'; break;
\r
381 languageBuf[--i] = k;
\r
386 barbaric = (j != 0);
\r
387 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
392 { // return the translation of the given string
\r
393 // efficiency can be improved a lot...
\r
395 static char buf[MSG_SIZ];
\r
396 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
397 if(!barbaric) return s;
\r
398 if(!s) return ""; // sanity
\r
399 while(english[i]) {
\r
400 if(!strcmp(s, english[i])) return foreign[i];
\r
401 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
402 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
411 Translate(HWND hDlg, int dialogID)
\r
412 { // translate all text items in the given dialog
\r
414 char buf[MSG_SIZ], *s;
\r
415 if(!barbaric) return;
\r
416 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
417 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
418 GetWindowText( hDlg, buf, MSG_SIZ );
\r
420 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
421 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
422 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
423 if(strlen(buf) == 0) continue;
\r
425 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
430 TranslateOneMenu(int i, HMENU subMenu)
\r
433 static MENUITEMINFO info;
\r
435 info.cbSize = sizeof(MENUITEMINFO);
\r
436 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
437 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
439 info.dwTypeData = buf;
\r
440 info.cch = sizeof(buf);
\r
441 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
443 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
444 else menuText[i][j] = strdup(buf); // remember original on first change
\r
446 if(buf[0] == NULLCHAR) continue;
\r
447 info.dwTypeData = T_(buf);
\r
448 info.cch = strlen(buf)+1;
\r
449 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
455 TranslateMenus(int addLanguage)
\r
458 WIN32_FIND_DATA fileData;
\r
460 #define IDM_English 1970
\r
462 HMENU mainMenu = GetMenu(hwndMain);
\r
463 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
464 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
465 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
466 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
467 TranslateOneMenu(i, subMenu);
\r
469 DrawMenuBar(hwndMain);
\r
472 if(!addLanguage) return;
\r
473 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
474 HMENU mainMenu = GetMenu(hwndMain);
\r
475 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
476 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
477 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
478 i = 0; lastChecked = IDM_English;
\r
480 char *p, *q = fileData.cFileName;
\r
481 int checkFlag = MF_UNCHECKED;
\r
482 languageFile[i] = strdup(q);
\r
483 if(barbaric && !strcmp(oldLanguage, q)) {
\r
484 checkFlag = MF_CHECKED;
\r
485 lastChecked = IDM_English + i + 1;
\r
486 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
488 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
489 p = strstr(fileData.cFileName, ".lng");
\r
491 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
492 } while(FindNextFile(hFind, &fileData));
\r
499 #define IDM_RecentEngines 3000
\r
502 RecentEngineMenu (char *s)
\r
504 if(appData.icsActive) return;
\r
505 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
506 HMENU mainMenu = GetMenu(hwndMain);
\r
507 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
508 int i=IDM_RecentEngines;
\r
509 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
510 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
512 char *p = strchr(s, '\n');
\r
513 if(p == NULL) return; // malformed!
\r
515 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
529 int cliWidth, cliHeight;
\r
532 SizeInfo sizeInfo[] =
\r
534 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
535 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
536 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
537 { "petite", 33, 1, 1, 1, 0, 0 },
\r
538 { "slim", 37, 2, 1, 0, 0, 0 },
\r
539 { "small", 40, 2, 1, 0, 0, 0 },
\r
540 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
541 { "middling", 49, 2, 0, 0, 0, 0 },
\r
542 { "average", 54, 2, 0, 0, 0, 0 },
\r
543 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
544 { "medium", 64, 3, 0, 0, 0, 0 },
\r
545 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
546 { "large", 80, 3, 0, 0, 0, 0 },
\r
547 { "big", 87, 3, 0, 0, 0, 0 },
\r
548 { "huge", 95, 3, 0, 0, 0, 0 },
\r
549 { "giant", 108, 3, 0, 0, 0, 0 },
\r
550 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
551 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
552 { NULL, 0, 0, 0, 0, 0, 0 }
\r
555 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
556 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
558 { 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
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
575 { 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
578 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
587 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
588 #define N_BUTTONS 5
\r
590 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
592 {"<<", IDM_ToStart, NULL, NULL},
\r
593 {"<", IDM_Backward, NULL, NULL},
\r
594 {"P", IDM_Pause, NULL, NULL},
\r
595 {">", IDM_Forward, NULL, NULL},
\r
596 {">>", IDM_ToEnd, NULL, NULL},
\r
599 int tinyLayout = 0, smallLayout = 0;
\r
600 #define MENU_BAR_ITEMS 9
\r
601 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
602 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
603 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
607 MySound sounds[(int)NSoundClasses];
\r
608 MyTextAttribs textAttribs[(int)NColorClasses];
\r
610 MyColorizeAttribs colorizeAttribs[] = {
\r
611 { (COLORREF)0, 0, N_("Shout Text") },
\r
612 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
613 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
614 { (COLORREF)0, 0, N_("Channel Text") },
\r
615 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
616 { (COLORREF)0, 0, N_("Tell Text") },
\r
617 { (COLORREF)0, 0, N_("Challenge Text") },
\r
618 { (COLORREF)0, 0, N_("Request Text") },
\r
619 { (COLORREF)0, 0, N_("Seek Text") },
\r
620 { (COLORREF)0, 0, N_("Normal Text") },
\r
621 { (COLORREF)0, 0, N_("None") }
\r
626 static char *commentTitle;
\r
627 static char *commentText;
\r
628 static int commentIndex;
\r
629 static Boolean editComment = FALSE;
\r
632 char errorTitle[MSG_SIZ];
\r
633 char errorMessage[2*MSG_SIZ];
\r
634 HWND errorDialog = NULL;
\r
635 BOOLEAN moveErrorMessageUp = FALSE;
\r
636 BOOLEAN consoleEcho = TRUE;
\r
637 CHARFORMAT consoleCF;
\r
638 COLORREF consoleBackgroundColor;
\r
640 char *programVersion;
\r
646 typedef int CPKind;
\r
655 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
658 #define INPUT_SOURCE_BUF_SIZE 4096
\r
660 typedef struct _InputSource {
\r
667 char buf[INPUT_SOURCE_BUF_SIZE];
\r
671 InputCallback func;
\r
672 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
676 InputSource *consoleInputSource;
\r
681 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
682 VOID ConsoleCreate();
\r
684 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
685 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
686 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
687 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
689 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
690 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
691 void ParseIcsTextMenu(char *icsTextMenuString);
\r
692 VOID PopUpNameDialog(char firstchar);
\r
693 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
697 int GameListOptions();
\r
699 int dummy; // [HGM] for obsolete args
\r
701 HWND hwndMain = NULL; /* root window*/
\r
702 HWND hwndConsole = NULL;
\r
703 HWND commentDialog = NULL;
\r
704 HWND moveHistoryDialog = NULL;
\r
705 HWND evalGraphDialog = NULL;
\r
706 HWND engineOutputDialog = NULL;
\r
707 HWND gameListDialog = NULL;
\r
708 HWND editTagsDialog = NULL;
\r
710 int commentUp = FALSE;
\r
712 WindowPlacement wpMain;
\r
713 WindowPlacement wpConsole;
\r
714 WindowPlacement wpComment;
\r
715 WindowPlacement wpMoveHistory;
\r
716 WindowPlacement wpEvalGraph;
\r
717 WindowPlacement wpEngineOutput;
\r
718 WindowPlacement wpGameList;
\r
719 WindowPlacement wpTags;
\r
721 VOID EngineOptionsPopup(); // [HGM] settings
\r
723 VOID GothicPopUp(char *title, VariantClass variant);
\r
725 * Setting "frozen" should disable all user input other than deleting
\r
726 * the window. We do this while engines are initializing themselves.
\r
728 static int frozen = 0;
\r
729 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
735 if (frozen) return;
\r
737 hmenu = GetMenu(hwndMain);
\r
738 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
739 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
741 DrawMenuBar(hwndMain);
\r
744 /* Undo a FreezeUI */
\r
750 if (!frozen) return;
\r
752 hmenu = GetMenu(hwndMain);
\r
753 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
754 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
756 DrawMenuBar(hwndMain);
\r
759 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
761 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
767 #define JAWS_ALT_INTERCEPT
\r
768 #define JAWS_KBUP_NAVIGATION
\r
769 #define JAWS_KBDOWN_NAVIGATION
\r
770 #define JAWS_MENU_ITEMS
\r
771 #define JAWS_SILENCE
\r
772 #define JAWS_REPLAY
\r
774 #define JAWS_COPYRIGHT
\r
775 #define JAWS_DELETE(X) X
\r
776 #define SAYMACHINEMOVE()
\r
780 /*---------------------------------------------------------------------------*\
\r
784 \*---------------------------------------------------------------------------*/
\r
787 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
788 LPSTR lpCmdLine, int nCmdShow)
\r
791 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
792 // INITCOMMONCONTROLSEX ex;
\r
796 LoadLibrary("RICHED32.DLL");
\r
797 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
799 if (!InitApplication(hInstance)) {
\r
802 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
809 // InitCommonControlsEx(&ex);
\r
810 InitCommonControls();
\r
812 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
813 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
814 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
816 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
818 while (GetMessage(&msg, /* message structure */
\r
819 NULL, /* handle of window receiving the message */
\r
820 0, /* lowest message to examine */
\r
821 0)) /* highest message to examine */
\r
824 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
825 // [HGM] navigate: switch between all windows with tab
\r
826 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
827 int i, currentElement = 0;
\r
829 // first determine what element of the chain we come from (if any)
\r
830 if(appData.icsActive) {
\r
831 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
832 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
834 if(engineOutputDialog && EngineOutputIsUp()) {
\r
835 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
836 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
838 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
839 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
841 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
842 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
843 if(msg.hwnd == e1) currentElement = 2; else
\r
844 if(msg.hwnd == e2) currentElement = 3; else
\r
845 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
846 if(msg.hwnd == mh) currentElement = 4; else
\r
847 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
848 if(msg.hwnd == hText) currentElement = 5; else
\r
849 if(msg.hwnd == hInput) currentElement = 6; else
\r
850 for (i = 0; i < N_BUTTONS; i++) {
\r
851 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
854 // determine where to go to
\r
855 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
857 currentElement = (currentElement + direction) % 7;
\r
858 switch(currentElement) {
\r
860 h = hwndMain; break; // passing this case always makes the loop exit
\r
862 h = buttonDesc[0].hwnd; break; // could be NULL
\r
864 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
867 if(!EngineOutputIsUp()) continue;
\r
870 if(!MoveHistoryIsUp()) continue;
\r
872 // case 6: // input to eval graph does not seem to get here!
\r
873 // if(!EvalGraphIsUp()) continue;
\r
874 // h = evalGraphDialog; break;
\r
876 if(!appData.icsActive) continue;
\r
880 if(!appData.icsActive) continue;
\r
886 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
887 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
890 continue; // this message now has been processed
\r
894 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
895 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
896 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
897 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
898 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
899 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
900 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
901 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
902 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
903 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
904 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
905 for(i=0; i<MAX_CHAT; i++)
\r
906 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
909 if(done) continue; // [HGM] chat: end patch
\r
910 TranslateMessage(&msg); /* Translates virtual key codes */
\r
911 DispatchMessage(&msg); /* Dispatches message to window */
\r
916 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
919 /*---------------------------------------------------------------------------*\
\r
921 * Initialization functions
\r
923 \*---------------------------------------------------------------------------*/
\r
927 { // update user logo if necessary
\r
928 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
930 if(appData.autoLogo) {
\r
931 curName = UserName();
\r
932 if(strcmp(curName, oldUserName)) {
\r
933 GetCurrentDirectory(MSG_SIZ, dir);
\r
934 SetCurrentDirectory(installDir);
\r
935 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
936 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
937 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
938 if(userLogo == NULL)
\r
939 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
940 SetCurrentDirectory(dir); /* return to prev directory */
\r
946 InitApplication(HINSTANCE hInstance)
\r
950 /* Fill in window class structure with parameters that describe the */
\r
953 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
954 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
955 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
956 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
957 wc.hInstance = hInstance; /* Owner of this class */
\r
958 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
959 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
960 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
961 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
962 wc.lpszClassName = szAppName; /* Name to register as */
\r
964 /* Register the window class and return success/failure code. */
\r
965 if (!RegisterClass(&wc)) return FALSE;
\r
967 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
968 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
970 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
971 wc.hInstance = hInstance;
\r
972 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
973 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
974 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
975 wc.lpszMenuName = NULL;
\r
976 wc.lpszClassName = szConsoleName;
\r
978 if (!RegisterClass(&wc)) return FALSE;
\r
983 /* Set by InitInstance, used by EnsureOnScreen */
\r
984 int screenHeight, screenWidth;
\r
987 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
989 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
990 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
991 if (*x > screenWidth - 32) *x = 0;
\r
992 if (*y > screenHeight - 32) *y = 0;
\r
993 if (*x < minX) *x = minX;
\r
994 if (*y < minY) *y = minY;
\r
998 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1000 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1001 GetCurrentDirectory(MSG_SIZ, dir);
\r
1002 SetCurrentDirectory(installDir);
\r
1003 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1004 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1006 if (cps->programLogo == NULL && appData.debugMode) {
\r
1007 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1009 } else if(appData.autoLogo) {
\r
1010 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1011 char *opponent = "";
\r
1012 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1013 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1014 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1015 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1016 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1017 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1020 if(appData.directory[n] && appData.directory[n][0]) {
\r
1021 SetCurrentDirectory(appData.directory[n]);
\r
1022 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1025 SetCurrentDirectory(dir); /* return to prev directory */
\r
1031 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1032 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1034 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1035 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1036 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1037 liteBackTextureMode = appData.liteBackTextureMode;
\r
1039 if (liteBackTexture == NULL && appData.debugMode) {
\r
1040 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1044 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1045 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1046 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1047 darkBackTextureMode = appData.darkBackTextureMode;
\r
1049 if (darkBackTexture == NULL && appData.debugMode) {
\r
1050 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1056 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1058 HWND hwnd; /* Main window handle. */
\r
1060 WINDOWPLACEMENT wp;
\r
1063 hInst = hInstance; /* Store instance handle in our global variable */
\r
1064 programName = szAppName;
\r
1066 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1067 *filepart = NULLCHAR;
\r
1068 SetCurrentDirectory(installDir);
\r
1070 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1072 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1073 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1074 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1075 /* xboard, and older WinBoards, controlled the move sound with the
\r
1076 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1077 always turn the option on (so that the backend will call us),
\r
1078 then let the user turn the sound off by setting it to silence if
\r
1079 desired. To accommodate old winboard.ini files saved by old
\r
1080 versions of WinBoard, we also turn off the sound if the option
\r
1081 was initially set to false. [HGM] taken out of InitAppData */
\r
1082 if (!appData.ringBellAfterMoves) {
\r
1083 sounds[(int)SoundMove].name = strdup("");
\r
1084 appData.ringBellAfterMoves = TRUE;
\r
1086 if (appData.debugMode) {
\r
1087 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1088 setbuf(debugFP, NULL);
\r
1091 LoadLanguageFile(appData.language);
\r
1095 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1096 // InitEngineUCI( installDir, &second );
\r
1098 /* Create a main window for this application instance. */
\r
1099 hwnd = CreateWindow(szAppName, szTitle,
\r
1100 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1101 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1102 NULL, NULL, hInstance, NULL);
\r
1105 /* If window could not be created, return "failure" */
\r
1110 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1111 LoadLogo(&first, 0, FALSE);
\r
1112 LoadLogo(&second, 1, appData.icsActive);
\r
1116 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1117 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1118 iconCurrent = iconWhite;
\r
1119 InitDrawingColors();
\r
1120 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1121 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1122 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1123 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1124 /* Compute window size for each board size, and use the largest
\r
1125 size that fits on this screen as the default. */
\r
1126 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1127 if (boardSize == (BoardSize)-1 &&
\r
1128 winH <= screenHeight
\r
1129 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1130 && winW <= screenWidth) {
\r
1131 boardSize = (BoardSize)ibs;
\r
1135 InitDrawingSizes(boardSize, 0);
\r
1136 RecentEngineMenu(appData.recentEngineList);
\r
1138 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1140 /* [AS] Load textures if specified */
\r
1143 mysrandom( (unsigned) time(NULL) );
\r
1145 /* [AS] Restore layout */
\r
1146 if( wpMoveHistory.visible ) {
\r
1147 MoveHistoryPopUp();
\r
1150 if( wpEvalGraph.visible ) {
\r
1154 if( wpEngineOutput.visible ) {
\r
1155 EngineOutputPopUp();
\r
1158 /* Make the window visible; update its client area; and return "success" */
\r
1159 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1160 wp.length = sizeof(WINDOWPLACEMENT);
\r
1162 wp.showCmd = nCmdShow;
\r
1163 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1164 wp.rcNormalPosition.left = wpMain.x;
\r
1165 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1166 wp.rcNormalPosition.top = wpMain.y;
\r
1167 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1168 SetWindowPlacement(hwndMain, &wp);
\r
1170 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1172 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1173 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1175 if (hwndConsole) {
\r
1177 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1178 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1180 ShowWindow(hwndConsole, nCmdShow);
\r
1181 SetActiveWindow(hwndConsole);
\r
1183 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1184 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1193 HMENU hmenu = GetMenu(hwndMain);
\r
1195 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1196 MF_BYCOMMAND|((appData.icsActive &&
\r
1197 *appData.icsCommPort != NULLCHAR) ?
\r
1198 MF_ENABLED : MF_GRAYED));
\r
1199 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1200 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1201 MF_CHECKED : MF_UNCHECKED));
\r
1204 //---------------------------------------------------------------------------------------------------------
\r
1206 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1207 #define XBOARD FALSE
\r
1209 #define OPTCHAR "/"
\r
1210 #define SEPCHAR "="
\r
1211 #define TOPLEVEL 0
\r
1215 // front-end part of option handling
\r
1218 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1220 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1221 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1224 lf->lfEscapement = 0;
\r
1225 lf->lfOrientation = 0;
\r
1226 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1227 lf->lfItalic = mfp->italic;
\r
1228 lf->lfUnderline = mfp->underline;
\r
1229 lf->lfStrikeOut = mfp->strikeout;
\r
1230 lf->lfCharSet = mfp->charset;
\r
1231 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1232 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1233 lf->lfQuality = DEFAULT_QUALITY;
\r
1234 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1235 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1239 CreateFontInMF(MyFont *mf)
\r
1241 LFfromMFP(&mf->lf, &mf->mfp);
\r
1242 if (mf->hf) DeleteObject(mf->hf);
\r
1243 mf->hf = CreateFontIndirect(&mf->lf);
\r
1246 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1248 colorVariable[] = {
\r
1249 &whitePieceColor,
\r
1250 &blackPieceColor,
\r
1251 &lightSquareColor,
\r
1252 &darkSquareColor,
\r
1253 &highlightSquareColor,
\r
1254 &premoveHighlightColor,
\r
1256 &consoleBackgroundColor,
\r
1257 &appData.fontForeColorWhite,
\r
1258 &appData.fontBackColorWhite,
\r
1259 &appData.fontForeColorBlack,
\r
1260 &appData.fontBackColorBlack,
\r
1261 &appData.evalHistColorWhite,
\r
1262 &appData.evalHistColorBlack,
\r
1263 &appData.highlightArrowColor,
\r
1266 /* Command line font name parser. NULL name means do nothing.
\r
1267 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1268 For backward compatibility, syntax without the colon is also
\r
1269 accepted, but font names with digits in them won't work in that case.
\r
1272 ParseFontName(char *name, MyFontParams *mfp)
\r
1275 if (name == NULL) return;
\r
1277 q = strchr(p, ':');
\r
1279 if (q - p >= sizeof(mfp->faceName))
\r
1280 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1281 memcpy(mfp->faceName, p, q - p);
\r
1282 mfp->faceName[q - p] = NULLCHAR;
\r
1285 q = mfp->faceName;
\r
1287 while (*p && !isdigit(*p)) {
\r
1289 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1290 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1292 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1295 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1296 mfp->pointSize = (float) atof(p);
\r
1297 mfp->bold = (strchr(p, 'b') != NULL);
\r
1298 mfp->italic = (strchr(p, 'i') != NULL);
\r
1299 mfp->underline = (strchr(p, 'u') != NULL);
\r
1300 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1301 mfp->charset = DEFAULT_CHARSET;
\r
1302 q = strchr(p, 'c');
\r
1304 mfp->charset = (BYTE) atoi(q+1);
\r
1308 ParseFont(char *name, int number)
\r
1309 { // wrapper to shield back-end from 'font'
\r
1310 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1315 { // in WB we have a 2D array of fonts; this initializes their description
\r
1317 /* Point font array elements to structures and
\r
1318 parse default font names */
\r
1319 for (i=0; i<NUM_FONTS; i++) {
\r
1320 for (j=0; j<NUM_SIZES; j++) {
\r
1321 font[j][i] = &fontRec[j][i];
\r
1322 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1329 { // here we create the actual fonts from the selected descriptions
\r
1331 for (i=0; i<NUM_FONTS; i++) {
\r
1332 for (j=0; j<NUM_SIZES; j++) {
\r
1333 CreateFontInMF(font[j][i]);
\r
1337 /* Color name parser.
\r
1338 X version accepts X color names, but this one
\r
1339 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1341 ParseColorName(char *name)
\r
1343 int red, green, blue, count;
\r
1344 char buf[MSG_SIZ];
\r
1346 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1348 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1349 &red, &green, &blue);
\r
1352 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1353 DisplayError(buf, 0);
\r
1354 return RGB(0, 0, 0);
\r
1356 return PALETTERGB(red, green, blue);
\r
1360 ParseColor(int n, char *name)
\r
1361 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1362 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1366 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1368 char *e = argValue;
\r
1372 if (*e == 'b') eff |= CFE_BOLD;
\r
1373 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1374 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1375 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1376 else if (*e == '#' || isdigit(*e)) break;
\r
1380 *color = ParseColorName(e);
\r
1384 ParseTextAttribs(ColorClass cc, char *s)
\r
1385 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1386 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1387 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1391 ParseBoardSize(void *addr, char *name)
\r
1392 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1393 BoardSize bs = SizeTiny;
\r
1394 while (sizeInfo[bs].name != NULL) {
\r
1395 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1396 *(BoardSize *)addr = bs;
\r
1401 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1406 { // [HGM] import name from appData first
\r
1409 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1410 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1411 textAttribs[cc].sound.data = NULL;
\r
1412 MyLoadSound(&textAttribs[cc].sound);
\r
1414 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1415 textAttribs[cc].sound.name = strdup("");
\r
1416 textAttribs[cc].sound.data = NULL;
\r
1418 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1419 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1420 sounds[sc].data = NULL;
\r
1421 MyLoadSound(&sounds[sc]);
\r
1426 SetCommPortDefaults()
\r
1428 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1429 dcb.DCBlength = sizeof(DCB);
\r
1430 dcb.BaudRate = 9600;
\r
1431 dcb.fBinary = TRUE;
\r
1432 dcb.fParity = FALSE;
\r
1433 dcb.fOutxCtsFlow = FALSE;
\r
1434 dcb.fOutxDsrFlow = FALSE;
\r
1435 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1436 dcb.fDsrSensitivity = FALSE;
\r
1437 dcb.fTXContinueOnXoff = TRUE;
\r
1438 dcb.fOutX = FALSE;
\r
1440 dcb.fNull = FALSE;
\r
1441 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1442 dcb.fAbortOnError = FALSE;
\r
1444 dcb.Parity = SPACEPARITY;
\r
1445 dcb.StopBits = ONESTOPBIT;
\r
1448 // [HGM] args: these three cases taken out to stay in front-end
\r
1450 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1451 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1452 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1453 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1455 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1456 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1457 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1458 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1459 ad->argName, mfp->faceName, mfp->pointSize,
\r
1460 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1461 mfp->bold ? "b" : "",
\r
1462 mfp->italic ? "i" : "",
\r
1463 mfp->underline ? "u" : "",
\r
1464 mfp->strikeout ? "s" : "",
\r
1465 (int)mfp->charset);
\r
1471 { // [HGM] copy the names from the internal WB variables to appData
\r
1474 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1475 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1476 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1477 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1481 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1482 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1483 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1484 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1485 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1486 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1487 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1488 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1489 (ta->effects) ? " " : "",
\r
1490 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1494 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1495 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1496 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1497 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1498 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1502 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1503 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1504 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1508 ParseCommPortSettings(char *s)
\r
1509 { // wrapper to keep dcb from back-end
\r
1510 ParseCommSettings(s, &dcb);
\r
1515 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1516 GetActualPlacement(hwndMain, &wpMain);
\r
1517 GetActualPlacement(hwndConsole, &wpConsole);
\r
1518 GetActualPlacement(commentDialog, &wpComment);
\r
1519 GetActualPlacement(editTagsDialog, &wpTags);
\r
1520 GetActualPlacement(gameListDialog, &wpGameList);
\r
1521 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1522 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1523 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1527 PrintCommPortSettings(FILE *f, char *name)
\r
1528 { // wrapper to shield back-end from DCB
\r
1529 PrintCommSettings(f, name, &dcb);
\r
1533 MySearchPath(char *installDir, char *name, char *fullname)
\r
1535 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1536 if(name[0]== '%') {
\r
1537 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1538 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1539 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1540 *strchr(buf, '%') = 0;
\r
1541 strcat(fullname, getenv(buf));
\r
1542 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1544 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1545 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1546 return (int) strlen(fullname);
\r
1548 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1552 MyGetFullPathName(char *name, char *fullname)
\r
1555 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1560 { // [HGM] args: allows testing if main window is realized from back-end
\r
1561 return hwndMain != NULL;
\r
1565 PopUpStartupDialog()
\r
1569 LoadLanguageFile(appData.language);
\r
1570 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1571 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1572 FreeProcInstance(lpProc);
\r
1575 /*---------------------------------------------------------------------------*\
\r
1577 * GDI board drawing routines
\r
1579 \*---------------------------------------------------------------------------*/
\r
1581 /* [AS] Draw square using background texture */
\r
1582 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1587 return; /* Should never happen! */
\r
1590 SetGraphicsMode( dst, GM_ADVANCED );
\r
1597 /* X reflection */
\r
1602 x.eDx = (FLOAT) dw + dx - 1;
\r
1605 SetWorldTransform( dst, &x );
\r
1608 /* Y reflection */
\r
1614 x.eDy = (FLOAT) dh + dy - 1;
\r
1616 SetWorldTransform( dst, &x );
\r
1624 x.eDx = (FLOAT) dx;
\r
1625 x.eDy = (FLOAT) dy;
\r
1628 SetWorldTransform( dst, &x );
\r
1632 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1640 SetWorldTransform( dst, &x );
\r
1642 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1645 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1647 PM_WP = (int) WhitePawn,
\r
1648 PM_WN = (int) WhiteKnight,
\r
1649 PM_WB = (int) WhiteBishop,
\r
1650 PM_WR = (int) WhiteRook,
\r
1651 PM_WQ = (int) WhiteQueen,
\r
1652 PM_WF = (int) WhiteFerz,
\r
1653 PM_WW = (int) WhiteWazir,
\r
1654 PM_WE = (int) WhiteAlfil,
\r
1655 PM_WM = (int) WhiteMan,
\r
1656 PM_WO = (int) WhiteCannon,
\r
1657 PM_WU = (int) WhiteUnicorn,
\r
1658 PM_WH = (int) WhiteNightrider,
\r
1659 PM_WA = (int) WhiteAngel,
\r
1660 PM_WC = (int) WhiteMarshall,
\r
1661 PM_WAB = (int) WhiteCardinal,
\r
1662 PM_WD = (int) WhiteDragon,
\r
1663 PM_WL = (int) WhiteLance,
\r
1664 PM_WS = (int) WhiteCobra,
\r
1665 PM_WV = (int) WhiteFalcon,
\r
1666 PM_WSG = (int) WhiteSilver,
\r
1667 PM_WG = (int) WhiteGrasshopper,
\r
1668 PM_WK = (int) WhiteKing,
\r
1669 PM_BP = (int) BlackPawn,
\r
1670 PM_BN = (int) BlackKnight,
\r
1671 PM_BB = (int) BlackBishop,
\r
1672 PM_BR = (int) BlackRook,
\r
1673 PM_BQ = (int) BlackQueen,
\r
1674 PM_BF = (int) BlackFerz,
\r
1675 PM_BW = (int) BlackWazir,
\r
1676 PM_BE = (int) BlackAlfil,
\r
1677 PM_BM = (int) BlackMan,
\r
1678 PM_BO = (int) BlackCannon,
\r
1679 PM_BU = (int) BlackUnicorn,
\r
1680 PM_BH = (int) BlackNightrider,
\r
1681 PM_BA = (int) BlackAngel,
\r
1682 PM_BC = (int) BlackMarshall,
\r
1683 PM_BG = (int) BlackGrasshopper,
\r
1684 PM_BAB = (int) BlackCardinal,
\r
1685 PM_BD = (int) BlackDragon,
\r
1686 PM_BL = (int) BlackLance,
\r
1687 PM_BS = (int) BlackCobra,
\r
1688 PM_BV = (int) BlackFalcon,
\r
1689 PM_BSG = (int) BlackSilver,
\r
1690 PM_BK = (int) BlackKing
\r
1693 static HFONT hPieceFont = NULL;
\r
1694 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1695 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1696 static int fontBitmapSquareSize = 0;
\r
1697 static char pieceToFontChar[(int) EmptySquare] =
\r
1698 { 'p', 'n', 'b', 'r', 'q',
\r
1699 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1700 'k', 'o', 'm', 'v', 't', 'w',
\r
1701 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1704 extern BOOL SetCharTable( char *table, const char * map );
\r
1705 /* [HGM] moved to backend.c */
\r
1707 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1710 BYTE r1 = GetRValue( color );
\r
1711 BYTE g1 = GetGValue( color );
\r
1712 BYTE b1 = GetBValue( color );
\r
1718 /* Create a uniform background first */
\r
1719 hbrush = CreateSolidBrush( color );
\r
1720 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1721 FillRect( hdc, &rc, hbrush );
\r
1722 DeleteObject( hbrush );
\r
1725 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1726 int steps = squareSize / 2;
\r
1729 for( i=0; i<steps; i++ ) {
\r
1730 BYTE r = r1 - (r1-r2) * i / steps;
\r
1731 BYTE g = g1 - (g1-g2) * i / steps;
\r
1732 BYTE b = b1 - (b1-b2) * i / steps;
\r
1734 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1735 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1736 FillRect( hdc, &rc, hbrush );
\r
1737 DeleteObject(hbrush);
\r
1740 else if( mode == 2 ) {
\r
1741 /* Diagonal gradient, good more or less for every piece */
\r
1742 POINT triangle[3];
\r
1743 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1744 HBRUSH hbrush_old;
\r
1745 int steps = squareSize;
\r
1748 triangle[0].x = squareSize - steps;
\r
1749 triangle[0].y = squareSize;
\r
1750 triangle[1].x = squareSize;
\r
1751 triangle[1].y = squareSize;
\r
1752 triangle[2].x = squareSize;
\r
1753 triangle[2].y = squareSize - steps;
\r
1755 for( i=0; i<steps; i++ ) {
\r
1756 BYTE r = r1 - (r1-r2) * i / steps;
\r
1757 BYTE g = g1 - (g1-g2) * i / steps;
\r
1758 BYTE b = b1 - (b1-b2) * i / steps;
\r
1760 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1761 hbrush_old = SelectObject( hdc, hbrush );
\r
1762 Polygon( hdc, triangle, 3 );
\r
1763 SelectObject( hdc, hbrush_old );
\r
1764 DeleteObject(hbrush);
\r
1769 SelectObject( hdc, hpen );
\r
1774 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1775 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1776 piece: follow the steps as explained below.
\r
1778 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1782 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1786 int backColor = whitePieceColor;
\r
1787 int foreColor = blackPieceColor;
\r
1789 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1790 backColor = appData.fontBackColorWhite;
\r
1791 foreColor = appData.fontForeColorWhite;
\r
1793 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1794 backColor = appData.fontBackColorBlack;
\r
1795 foreColor = appData.fontForeColorBlack;
\r
1799 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1801 hbm_old = SelectObject( hdc, hbm );
\r
1805 rc.right = squareSize;
\r
1806 rc.bottom = squareSize;
\r
1808 /* Step 1: background is now black */
\r
1809 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1811 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1813 pt.x = (squareSize - sz.cx) / 2;
\r
1814 pt.y = (squareSize - sz.cy) / 2;
\r
1816 SetBkMode( hdc, TRANSPARENT );
\r
1817 SetTextColor( hdc, chroma );
\r
1818 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1819 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1821 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1822 /* Step 3: the area outside the piece is filled with white */
\r
1823 // FloodFill( hdc, 0, 0, chroma );
\r
1824 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1825 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1826 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1827 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1828 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1830 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1831 but if the start point is not inside the piece we're lost!
\r
1832 There should be a better way to do this... if we could create a region or path
\r
1833 from the fill operation we would be fine for example.
\r
1835 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1836 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1838 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1839 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1840 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1842 SelectObject( dc2, bm2 );
\r
1843 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1844 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1845 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1846 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1847 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1850 DeleteObject( bm2 );
\r
1853 SetTextColor( hdc, 0 );
\r
1855 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1856 draw the piece again in black for safety.
\r
1858 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1860 SelectObject( hdc, hbm_old );
\r
1862 if( hPieceMask[index] != NULL ) {
\r
1863 DeleteObject( hPieceMask[index] );
\r
1866 hPieceMask[index] = hbm;
\r
1869 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1871 SelectObject( hdc, hbm );
\r
1874 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1875 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1876 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1878 SelectObject( dc1, hPieceMask[index] );
\r
1879 SelectObject( dc2, bm2 );
\r
1880 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1881 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1884 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1885 the piece background and deletes (makes transparent) the rest.
\r
1886 Thanks to that mask, we are free to paint the background with the greates
\r
1887 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1888 We use this, to make gradients and give the pieces a "roundish" look.
\r
1890 SetPieceBackground( hdc, backColor, 2 );
\r
1891 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1895 DeleteObject( bm2 );
\r
1898 SetTextColor( hdc, foreColor );
\r
1899 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1901 SelectObject( hdc, hbm_old );
\r
1903 if( hPieceFace[index] != NULL ) {
\r
1904 DeleteObject( hPieceFace[index] );
\r
1907 hPieceFace[index] = hbm;
\r
1910 static int TranslatePieceToFontPiece( int piece )
\r
1940 case BlackMarshall:
\r
1944 case BlackNightrider:
\r
1950 case BlackUnicorn:
\r
1954 case BlackGrasshopper:
\r
1966 case BlackCardinal:
\r
1973 case WhiteMarshall:
\r
1977 case WhiteNightrider:
\r
1983 case WhiteUnicorn:
\r
1987 case WhiteGrasshopper:
\r
1999 case WhiteCardinal:
\r
2008 void CreatePiecesFromFont()
\r
2011 HDC hdc_window = NULL;
\r
2017 if( fontBitmapSquareSize < 0 ) {
\r
2018 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2022 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2023 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2024 fontBitmapSquareSize = -1;
\r
2028 if( fontBitmapSquareSize != squareSize ) {
\r
2029 hdc_window = GetDC( hwndMain );
\r
2030 hdc = CreateCompatibleDC( hdc_window );
\r
2032 if( hPieceFont != NULL ) {
\r
2033 DeleteObject( hPieceFont );
\r
2036 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2037 hPieceMask[i] = NULL;
\r
2038 hPieceFace[i] = NULL;
\r
2044 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2045 fontHeight = appData.fontPieceSize;
\r
2048 fontHeight = (fontHeight * squareSize) / 100;
\r
2050 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2052 lf.lfEscapement = 0;
\r
2053 lf.lfOrientation = 0;
\r
2054 lf.lfWeight = FW_NORMAL;
\r
2056 lf.lfUnderline = 0;
\r
2057 lf.lfStrikeOut = 0;
\r
2058 lf.lfCharSet = DEFAULT_CHARSET;
\r
2059 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2060 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2061 lf.lfQuality = PROOF_QUALITY;
\r
2062 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2063 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2064 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2066 hPieceFont = CreateFontIndirect( &lf );
\r
2068 if( hPieceFont == NULL ) {
\r
2069 fontBitmapSquareSize = -2;
\r
2072 /* Setup font-to-piece character table */
\r
2073 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2074 /* No (or wrong) global settings, try to detect the font */
\r
2075 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2077 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2079 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2080 /* DiagramTT* family */
\r
2081 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2083 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2084 /* Fairy symbols */
\r
2085 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2087 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2088 /* Good Companion (Some characters get warped as literal :-( */
\r
2089 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2090 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2091 SetCharTable(pieceToFontChar, s);
\r
2094 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2095 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2099 /* Create bitmaps */
\r
2100 hfont_old = SelectObject( hdc, hPieceFont );
\r
2101 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2102 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2103 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2105 SelectObject( hdc, hfont_old );
\r
2107 fontBitmapSquareSize = squareSize;
\r
2111 if( hdc != NULL ) {
\r
2115 if( hdc_window != NULL ) {
\r
2116 ReleaseDC( hwndMain, hdc_window );
\r
2121 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2123 char name[128], buf[MSG_SIZ];
\r
2125 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2126 if(appData.pieceDirectory[0]) {
\r
2128 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2129 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2130 if(res) return res;
\r
2132 if (gameInfo.event &&
\r
2133 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2134 strcmp(name, "k80s") == 0) {
\r
2135 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2137 return LoadBitmap(hinst, name);
\r
2141 /* Insert a color into the program's logical palette
\r
2142 structure. This code assumes the given color is
\r
2143 the result of the RGB or PALETTERGB macro, and it
\r
2144 knows how those macros work (which is documented).
\r
2147 InsertInPalette(COLORREF color)
\r
2149 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2151 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2152 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2153 pLogPal->palNumEntries--;
\r
2157 pe->peFlags = (char) 0;
\r
2158 pe->peRed = (char) (0xFF & color);
\r
2159 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2160 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2166 InitDrawingColors()
\r
2168 if (pLogPal == NULL) {
\r
2169 /* Allocate enough memory for a logical palette with
\r
2170 * PALETTESIZE entries and set the size and version fields
\r
2171 * of the logical palette structure.
\r
2173 pLogPal = (NPLOGPALETTE)
\r
2174 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2175 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2176 pLogPal->palVersion = 0x300;
\r
2178 pLogPal->palNumEntries = 0;
\r
2180 InsertInPalette(lightSquareColor);
\r
2181 InsertInPalette(darkSquareColor);
\r
2182 InsertInPalette(whitePieceColor);
\r
2183 InsertInPalette(blackPieceColor);
\r
2184 InsertInPalette(highlightSquareColor);
\r
2185 InsertInPalette(premoveHighlightColor);
\r
2187 /* create a logical color palette according the information
\r
2188 * in the LOGPALETTE structure.
\r
2190 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2192 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2193 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2194 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2195 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2196 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2197 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2198 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2199 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2200 /* [AS] Force rendering of the font-based pieces */
\r
2201 if( fontBitmapSquareSize > 0 ) {
\r
2202 fontBitmapSquareSize = 0;
\r
2208 BoardWidth(int boardSize, int n)
\r
2209 { /* [HGM] argument n added to allow different width and height */
\r
2210 int lineGap = sizeInfo[boardSize].lineGap;
\r
2212 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2213 lineGap = appData.overrideLineGap;
\r
2216 return (n + 1) * lineGap +
\r
2217 n * sizeInfo[boardSize].squareSize;
\r
2220 /* Respond to board resize by dragging edge */
\r
2222 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2224 BoardSize newSize = NUM_SIZES - 1;
\r
2225 static int recurse = 0;
\r
2226 if (IsIconic(hwndMain)) return;
\r
2227 if (recurse > 0) return;
\r
2229 while (newSize > 0) {
\r
2230 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2231 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2232 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2235 boardSize = newSize;
\r
2236 InitDrawingSizes(boardSize, flags);
\r
2241 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2244 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2246 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2247 ChessSquare piece;
\r
2248 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2250 SIZE clockSize, messageSize;
\r
2252 char buf[MSG_SIZ];
\r
2254 HMENU hmenu = GetMenu(hwndMain);
\r
2255 RECT crect, wrect, oldRect;
\r
2257 LOGBRUSH logbrush;
\r
2258 VariantClass v = gameInfo.variant;
\r
2260 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2261 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2263 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2264 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2265 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2266 oldBoardSize = boardSize;
\r
2268 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2269 { // correct board size to one where built-in pieces exist
\r
2270 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2271 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2272 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2273 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2274 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {
\r
2275 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2276 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2277 boardSize = SizeMiddling;
\r
2280 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2282 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2283 oldRect.top = wpMain.y;
\r
2284 oldRect.right = wpMain.x + wpMain.width;
\r
2285 oldRect.bottom = wpMain.y + wpMain.height;
\r
2287 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2288 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2289 squareSize = sizeInfo[boardSize].squareSize;
\r
2290 lineGap = sizeInfo[boardSize].lineGap;
\r
2291 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2292 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2294 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2295 lineGap = appData.overrideLineGap;
\r
2298 if (tinyLayout != oldTinyLayout) {
\r
2299 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2301 style &= ~WS_SYSMENU;
\r
2302 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2303 "&Minimize\tCtrl+F4");
\r
2305 style |= WS_SYSMENU;
\r
2306 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2308 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2310 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2311 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2312 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2314 DrawMenuBar(hwndMain);
\r
2317 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2318 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2320 /* Get text area sizes */
\r
2321 hdc = GetDC(hwndMain);
\r
2322 if (appData.clockMode) {
\r
2323 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2325 snprintf(buf, MSG_SIZ, _("White"));
\r
2327 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2328 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2329 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2330 str = _("We only care about the height here");
\r
2331 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2332 SelectObject(hdc, oldFont);
\r
2333 ReleaseDC(hwndMain, hdc);
\r
2335 /* Compute where everything goes */
\r
2336 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2337 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2338 logoHeight = 2*clockSize.cy;
\r
2339 leftLogoRect.left = OUTER_MARGIN;
\r
2340 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2341 leftLogoRect.top = OUTER_MARGIN;
\r
2342 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2344 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2345 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2346 rightLogoRect.top = OUTER_MARGIN;
\r
2347 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2350 whiteRect.left = leftLogoRect.right;
\r
2351 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2352 whiteRect.top = OUTER_MARGIN;
\r
2353 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2355 blackRect.right = rightLogoRect.left;
\r
2356 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2357 blackRect.top = whiteRect.top;
\r
2358 blackRect.bottom = whiteRect.bottom;
\r
2360 whiteRect.left = OUTER_MARGIN;
\r
2361 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2362 whiteRect.top = OUTER_MARGIN;
\r
2363 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2365 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2366 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2367 blackRect.top = whiteRect.top;
\r
2368 blackRect.bottom = whiteRect.bottom;
\r
2370 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2373 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2374 if (appData.showButtonBar) {
\r
2375 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2376 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2378 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2380 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2381 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2383 boardRect.left = OUTER_MARGIN;
\r
2384 boardRect.right = boardRect.left + boardWidth;
\r
2385 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2386 boardRect.bottom = boardRect.top + boardHeight;
\r
2388 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2389 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2390 oldTinyLayout = tinyLayout;
\r
2391 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2392 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2393 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2394 winW *= 1 + twoBoards;
\r
2395 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2396 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2397 wpMain.height = winH; // without disturbing window attachments
\r
2398 GetWindowRect(hwndMain, &wrect);
\r
2399 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2400 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2402 // [HGM] placement: let attached windows follow size change.
\r
2403 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2404 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2405 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2406 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2407 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2409 /* compensate if menu bar wrapped */
\r
2410 GetClientRect(hwndMain, &crect);
\r
2411 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2412 wpMain.height += offby;
\r
2414 case WMSZ_TOPLEFT:
\r
2415 SetWindowPos(hwndMain, NULL,
\r
2416 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2417 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2420 case WMSZ_TOPRIGHT:
\r
2422 SetWindowPos(hwndMain, NULL,
\r
2423 wrect.left, wrect.bottom - wpMain.height,
\r
2424 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2427 case WMSZ_BOTTOMLEFT:
\r
2429 SetWindowPos(hwndMain, NULL,
\r
2430 wrect.right - wpMain.width, wrect.top,
\r
2431 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2434 case WMSZ_BOTTOMRIGHT:
\r
2438 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2439 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2444 for (i = 0; i < N_BUTTONS; i++) {
\r
2445 if (buttonDesc[i].hwnd != NULL) {
\r
2446 DestroyWindow(buttonDesc[i].hwnd);
\r
2447 buttonDesc[i].hwnd = NULL;
\r
2449 if (appData.showButtonBar) {
\r
2450 buttonDesc[i].hwnd =
\r
2451 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2452 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2453 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2454 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2455 (HMENU) buttonDesc[i].id,
\r
2456 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2458 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2459 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2460 MAKELPARAM(FALSE, 0));
\r
2462 if (buttonDesc[i].id == IDM_Pause)
\r
2463 hwndPause = buttonDesc[i].hwnd;
\r
2464 buttonDesc[i].wndproc = (WNDPROC)
\r
2465 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2468 if (gridPen != NULL) DeleteObject(gridPen);
\r
2469 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2470 if (premovePen != NULL) DeleteObject(premovePen);
\r
2471 if (lineGap != 0) {
\r
2472 logbrush.lbStyle = BS_SOLID;
\r
2473 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2475 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2476 lineGap, &logbrush, 0, NULL);
\r
2477 logbrush.lbColor = highlightSquareColor;
\r
2479 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2480 lineGap, &logbrush, 0, NULL);
\r
2482 logbrush.lbColor = premoveHighlightColor;
\r
2484 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2485 lineGap, &logbrush, 0, NULL);
\r
2487 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2488 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2489 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2490 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2491 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2492 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2493 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2494 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2496 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2497 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2498 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2499 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2500 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2501 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2502 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2503 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2507 /* [HGM] Licensing requirement */
\r
2509 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2512 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2514 GothicPopUp( "", VariantNormal);
\r
2517 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2519 /* Load piece bitmaps for this board size */
\r
2520 for (i=0; i<=2; i++) {
\r
2521 for (piece = WhitePawn;
\r
2522 (int) piece < (int) BlackPawn;
\r
2523 piece = (ChessSquare) ((int) piece + 1)) {
\r
2524 if (pieceBitmap[i][piece] != NULL)
\r
2525 DeleteObject(pieceBitmap[i][piece]);
\r
2529 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2530 // Orthodox Chess pieces
\r
2531 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2532 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2533 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2534 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2535 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2536 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2537 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2538 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2539 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2540 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2541 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2542 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2543 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2544 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2545 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2546 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2547 // in Shogi, Hijack the unused Queen for Lance
\r
2548 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2549 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2550 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2552 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2553 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2554 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2557 if(squareSize <= 72 && squareSize >= 33) {
\r
2558 /* A & C are available in most sizes now */
\r
2559 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2560 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2561 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2562 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2563 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2564 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2565 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2566 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2567 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2568 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2569 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2570 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2571 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2572 } else { // Smirf-like
\r
2573 if(gameInfo.variant == VariantSChess) {
\r
2574 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2575 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2576 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2578 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2579 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2580 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2583 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2584 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2585 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2586 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2587 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2588 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2589 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2590 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2591 } else { // WinBoard standard
\r
2592 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2593 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2594 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2599 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2600 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2601 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2602 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2603 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2604 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2605 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2606 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2607 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2608 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2609 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2610 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2611 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2612 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2613 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2614 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2615 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2616 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2617 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2618 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2621 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2622 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2623 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2624 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2625 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2626 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2627 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2628 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2629 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2631 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2632 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2633 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2634 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2635 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2636 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2637 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2638 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2639 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2640 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2641 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2642 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2643 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2645 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2646 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2647 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2648 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2651 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2652 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2653 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2654 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2655 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2656 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2659 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2660 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2661 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2662 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2663 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2664 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2665 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2666 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2667 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2668 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2669 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2670 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2671 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2672 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2673 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2677 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2678 /* special Shogi support in this size */
\r
2679 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2680 for (piece = WhitePawn;
\r
2681 (int) piece < (int) BlackPawn;
\r
2682 piece = (ChessSquare) ((int) piece + 1)) {
\r
2683 if (pieceBitmap[i][piece] != NULL)
\r
2684 DeleteObject(pieceBitmap[i][piece]);
\r
2687 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2688 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2689 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2690 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2691 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2692 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2693 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2694 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2695 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2696 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2697 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2698 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2699 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2700 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2701 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2702 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2703 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2704 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2705 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2706 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2707 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2708 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2709 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2710 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2711 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2712 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2713 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2714 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2715 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2716 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2717 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2718 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2719 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2720 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2721 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2722 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2723 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2724 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2725 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2726 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2727 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2728 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2734 PieceBitmap(ChessSquare p, int kind)
\r
2736 if ((int) p >= (int) BlackPawn)
\r
2737 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2739 return pieceBitmap[kind][(int) p];
\r
2742 /***************************************************************/
\r
2744 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2745 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2747 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2748 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2752 SquareToPos(int row, int column, int * x, int * y)
\r
2755 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2756 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2758 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2759 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2764 DrawCoordsOnDC(HDC hdc)
\r
2766 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2767 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2768 char str[2] = { NULLCHAR, NULLCHAR };
\r
2769 int oldMode, oldAlign, x, y, start, i;
\r
2773 if (!appData.showCoords)
\r
2776 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2778 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2779 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2780 oldAlign = GetTextAlign(hdc);
\r
2781 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2783 y = boardRect.top + lineGap;
\r
2784 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2787 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2788 x += border - lineGap - 4; y += squareSize - 6;
\r
2790 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2791 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2792 str[0] = files[start + i];
\r
2793 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2794 y += squareSize + lineGap;
\r
2797 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2800 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2801 x += -border + 4; y += border - squareSize + 6;
\r
2803 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2804 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2805 str[0] = ranks[start + i];
\r
2806 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2807 x += squareSize + lineGap;
\r
2810 SelectObject(hdc, oldBrush);
\r
2811 SetBkMode(hdc, oldMode);
\r
2812 SetTextAlign(hdc, oldAlign);
\r
2813 SelectObject(hdc, oldFont);
\r
2817 DrawGridOnDC(HDC hdc)
\r
2821 if (lineGap != 0) {
\r
2822 oldPen = SelectObject(hdc, gridPen);
\r
2823 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2824 SelectObject(hdc, oldPen);
\r
2828 #define HIGHLIGHT_PEN 0
\r
2829 #define PREMOVE_PEN 1
\r
2832 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2835 HPEN oldPen, hPen;
\r
2836 if (lineGap == 0) return;
\r
2838 x1 = boardRect.left +
\r
2839 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2840 y1 = boardRect.top +
\r
2841 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2843 x1 = boardRect.left +
\r
2844 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2845 y1 = boardRect.top +
\r
2846 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2848 hPen = pen ? premovePen : highlightPen;
\r
2849 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2850 MoveToEx(hdc, x1, y1, NULL);
\r
2851 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2852 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2853 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2854 LineTo(hdc, x1, y1);
\r
2855 SelectObject(hdc, oldPen);
\r
2859 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2862 for (i=0; i<2; i++) {
\r
2863 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2864 DrawHighlightOnDC(hdc, TRUE,
\r
2865 h->sq[i].x, h->sq[i].y,
\r
2870 /* Note: sqcolor is used only in monoMode */
\r
2871 /* Note that this code is largely duplicated in woptions.c,
\r
2872 function DrawSampleSquare, so that needs to be updated too */
\r
2874 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2876 HBITMAP oldBitmap;
\r
2880 if (appData.blindfold) return;
\r
2882 /* [AS] Use font-based pieces if needed */
\r
2883 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2884 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2885 CreatePiecesFromFont();
\r
2887 if( fontBitmapSquareSize == squareSize ) {
\r
2888 int index = TranslatePieceToFontPiece(piece);
\r
2890 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2892 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2893 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2897 squareSize, squareSize,
\r
2902 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2904 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2905 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2909 squareSize, squareSize,
\r
2918 if (appData.monoMode) {
\r
2919 SelectObject(tmphdc, PieceBitmap(piece,
\r
2920 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2921 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2922 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2924 HBRUSH xBrush = whitePieceBrush;
\r
2925 tmpSize = squareSize;
\r
2926 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2928 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2929 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2930 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2931 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2932 x += (squareSize - minorSize)>>1;
\r
2933 y += squareSize - minorSize - 2;
\r
2934 tmpSize = minorSize;
\r
2936 if (color || appData.allWhite ) {
\r
2937 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2939 oldBrush = SelectObject(hdc, xBrush);
\r
2940 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2941 if(appData.upsideDown && color==flipView)
\r
2942 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2944 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2945 /* Use black for outline of white pieces */
\r
2946 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2947 if(appData.upsideDown && color==flipView)
\r
2948 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2950 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2951 } else if(appData.pieceDirectory[0]) {
\r
2952 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2953 oldBrush = SelectObject(hdc, xBrush);
\r
2954 if(appData.upsideDown && color==flipView)
\r
2955 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2957 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2958 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2959 if(appData.upsideDown && color==flipView)
\r
2960 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2962 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2964 /* Use square color for details of black pieces */
\r
2965 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2966 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2967 if(appData.upsideDown && !flipView)
\r
2968 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2970 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2972 SelectObject(hdc, oldBrush);
\r
2973 SelectObject(tmphdc, oldBitmap);
\r
2977 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2978 int GetBackTextureMode( int algo )
\r
2980 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2984 case BACK_TEXTURE_MODE_PLAIN:
\r
2985 result = 1; /* Always use identity map */
\r
2987 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2988 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2996 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2997 to handle redraws cleanly (as random numbers would always be different).
\r
2999 VOID RebuildTextureSquareInfo()
\r
3009 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3011 if( liteBackTexture != NULL ) {
\r
3012 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3013 lite_w = bi.bmWidth;
\r
3014 lite_h = bi.bmHeight;
\r
3018 if( darkBackTexture != NULL ) {
\r
3019 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3020 dark_w = bi.bmWidth;
\r
3021 dark_h = bi.bmHeight;
\r
3025 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3026 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3027 if( (col + row) & 1 ) {
\r
3029 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3030 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3031 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3033 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3034 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3035 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3037 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3038 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3043 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3044 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3045 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3047 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3048 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3049 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3051 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3052 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3059 /* [AS] Arrow highlighting support */
\r
3061 static double A_WIDTH = 5; /* Width of arrow body */
\r
3063 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3064 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3066 static double Sqr( double x )
\r
3071 static int Round( double x )
\r
3073 return (int) (x + 0.5);
\r
3076 /* Draw an arrow between two points using current settings */
\r
3077 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3080 double dx, dy, j, k, x, y;
\r
3082 if( d_x == s_x ) {
\r
3083 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3085 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3088 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3089 arrow[1].y = d_y - h;
\r
3091 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3092 arrow[2].y = d_y - h;
\r
3097 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3098 arrow[5].y = d_y - h;
\r
3100 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3101 arrow[4].y = d_y - h;
\r
3103 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3106 else if( d_y == s_y ) {
\r
3107 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3110 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3112 arrow[1].x = d_x - w;
\r
3113 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3115 arrow[2].x = d_x - w;
\r
3116 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3121 arrow[5].x = d_x - w;
\r
3122 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3124 arrow[4].x = d_x - w;
\r
3125 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3128 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3131 /* [AS] Needed a lot of paper for this! :-) */
\r
3132 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3133 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3135 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3137 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3142 arrow[0].x = Round(x - j);
\r
3143 arrow[0].y = Round(y + j*dx);
\r
3145 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3146 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3149 x = (double) d_x - k;
\r
3150 y = (double) d_y - k*dy;
\r
3153 x = (double) d_x + k;
\r
3154 y = (double) d_y + k*dy;
\r
3157 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3159 arrow[6].x = Round(x - j);
\r
3160 arrow[6].y = Round(y + j*dx);
\r
3162 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3163 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3165 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3166 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3171 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3172 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3175 Polygon( hdc, arrow, 7 );
\r
3178 /* [AS] Draw an arrow between two squares */
\r
3179 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3181 int s_x, s_y, d_x, d_y;
\r