2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
95 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
98 void mysrandom(unsigned int seed);
\r
100 extern int whiteFlag, blackFlag;
\r
101 Boolean flipClock = FALSE;
\r
102 extern HANDLE chatHandle[];
\r
103 extern 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;
\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
225 #if defined(_winmajor)
\r
226 #define oldDialog (_winmajor < 4)
\r
228 #define oldDialog 0
\r
232 #define INTERNATIONAL
\r
234 #ifdef INTERNATIONAL
\r
235 # define _(s) T_(s)
\r
241 # define Translate(x, y)
\r
242 # define LoadLanguageFile(s)
\r
245 #ifdef INTERNATIONAL
\r
247 Boolean barbaric; // flag indicating if translation is needed
\r
249 // list of item numbers used in each dialog (used to alter language at run time)
\r
251 #define ABOUTBOX -1 /* not sure why these are needed */
\r
252 #define ABOUTBOX2 -1
\r
254 int dialogItems[][42] = {
\r
255 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
256 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
257 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
258 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
259 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
260 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
261 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
262 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
263 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
264 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
265 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
266 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
267 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
268 { ABOUTBOX2, IDC_ChessBoard },
\r
269 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
270 OPT_GameListClose, IDC_GameListDoFilter },
\r
271 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
272 { DLG_Error, IDOK },
\r
273 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
274 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
275 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
276 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
277 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
278 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
279 { DLG_IndexNumber, IDC_Index },
\r
280 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
281 { DLG_TypeInName, IDOK, IDCANCEL },
\r
282 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
283 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
284 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
285 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
286 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
287 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
288 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
289 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
290 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
291 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
292 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
293 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
294 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
295 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
296 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
297 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
298 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
299 GPB_General, GPB_Alarm },
\r
300 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
301 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
302 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
303 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
304 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
305 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
306 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
307 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
308 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
309 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
310 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
311 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
312 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
313 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
314 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
315 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
316 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
317 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
318 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
319 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
320 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
321 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
322 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
323 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
324 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
325 { DLG_MoveHistory },
\r
326 { DLG_EvalGraph },
\r
327 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
328 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
329 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
330 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
331 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
332 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
333 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
334 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
335 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
339 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
340 static int lastChecked;
\r
341 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
342 extern int tinyLayout;
\r
343 extern char * menuBarText[][10];
\r
346 LoadLanguageFile(char *name)
\r
347 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
349 int i=0, j=0, n=0, k;
\r
352 if(!name || name[0] == NULLCHAR) return;
\r
353 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
354 appData.language = oldLanguage;
\r
355 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
356 if((f = fopen(buf, "r")) == NULL) return;
\r
357 while((k = fgetc(f)) != EOF) {
\r
358 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
359 languageBuf[i] = k;
\r
361 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
363 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
364 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
365 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
366 english[j] = languageBuf + n + 1; *p = 0;
\r
367 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
368 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
373 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
375 case 'n': k = '\n'; break;
\r
376 case 'r': k = '\r'; break;
\r
377 case 't': k = '\t'; break;
\r
379 languageBuf[--i] = k;
\r
384 barbaric = (j != 0);
\r
385 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
390 { // return the translation of the given string
\r
391 // efficiency can be improved a lot...
\r
393 static char buf[MSG_SIZ];
\r
394 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
395 if(!barbaric) return s;
\r
396 if(!s) return ""; // sanity
\r
397 while(english[i]) {
\r
398 if(!strcmp(s, english[i])) return foreign[i];
\r
399 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
400 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
409 Translate(HWND hDlg, int dialogID)
\r
410 { // translate all text items in the given dialog
\r
412 char buf[MSG_SIZ], *s;
\r
413 if(!barbaric) return;
\r
414 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
415 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
416 GetWindowText( hDlg, buf, MSG_SIZ );
\r
418 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
419 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
420 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
421 if(strlen(buf) == 0) continue;
\r
423 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
428 TranslateOneMenu(int i, HMENU subMenu)
\r
431 static MENUITEMINFO info;
\r
433 info.cbSize = sizeof(MENUITEMINFO);
\r
434 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
435 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
437 info.dwTypeData = buf;
\r
438 info.cch = sizeof(buf);
\r
439 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
441 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
442 else menuText[i][j] = strdup(buf); // remember original on first change
\r
444 if(buf[0] == NULLCHAR) continue;
\r
445 info.dwTypeData = T_(buf);
\r
446 info.cch = strlen(buf)+1;
\r
447 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
453 TranslateMenus(int addLanguage)
\r
456 WIN32_FIND_DATA fileData;
\r
458 #define IDM_English 1970
\r
460 HMENU mainMenu = GetMenu(hwndMain);
\r
461 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
462 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
463 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
464 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
465 TranslateOneMenu(i, subMenu);
\r
467 DrawMenuBar(hwndMain);
\r
470 if(!addLanguage) return;
\r
471 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
472 HMENU mainMenu = GetMenu(hwndMain);
\r
473 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
474 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
475 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
476 i = 0; lastChecked = IDM_English;
\r
478 char *p, *q = fileData.cFileName;
\r
479 int checkFlag = MF_UNCHECKED;
\r
480 languageFile[i] = strdup(q);
\r
481 if(barbaric && !strcmp(oldLanguage, q)) {
\r
482 checkFlag = MF_CHECKED;
\r
483 lastChecked = IDM_English + i + 1;
\r
484 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
486 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
487 p = strstr(fileData.cFileName, ".lng");
\r
489 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
490 } while(FindNextFile(hFind, &fileData));
\r
497 #define IDM_RecentEngines 3000
\r
500 RecentEngineMenu (char *s)
\r
502 if(appData.icsActive) return;
\r
503 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
504 HMENU mainMenu = GetMenu(hwndMain);
\r
505 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
506 int i=IDM_RecentEngines;
\r
507 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
508 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
510 char *p = strchr(s, '\n');
\r
511 if(p == NULL) return; // malformed!
\r
513 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
527 int cliWidth, cliHeight;
\r
530 SizeInfo sizeInfo[] =
\r
532 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
533 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
534 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
535 { "petite", 33, 1, 1, 1, 0, 0 },
\r
536 { "slim", 37, 2, 1, 0, 0, 0 },
\r
537 { "small", 40, 2, 1, 0, 0, 0 },
\r
538 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
539 { "middling", 49, 2, 0, 0, 0, 0 },
\r
540 { "average", 54, 2, 0, 0, 0, 0 },
\r
541 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
542 { "medium", 64, 3, 0, 0, 0, 0 },
\r
543 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
544 { "large", 80, 3, 0, 0, 0, 0 },
\r
545 { "big", 87, 3, 0, 0, 0, 0 },
\r
546 { "huge", 95, 3, 0, 0, 0, 0 },
\r
547 { "giant", 108, 3, 0, 0, 0, 0 },
\r
548 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
549 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
550 { NULL, 0, 0, 0, 0, 0, 0 }
\r
553 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
554 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
556 { 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
557 { 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
558 { 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
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
576 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
585 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
586 #define N_BUTTONS 5
\r
588 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
590 {"<<", IDM_ToStart, NULL, NULL},
\r
591 {"<", IDM_Backward, NULL, NULL},
\r
592 {"P", IDM_Pause, NULL, NULL},
\r
593 {">", IDM_Forward, NULL, NULL},
\r
594 {">>", IDM_ToEnd, NULL, NULL},
\r
597 int tinyLayout = 0, smallLayout = 0;
\r
598 #define MENU_BAR_ITEMS 9
\r
599 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
600 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
601 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
605 MySound sounds[(int)NSoundClasses];
\r
606 MyTextAttribs textAttribs[(int)NColorClasses];
\r
608 MyColorizeAttribs colorizeAttribs[] = {
\r
609 { (COLORREF)0, 0, N_("Shout Text") },
\r
610 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
611 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
612 { (COLORREF)0, 0, N_("Channel Text") },
\r
613 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
614 { (COLORREF)0, 0, N_("Tell Text") },
\r
615 { (COLORREF)0, 0, N_("Challenge Text") },
\r
616 { (COLORREF)0, 0, N_("Request Text") },
\r
617 { (COLORREF)0, 0, N_("Seek Text") },
\r
618 { (COLORREF)0, 0, N_("Normal Text") },
\r
619 { (COLORREF)0, 0, N_("None") }
\r
624 static char *commentTitle;
\r
625 static char *commentText;
\r
626 static int commentIndex;
\r
627 static Boolean editComment = FALSE;
\r
630 char errorTitle[MSG_SIZ];
\r
631 char errorMessage[2*MSG_SIZ];
\r
632 HWND errorDialog = NULL;
\r
633 BOOLEAN moveErrorMessageUp = FALSE;
\r
634 BOOLEAN consoleEcho = TRUE;
\r
635 CHARFORMAT consoleCF;
\r
636 COLORREF consoleBackgroundColor;
\r
638 char *programVersion;
\r
644 typedef int CPKind;
\r
653 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
656 #define INPUT_SOURCE_BUF_SIZE 4096
\r
658 typedef struct _InputSource {
\r
665 char buf[INPUT_SOURCE_BUF_SIZE];
\r
669 InputCallback func;
\r
670 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
674 InputSource *consoleInputSource;
\r
679 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
680 VOID ConsoleCreate();
\r
682 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
683 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
684 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
685 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
687 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
689 void ParseIcsTextMenu(char *icsTextMenuString);
\r
690 VOID PopUpNameDialog(char firstchar);
\r
691 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
695 int GameListOptions();
\r
697 int dummy; // [HGM] for obsolete args
\r
699 HWND hwndMain = NULL; /* root window*/
\r
700 HWND hwndConsole = NULL;
\r
701 HWND commentDialog = NULL;
\r
702 HWND moveHistoryDialog = NULL;
\r
703 HWND evalGraphDialog = NULL;
\r
704 HWND engineOutputDialog = NULL;
\r
705 HWND gameListDialog = NULL;
\r
706 HWND editTagsDialog = NULL;
\r
708 int commentUp = FALSE;
\r
710 WindowPlacement wpMain;
\r
711 WindowPlacement wpConsole;
\r
712 WindowPlacement wpComment;
\r
713 WindowPlacement wpMoveHistory;
\r
714 WindowPlacement wpEvalGraph;
\r
715 WindowPlacement wpEngineOutput;
\r
716 WindowPlacement wpGameList;
\r
717 WindowPlacement wpTags;
\r
719 VOID EngineOptionsPopup(); // [HGM] settings
\r
721 VOID GothicPopUp(char *title, VariantClass variant);
\r
723 * Setting "frozen" should disable all user input other than deleting
\r
724 * the window. We do this while engines are initializing themselves.
\r
726 static int frozen = 0;
\r
727 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
733 if (frozen) return;
\r
735 hmenu = GetMenu(hwndMain);
\r
736 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
737 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
739 DrawMenuBar(hwndMain);
\r
742 /* Undo a FreezeUI */
\r
748 if (!frozen) return;
\r
750 hmenu = GetMenu(hwndMain);
\r
751 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
752 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
754 DrawMenuBar(hwndMain);
\r
757 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
759 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
765 #define JAWS_ALT_INTERCEPT
\r
766 #define JAWS_KBUP_NAVIGATION
\r
767 #define JAWS_KBDOWN_NAVIGATION
\r
768 #define JAWS_MENU_ITEMS
\r
769 #define JAWS_SILENCE
\r
770 #define JAWS_REPLAY
\r
772 #define JAWS_COPYRIGHT
\r
773 #define JAWS_DELETE(X) X
\r
774 #define SAYMACHINEMOVE()
\r
778 /*---------------------------------------------------------------------------*\
\r
782 \*---------------------------------------------------------------------------*/
\r
785 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
786 LPSTR lpCmdLine, int nCmdShow)
\r
789 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
790 // INITCOMMONCONTROLSEX ex;
\r
794 LoadLibrary("RICHED32.DLL");
\r
795 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
797 if (!InitApplication(hInstance)) {
\r
800 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
807 // InitCommonControlsEx(&ex);
\r
808 InitCommonControls();
\r
810 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
811 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
812 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
814 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
816 while (GetMessage(&msg, /* message structure */
\r
817 NULL, /* handle of window receiving the message */
\r
818 0, /* lowest message to examine */
\r
819 0)) /* highest message to examine */
\r
822 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
823 // [HGM] navigate: switch between all windows with tab
\r
824 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
825 int i, currentElement = 0;
\r
827 // first determine what element of the chain we come from (if any)
\r
828 if(appData.icsActive) {
\r
829 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
830 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
832 if(engineOutputDialog && EngineOutputIsUp()) {
\r
833 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
834 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
836 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
837 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
839 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
840 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
841 if(msg.hwnd == e1) currentElement = 2; else
\r
842 if(msg.hwnd == e2) currentElement = 3; else
\r
843 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
844 if(msg.hwnd == mh) currentElement = 4; else
\r
845 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
846 if(msg.hwnd == hText) currentElement = 5; else
\r
847 if(msg.hwnd == hInput) currentElement = 6; else
\r
848 for (i = 0; i < N_BUTTONS; i++) {
\r
849 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
852 // determine where to go to
\r
853 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
855 currentElement = (currentElement + direction) % 7;
\r
856 switch(currentElement) {
\r
858 h = hwndMain; break; // passing this case always makes the loop exit
\r
860 h = buttonDesc[0].hwnd; break; // could be NULL
\r
862 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
865 if(!EngineOutputIsUp()) continue;
\r
868 if(!MoveHistoryIsUp()) continue;
\r
870 // case 6: // input to eval graph does not seem to get here!
\r
871 // if(!EvalGraphIsUp()) continue;
\r
872 // h = evalGraphDialog; break;
\r
874 if(!appData.icsActive) continue;
\r
878 if(!appData.icsActive) continue;
\r
884 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
885 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
888 continue; // this message now has been processed
\r
892 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
893 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
894 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
895 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
896 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
897 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
898 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
899 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
900 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
901 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
902 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
903 for(i=0; i<MAX_CHAT; i++)
\r
904 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
907 if(done) continue; // [HGM] chat: end patch
\r
908 TranslateMessage(&msg); /* Translates virtual key codes */
\r
909 DispatchMessage(&msg); /* Dispatches message to window */
\r
914 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
917 /*---------------------------------------------------------------------------*\
\r
919 * Initialization functions
\r
921 \*---------------------------------------------------------------------------*/
\r
925 { // update user logo if necessary
\r
926 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
928 if(appData.autoLogo) {
\r
929 curName = UserName();
\r
930 if(strcmp(curName, oldUserName)) {
\r
931 GetCurrentDirectory(MSG_SIZ, dir);
\r
932 SetCurrentDirectory(installDir);
\r
933 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
934 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
935 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
936 if(userLogo == NULL)
\r
937 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
938 SetCurrentDirectory(dir); /* return to prev directory */
\r
944 InitApplication(HINSTANCE hInstance)
\r
948 /* Fill in window class structure with parameters that describe the */
\r
951 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
952 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
953 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
954 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
955 wc.hInstance = hInstance; /* Owner of this class */
\r
956 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
957 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
958 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
959 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
960 wc.lpszClassName = szAppName; /* Name to register as */
\r
962 /* Register the window class and return success/failure code. */
\r
963 if (!RegisterClass(&wc)) return FALSE;
\r
965 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
966 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
968 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
969 wc.hInstance = hInstance;
\r
970 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
971 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
972 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
973 wc.lpszMenuName = NULL;
\r
974 wc.lpszClassName = szConsoleName;
\r
976 if (!RegisterClass(&wc)) return FALSE;
\r
981 /* Set by InitInstance, used by EnsureOnScreen */
\r
982 int screenHeight, screenWidth;
\r
985 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
987 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
988 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
989 if (*x > screenWidth - 32) *x = 0;
\r
990 if (*y > screenHeight - 32) *y = 0;
\r
991 if (*x < minX) *x = minX;
\r
992 if (*y < minY) *y = minY;
\r
996 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
998 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
999 GetCurrentDirectory(MSG_SIZ, dir);
\r
1000 SetCurrentDirectory(installDir);
\r
1001 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1002 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1004 if (cps->programLogo == NULL && appData.debugMode) {
\r
1005 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1007 } else if(appData.autoLogo) {
\r
1008 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1009 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1010 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1012 if(appData.directory[n] && appData.directory[n][0]) {
\r
1013 SetCurrentDirectory(appData.directory[n]);
\r
1014 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1017 SetCurrentDirectory(dir); /* return to prev directory */
\r
1023 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1024 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1026 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1027 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1028 liteBackTextureMode = appData.liteBackTextureMode;
\r
1030 if (liteBackTexture == NULL && appData.debugMode) {
\r
1031 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1035 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1036 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1037 darkBackTextureMode = appData.darkBackTextureMode;
\r
1039 if (darkBackTexture == NULL && appData.debugMode) {
\r
1040 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1046 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1048 HWND hwnd; /* Main window handle. */
\r
1050 WINDOWPLACEMENT wp;
\r
1053 hInst = hInstance; /* Store instance handle in our global variable */
\r
1054 programName = szAppName;
\r
1056 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1057 *filepart = NULLCHAR;
\r
1059 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1061 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1062 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1063 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1064 /* xboard, and older WinBoards, controlled the move sound with the
\r
1065 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1066 always turn the option on (so that the backend will call us),
\r
1067 then let the user turn the sound off by setting it to silence if
\r
1068 desired. To accommodate old winboard.ini files saved by old
\r
1069 versions of WinBoard, we also turn off the sound if the option
\r
1070 was initially set to false. [HGM] taken out of InitAppData */
\r
1071 if (!appData.ringBellAfterMoves) {
\r
1072 sounds[(int)SoundMove].name = strdup("");
\r
1073 appData.ringBellAfterMoves = TRUE;
\r
1075 if (appData.debugMode) {
\r
1076 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1077 setbuf(debugFP, NULL);
\r
1080 LoadLanguageFile(appData.language);
\r
1084 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1085 // InitEngineUCI( installDir, &second );
\r
1087 /* Create a main window for this application instance. */
\r
1088 hwnd = CreateWindow(szAppName, szTitle,
\r
1089 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1090 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1091 NULL, NULL, hInstance, NULL);
\r
1094 /* If window could not be created, return "failure" */
\r
1099 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1100 LoadLogo(&first, 0, FALSE);
\r
1101 LoadLogo(&second, 1, appData.icsActive);
\r
1105 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1106 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1107 iconCurrent = iconWhite;
\r
1108 InitDrawingColors();
\r
1109 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1110 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1111 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1112 /* Compute window size for each board size, and use the largest
\r
1113 size that fits on this screen as the default. */
\r
1114 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1115 if (boardSize == (BoardSize)-1 &&
\r
1116 winH <= screenHeight
\r
1117 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1118 && winW <= screenWidth) {
\r
1119 boardSize = (BoardSize)ibs;
\r
1123 InitDrawingSizes(boardSize, 0);
\r
1124 RecentEngineMenu(appData.recentEngineList);
\r
1126 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1128 /* [AS] Load textures if specified */
\r
1131 mysrandom( (unsigned) time(NULL) );
\r
1133 /* [AS] Restore layout */
\r
1134 if( wpMoveHistory.visible ) {
\r
1135 MoveHistoryPopUp();
\r
1138 if( wpEvalGraph.visible ) {
\r
1142 if( wpEngineOutput.visible ) {
\r
1143 EngineOutputPopUp();
\r
1146 /* Make the window visible; update its client area; and return "success" */
\r
1147 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1148 wp.length = sizeof(WINDOWPLACEMENT);
\r
1150 wp.showCmd = nCmdShow;
\r
1151 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1152 wp.rcNormalPosition.left = wpMain.x;
\r
1153 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1154 wp.rcNormalPosition.top = wpMain.y;
\r
1155 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1156 SetWindowPlacement(hwndMain, &wp);
\r
1158 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1160 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1161 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1163 if (hwndConsole) {
\r
1165 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1166 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1168 ShowWindow(hwndConsole, nCmdShow);
\r
1169 SetActiveWindow(hwndConsole);
\r
1171 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1172 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1181 HMENU hmenu = GetMenu(hwndMain);
\r
1183 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1184 MF_BYCOMMAND|((appData.icsActive &&
\r
1185 *appData.icsCommPort != NULLCHAR) ?
\r
1186 MF_ENABLED : MF_GRAYED));
\r
1187 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1188 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1189 MF_CHECKED : MF_UNCHECKED));
\r
1192 //---------------------------------------------------------------------------------------------------------
\r
1194 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1195 #define XBOARD FALSE
\r
1197 #define OPTCHAR "/"
\r
1198 #define SEPCHAR "="
\r
1199 #define TOPLEVEL 0
\r
1203 // front-end part of option handling
\r
1206 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1208 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1209 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1212 lf->lfEscapement = 0;
\r
1213 lf->lfOrientation = 0;
\r
1214 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1215 lf->lfItalic = mfp->italic;
\r
1216 lf->lfUnderline = mfp->underline;
\r
1217 lf->lfStrikeOut = mfp->strikeout;
\r
1218 lf->lfCharSet = mfp->charset;
\r
1219 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1220 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1221 lf->lfQuality = DEFAULT_QUALITY;
\r
1222 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1223 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1227 CreateFontInMF(MyFont *mf)
\r
1229 LFfromMFP(&mf->lf, &mf->mfp);
\r
1230 if (mf->hf) DeleteObject(mf->hf);
\r
1231 mf->hf = CreateFontIndirect(&mf->lf);
\r
1234 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1236 colorVariable[] = {
\r
1237 &whitePieceColor,
\r
1238 &blackPieceColor,
\r
1239 &lightSquareColor,
\r
1240 &darkSquareColor,
\r
1241 &highlightSquareColor,
\r
1242 &premoveHighlightColor,
\r
1244 &consoleBackgroundColor,
\r
1245 &appData.fontForeColorWhite,
\r
1246 &appData.fontBackColorWhite,
\r
1247 &appData.fontForeColorBlack,
\r
1248 &appData.fontBackColorBlack,
\r
1249 &appData.evalHistColorWhite,
\r
1250 &appData.evalHistColorBlack,
\r
1251 &appData.highlightArrowColor,
\r
1254 /* Command line font name parser. NULL name means do nothing.
\r
1255 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1256 For backward compatibility, syntax without the colon is also
\r
1257 accepted, but font names with digits in them won't work in that case.
\r
1260 ParseFontName(char *name, MyFontParams *mfp)
\r
1263 if (name == NULL) return;
\r
1265 q = strchr(p, ':');
\r
1267 if (q - p >= sizeof(mfp->faceName))
\r
1268 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1269 memcpy(mfp->faceName, p, q - p);
\r
1270 mfp->faceName[q - p] = NULLCHAR;
\r
1273 q = mfp->faceName;
\r
1274 while (*p && !isdigit(*p)) {
\r
1276 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1277 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1279 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1282 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1283 mfp->pointSize = (float) atof(p);
\r
1284 mfp->bold = (strchr(p, 'b') != NULL);
\r
1285 mfp->italic = (strchr(p, 'i') != NULL);
\r
1286 mfp->underline = (strchr(p, 'u') != NULL);
\r
1287 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1288 mfp->charset = DEFAULT_CHARSET;
\r
1289 q = strchr(p, 'c');
\r
1291 mfp->charset = (BYTE) atoi(q+1);
\r
1295 ParseFont(char *name, int number)
\r
1296 { // wrapper to shield back-end from 'font'
\r
1297 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1302 { // in WB we have a 2D array of fonts; this initializes their description
\r
1304 /* Point font array elements to structures and
\r
1305 parse default font names */
\r
1306 for (i=0; i<NUM_FONTS; i++) {
\r
1307 for (j=0; j<NUM_SIZES; j++) {
\r
1308 font[j][i] = &fontRec[j][i];
\r
1309 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1316 { // here we create the actual fonts from the selected descriptions
\r
1318 for (i=0; i<NUM_FONTS; i++) {
\r
1319 for (j=0; j<NUM_SIZES; j++) {
\r
1320 CreateFontInMF(font[j][i]);
\r
1324 /* Color name parser.
\r
1325 X version accepts X color names, but this one
\r
1326 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1328 ParseColorName(char *name)
\r
1330 int red, green, blue, count;
\r
1331 char buf[MSG_SIZ];
\r
1333 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1335 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1336 &red, &green, &blue);
\r
1339 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1340 DisplayError(buf, 0);
\r
1341 return RGB(0, 0, 0);
\r
1343 return PALETTERGB(red, green, blue);
\r
1347 ParseColor(int n, char *name)
\r
1348 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1349 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1353 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1355 char *e = argValue;
\r
1359 if (*e == 'b') eff |= CFE_BOLD;
\r
1360 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1361 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1362 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1363 else if (*e == '#' || isdigit(*e)) break;
\r
1367 *color = ParseColorName(e);
\r
1371 ParseTextAttribs(ColorClass cc, char *s)
\r
1372 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1373 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1374 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1378 ParseBoardSize(void *addr, char *name)
\r
1379 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1380 BoardSize bs = SizeTiny;
\r
1381 while (sizeInfo[bs].name != NULL) {
\r
1382 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1383 *(BoardSize *)addr = bs;
\r
1388 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1393 { // [HGM] import name from appData first
\r
1396 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1397 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1398 textAttribs[cc].sound.data = NULL;
\r
1399 MyLoadSound(&textAttribs[cc].sound);
\r
1401 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1402 textAttribs[cc].sound.name = strdup("");
\r
1403 textAttribs[cc].sound.data = NULL;
\r
1405 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1406 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1407 sounds[sc].data = NULL;
\r
1408 MyLoadSound(&sounds[sc]);
\r
1413 SetCommPortDefaults()
\r
1415 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1416 dcb.DCBlength = sizeof(DCB);
\r
1417 dcb.BaudRate = 9600;
\r
1418 dcb.fBinary = TRUE;
\r
1419 dcb.fParity = FALSE;
\r
1420 dcb.fOutxCtsFlow = FALSE;
\r
1421 dcb.fOutxDsrFlow = FALSE;
\r
1422 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1423 dcb.fDsrSensitivity = FALSE;
\r
1424 dcb.fTXContinueOnXoff = TRUE;
\r
1425 dcb.fOutX = FALSE;
\r
1427 dcb.fNull = FALSE;
\r
1428 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1429 dcb.fAbortOnError = FALSE;
\r
1431 dcb.Parity = SPACEPARITY;
\r
1432 dcb.StopBits = ONESTOPBIT;
\r
1435 // [HGM] args: these three cases taken out to stay in front-end
\r
1437 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1438 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1439 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1440 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1442 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1443 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1444 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1445 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1446 ad->argName, mfp->faceName, mfp->pointSize,
\r
1447 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1448 mfp->bold ? "b" : "",
\r
1449 mfp->italic ? "i" : "",
\r
1450 mfp->underline ? "u" : "",
\r
1451 mfp->strikeout ? "s" : "",
\r
1452 (int)mfp->charset);
\r
1458 { // [HGM] copy the names from the internal WB variables to appData
\r
1461 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1462 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1463 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1464 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1468 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1469 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1470 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1471 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1472 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1473 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1474 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1475 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1476 (ta->effects) ? " " : "",
\r
1477 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1481 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1482 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1483 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1484 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1485 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1489 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1490 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1491 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1495 ParseCommPortSettings(char *s)
\r
1496 { // wrapper to keep dcb from back-end
\r
1497 ParseCommSettings(s, &dcb);
\r
1502 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1503 GetActualPlacement(hwndMain, &wpMain);
\r
1504 GetActualPlacement(hwndConsole, &wpConsole);
\r
1505 GetActualPlacement(commentDialog, &wpComment);
\r
1506 GetActualPlacement(editTagsDialog, &wpTags);
\r
1507 GetActualPlacement(gameListDialog, &wpGameList);
\r
1508 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1509 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1510 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1514 PrintCommPortSettings(FILE *f, char *name)
\r
1515 { // wrapper to shield back-end from DCB
\r
1516 PrintCommSettings(f, name, &dcb);
\r
1520 MySearchPath(char *installDir, char *name, char *fullname)
\r
1522 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1523 if(name[0]== '%') {
\r
1524 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1525 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1526 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1527 *strchr(buf, '%') = 0;
\r
1528 strcat(fullname, getenv(buf));
\r
1529 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1531 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1532 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1533 return (int) strlen(fullname);
\r
1535 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1539 MyGetFullPathName(char *name, char *fullname)
\r
1542 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1547 { // [HGM] args: allows testing if main window is realized from back-end
\r
1548 return hwndMain != NULL;
\r
1552 PopUpStartupDialog()
\r
1556 LoadLanguageFile(appData.language);
\r
1557 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1558 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1559 FreeProcInstance(lpProc);
\r
1562 /*---------------------------------------------------------------------------*\
\r
1564 * GDI board drawing routines
\r
1566 \*---------------------------------------------------------------------------*/
\r
1568 /* [AS] Draw square using background texture */
\r
1569 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1574 return; /* Should never happen! */
\r
1577 SetGraphicsMode( dst, GM_ADVANCED );
\r
1584 /* X reflection */
\r
1589 x.eDx = (FLOAT) dw + dx - 1;
\r
1592 SetWorldTransform( dst, &x );
\r
1595 /* Y reflection */
\r
1601 x.eDy = (FLOAT) dh + dy - 1;
\r
1603 SetWorldTransform( dst, &x );
\r
1611 x.eDx = (FLOAT) dx;
\r
1612 x.eDy = (FLOAT) dy;
\r
1615 SetWorldTransform( dst, &x );
\r
1619 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1627 SetWorldTransform( dst, &x );
\r
1629 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1632 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1634 PM_WP = (int) WhitePawn,
\r
1635 PM_WN = (int) WhiteKnight,
\r
1636 PM_WB = (int) WhiteBishop,
\r
1637 PM_WR = (int) WhiteRook,
\r
1638 PM_WQ = (int) WhiteQueen,
\r
1639 PM_WF = (int) WhiteFerz,
\r
1640 PM_WW = (int) WhiteWazir,
\r
1641 PM_WE = (int) WhiteAlfil,
\r
1642 PM_WM = (int) WhiteMan,
\r
1643 PM_WO = (int) WhiteCannon,
\r
1644 PM_WU = (int) WhiteUnicorn,
\r
1645 PM_WH = (int) WhiteNightrider,
\r
1646 PM_WA = (int) WhiteAngel,
\r
1647 PM_WC = (int) WhiteMarshall,
\r
1648 PM_WAB = (int) WhiteCardinal,
\r
1649 PM_WD = (int) WhiteDragon,
\r
1650 PM_WL = (int) WhiteLance,
\r
1651 PM_WS = (int) WhiteCobra,
\r
1652 PM_WV = (int) WhiteFalcon,
\r
1653 PM_WSG = (int) WhiteSilver,
\r
1654 PM_WG = (int) WhiteGrasshopper,
\r
1655 PM_WK = (int) WhiteKing,
\r
1656 PM_BP = (int) BlackPawn,
\r
1657 PM_BN = (int) BlackKnight,
\r
1658 PM_BB = (int) BlackBishop,
\r
1659 PM_BR = (int) BlackRook,
\r
1660 PM_BQ = (int) BlackQueen,
\r
1661 PM_BF = (int) BlackFerz,
\r
1662 PM_BW = (int) BlackWazir,
\r
1663 PM_BE = (int) BlackAlfil,
\r
1664 PM_BM = (int) BlackMan,
\r
1665 PM_BO = (int) BlackCannon,
\r
1666 PM_BU = (int) BlackUnicorn,
\r
1667 PM_BH = (int) BlackNightrider,
\r
1668 PM_BA = (int) BlackAngel,
\r
1669 PM_BC = (int) BlackMarshall,
\r
1670 PM_BG = (int) BlackGrasshopper,
\r
1671 PM_BAB = (int) BlackCardinal,
\r
1672 PM_BD = (int) BlackDragon,
\r
1673 PM_BL = (int) BlackLance,
\r
1674 PM_BS = (int) BlackCobra,
\r
1675 PM_BV = (int) BlackFalcon,
\r
1676 PM_BSG = (int) BlackSilver,
\r
1677 PM_BK = (int) BlackKing
\r
1680 static HFONT hPieceFont = NULL;
\r
1681 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1682 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1683 static int fontBitmapSquareSize = 0;
\r
1684 static char pieceToFontChar[(int) EmptySquare] =
\r
1685 { 'p', 'n', 'b', 'r', 'q',
\r
1686 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1687 'k', 'o', 'm', 'v', 't', 'w',
\r
1688 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1691 extern BOOL SetCharTable( char *table, const char * map );
\r
1692 /* [HGM] moved to backend.c */
\r
1694 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1697 BYTE r1 = GetRValue( color );
\r
1698 BYTE g1 = GetGValue( color );
\r
1699 BYTE b1 = GetBValue( color );
\r
1705 /* Create a uniform background first */
\r
1706 hbrush = CreateSolidBrush( color );
\r
1707 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1708 FillRect( hdc, &rc, hbrush );
\r
1709 DeleteObject( hbrush );
\r
1712 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1713 int steps = squareSize / 2;
\r
1716 for( i=0; i<steps; i++ ) {
\r
1717 BYTE r = r1 - (r1-r2) * i / steps;
\r
1718 BYTE g = g1 - (g1-g2) * i / steps;
\r
1719 BYTE b = b1 - (b1-b2) * i / steps;
\r
1721 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1722 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1723 FillRect( hdc, &rc, hbrush );
\r
1724 DeleteObject(hbrush);
\r
1727 else if( mode == 2 ) {
\r
1728 /* Diagonal gradient, good more or less for every piece */
\r
1729 POINT triangle[3];
\r
1730 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1731 HBRUSH hbrush_old;
\r
1732 int steps = squareSize;
\r
1735 triangle[0].x = squareSize - steps;
\r
1736 triangle[0].y = squareSize;
\r
1737 triangle[1].x = squareSize;
\r
1738 triangle[1].y = squareSize;
\r
1739 triangle[2].x = squareSize;
\r
1740 triangle[2].y = squareSize - steps;
\r
1742 for( i=0; i<steps; i++ ) {
\r
1743 BYTE r = r1 - (r1-r2) * i / steps;
\r
1744 BYTE g = g1 - (g1-g2) * i / steps;
\r
1745 BYTE b = b1 - (b1-b2) * i / steps;
\r
1747 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1748 hbrush_old = SelectObject( hdc, hbrush );
\r
1749 Polygon( hdc, triangle, 3 );
\r
1750 SelectObject( hdc, hbrush_old );
\r
1751 DeleteObject(hbrush);
\r
1756 SelectObject( hdc, hpen );
\r
1761 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1762 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1763 piece: follow the steps as explained below.
\r
1765 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1769 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1773 int backColor = whitePieceColor;
\r
1774 int foreColor = blackPieceColor;
\r
1776 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1777 backColor = appData.fontBackColorWhite;
\r
1778 foreColor = appData.fontForeColorWhite;
\r
1780 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1781 backColor = appData.fontBackColorBlack;
\r
1782 foreColor = appData.fontForeColorBlack;
\r
1786 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1788 hbm_old = SelectObject( hdc, hbm );
\r
1792 rc.right = squareSize;
\r
1793 rc.bottom = squareSize;
\r
1795 /* Step 1: background is now black */
\r
1796 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1798 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1800 pt.x = (squareSize - sz.cx) / 2;
\r
1801 pt.y = (squareSize - sz.cy) / 2;
\r
1803 SetBkMode( hdc, TRANSPARENT );
\r
1804 SetTextColor( hdc, chroma );
\r
1805 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1806 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1808 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1809 /* Step 3: the area outside the piece is filled with white */
\r
1810 // FloodFill( hdc, 0, 0, chroma );
\r
1811 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1812 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1813 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1814 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1815 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1817 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1818 but if the start point is not inside the piece we're lost!
\r
1819 There should be a better way to do this... if we could create a region or path
\r
1820 from the fill operation we would be fine for example.
\r
1822 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1823 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1825 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1826 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1827 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1829 SelectObject( dc2, bm2 );
\r
1830 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1831 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1832 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1833 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1834 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1837 DeleteObject( bm2 );
\r
1840 SetTextColor( hdc, 0 );
\r
1842 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1843 draw the piece again in black for safety.
\r
1845 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1847 SelectObject( hdc, hbm_old );
\r
1849 if( hPieceMask[index] != NULL ) {
\r
1850 DeleteObject( hPieceMask[index] );
\r
1853 hPieceMask[index] = hbm;
\r
1856 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1858 SelectObject( hdc, hbm );
\r
1861 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1862 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1863 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1865 SelectObject( dc1, hPieceMask[index] );
\r
1866 SelectObject( dc2, bm2 );
\r
1867 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1868 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1871 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1872 the piece background and deletes (makes transparent) the rest.
\r
1873 Thanks to that mask, we are free to paint the background with the greates
\r
1874 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1875 We use this, to make gradients and give the pieces a "roundish" look.
\r
1877 SetPieceBackground( hdc, backColor, 2 );
\r
1878 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1882 DeleteObject( bm2 );
\r
1885 SetTextColor( hdc, foreColor );
\r
1886 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1888 SelectObject( hdc, hbm_old );
\r
1890 if( hPieceFace[index] != NULL ) {
\r
1891 DeleteObject( hPieceFace[index] );
\r
1894 hPieceFace[index] = hbm;
\r
1897 static int TranslatePieceToFontPiece( int piece )
\r
1927 case BlackMarshall:
\r
1931 case BlackNightrider:
\r
1937 case BlackUnicorn:
\r
1941 case BlackGrasshopper:
\r
1953 case BlackCardinal:
\r
1960 case WhiteMarshall:
\r
1964 case WhiteNightrider:
\r
1970 case WhiteUnicorn:
\r
1974 case WhiteGrasshopper:
\r
1986 case WhiteCardinal:
\r
1995 void CreatePiecesFromFont()
\r
1998 HDC hdc_window = NULL;
\r
2004 if( fontBitmapSquareSize < 0 ) {
\r
2005 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2009 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2010 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2011 fontBitmapSquareSize = -1;
\r
2015 if( fontBitmapSquareSize != squareSize ) {
\r
2016 hdc_window = GetDC( hwndMain );
\r
2017 hdc = CreateCompatibleDC( hdc_window );
\r
2019 if( hPieceFont != NULL ) {
\r
2020 DeleteObject( hPieceFont );
\r
2023 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2024 hPieceMask[i] = NULL;
\r
2025 hPieceFace[i] = NULL;
\r
2031 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2032 fontHeight = appData.fontPieceSize;
\r
2035 fontHeight = (fontHeight * squareSize) / 100;
\r
2037 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2039 lf.lfEscapement = 0;
\r
2040 lf.lfOrientation = 0;
\r
2041 lf.lfWeight = FW_NORMAL;
\r
2043 lf.lfUnderline = 0;
\r
2044 lf.lfStrikeOut = 0;
\r
2045 lf.lfCharSet = DEFAULT_CHARSET;
\r
2046 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2047 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2048 lf.lfQuality = PROOF_QUALITY;
\r
2049 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2050 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2051 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2053 hPieceFont = CreateFontIndirect( &lf );
\r
2055 if( hPieceFont == NULL ) {
\r
2056 fontBitmapSquareSize = -2;
\r
2059 /* Setup font-to-piece character table */
\r
2060 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2061 /* No (or wrong) global settings, try to detect the font */
\r
2062 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2064 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2066 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2067 /* DiagramTT* family */
\r
2068 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2070 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2071 /* Fairy symbols */
\r
2072 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2074 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2075 /* Good Companion (Some characters get warped as literal :-( */
\r
2076 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2077 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2078 SetCharTable(pieceToFontChar, s);
\r
2081 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2082 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2086 /* Create bitmaps */
\r
2087 hfont_old = SelectObject( hdc, hPieceFont );
\r
2088 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2089 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2090 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2092 SelectObject( hdc, hfont_old );
\r
2094 fontBitmapSquareSize = squareSize;
\r
2098 if( hdc != NULL ) {
\r
2102 if( hdc_window != NULL ) {
\r
2103 ReleaseDC( hwndMain, hdc_window );
\r
2108 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2112 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2113 if (gameInfo.event &&
\r
2114 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2115 strcmp(name, "k80s") == 0) {
\r
2116 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2118 return LoadBitmap(hinst, name);
\r
2122 /* Insert a color into the program's logical palette
\r
2123 structure. This code assumes the given color is
\r
2124 the result of the RGB or PALETTERGB macro, and it
\r
2125 knows how those macros work (which is documented).
\r
2128 InsertInPalette(COLORREF color)
\r
2130 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2132 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2133 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2134 pLogPal->palNumEntries--;
\r
2138 pe->peFlags = (char) 0;
\r
2139 pe->peRed = (char) (0xFF & color);
\r
2140 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2141 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2147 InitDrawingColors()
\r
2149 if (pLogPal == NULL) {
\r
2150 /* Allocate enough memory for a logical palette with
\r
2151 * PALETTESIZE entries and set the size and version fields
\r
2152 * of the logical palette structure.
\r
2154 pLogPal = (NPLOGPALETTE)
\r
2155 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2156 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2157 pLogPal->palVersion = 0x300;
\r
2159 pLogPal->palNumEntries = 0;
\r
2161 InsertInPalette(lightSquareColor);
\r
2162 InsertInPalette(darkSquareColor);
\r
2163 InsertInPalette(whitePieceColor);
\r
2164 InsertInPalette(blackPieceColor);
\r
2165 InsertInPalette(highlightSquareColor);
\r
2166 InsertInPalette(premoveHighlightColor);
\r
2168 /* create a logical color palette according the information
\r
2169 * in the LOGPALETTE structure.
\r
2171 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2173 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2174 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2175 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2176 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2177 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2178 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2179 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2180 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2181 /* [AS] Force rendering of the font-based pieces */
\r
2182 if( fontBitmapSquareSize > 0 ) {
\r
2183 fontBitmapSquareSize = 0;
\r
2189 BoardWidth(int boardSize, int n)
\r
2190 { /* [HGM] argument n added to allow different width and height */
\r
2191 int lineGap = sizeInfo[boardSize].lineGap;
\r
2193 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2194 lineGap = appData.overrideLineGap;
\r
2197 return (n + 1) * lineGap +
\r
2198 n * sizeInfo[boardSize].squareSize;
\r
2201 /* Respond to board resize by dragging edge */
\r
2203 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2205 BoardSize newSize = NUM_SIZES - 1;
\r
2206 static int recurse = 0;
\r
2207 if (IsIconic(hwndMain)) return;
\r
2208 if (recurse > 0) return;
\r
2210 while (newSize > 0) {
\r
2211 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2212 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2213 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2216 boardSize = newSize;
\r
2217 InitDrawingSizes(boardSize, flags);
\r
2222 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2225 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2227 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2228 ChessSquare piece;
\r
2229 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2231 SIZE clockSize, messageSize;
\r
2233 char buf[MSG_SIZ];
\r
2235 HMENU hmenu = GetMenu(hwndMain);
\r
2236 RECT crect, wrect, oldRect;
\r
2238 LOGBRUSH logbrush;
\r
2240 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2241 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2243 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2244 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2246 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2247 oldRect.top = wpMain.y;
\r
2248 oldRect.right = wpMain.x + wpMain.width;
\r
2249 oldRect.bottom = wpMain.y + wpMain.height;
\r
2251 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2252 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2253 squareSize = sizeInfo[boardSize].squareSize;
\r
2254 lineGap = sizeInfo[boardSize].lineGap;
\r
2255 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2257 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2258 lineGap = appData.overrideLineGap;
\r
2261 if (tinyLayout != oldTinyLayout) {
\r
2262 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2264 style &= ~WS_SYSMENU;
\r
2265 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2266 "&Minimize\tCtrl+F4");
\r
2268 style |= WS_SYSMENU;
\r
2269 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2271 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2273 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2274 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2275 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2277 DrawMenuBar(hwndMain);
\r
2280 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2281 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2283 /* Get text area sizes */
\r
2284 hdc = GetDC(hwndMain);
\r
2285 if (appData.clockMode) {
\r
2286 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2288 snprintf(buf, MSG_SIZ, _("White"));
\r
2290 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2291 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2292 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2293 str = _("We only care about the height here");
\r
2294 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2295 SelectObject(hdc, oldFont);
\r
2296 ReleaseDC(hwndMain, hdc);
\r
2298 /* Compute where everything goes */
\r
2299 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2300 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2301 logoHeight = 2*clockSize.cy;
\r
2302 leftLogoRect.left = OUTER_MARGIN;
\r
2303 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2304 leftLogoRect.top = OUTER_MARGIN;
\r
2305 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2307 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2308 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2309 rightLogoRect.top = OUTER_MARGIN;
\r
2310 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2313 whiteRect.left = leftLogoRect.right;
\r
2314 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2315 whiteRect.top = OUTER_MARGIN;
\r
2316 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2318 blackRect.right = rightLogoRect.left;
\r
2319 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2320 blackRect.top = whiteRect.top;
\r
2321 blackRect.bottom = whiteRect.bottom;
\r
2323 whiteRect.left = OUTER_MARGIN;
\r
2324 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2325 whiteRect.top = OUTER_MARGIN;
\r
2326 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2328 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2329 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2330 blackRect.top = whiteRect.top;
\r
2331 blackRect.bottom = whiteRect.bottom;
\r
2333 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2336 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2337 if (appData.showButtonBar) {
\r
2338 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2339 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2341 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2343 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2344 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2346 boardRect.left = OUTER_MARGIN;
\r
2347 boardRect.right = boardRect.left + boardWidth;
\r
2348 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2349 boardRect.bottom = boardRect.top + boardHeight;
\r
2351 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2352 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2353 oldBoardSize = boardSize;
\r
2354 oldTinyLayout = tinyLayout;
\r
2355 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2356 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2357 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2358 winW *= 1 + twoBoards;
\r
2359 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2360 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2361 wpMain.height = winH; // without disturbing window attachments
\r
2362 GetWindowRect(hwndMain, &wrect);
\r
2363 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2364 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2366 // [HGM] placement: let attached windows follow size change.
\r
2367 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2368 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2369 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2370 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2371 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2373 /* compensate if menu bar wrapped */
\r
2374 GetClientRect(hwndMain, &crect);
\r
2375 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2376 wpMain.height += offby;
\r
2378 case WMSZ_TOPLEFT:
\r
2379 SetWindowPos(hwndMain, NULL,
\r
2380 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2381 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2384 case WMSZ_TOPRIGHT:
\r
2386 SetWindowPos(hwndMain, NULL,
\r
2387 wrect.left, wrect.bottom - wpMain.height,
\r
2388 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2391 case WMSZ_BOTTOMLEFT:
\r
2393 SetWindowPos(hwndMain, NULL,
\r
2394 wrect.right - wpMain.width, wrect.top,
\r
2395 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2398 case WMSZ_BOTTOMRIGHT:
\r
2402 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2403 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2408 for (i = 0; i < N_BUTTONS; i++) {
\r
2409 if (buttonDesc[i].hwnd != NULL) {
\r
2410 DestroyWindow(buttonDesc[i].hwnd);
\r
2411 buttonDesc[i].hwnd = NULL;
\r
2413 if (appData.showButtonBar) {
\r
2414 buttonDesc[i].hwnd =
\r
2415 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2416 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2417 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2418 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2419 (HMENU) buttonDesc[i].id,
\r
2420 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2422 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2423 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2424 MAKELPARAM(FALSE, 0));
\r
2426 if (buttonDesc[i].id == IDM_Pause)
\r
2427 hwndPause = buttonDesc[i].hwnd;
\r
2428 buttonDesc[i].wndproc = (WNDPROC)
\r
2429 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2432 if (gridPen != NULL) DeleteObject(gridPen);
\r
2433 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2434 if (premovePen != NULL) DeleteObject(premovePen);
\r
2435 if (lineGap != 0) {
\r
2436 logbrush.lbStyle = BS_SOLID;
\r
2437 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2439 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2440 lineGap, &logbrush, 0, NULL);
\r
2441 logbrush.lbColor = highlightSquareColor;
\r
2443 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2444 lineGap, &logbrush, 0, NULL);
\r
2446 logbrush.lbColor = premoveHighlightColor;
\r
2448 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2449 lineGap, &logbrush, 0, NULL);
\r
2451 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2452 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2453 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2454 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2455 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2456 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2457 BOARD_WIDTH * (squareSize + lineGap);
\r
2458 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2460 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2461 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2462 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2463 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2464 lineGap / 2 + (i * (squareSize + lineGap));
\r
2465 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2466 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2467 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2471 /* [HGM] Licensing requirement */
\r
2473 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2476 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2478 GothicPopUp( "", VariantNormal);
\r
2481 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2483 /* Load piece bitmaps for this board size */
\r
2484 for (i=0; i<=2; i++) {
\r
2485 for (piece = WhitePawn;
\r
2486 (int) piece < (int) BlackPawn;
\r
2487 piece = (ChessSquare) ((int) piece + 1)) {
\r
2488 if (pieceBitmap[i][piece] != NULL)
\r
2489 DeleteObject(pieceBitmap[i][piece]);
\r
2493 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2494 // Orthodox Chess pieces
\r
2495 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2496 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2497 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2498 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2499 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2500 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2501 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2502 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2503 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2504 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2505 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2506 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2507 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2508 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2509 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2510 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2511 // in Shogi, Hijack the unused Queen for Lance
\r
2512 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2513 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2514 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2516 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2517 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2518 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2521 if(squareSize <= 72 && squareSize >= 33) {
\r
2522 /* A & C are available in most sizes now */
\r
2523 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2524 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2525 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2526 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2527 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2528 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2529 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2530 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2531 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2532 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2533 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2534 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2535 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2536 } else { // Smirf-like
\r
2537 if(gameInfo.variant == VariantSChess) {
\r
2538 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2539 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2540 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2542 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2543 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2544 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2547 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2548 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2549 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2550 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2551 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2552 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2553 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2554 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2555 } else { // WinBoard standard
\r
2556 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2557 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2558 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2563 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2564 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2565 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2566 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2567 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2568 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2569 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2570 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2571 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2572 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2573 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2574 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2575 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2576 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2577 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2578 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2579 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2580 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2581 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2582 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2583 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2584 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2585 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2586 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2587 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2588 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2589 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2590 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2591 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2592 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2593 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2595 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2596 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2597 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2598 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2599 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2600 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2601 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2602 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2603 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2604 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2605 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2606 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2607 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2609 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2610 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2611 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2612 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2613 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2614 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2615 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2616 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2617 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2618 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2623 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2624 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2625 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2626 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2627 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2628 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2629 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2630 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2631 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2632 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2633 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2634 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2635 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2636 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2637 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2641 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2642 /* special Shogi support in this size */
\r
2643 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2644 for (piece = WhitePawn;
\r
2645 (int) piece < (int) BlackPawn;
\r
2646 piece = (ChessSquare) ((int) piece + 1)) {
\r
2647 if (pieceBitmap[i][piece] != NULL)
\r
2648 DeleteObject(pieceBitmap[i][piece]);
\r
2651 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2652 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2653 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2654 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2655 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2656 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2657 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2658 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2659 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2660 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2661 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2662 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2663 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2664 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2665 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2666 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2667 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2668 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2669 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2670 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2671 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2672 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2673 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2674 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2675 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2676 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2677 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2678 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2679 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2680 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2681 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2682 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2683 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2684 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2685 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2686 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2687 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2688 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2689 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2690 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2691 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2692 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2698 PieceBitmap(ChessSquare p, int kind)
\r
2700 if ((int) p >= (int) BlackPawn)
\r
2701 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2703 return pieceBitmap[kind][(int) p];
\r
2706 /***************************************************************/
\r
2708 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2709 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2711 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2712 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2716 SquareToPos(int row, int column, int * x, int * y)
\r
2719 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2720 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2722 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2723 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2728 DrawCoordsOnDC(HDC hdc)
\r
2730 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2731 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2732 char str[2] = { NULLCHAR, NULLCHAR };
\r
2733 int oldMode, oldAlign, x, y, start, i;
\r
2737 if (!appData.showCoords)
\r
2740 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2742 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2743 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2744 oldAlign = GetTextAlign(hdc);
\r
2745 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2747 y = boardRect.top + lineGap;
\r
2748 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2750 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2751 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2752 str[0] = files[start + i];
\r
2753 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2754 y += squareSize + lineGap;
\r
2757 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2759 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2760 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2761 str[0] = ranks[start + i];
\r
2762 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2763 x += squareSize + lineGap;
\r
2766 SelectObject(hdc, oldBrush);
\r
2767 SetBkMode(hdc, oldMode);
\r
2768 SetTextAlign(hdc, oldAlign);
\r
2769 SelectObject(hdc, oldFont);
\r
2773 DrawGridOnDC(HDC hdc)
\r
2777 if (lineGap != 0) {
\r
2778 oldPen = SelectObject(hdc, gridPen);
\r
2779 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2780 SelectObject(hdc, oldPen);
\r
2784 #define HIGHLIGHT_PEN 0
\r
2785 #define PREMOVE_PEN 1
\r
2788 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2791 HPEN oldPen, hPen;
\r
2792 if (lineGap == 0) return;
\r
2794 x1 = boardRect.left +
\r
2795 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2796 y1 = boardRect.top +
\r
2797 lineGap/2 + y * (squareSize + lineGap);
\r
2799 x1 = boardRect.left +
\r
2800 lineGap/2 + x * (squareSize + lineGap);
\r
2801 y1 = boardRect.top +
\r
2802 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2804 hPen = pen ? premovePen : highlightPen;
\r
2805 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2806 MoveToEx(hdc, x1, y1, NULL);
\r
2807 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2808 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2809 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2810 LineTo(hdc, x1, y1);
\r
2811 SelectObject(hdc, oldPen);
\r
2815 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2818 for (i=0; i<2; i++) {
\r
2819 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2820 DrawHighlightOnDC(hdc, TRUE,
\r
2821 h->sq[i].x, h->sq[i].y,
\r
2826 /* Note: sqcolor is used only in monoMode */
\r
2827 /* Note that this code is largely duplicated in woptions.c,
\r
2828 function DrawSampleSquare, so that needs to be updated too */
\r
2830 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2832 HBITMAP oldBitmap;
\r
2836 if (appData.blindfold) return;
\r
2838 /* [AS] Use font-based pieces if needed */
\r
2839 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2840 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2841 CreatePiecesFromFont();
\r
2843 if( fontBitmapSquareSize == squareSize ) {
\r
2844 int index = TranslatePieceToFontPiece(piece);
\r
2846 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2848 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2849 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2853 squareSize, squareSize,
\r
2858 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2860 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2861 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2865 squareSize, squareSize,
\r
2874 if (appData.monoMode) {
\r
2875 SelectObject(tmphdc, PieceBitmap(piece,
\r
2876 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2877 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2878 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2880 tmpSize = squareSize;
\r
2882 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2883 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2884 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2885 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2886 x += (squareSize - minorSize)>>1;
\r
2887 y += squareSize - minorSize - 2;
\r
2888 tmpSize = minorSize;
\r
2890 if (color || appData.allWhite ) {
\r
2891 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2893 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2894 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2895 if(appData.upsideDown && color==flipView)
\r
2896 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2898 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2899 /* Use black for outline of white pieces */
\r
2900 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2901 if(appData.upsideDown && color==flipView)
\r
2902 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2904 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2906 /* Use square color for details of black pieces */
\r
2907 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2908 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2909 if(appData.upsideDown && !flipView)
\r
2910 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2912 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2914 SelectObject(hdc, oldBrush);
\r
2915 SelectObject(tmphdc, oldBitmap);
\r
2919 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2920 int GetBackTextureMode( int algo )
\r
2922 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2926 case BACK_TEXTURE_MODE_PLAIN:
\r
2927 result = 1; /* Always use identity map */
\r
2929 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2930 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2938 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2939 to handle redraws cleanly (as random numbers would always be different).
\r
2941 VOID RebuildTextureSquareInfo()
\r
2951 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2953 if( liteBackTexture != NULL ) {
\r
2954 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2955 lite_w = bi.bmWidth;
\r
2956 lite_h = bi.bmHeight;
\r
2960 if( darkBackTexture != NULL ) {
\r
2961 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2962 dark_w = bi.bmWidth;
\r
2963 dark_h = bi.bmHeight;
\r
2967 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2968 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2969 if( (col + row) & 1 ) {
\r
2971 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2972 if( lite_w >= squareSize*BOARD_WIDTH )
\r
2973 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
2975 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2976 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
2977 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
2979 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2980 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2985 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2986 if( dark_w >= squareSize*BOARD_WIDTH )
\r
2987 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
2989 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2990 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
2991 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
2993 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2994 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3001 /* [AS] Arrow highlighting support */
\r
3003 static double A_WIDTH = 5; /* Width of arrow body */
\r
3005 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3006 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3008 static double Sqr( double x )
\r
3013 static int Round( double x )
\r
3015 return (int) (x + 0.5);
\r
3018 /* Draw an arrow between two points using current settings */
\r
3019 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3022 double dx, dy, j, k, x, y;
\r
3024 if( d_x == s_x ) {
\r
3025 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3027 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3030 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3031 arrow[1].y = d_y - h;
\r
3033 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3034 arrow[2].y = d_y - h;
\r
3039 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3040 arrow[5].y = d_y - h;
\r
3042 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3043 arrow[4].y = d_y - h;
\r
3045 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3048 else if( d_y == s_y ) {
\r
3049 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3052 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3054 arrow[1].x = d_x - w;
\r
3055 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3057 arrow[2].x = d_x - w;
\r
3058 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3063 arrow[5].x = d_x - w;
\r
3064 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3066 arrow[4].x = d_x - w;
\r
3067 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3070 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3073 /* [AS] Needed a lot of paper for this! :-) */
\r
3074 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3075 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3077 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3079 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3084 arrow[0].x = Round(x - j);
\r
3085 arrow[0].y = Round(y + j*dx);
\r
3087 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3088 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3091 x = (double) d_x - k;
\r
3092 y = (double) d_y - k*dy;
\r
3095 x = (double) d_x + k;
\r
3096 y = (double) d_y + k*dy;
\r
3099 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3101 arrow[6].x = Round(x - j);
\r
3102 arrow[6].y = Round(y + j*dx);
\r
3104 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3105 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3107 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3108 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3113 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3114 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3117 Polygon( hdc, arrow, 7 );
\r
3120 /* [AS] Draw an arrow between two squares */
\r
3121 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3123 int s_x, s_y, d_x, d_y;
\r
3130 if( s_col == d_col && s_row == d_row ) {
\r
3134 /* Get source and destination points */
\r
3135 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3136 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3139 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3141 else if( d_y < s_y ) {
\r
3142 d_y += squareSize / 2 + squareSize / 4;
\r
3145 d_y += squareSize / 2;
\r
3149 d_x += squareSize / 2 - squareSize / 4;
\r
3151 else if( d_x < s_x ) {
\r
3152 d_x += squareSize / 2 + squareSize / 4;
\r
3155 d_x += squareSize / 2;
\r
3158 s_x += squareSize / 2;
\r
3159 s_y += squareSize / 2;
\r
3161 /* Adjust width */
\r
3162 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3165 stLB.lbStyle = BS_SOLID;
\r
3166 stLB.lbColor = appData.highlightArrowColor;
\r
3169 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3170 holdpen = SelectObject( hdc, hpen );
\r
3171 hbrush = CreateBrushIndirect( &stLB );
\r
3172 holdbrush = SelectObject( hdc, hbrush );
\r
3174 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3176 SelectObject( hdc, holdpen );
\r
3177 SelectObject( hdc, holdbrush );
\r
3178 DeleteObject( hpen );
\r
3179 DeleteObject( hbrush );
\r
3182 BOOL HasHighlightInfo()
\r
3184 BOOL result = FALSE;
\r
3186 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3187 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3195 BOOL IsDrawArrowEnabled()
\r
3197 BOOL result = FALSE;