2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
95 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
98 void mysrandom(unsigned int seed);
\r
100 extern int whiteFlag, blackFlag;
\r
101 Boolean flipClock = FALSE;
\r
102 extern HANDLE chatHandle[];
\r
103 extern enum ICS_TYPE ics_type;
\r
105 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
106 int MyGetFullPathName P((char *name, char *fullname));
\r
107 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
108 VOID NewVariantPopup(HWND hwnd);
\r
109 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
110 /*char*/int promoChar));
\r
111 void DisplayMove P((int moveNumber));
\r
112 void ChatPopUp P((char *s));
\r
114 ChessSquare piece;
\r
115 POINT pos; /* window coordinates of current pos */
\r
116 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
117 POINT from; /* board coordinates of the piece's orig pos */
\r
118 POINT to; /* board coordinates of the piece's new pos */
\r
121 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
124 POINT start; /* window coordinates of start pos */
\r
125 POINT pos; /* window coordinates of current pos */
\r
126 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
127 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
139 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
142 typedef struct { // [HGM] atomic
\r
143 int fromX, fromY, toX, toY, radius;
\r
146 static ExplodeInfo explodeInfo;
\r
148 /* Window class names */
\r
149 char szAppName[] = "WinBoard";
\r
150 char szConsoleName[] = "WBConsole";
\r
152 /* Title bar text */
\r
153 char szTitle[] = "WinBoard";
\r
154 char szConsoleTitle[] = "I C S Interaction";
\r
157 char *settingsFileName;
\r
158 Boolean saveSettingsOnExit;
\r
159 char installDir[MSG_SIZ];
\r
160 int errorExitStatus;
\r
162 BoardSize boardSize;
\r
163 Boolean chessProgram;
\r
164 //static int boardX, boardY;
\r
165 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
166 int squareSize, lineGap, minorSize, border;
\r
167 static int winW, winH;
\r
168 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
169 static int logoHeight = 0;
\r
170 static char messageText[MESSAGE_TEXT_MAX];
\r
171 static int clockTimerEvent = 0;
\r
172 static int loadGameTimerEvent = 0;
\r
173 static int analysisTimerEvent = 0;
\r
174 static DelayedEventCallback delayedTimerCallback;
\r
175 static int delayedTimerEvent = 0;
\r
176 static int buttonCount = 2;
\r
177 char *icsTextMenuString;
\r
179 char *firstChessProgramNames;
\r
180 char *secondChessProgramNames;
\r
182 #define PALETTESIZE 256
\r
184 HINSTANCE hInst; /* current instance */
\r
185 Boolean alwaysOnTop = FALSE;
\r
187 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
188 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
189 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\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[8], /* [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
226 #if defined(_winmajor)
\r
227 #define oldDialog (_winmajor < 4)
\r
229 #define oldDialog 0
\r
233 #define INTERNATIONAL
\r
235 #ifdef INTERNATIONAL
\r
236 # define _(s) T_(s)
\r
242 # define Translate(x, y)
\r
243 # define LoadLanguageFile(s)
\r
246 #ifdef INTERNATIONAL
\r
248 Boolean barbaric; // flag indicating if translation is needed
\r
250 // list of item numbers used in each dialog (used to alter language at run time)
\r
252 #define ABOUTBOX -1 /* not sure why these are needed */
\r
253 #define ABOUTBOX2 -1
\r
255 int dialogItems[][42] = {
\r
256 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
257 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
258 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
259 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
260 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
261 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
262 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
263 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
264 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
265 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
266 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
267 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
268 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
269 { ABOUTBOX2, IDC_ChessBoard },
\r
270 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
271 OPT_GameListClose, IDC_GameListDoFilter },
\r
272 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
273 { DLG_Error, IDOK },
\r
274 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
275 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
276 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
277 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
278 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
279 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
280 { DLG_IndexNumber, IDC_Index },
\r
281 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
282 { DLG_TypeInName, IDOK, IDCANCEL },
\r
283 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
284 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
285 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
286 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
287 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
288 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
289 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
290 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
291 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
292 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
293 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
294 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
295 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
296 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
297 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
298 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
299 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
300 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
301 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
302 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
303 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
304 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
305 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
306 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
307 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
308 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
309 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
310 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
311 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
312 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
313 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
314 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
315 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
316 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
317 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
318 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
319 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
320 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
321 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
322 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
323 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
324 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
325 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
326 { DLG_MoveHistory },
\r
327 { DLG_EvalGraph },
\r
328 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
329 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
330 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
331 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
332 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
333 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
334 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
335 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
336 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
340 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
341 static int lastChecked;
\r
342 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
343 extern int tinyLayout;
\r
344 extern char * menuBarText[][10];
\r
347 LoadLanguageFile(char *name)
\r
348 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
350 int i=0, j=0, n=0, k;
\r
353 if(!name || name[0] == NULLCHAR) return;
\r
354 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
355 appData.language = oldLanguage;
\r
356 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
357 if((f = fopen(buf, "r")) == NULL) return;
\r
358 while((k = fgetc(f)) != EOF) {
\r
359 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
360 languageBuf[i] = k;
\r
362 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
364 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
365 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
366 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
367 english[j] = languageBuf + n + 1; *p = 0;
\r
368 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
369 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
374 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
376 case 'n': k = '\n'; break;
\r
377 case 'r': k = '\r'; break;
\r
378 case 't': k = '\t'; break;
\r
380 languageBuf[--i] = k;
\r
385 barbaric = (j != 0);
\r
386 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
391 { // return the translation of the given string
\r
392 // efficiency can be improved a lot...
\r
394 static char buf[MSG_SIZ];
\r
395 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
396 if(!barbaric) return s;
\r
397 if(!s) return ""; // sanity
\r
398 while(english[i]) {
\r
399 if(!strcmp(s, english[i])) return foreign[i];
\r
400 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
401 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
410 Translate(HWND hDlg, int dialogID)
\r
411 { // translate all text items in the given dialog
\r
413 char buf[MSG_SIZ], *s;
\r
414 if(!barbaric) return;
\r
415 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
416 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
417 GetWindowText( hDlg, buf, MSG_SIZ );
\r
419 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
420 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
421 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
422 if(strlen(buf) == 0) continue;
\r
424 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
429 TranslateOneMenu(int i, HMENU subMenu)
\r
432 static MENUITEMINFO info;
\r
434 info.cbSize = sizeof(MENUITEMINFO);
\r
435 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
436 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
438 info.dwTypeData = buf;
\r
439 info.cch = sizeof(buf);
\r
440 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
442 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
443 else menuText[i][j] = strdup(buf); // remember original on first change
\r
445 if(buf[0] == NULLCHAR) continue;
\r
446 info.dwTypeData = T_(buf);
\r
447 info.cch = strlen(buf)+1;
\r
448 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
454 TranslateMenus(int addLanguage)
\r
457 WIN32_FIND_DATA fileData;
\r
459 #define IDM_English 1970
\r
461 HMENU mainMenu = GetMenu(hwndMain);
\r
462 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
463 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
464 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
465 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
466 TranslateOneMenu(i, subMenu);
\r
468 DrawMenuBar(hwndMain);
\r
471 if(!addLanguage) return;
\r
472 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
473 HMENU mainMenu = GetMenu(hwndMain);
\r
474 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
475 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
476 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
477 i = 0; lastChecked = IDM_English;
\r
479 char *p, *q = fileData.cFileName;
\r
480 int checkFlag = MF_UNCHECKED;
\r
481 languageFile[i] = strdup(q);
\r
482 if(barbaric && !strcmp(oldLanguage, q)) {
\r
483 checkFlag = MF_CHECKED;
\r
484 lastChecked = IDM_English + i + 1;
\r
485 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
487 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
488 p = strstr(fileData.cFileName, ".lng");
\r
490 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
491 } while(FindNextFile(hFind, &fileData));
\r
498 #define IDM_RecentEngines 3000
\r
501 RecentEngineMenu (char *s)
\r
503 if(appData.icsActive) return;
\r
504 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
505 HMENU mainMenu = GetMenu(hwndMain);
\r
506 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
507 int i=IDM_RecentEngines;
\r
508 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
509 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
511 char *p = strchr(s, '\n');
\r
512 if(p == NULL) return; // malformed!
\r
514 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
528 int cliWidth, cliHeight;
\r
531 SizeInfo sizeInfo[] =
\r
533 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
534 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
535 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
536 { "petite", 33, 1, 1, 1, 0, 0 },
\r
537 { "slim", 37, 2, 1, 0, 0, 0 },
\r
538 { "small", 40, 2, 1, 0, 0, 0 },
\r
539 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
540 { "middling", 49, 2, 0, 0, 0, 0 },
\r
541 { "average", 54, 2, 0, 0, 0, 0 },
\r
542 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
543 { "medium", 64, 3, 0, 0, 0, 0 },
\r
544 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
545 { "large", 80, 3, 0, 0, 0, 0 },
\r
546 { "big", 87, 3, 0, 0, 0, 0 },
\r
547 { "huge", 95, 3, 0, 0, 0, 0 },
\r
548 { "giant", 108, 3, 0, 0, 0, 0 },
\r
549 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
550 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
551 { NULL, 0, 0, 0, 0, 0, 0 }
\r
554 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
555 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
557 { 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
558 { 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
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
577 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
586 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
587 #define N_BUTTONS 5
\r
589 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
591 {"<<", IDM_ToStart, NULL, NULL},
\r
592 {"<", IDM_Backward, NULL, NULL},
\r
593 {"P", IDM_Pause, NULL, NULL},
\r
594 {">", IDM_Forward, NULL, NULL},
\r
595 {">>", IDM_ToEnd, NULL, NULL},
\r
598 int tinyLayout = 0, smallLayout = 0;
\r
599 #define MENU_BAR_ITEMS 9
\r
600 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
601 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
602 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
606 MySound sounds[(int)NSoundClasses];
\r
607 MyTextAttribs textAttribs[(int)NColorClasses];
\r
609 MyColorizeAttribs colorizeAttribs[] = {
\r
610 { (COLORREF)0, 0, N_("Shout Text") },
\r
611 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
612 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
613 { (COLORREF)0, 0, N_("Channel Text") },
\r
614 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
615 { (COLORREF)0, 0, N_("Tell Text") },
\r
616 { (COLORREF)0, 0, N_("Challenge Text") },
\r
617 { (COLORREF)0, 0, N_("Request Text") },
\r
618 { (COLORREF)0, 0, N_("Seek Text") },
\r
619 { (COLORREF)0, 0, N_("Normal Text") },
\r
620 { (COLORREF)0, 0, N_("None") }
\r
625 static char *commentTitle;
\r
626 static char *commentText;
\r
627 static int commentIndex;
\r
628 static Boolean editComment = FALSE;
\r
631 char errorTitle[MSG_SIZ];
\r
632 char errorMessage[2*MSG_SIZ];
\r
633 HWND errorDialog = NULL;
\r
634 BOOLEAN moveErrorMessageUp = FALSE;
\r
635 BOOLEAN consoleEcho = TRUE;
\r
636 CHARFORMAT consoleCF;
\r
637 COLORREF consoleBackgroundColor;
\r
639 char *programVersion;
\r
645 typedef int CPKind;
\r
654 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
657 #define INPUT_SOURCE_BUF_SIZE 4096
\r
659 typedef struct _InputSource {
\r
666 char buf[INPUT_SOURCE_BUF_SIZE];
\r
670 InputCallback func;
\r
671 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
675 InputSource *consoleInputSource;
\r
680 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
681 VOID ConsoleCreate();
\r
683 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
684 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
685 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
686 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
688 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
689 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
690 void ParseIcsTextMenu(char *icsTextMenuString);
\r
691 VOID PopUpNameDialog(char firstchar);
\r
692 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
696 int GameListOptions();
\r
698 int dummy; // [HGM] for obsolete args
\r
700 HWND hwndMain = NULL; /* root window*/
\r
701 HWND hwndConsole = NULL;
\r
702 HWND commentDialog = NULL;
\r
703 HWND moveHistoryDialog = NULL;
\r
704 HWND evalGraphDialog = NULL;
\r
705 HWND engineOutputDialog = NULL;
\r
706 HWND gameListDialog = NULL;
\r
707 HWND editTagsDialog = NULL;
\r
709 int commentUp = FALSE;
\r
711 WindowPlacement wpMain;
\r
712 WindowPlacement wpConsole;
\r
713 WindowPlacement wpComment;
\r
714 WindowPlacement wpMoveHistory;
\r
715 WindowPlacement wpEvalGraph;
\r
716 WindowPlacement wpEngineOutput;
\r
717 WindowPlacement wpGameList;
\r
718 WindowPlacement wpTags;
\r
720 VOID EngineOptionsPopup(); // [HGM] settings
\r
722 VOID GothicPopUp(char *title, VariantClass variant);
\r
724 * Setting "frozen" should disable all user input other than deleting
\r
725 * the window. We do this while engines are initializing themselves.
\r
727 static int frozen = 0;
\r
728 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
734 if (frozen) return;
\r
736 hmenu = GetMenu(hwndMain);
\r
737 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
738 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
740 DrawMenuBar(hwndMain);
\r
743 /* Undo a FreezeUI */
\r
749 if (!frozen) return;
\r
751 hmenu = GetMenu(hwndMain);
\r
752 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
753 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
755 DrawMenuBar(hwndMain);
\r
758 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
760 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
766 #define JAWS_ALT_INTERCEPT
\r
767 #define JAWS_KBUP_NAVIGATION
\r
768 #define JAWS_KBDOWN_NAVIGATION
\r
769 #define JAWS_MENU_ITEMS
\r
770 #define JAWS_SILENCE
\r
771 #define JAWS_REPLAY
\r
773 #define JAWS_COPYRIGHT
\r
774 #define JAWS_DELETE(X) X
\r
775 #define SAYMACHINEMOVE()
\r
779 /*---------------------------------------------------------------------------*\
\r
783 \*---------------------------------------------------------------------------*/
\r
786 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
787 LPSTR lpCmdLine, int nCmdShow)
\r
790 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
791 // INITCOMMONCONTROLSEX ex;
\r
795 LoadLibrary("RICHED32.DLL");
\r
796 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
798 if (!InitApplication(hInstance)) {
\r
801 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
808 // InitCommonControlsEx(&ex);
\r
809 InitCommonControls();
\r
811 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
812 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
813 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
815 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
817 while (GetMessage(&msg, /* message structure */
\r
818 NULL, /* handle of window receiving the message */
\r
819 0, /* lowest message to examine */
\r
820 0)) /* highest message to examine */
\r
823 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
824 // [HGM] navigate: switch between all windows with tab
\r
825 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
826 int i, currentElement = 0;
\r
828 // first determine what element of the chain we come from (if any)
\r
829 if(appData.icsActive) {
\r
830 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
831 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
833 if(engineOutputDialog && EngineOutputIsUp()) {
\r
834 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
835 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
837 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
838 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
840 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
841 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
842 if(msg.hwnd == e1) currentElement = 2; else
\r
843 if(msg.hwnd == e2) currentElement = 3; else
\r
844 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
845 if(msg.hwnd == mh) currentElement = 4; else
\r
846 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
847 if(msg.hwnd == hText) currentElement = 5; else
\r
848 if(msg.hwnd == hInput) currentElement = 6; else
\r
849 for (i = 0; i < N_BUTTONS; i++) {
\r
850 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
853 // determine where to go to
\r
854 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
856 currentElement = (currentElement + direction) % 7;
\r
857 switch(currentElement) {
\r
859 h = hwndMain; break; // passing this case always makes the loop exit
\r
861 h = buttonDesc[0].hwnd; break; // could be NULL
\r
863 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
866 if(!EngineOutputIsUp()) continue;
\r
869 if(!MoveHistoryIsUp()) continue;
\r
871 // case 6: // input to eval graph does not seem to get here!
\r
872 // if(!EvalGraphIsUp()) continue;
\r
873 // h = evalGraphDialog; break;
\r
875 if(!appData.icsActive) continue;
\r
879 if(!appData.icsActive) continue;
\r
885 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
886 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
889 continue; // this message now has been processed
\r
893 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
894 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
895 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
896 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
897 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
898 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
899 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
900 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
901 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
902 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
903 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
904 for(i=0; i<MAX_CHAT; i++)
\r
905 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
908 if(done) continue; // [HGM] chat: end patch
\r
909 TranslateMessage(&msg); /* Translates virtual key codes */
\r
910 DispatchMessage(&msg); /* Dispatches message to window */
\r
915 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
918 /*---------------------------------------------------------------------------*\
\r
920 * Initialization functions
\r
922 \*---------------------------------------------------------------------------*/
\r
926 { // update user logo if necessary
\r
927 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
929 if(appData.autoLogo) {
\r
930 curName = UserName();
\r
931 if(strcmp(curName, oldUserName)) {
\r
932 GetCurrentDirectory(MSG_SIZ, dir);
\r
933 SetCurrentDirectory(installDir);
\r
934 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
935 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
936 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
937 if(userLogo == NULL)
\r
938 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
939 SetCurrentDirectory(dir); /* return to prev directory */
\r
945 InitApplication(HINSTANCE hInstance)
\r
949 /* Fill in window class structure with parameters that describe the */
\r
952 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
953 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
954 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
955 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
956 wc.hInstance = hInstance; /* Owner of this class */
\r
957 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
958 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
959 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
960 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
961 wc.lpszClassName = szAppName; /* Name to register as */
\r
963 /* Register the window class and return success/failure code. */
\r
964 if (!RegisterClass(&wc)) return FALSE;
\r
966 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
967 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
969 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
970 wc.hInstance = hInstance;
\r
971 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
972 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
973 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
974 wc.lpszMenuName = NULL;
\r
975 wc.lpszClassName = szConsoleName;
\r
977 if (!RegisterClass(&wc)) return FALSE;
\r
982 /* Set by InitInstance, used by EnsureOnScreen */
\r
983 int screenHeight, screenWidth;
\r
986 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
988 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
989 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
990 if (*x > screenWidth - 32) *x = 0;
\r
991 if (*y > screenHeight - 32) *y = 0;
\r
992 if (*x < minX) *x = minX;
\r
993 if (*y < minY) *y = minY;
\r
997 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
999 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1000 GetCurrentDirectory(MSG_SIZ, dir);
\r
1001 SetCurrentDirectory(installDir);
\r
1002 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1003 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1005 if (cps->programLogo == NULL && appData.debugMode) {
\r
1006 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1008 } else if(appData.autoLogo) {
\r
1009 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1010 char *opponent = "";
\r
1011 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1012 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1013 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1014 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1015 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1016 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1019 if(appData.directory[n] && appData.directory[n][0]) {
\r
1020 SetCurrentDirectory(appData.directory[n]);
\r
1021 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1024 SetCurrentDirectory(dir); /* return to prev directory */
\r
1030 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1031 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1033 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1034 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1035 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1036 liteBackTextureMode = appData.liteBackTextureMode;
\r
1038 if (liteBackTexture == NULL && appData.debugMode) {
\r
1039 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1043 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1044 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1045 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1046 darkBackTextureMode = appData.darkBackTextureMode;
\r
1048 if (darkBackTexture == NULL && appData.debugMode) {
\r
1049 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1055 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1057 HWND hwnd; /* Main window handle. */
\r
1059 WINDOWPLACEMENT wp;
\r
1062 hInst = hInstance; /* Store instance handle in our global variable */
\r
1063 programName = szAppName;
\r
1065 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1066 *filepart = NULLCHAR;
\r
1067 SetCurrentDirectory(installDir);
\r
1069 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1071 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1072 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1073 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1074 /* xboard, and older WinBoards, controlled the move sound with the
\r
1075 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1076 always turn the option on (so that the backend will call us),
\r
1077 then let the user turn the sound off by setting it to silence if
\r
1078 desired. To accommodate old winboard.ini files saved by old
\r
1079 versions of WinBoard, we also turn off the sound if the option
\r
1080 was initially set to false. [HGM] taken out of InitAppData */
\r
1081 if (!appData.ringBellAfterMoves) {
\r
1082 sounds[(int)SoundMove].name = strdup("");
\r
1083 appData.ringBellAfterMoves = TRUE;
\r
1085 if (appData.debugMode) {
\r
1086 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1087 setbuf(debugFP, NULL);
\r
1090 LoadLanguageFile(appData.language);
\r
1094 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1095 // InitEngineUCI( installDir, &second );
\r
1097 /* Create a main window for this application instance. */
\r
1098 hwnd = CreateWindow(szAppName, szTitle,
\r
1099 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1100 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1101 NULL, NULL, hInstance, NULL);
\r
1104 /* If window could not be created, return "failure" */
\r
1109 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1110 LoadLogo(&first, 0, FALSE);
\r
1111 LoadLogo(&second, 1, appData.icsActive);
\r
1115 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1116 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1117 iconCurrent = iconWhite;
\r
1118 InitDrawingColors();
\r
1119 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1120 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1121 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1122 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1123 /* Compute window size for each board size, and use the largest
\r
1124 size that fits on this screen as the default. */
\r
1125 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1126 if (boardSize == (BoardSize)-1 &&
\r
1127 winH <= screenHeight
\r
1128 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1129 && winW <= screenWidth) {
\r
1130 boardSize = (BoardSize)ibs;
\r
1134 InitDrawingSizes(boardSize, 0);
\r
1135 RecentEngineMenu(appData.recentEngineList);
\r
1137 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1139 /* [AS] Load textures if specified */
\r
1142 mysrandom( (unsigned) time(NULL) );
\r
1144 /* [AS] Restore layout */
\r
1145 if( wpMoveHistory.visible ) {
\r
1146 MoveHistoryPopUp();
\r
1149 if( wpEvalGraph.visible ) {
\r
1153 if( wpEngineOutput.visible ) {
\r
1154 EngineOutputPopUp();
\r
1157 /* Make the window visible; update its client area; and return "success" */
\r
1158 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1159 wp.length = sizeof(WINDOWPLACEMENT);
\r
1161 wp.showCmd = nCmdShow;
\r
1162 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1163 wp.rcNormalPosition.left = wpMain.x;
\r
1164 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1165 wp.rcNormalPosition.top = wpMain.y;
\r
1166 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1167 SetWindowPlacement(hwndMain, &wp);
\r
1169 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1171 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1172 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1174 if (hwndConsole) {
\r
1176 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1177 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1179 ShowWindow(hwndConsole, nCmdShow);
\r
1180 SetActiveWindow(hwndConsole);
\r
1182 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1183 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1192 HMENU hmenu = GetMenu(hwndMain);
\r
1194 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1195 MF_BYCOMMAND|((appData.icsActive &&
\r
1196 *appData.icsCommPort != NULLCHAR) ?
\r
1197 MF_ENABLED : MF_GRAYED));
\r
1198 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1199 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1200 MF_CHECKED : MF_UNCHECKED));
\r
1203 //---------------------------------------------------------------------------------------------------------
\r
1205 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1206 #define XBOARD FALSE
\r
1208 #define OPTCHAR "/"
\r
1209 #define SEPCHAR "="
\r
1210 #define TOPLEVEL 0
\r
1214 // front-end part of option handling
\r
1217 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1219 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1220 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1223 lf->lfEscapement = 0;
\r
1224 lf->lfOrientation = 0;
\r
1225 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1226 lf->lfItalic = mfp->italic;
\r
1227 lf->lfUnderline = mfp->underline;
\r
1228 lf->lfStrikeOut = mfp->strikeout;
\r
1229 lf->lfCharSet = mfp->charset;
\r
1230 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1231 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1232 lf->lfQuality = DEFAULT_QUALITY;
\r
1233 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1234 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1238 CreateFontInMF(MyFont *mf)
\r
1240 LFfromMFP(&mf->lf, &mf->mfp);
\r
1241 if (mf->hf) DeleteObject(mf->hf);
\r
1242 mf->hf = CreateFontIndirect(&mf->lf);
\r
1245 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1247 colorVariable[] = {
\r
1248 &whitePieceColor,
\r
1249 &blackPieceColor,
\r
1250 &lightSquareColor,
\r
1251 &darkSquareColor,
\r
1252 &highlightSquareColor,
\r
1253 &premoveHighlightColor,
\r
1255 &consoleBackgroundColor,
\r
1256 &appData.fontForeColorWhite,
\r
1257 &appData.fontBackColorWhite,
\r
1258 &appData.fontForeColorBlack,
\r
1259 &appData.fontBackColorBlack,
\r
1260 &appData.evalHistColorWhite,
\r
1261 &appData.evalHistColorBlack,
\r
1262 &appData.highlightArrowColor,
\r
1265 /* Command line font name parser. NULL name means do nothing.
\r
1266 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1267 For backward compatibility, syntax without the colon is also
\r
1268 accepted, but font names with digits in them won't work in that case.
\r
1271 ParseFontName(char *name, MyFontParams *mfp)
\r
1274 if (name == NULL) return;
\r
1276 q = strchr(p, ':');
\r
1278 if (q - p >= sizeof(mfp->faceName))
\r
1279 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1280 memcpy(mfp->faceName, p, q - p);
\r
1281 mfp->faceName[q - p] = NULLCHAR;
\r
1284 q = mfp->faceName;
\r
1286 while (*p && !isdigit(*p)) {
\r
1288 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1289 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1291 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1294 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1295 mfp->pointSize = (float) atof(p);
\r
1296 mfp->bold = (strchr(p, 'b') != NULL);
\r
1297 mfp->italic = (strchr(p, 'i') != NULL);
\r
1298 mfp->underline = (strchr(p, 'u') != NULL);
\r
1299 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1300 mfp->charset = DEFAULT_CHARSET;
\r
1301 q = strchr(p, 'c');
\r
1303 mfp->charset = (BYTE) atoi(q+1);
\r
1307 ParseFont(char *name, int number)
\r
1308 { // wrapper to shield back-end from 'font'
\r
1309 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1314 { // in WB we have a 2D array of fonts; this initializes their description
\r
1316 /* Point font array elements to structures and
\r
1317 parse default font names */
\r
1318 for (i=0; i<NUM_FONTS; i++) {
\r
1319 for (j=0; j<NUM_SIZES; j++) {
\r
1320 font[j][i] = &fontRec[j][i];
\r
1321 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1328 { // here we create the actual fonts from the selected descriptions
\r
1330 for (i=0; i<NUM_FONTS; i++) {
\r
1331 for (j=0; j<NUM_SIZES; j++) {
\r
1332 CreateFontInMF(font[j][i]);
\r
1336 /* Color name parser.
\r
1337 X version accepts X color names, but this one
\r
1338 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1340 ParseColorName(char *name)
\r
1342 int red, green, blue, count;
\r
1343 char buf[MSG_SIZ];
\r
1345 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1347 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1348 &red, &green, &blue);
\r
1351 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1352 DisplayError(buf, 0);
\r
1353 return RGB(0, 0, 0);
\r
1355 return PALETTERGB(red, green, blue);
\r
1359 ParseColor(int n, char *name)
\r
1360 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1361 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1365 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1367 char *e = argValue;
\r
1371 if (*e == 'b') eff |= CFE_BOLD;
\r
1372 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1373 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1374 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1375 else if (*e == '#' || isdigit(*e)) break;
\r
1379 *color = ParseColorName(e);
\r
1383 ParseTextAttribs(ColorClass cc, char *s)
\r
1384 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1385 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1386 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1390 ParseBoardSize(void *addr, char *name)
\r
1391 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1392 BoardSize bs = SizeTiny;
\r
1393 while (sizeInfo[bs].name != NULL) {
\r
1394 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1395 *(BoardSize *)addr = bs;
\r
1400 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1405 { // [HGM] import name from appData first
\r
1408 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1409 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1410 textAttribs[cc].sound.data = NULL;
\r
1411 MyLoadSound(&textAttribs[cc].sound);
\r
1413 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1414 textAttribs[cc].sound.name = strdup("");
\r
1415 textAttribs[cc].sound.data = NULL;
\r
1417 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1418 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1419 sounds[sc].data = NULL;
\r
1420 MyLoadSound(&sounds[sc]);
\r
1425 SetCommPortDefaults()
\r
1427 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1428 dcb.DCBlength = sizeof(DCB);
\r
1429 dcb.BaudRate = 9600;
\r
1430 dcb.fBinary = TRUE;
\r
1431 dcb.fParity = FALSE;
\r
1432 dcb.fOutxCtsFlow = FALSE;
\r
1433 dcb.fOutxDsrFlow = FALSE;
\r
1434 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1435 dcb.fDsrSensitivity = FALSE;
\r
1436 dcb.fTXContinueOnXoff = TRUE;
\r
1437 dcb.fOutX = FALSE;
\r
1439 dcb.fNull = FALSE;
\r
1440 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1441 dcb.fAbortOnError = FALSE;
\r
1443 dcb.Parity = SPACEPARITY;
\r
1444 dcb.StopBits = ONESTOPBIT;
\r
1447 // [HGM] args: these three cases taken out to stay in front-end
\r
1449 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1450 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1451 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1452 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1454 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1455 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1456 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1457 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1458 ad->argName, mfp->faceName, mfp->pointSize,
\r
1459 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1460 mfp->bold ? "b" : "",
\r
1461 mfp->italic ? "i" : "",
\r
1462 mfp->underline ? "u" : "",
\r
1463 mfp->strikeout ? "s" : "",
\r
1464 (int)mfp->charset);
\r
1470 { // [HGM] copy the names from the internal WB variables to appData
\r
1473 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1474 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1475 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1476 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1480 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1481 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1482 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1483 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1484 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1485 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1486 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1487 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1488 (ta->effects) ? " " : "",
\r
1489 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1493 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1494 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1495 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1496 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1497 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1501 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1502 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1503 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1507 ParseCommPortSettings(char *s)
\r
1508 { // wrapper to keep dcb from back-end
\r
1509 ParseCommSettings(s, &dcb);
\r
1514 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1515 GetActualPlacement(hwndMain, &wpMain);
\r
1516 GetActualPlacement(hwndConsole, &wpConsole);
\r
1517 GetActualPlacement(commentDialog, &wpComment);
\r
1518 GetActualPlacement(editTagsDialog, &wpTags);
\r
1519 GetActualPlacement(gameListDialog, &wpGameList);
\r
1520 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1521 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1522 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1526 PrintCommPortSettings(FILE *f, char *name)
\r
1527 { // wrapper to shield back-end from DCB
\r
1528 PrintCommSettings(f, name, &dcb);
\r
1532 MySearchPath(char *installDir, char *name, char *fullname)
\r
1534 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1535 if(name[0]== '%') {
\r
1536 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1537 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1538 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1539 *strchr(buf, '%') = 0;
\r
1540 strcat(fullname, getenv(buf));
\r
1541 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1543 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1544 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1545 return (int) strlen(fullname);
\r
1547 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1551 MyGetFullPathName(char *name, char *fullname)
\r
1554 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1559 { // [HGM] args: allows testing if main window is realized from back-end
\r
1560 return hwndMain != NULL;
\r
1564 PopUpStartupDialog()
\r
1568 LoadLanguageFile(appData.language);
\r
1569 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1570 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1571 FreeProcInstance(lpProc);
\r
1574 /*---------------------------------------------------------------------------*\
\r
1576 * GDI board drawing routines
\r
1578 \*---------------------------------------------------------------------------*/
\r
1580 /* [AS] Draw square using background texture */
\r
1581 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1586 return; /* Should never happen! */
\r
1589 SetGraphicsMode( dst, GM_ADVANCED );
\r
1596 /* X reflection */
\r
1601 x.eDx = (FLOAT) dw + dx - 1;
\r
1604 SetWorldTransform( dst, &x );
\r
1607 /* Y reflection */
\r
1613 x.eDy = (FLOAT) dh + dy - 1;
\r
1615 SetWorldTransform( dst, &x );
\r
1623 x.eDx = (FLOAT) dx;
\r
1624 x.eDy = (FLOAT) dy;
\r
1627 SetWorldTransform( dst, &x );
\r
1631 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1639 SetWorldTransform( dst, &x );
\r
1641 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1644 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1646 PM_WP = (int) WhitePawn,
\r
1647 PM_WN = (int) WhiteKnight,
\r
1648 PM_WB = (int) WhiteBishop,
\r
1649 PM_WR = (int) WhiteRook,
\r
1650 PM_WQ = (int) WhiteQueen,
\r
1651 PM_WF = (int) WhiteFerz,
\r
1652 PM_WW = (int) WhiteWazir,
\r
1653 PM_WE = (int) WhiteAlfil,
\r
1654 PM_WM = (int) WhiteMan,
\r
1655 PM_WO = (int) WhiteCannon,
\r
1656 PM_WU = (int) WhiteUnicorn,
\r
1657 PM_WH = (int) WhiteNightrider,
\r
1658 PM_WA = (int) WhiteAngel,
\r
1659 PM_WC = (int) WhiteMarshall,
\r
1660 PM_WAB = (int) WhiteCardinal,
\r
1661 PM_WD = (int) WhiteDragon,
\r
1662 PM_WL = (int) WhiteLance,
\r
1663 PM_WS = (int) WhiteCobra,
\r
1664 PM_WV = (int) WhiteFalcon,
\r
1665 PM_WSG = (int) WhiteSilver,
\r
1666 PM_WG = (int) WhiteGrasshopper,
\r
1667 PM_WK = (int) WhiteKing,
\r
1668 PM_BP = (int) BlackPawn,
\r
1669 PM_BN = (int) BlackKnight,
\r
1670 PM_BB = (int) BlackBishop,
\r
1671 PM_BR = (int) BlackRook,
\r
1672 PM_BQ = (int) BlackQueen,
\r
1673 PM_BF = (int) BlackFerz,
\r
1674 PM_BW = (int) BlackWazir,
\r
1675 PM_BE = (int) BlackAlfil,
\r
1676 PM_BM = (int) BlackMan,
\r
1677 PM_BO = (int) BlackCannon,
\r
1678 PM_BU = (int) BlackUnicorn,
\r
1679 PM_BH = (int) BlackNightrider,
\r
1680 PM_BA = (int) BlackAngel,
\r
1681 PM_BC = (int) BlackMarshall,
\r
1682 PM_BG = (int) BlackGrasshopper,
\r
1683 PM_BAB = (int) BlackCardinal,
\r
1684 PM_BD = (int) BlackDragon,
\r
1685 PM_BL = (int) BlackLance,
\r
1686 PM_BS = (int) BlackCobra,
\r
1687 PM_BV = (int) BlackFalcon,
\r
1688 PM_BSG = (int) BlackSilver,
\r
1689 PM_BK = (int) BlackKing
\r
1692 static HFONT hPieceFont = NULL;
\r
1693 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1694 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1695 static int fontBitmapSquareSize = 0;
\r
1696 static char pieceToFontChar[(int) EmptySquare] =
\r
1697 { 'p', 'n', 'b', 'r', 'q',
\r
1698 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1699 'k', 'o', 'm', 'v', 't', 'w',
\r
1700 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1703 extern BOOL SetCharTable( char *table, const char * map );
\r
1704 /* [HGM] moved to backend.c */
\r
1706 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1709 BYTE r1 = GetRValue( color );
\r
1710 BYTE g1 = GetGValue( color );
\r
1711 BYTE b1 = GetBValue( color );
\r
1717 /* Create a uniform background first */
\r
1718 hbrush = CreateSolidBrush( color );
\r
1719 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1720 FillRect( hdc, &rc, hbrush );
\r
1721 DeleteObject( hbrush );
\r
1724 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1725 int steps = squareSize / 2;
\r
1728 for( i=0; i<steps; i++ ) {
\r
1729 BYTE r = r1 - (r1-r2) * i / steps;
\r
1730 BYTE g = g1 - (g1-g2) * i / steps;
\r
1731 BYTE b = b1 - (b1-b2) * i / steps;
\r
1733 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1734 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1735 FillRect( hdc, &rc, hbrush );
\r
1736 DeleteObject(hbrush);
\r
1739 else if( mode == 2 ) {
\r
1740 /* Diagonal gradient, good more or less for every piece */
\r
1741 POINT triangle[3];
\r
1742 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1743 HBRUSH hbrush_old;
\r
1744 int steps = squareSize;
\r
1747 triangle[0].x = squareSize - steps;
\r
1748 triangle[0].y = squareSize;
\r
1749 triangle[1].x = squareSize;
\r
1750 triangle[1].y = squareSize;
\r
1751 triangle[2].x = squareSize;
\r
1752 triangle[2].y = squareSize - steps;
\r
1754 for( i=0; i<steps; i++ ) {
\r
1755 BYTE r = r1 - (r1-r2) * i / steps;
\r
1756 BYTE g = g1 - (g1-g2) * i / steps;
\r
1757 BYTE b = b1 - (b1-b2) * i / steps;
\r
1759 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1760 hbrush_old = SelectObject( hdc, hbrush );
\r
1761 Polygon( hdc, triangle, 3 );
\r
1762 SelectObject( hdc, hbrush_old );
\r
1763 DeleteObject(hbrush);
\r
1768 SelectObject( hdc, hpen );
\r
1773 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1774 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1775 piece: follow the steps as explained below.
\r
1777 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1781 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1785 int backColor = whitePieceColor;
\r
1786 int foreColor = blackPieceColor;
\r
1788 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1789 backColor = appData.fontBackColorWhite;
\r
1790 foreColor = appData.fontForeColorWhite;
\r
1792 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1793 backColor = appData.fontBackColorBlack;
\r
1794 foreColor = appData.fontForeColorBlack;
\r
1798 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1800 hbm_old = SelectObject( hdc, hbm );
\r
1804 rc.right = squareSize;
\r
1805 rc.bottom = squareSize;
\r
1807 /* Step 1: background is now black */
\r
1808 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1810 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1812 pt.x = (squareSize - sz.cx) / 2;
\r
1813 pt.y = (squareSize - sz.cy) / 2;
\r
1815 SetBkMode( hdc, TRANSPARENT );
\r
1816 SetTextColor( hdc, chroma );
\r
1817 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1818 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1820 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1821 /* Step 3: the area outside the piece is filled with white */
\r
1822 // FloodFill( hdc, 0, 0, chroma );
\r
1823 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1824 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1825 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1826 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1827 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1829 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1830 but if the start point is not inside the piece we're lost!
\r
1831 There should be a better way to do this... if we could create a region or path
\r
1832 from the fill operation we would be fine for example.
\r
1834 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1835 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1837 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1838 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1839 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1841 SelectObject( dc2, bm2 );
\r
1842 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1843 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1844 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1845 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1846 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1849 DeleteObject( bm2 );
\r
1852 SetTextColor( hdc, 0 );
\r
1854 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1855 draw the piece again in black for safety.
\r
1857 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1859 SelectObject( hdc, hbm_old );
\r
1861 if( hPieceMask[index] != NULL ) {
\r
1862 DeleteObject( hPieceMask[index] );
\r
1865 hPieceMask[index] = hbm;
\r
1868 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1870 SelectObject( hdc, hbm );
\r
1873 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1874 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1875 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1877 SelectObject( dc1, hPieceMask[index] );
\r
1878 SelectObject( dc2, bm2 );
\r
1879 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1880 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1883 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1884 the piece background and deletes (makes transparent) the rest.
\r
1885 Thanks to that mask, we are free to paint the background with the greates
\r
1886 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1887 We use this, to make gradients and give the pieces a "roundish" look.
\r
1889 SetPieceBackground( hdc, backColor, 2 );
\r
1890 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1894 DeleteObject( bm2 );
\r
1897 SetTextColor( hdc, foreColor );
\r
1898 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1900 SelectObject( hdc, hbm_old );
\r
1902 if( hPieceFace[index] != NULL ) {
\r
1903 DeleteObject( hPieceFace[index] );
\r
1906 hPieceFace[index] = hbm;
\r
1909 static int TranslatePieceToFontPiece( int piece )
\r
1939 case BlackMarshall:
\r
1943 case BlackNightrider:
\r
1949 case BlackUnicorn:
\r
1953 case BlackGrasshopper:
\r
1965 case BlackCardinal:
\r
1972 case WhiteMarshall:
\r
1976 case WhiteNightrider:
\r
1982 case WhiteUnicorn:
\r
1986 case WhiteGrasshopper:
\r
1998 case WhiteCardinal:
\r
2007 void CreatePiecesFromFont()
\r
2010 HDC hdc_window = NULL;
\r
2016 if( fontBitmapSquareSize < 0 ) {
\r
2017 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2021 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2022 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2023 fontBitmapSquareSize = -1;
\r
2027 if( fontBitmapSquareSize != squareSize ) {
\r
2028 hdc_window = GetDC( hwndMain );
\r
2029 hdc = CreateCompatibleDC( hdc_window );
\r
2031 if( hPieceFont != NULL ) {
\r
2032 DeleteObject( hPieceFont );
\r
2035 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2036 hPieceMask[i] = NULL;
\r
2037 hPieceFace[i] = NULL;
\r
2043 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2044 fontHeight = appData.fontPieceSize;
\r
2047 fontHeight = (fontHeight * squareSize) / 100;
\r
2049 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2051 lf.lfEscapement = 0;
\r
2052 lf.lfOrientation = 0;
\r
2053 lf.lfWeight = FW_NORMAL;
\r
2055 lf.lfUnderline = 0;
\r
2056 lf.lfStrikeOut = 0;
\r
2057 lf.lfCharSet = DEFAULT_CHARSET;
\r
2058 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2059 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2060 lf.lfQuality = PROOF_QUALITY;
\r
2061 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2062 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2063 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2065 hPieceFont = CreateFontIndirect( &lf );
\r
2067 if( hPieceFont == NULL ) {
\r
2068 fontBitmapSquareSize = -2;
\r
2071 /* Setup font-to-piece character table */
\r
2072 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2073 /* No (or wrong) global settings, try to detect the font */
\r
2074 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2076 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2078 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2079 /* DiagramTT* family */
\r
2080 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2082 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2083 /* Fairy symbols */
\r
2084 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2086 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2087 /* Good Companion (Some characters get warped as literal :-( */
\r
2088 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2089 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2090 SetCharTable(pieceToFontChar, s);
\r
2093 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2094 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2098 /* Create bitmaps */
\r
2099 hfont_old = SelectObject( hdc, hPieceFont );
\r
2100 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2101 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2102 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2104 SelectObject( hdc, hfont_old );
\r
2106 fontBitmapSquareSize = squareSize;
\r
2110 if( hdc != NULL ) {
\r
2114 if( hdc_window != NULL ) {
\r
2115 ReleaseDC( hwndMain, hdc_window );
\r
2120 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2122 char name[128], buf[MSG_SIZ];
\r
2124 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2125 if(appData.pieceDirectory[0]) {
\r
2127 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2128 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2129 if(res) return res;
\r
2131 if (gameInfo.event &&
\r
2132 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2133 strcmp(name, "k80s") == 0) {
\r
2134 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2136 return LoadBitmap(hinst, name);
\r
2140 /* Insert a color into the program's logical palette
\r
2141 structure. This code assumes the given color is
\r
2142 the result of the RGB or PALETTERGB macro, and it
\r
2143 knows how those macros work (which is documented).
\r
2146 InsertInPalette(COLORREF color)
\r
2148 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2150 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2151 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2152 pLogPal->palNumEntries--;
\r
2156 pe->peFlags = (char) 0;
\r
2157 pe->peRed = (char) (0xFF & color);
\r
2158 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2159 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2165 InitDrawingColors()
\r
2168 if (pLogPal == NULL) {
\r
2169 /* Allocate enough memory for a logical palette with
\r
2170 * PALETTESIZE entries and set the size and version fields
\r
2171 * of the logical palette structure.
\r
2173 pLogPal = (NPLOGPALETTE)
\r
2174 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2175 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2176 pLogPal->palVersion = 0x300;
\r
2178 pLogPal->palNumEntries = 0;
\r
2180 InsertInPalette(lightSquareColor);
\r
2181 InsertInPalette(darkSquareColor);
\r
2182 InsertInPalette(whitePieceColor);
\r
2183 InsertInPalette(blackPieceColor);
\r
2184 InsertInPalette(highlightSquareColor);
\r
2185 InsertInPalette(premoveHighlightColor);
\r
2187 /* create a logical color palette according the information
\r
2188 * in the LOGPALETTE structure.
\r
2190 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2192 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2193 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2194 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2195 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2196 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2197 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2198 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2199 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2201 /* [AS] Force rendering of the font-based pieces */
\r
2202 if( fontBitmapSquareSize > 0 ) {
\r
2203 fontBitmapSquareSize = 0;
\r
2209 BoardWidth(int boardSize, int n)
\r
2210 { /* [HGM] argument n added to allow different width and height */
\r
2211 int lineGap = sizeInfo[boardSize].lineGap;
\r
2213 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2214 lineGap = appData.overrideLineGap;
\r
2217 return (n + 1) * lineGap +
\r
2218 n * sizeInfo[boardSize].squareSize;
\r
2221 /* Respond to board resize by dragging edge */
\r
2223 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2225 BoardSize newSize = NUM_SIZES - 1;
\r
2226 static int recurse = 0;
\r
2227 if (IsIconic(hwndMain)) return;
\r
2228 if (recurse > 0) return;
\r
2230 while (newSize > 0) {
\r
2231 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2232 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2233 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2236 boardSize = newSize;
\r
2237 InitDrawingSizes(boardSize, flags);
\r
2242 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2245 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2247 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2248 ChessSquare piece;
\r
2249 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2251 SIZE clockSize, messageSize;
\r
2253 char buf[MSG_SIZ];
\r
2255 HMENU hmenu = GetMenu(hwndMain);
\r
2256 RECT crect, wrect, oldRect;
\r
2258 LOGBRUSH logbrush;
\r
2259 VariantClass v = gameInfo.variant;
\r
2261 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2262 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2264 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2265 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2266 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2267 oldBoardSize = boardSize;
\r
2269 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2270 { // correct board size to one where built-in pieces exist
\r
2271 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2272 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2273 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2274 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2275 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2276 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2277 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2278 boardSize = SizeMiddling;
\r
2281 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2283 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2284 oldRect.top = wpMain.y;
\r
2285 oldRect.right = wpMain.x + wpMain.width;
\r
2286 oldRect.bottom = wpMain.y + wpMain.height;
\r
2288 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2289 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2290 squareSize = sizeInfo[boardSize].squareSize;
\r
2291 lineGap = sizeInfo[boardSize].lineGap;
\r
2292 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2293 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2295 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2296 lineGap = appData.overrideLineGap;
\r
2299 if (tinyLayout != oldTinyLayout) {
\r
2300 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2302 style &= ~WS_SYSMENU;
\r
2303 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2304 "&Minimize\tCtrl+F4");
\r
2306 style |= WS_SYSMENU;
\r
2307 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2309 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2311 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2312 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2313 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2315 DrawMenuBar(hwndMain);
\r
2318 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2319 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2321 /* Get text area sizes */
\r
2322 hdc = GetDC(hwndMain);
\r
2323 if (appData.clockMode) {
\r
2324 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2326 snprintf(buf, MSG_SIZ, _("White"));
\r
2328 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2329 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2330 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2331 str = _("We only care about the height here");
\r
2332 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2333 SelectObject(hdc, oldFont);
\r
2334 ReleaseDC(hwndMain, hdc);
\r
2336 /* Compute where everything goes */
\r
2337 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2338 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2339 logoHeight = 2*clockSize.cy;
\r
2340 leftLogoRect.left = OUTER_MARGIN;
\r
2341 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2342 leftLogoRect.top = OUTER_MARGIN;
\r
2343 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2345 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2346 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2347 rightLogoRect.top = OUTER_MARGIN;
\r
2348 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2351 whiteRect.left = leftLogoRect.right;
\r
2352 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2353 whiteRect.top = OUTER_MARGIN;
\r
2354 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2356 blackRect.right = rightLogoRect.left;
\r
2357 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2358 blackRect.top = whiteRect.top;
\r
2359 blackRect.bottom = whiteRect.bottom;
\r
2361 whiteRect.left = OUTER_MARGIN;
\r
2362 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2363 whiteRect.top = OUTER_MARGIN;
\r
2364 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2366 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2367 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2368 blackRect.top = whiteRect.top;
\r
2369 blackRect.bottom = whiteRect.bottom;
\r
2371 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2374 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2375 if (appData.showButtonBar) {
\r
2376 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2377 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2379 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2381 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2382 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2384 boardRect.left = OUTER_MARGIN;
\r
2385 boardRect.right = boardRect.left + boardWidth;
\r
2386 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2387 boardRect.bottom = boardRect.top + boardHeight;
\r
2389 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2390 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2391 oldTinyLayout = tinyLayout;
\r
2392 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2393 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2394 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2395 winW *= 1 + twoBoards;
\r
2396 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2397 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2398 wpMain.height = winH; // without disturbing window attachments
\r
2399 GetWindowRect(hwndMain, &wrect);
\r
2400 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2401 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2403 // [HGM] placement: let attached windows follow size change.
\r
2404 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2405 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2406 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2407 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2408 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2410 /* compensate if menu bar wrapped */
\r
2411 GetClientRect(hwndMain, &crect);
\r
2412 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2413 wpMain.height += offby;
\r
2415 case WMSZ_TOPLEFT:
\r
2416 SetWindowPos(hwndMain, NULL,
\r
2417 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2418 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2421 case WMSZ_TOPRIGHT:
\r
2423 SetWindowPos(hwndMain, NULL,
\r
2424 wrect.left, wrect.bottom - wpMain.height,
\r
2425 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2428 case WMSZ_BOTTOMLEFT:
\r
2430 SetWindowPos(hwndMain, NULL,
\r
2431 wrect.right - wpMain.width, wrect.top,
\r
2432 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2435 case WMSZ_BOTTOMRIGHT:
\r
2439 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2440 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2445 for (i = 0; i < N_BUTTONS; i++) {
\r
2446 if (buttonDesc[i].hwnd != NULL) {
\r
2447 DestroyWindow(buttonDesc[i].hwnd);
\r
2448 buttonDesc[i].hwnd = NULL;
\r
2450 if (appData.showButtonBar) {
\r
2451 buttonDesc[i].hwnd =
\r
2452 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2453 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2454 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2455 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2456 (HMENU) buttonDesc[i].id,
\r
2457 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2459 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2460 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2461 MAKELPARAM(FALSE, 0));
\r
2463 if (buttonDesc[i].id == IDM_Pause)
\r
2464 hwndPause = buttonDesc[i].hwnd;
\r
2465 buttonDesc[i].wndproc = (WNDPROC)
\r
2466 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2469 if (gridPen != NULL) DeleteObject(gridPen);
\r
2470 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2471 if (premovePen != NULL) DeleteObject(premovePen);
\r
2472 if (lineGap != 0) {
\r
2473 logbrush.lbStyle = BS_SOLID;
\r
2474 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2476 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2477 lineGap, &logbrush, 0, NULL);
\r
2478 logbrush.lbColor = highlightSquareColor;
\r
2480 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2481 lineGap, &logbrush, 0, NULL);
\r
2483 logbrush.lbColor = premoveHighlightColor;
\r
2485 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2486 lineGap, &logbrush, 0, NULL);
\r
2488 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2489 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2490 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2491 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2492 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2493 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2494 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2495 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2497 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2498 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2499 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2500 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2501 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2502 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2503 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2504 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2508 /* [HGM] Licensing requirement */
\r
2510 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2513 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2515 GothicPopUp( "", VariantNormal);
\r
2518 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2520 /* Load piece bitmaps for this board size */
\r
2521 for (i=0; i<=2; i++) {
\r
2522 for (piece = WhitePawn;
\r
2523 (int) piece < (int) BlackPawn;
\r
2524 piece = (ChessSquare) ((int) piece + 1)) {
\r
2525 if (pieceBitmap[i][piece] != NULL)
\r
2526 DeleteObject(pieceBitmap[i][piece]);
\r
2530 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2531 // Orthodox Chess pieces
\r
2532 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2533 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2534 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2535 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2536 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2537 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2538 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2539 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2540 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2541 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2542 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2543 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2544 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2545 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2546 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2547 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2548 // in Shogi, Hijack the unused Queen for Lance
\r
2549 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2550 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2551 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2553 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2554 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2555 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2558 if(squareSize <= 72 && squareSize >= 33) {
\r
2559 /* A & C are available in most sizes now */
\r
2560 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2561 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2562 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2563 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2564 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2565 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2566 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2567 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2568 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2569 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2570 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2571 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2572 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2573 } else { // Smirf-like
\r
2574 if(gameInfo.variant == VariantSChess) {
\r
2575 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2576 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2577 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2579 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2580 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2581 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2584 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2585 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2586 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2587 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2588 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2589 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2590 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2591 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2592 } else { // WinBoard standard
\r
2593 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2594 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2595 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2600 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2601 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2602 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2603 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2604 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2605 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2606 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2607 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2608 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2609 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2610 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2611 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2612 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2613 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2614 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2615 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2616 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2617 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2618 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2619 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2620 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2621 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2622 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2623 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2624 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2625 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2626 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2627 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2628 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2629 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2630 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2631 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2632 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2633 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2635 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2636 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2637 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2638 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2639 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2640 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2641 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2642 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2645 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2646 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2647 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2649 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2650 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2651 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2652 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2653 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2654 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2655 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2656 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2657 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2658 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2659 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2660 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2663 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2664 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2665 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2666 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2667 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2668 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2669 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2670 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2671 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2672 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2673 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2674 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2675 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2676 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2677 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2681 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2682 /* special Shogi support in this size */
\r
2683 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2684 for (piece = WhitePawn;
\r
2685 (int) piece < (int) BlackPawn;
\r
2686 piece = (ChessSquare) ((int) piece + 1)) {
\r
2687 if (pieceBitmap[i][piece] != NULL)
\r
2688 DeleteObject(pieceBitmap[i][piece]);
\r
2691 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2692 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2693 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2694 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2695 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2696 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2697 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2698 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2699 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2700 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2701 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2702 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2703 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2704 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2705 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2706 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2707 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2708 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2709 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2710 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2711 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2712 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2713 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2714 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2715 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2716 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2717 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2718 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2719 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2720 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2721 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2722 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2723 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2724 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2725 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2726 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2727 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2728 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2729 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2730 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2731 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2732 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2738 PieceBitmap(ChessSquare p, int kind)
\r
2740 if ((int) p >= (int) BlackPawn)
\r
2741 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2743 return pieceBitmap[kind][(int) p];
\r
2746 /***************************************************************/
\r
2748 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2749 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2751 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2752 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2756 SquareToPos(int row, int column, int * x, int * y)
\r
2759 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2760 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2762 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2763 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2768 DrawCoordsOnDC(HDC hdc)
\r
2770 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2771 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2772 char str[2] = { NULLCHAR, NULLCHAR };
\r
2773 int oldMode, oldAlign, x, y, start, i;
\r
2777 if (!appData.showCoords)
\r
2780 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2782 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2783 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2784 oldAlign = GetTextAlign(hdc);
\r
2785 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2787 y = boardRect.top + lineGap;
\r
2788 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2791 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2792 x += border - lineGap - 4; y += squareSize - 6;
\r
2794 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2795 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2796 str[0] = files[start + i];
\r
2797 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2798 y += squareSize + lineGap;
\r
2801 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2804 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2805 x += -border + 4; y += border - squareSize + 6;
\r
2807 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2808 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2809 str[0] = ranks[start + i];
\r
2810 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2811 x += squareSize + lineGap;
\r
2814 SelectObject(hdc, oldBrush);
\r
2815 SetBkMode(hdc, oldMode);
\r
2816 SetTextAlign(hdc, oldAlign);
\r
2817 SelectObject(hdc, oldFont);
\r
2821 DrawGridOnDC(HDC hdc)
\r
2825 if (lineGap != 0) {
\r
2826 oldPen = SelectObject(hdc, gridPen);
\r
2827 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2828 SelectObject(hdc, oldPen);
\r
2832 #define HIGHLIGHT_PEN 0
\r
2833 #define PREMOVE_PEN 1
\r
2836 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2839 HPEN oldPen, hPen;
\r
2840 if (lineGap == 0) return;
\r
2842 x1 = boardRect.left +
\r
2843 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2844 y1 = boardRect.top +
\r
2845 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2847 x1 = boardRect.left +
\r
2848 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2849 y1 = boardRect.top +
\r
2850 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2852 hPen = pen ? premovePen : highlightPen;
\r
2853 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2854 MoveToEx(hdc, x1, y1, NULL);
\r
2855 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2856 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2857 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2858 LineTo(hdc, x1, y1);
\r
2859 SelectObject(hdc, oldPen);
\r
2863 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2866 for (i=0; i<2; i++) {
\r
2867 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2868 DrawHighlightOnDC(hdc, TRUE,
\r
2869 h->sq[i].x, h->sq[i].y,
\r
2874 /* Note: sqcolor is used only in monoMode */
\r
2875 /* Note that this code is largely duplicated in woptions.c,
\r
2876 function DrawSampleSquare, so that needs to be updated too */
\r
2878 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2880 HBITMAP oldBitmap;
\r
2884 if (appData.blindfold) return;
\r
2886 /* [AS] Use font-based pieces if needed */
\r
2887 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2888 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2889 CreatePiecesFromFont();
\r
2891 if( fontBitmapSquareSize == squareSize ) {
\r
2892 int index = TranslatePieceToFontPiece(piece);
\r
2894 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2896 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2897 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2901 squareSize, squareSize,
\r
2906 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2908 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2909 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2913 squareSize, squareSize,
\r
2922 if (appData.monoMode) {
\r
2923 SelectObject(tmphdc, PieceBitmap(piece,
\r
2924 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2925 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2926 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2928 HBRUSH xBrush = whitePieceBrush;
\r
2929 tmpSize = squareSize;
\r
2930 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2932 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2933 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2934 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2935 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2936 x += (squareSize - minorSize)>>1;
\r
2937 y += squareSize - minorSize - 2;
\r
2938 tmpSize = minorSize;
\r
2940 if (color || appData.allWhite ) {
\r
2941 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2943 oldBrush = SelectObject(hdc, xBrush);
\r
2944 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2945 if(appData.upsideDown && color==flipView)
\r
2946 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2948 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2949 /* Use black for outline of white pieces */
\r
2950 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2951 if(appData.upsideDown && color==flipView)
\r
2952 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2954 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2955 } else if(appData.pieceDirectory[0]) {
\r
2956 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2957 oldBrush = SelectObject(hdc, xBrush);
\r
2958 if(appData.upsideDown && color==flipView)
\r
2959 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2961 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2962 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2963 if(appData.upsideDown && color==flipView)
\r
2964 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2966 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2968 /* Use square color for details of black pieces */
\r
2969 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2970 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2971 if(appData.upsideDown && !flipView)
\r
2972 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2974 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2976 SelectObject(hdc, oldBrush);
\r
2977 SelectObject(tmphdc, oldBitmap);
\r
2981 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2982 int GetBackTextureMode( int algo )
\r
2984 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2988 case BACK_TEXTURE_MODE_PLAIN:
\r
2989 result = 1; /* Always use identity map */
\r
2991 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2992 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3000 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3001 to handle redraws cleanly (as random numbers would always be different).
\r
3003 VOID RebuildTextureSquareInfo()
\r
3013 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3015 if( liteBackTexture != NULL ) {
\r
3016 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3017 lite_w = bi.bmWidth;
\r
3018 lite_h = bi.bmHeight;
\r
3022 if( darkBackTexture != NULL ) {
\r
3023 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3024 dark_w = bi.bmWidth;
\r
3025 dark_h = bi.bmHeight;
\r
3029 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3030 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3031 if( (col + row) & 1 ) {
\r
3033 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3034 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3035 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3037 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3038 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3039 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3041 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3042 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3047 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3048 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3049 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3051 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3052 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3053 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3055 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3056 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3063 /* [AS] Arrow highlighting support */
\r
3065 static double A_WIDTH = 5; /* Width of arrow body */
\r
3067 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3068 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3070 static double Sqr( double x )
\r
3075 static int Round( double x )
\r
3077 return (int) (x + 0.5);
\r
3080 /* Draw an arrow between two points using current settings */
\r
3081 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3084 double dx, dy, j, k, x, y;
\r
3086 if( d_x == s_x ) {
\r
3087 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3089 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3092 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3093 arrow[1].y = d_y - h;
\r
3095 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3096 arrow[2].y = d_y - h;
\r
3101 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3102 arrow[5].y = d_y - h;
\r
3104 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3105 arrow[4].y = d_y - h;
\r
3107 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3110 else if( d_y == s_y ) {
\r
3111 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3114 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3116 arrow[1].x = d_x - w;
\r
3117 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3119 arrow[2].x = d_x - w;
\r
3120 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3125 arrow[5].x = d_x - w;
\r
3126 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3128 arrow[4].x = d_x - w;
\r
3129 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3132 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3135 /* [AS] Needed a lot of paper for this! :-) */
\r
3136 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3137 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3139 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3141 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3146 arrow[0].x = Round(x - j);
\r
3147 arrow[0].y = Round(y + j*dx);
\r
3149 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3150 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3153 x = (double) d_x - k;
\r
3154 y = (double) d_y - k*dy;
\r
3157 x = (double) d_x + k;
\r
3158 y = (double) d_y + k*dy;
\r
3161 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3163 arrow[6].x = Round(x - j);
\r
3164 arrow[6].y = Round(y + j*dx);
\r
3166 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3167 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3169 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3170 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3175 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3176 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3179 Polygon( hdc, arrow, 7 );
\r
3182 /* [AS] Draw an arrow between two squares */
\r
3183 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3185 int s_x, s_y, d_x, d_y;
\r
3192 if( s_col == d_col && s_row == d_row ) {
\r
3196 /* Get source and destination points */
\r
3197 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3198 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3201 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3203 else if( d_y < s_y ) {
\r
3204 d_y += squareSize / 2 + squareSize / 4;
\r
3207 d_y += squareSize / 2;
\r
3211 d_x += squareSize / 2 - squareSize / 4;
\r
3213 else if( d_x < s_x ) {
\r
3214 d_x += squareSize / 2 + squareSize / 4;
\r
3217 d_x += squareSize / 2;
\r
3220 s_x += squareSize / 2;
\r
3221 s_y += squareSize / 2;
\r
3223 /* Adjust width */
\r
3224 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3227 stLB.lbStyle = BS_SOLID;
\r
3228 stLB.lbColor = appData.highlightArrowColor;
\r
3231 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3232 holdpen = SelectObject( hdc, hpen );
\r
3233 hbrush = CreateBrushIndirect( &stLB );
\r
3234 holdbrush = SelectObject( hdc, hbrush );
\r
3236 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3238 SelectObject( hdc, holdpen );
\r
3239 SelectObject( hdc, holdbrush );
\r
3240 DeleteObject( hpen );
\r
3241 DeleteObject( hbrush );
\r
3244 BOOL HasHighlightInfo()
\r
3246 BOOL result = FALSE;
\r
3248 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3249 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3260 BOOL IsDrawArrowEnabled()
\r
3262 BOOL result = FALSE;
\r
3264 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3271 VOID DrawArrowHighlight( HDC hdc )
\r
3273 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3274 DrawArrowBetweenSquares( hdc,
\r
3275 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3276 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3280 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3282 HRGN result = NULL;
\r
3284 if( HasHighlightInfo() ) {
\r
3285 int x1, y1, x2, y2;
\r
3286 int sx, sy, dx, dy;
\r
3288 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3289 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3291 sx = MIN( x1, x2 );
\r
3292 sy = MIN( y1, y2 );
\r
3293 dx = MAX( x1, x2 ) + squareSize;
\r
3294 dy = MAX( y1, y2 ) + squareSize;
\r
3296 result = CreateRectRgn( sx, sy, dx, dy );
\r
3303 Warning: this function modifies the behavior of several other functions.
\r
3305 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3306 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3307 repaint is scattered all over the place, which is not good for features such as
\r
3308 "arrow highlighting" that require a full repaint of the board.
\r
3310 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3311 user interaction, when speed is not so important) but especially to avoid errors
\r
3312 in the displayed graphics.
\r
3314 In such patched places, I always try refer to this function so there is a single
\r
3315 place to maintain knowledge.
\r
3317 To restore the original behavior, just return FALSE unconditionally.
\r
3319 BOOL IsFullRepaintPreferrable()
\r
3321 BOOL result = FALSE;
\r
3323 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3324 /* Arrow may appear on the board */
\r
3332 This function is called by DrawPosition to know whether a full repaint must
\r
3335 Only DrawPosition may directly call this function, which makes use of
\r
3336 some state information. Other function should call DrawPosition specifying
\r
3337 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3339 BOOL DrawPositionNeedsFullRepaint()
\r
3341 BOOL result = FALSE;
\r
3344 Probably a slightly better policy would be to trigger a full repaint
\r
3345 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3346 but animation is fast enough that it's difficult to notice.
\r
3348 if( animInfo.piece == EmptySquare ) {
\r
3349 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3357 static HBITMAP borderBitmap;
\r
3360 DrawBackgroundOnDC(HDC hdc)
\r
3366 static char oldBorder[MSG_SIZ];
\r
3367 int w = 600, h = 600, mode;
\r
3369 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3370 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3371 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3373 if(borderBitmap == NULL) { // loading failed, use white
\r
3374 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3377 tmphdc = CreateCompatibleDC(hdc);
\r
3378 hbm = SelectObject(tmphdc, borderBitmap);
\r
3379 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3383 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3384 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3385 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3386 SetStretchBltMode(hdc, mode);
\r
3387 SelectObject(tmphdc, hbm);
\r
3392 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3394 int row, column, x, y, square_color, piece_color;
\r
3395 ChessSquare piece;
\r
3397 HDC texture_hdc = NULL;
\r
3399 /* [AS] Initialize background textures if needed */
\r
3400 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3401 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3402 if( backTextureSquareSize != squareSize
\r
3403 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3404 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3405 backTextureSquareSize = squareSize;
\r
3406 RebuildTextureSquareInfo();
\r
3409 texture_hdc = CreateCompatibleDC( hdc );
\r
3412 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3413 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3415 SquareToPos(row, column, &x, &y);
\r
3417 piece = board[row][column];
\r
3419 square_color = ((column + row) % 2) == 1;
\r
3420 if( gameInfo.variant == VariantXiangqi ) {
\r
3421 square_color = !InPalace(row, column);
\r
3422 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3423 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3425 piece_color = (int) piece < (int) BlackPawn;
\r
3428 /* [HGM] holdings file: light square or black */
\r
3429 if(column == BOARD_LEFT-2) {
\r
3430 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3433 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3437 if(column == BOARD_RGHT + 1 ) {
\r
3438 if( row < gameInfo.holdingsSize )
\r
3441 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3445 if(column == BOARD_LEFT-1 ) /* left align */
\r
3446 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3447 else if( column == BOARD_RGHT) /* right align */
\r
3448 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3449 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3451 if (appData.monoMode) {
\r
3452 if (piece == EmptySquare) {
\r
3453 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3454 square_color ? WHITENESS : BLACKNESS);
\r
3456 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3459 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3460 /* [AS] Draw the square using a texture bitmap */
\r
3461 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3462 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3463 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3466 squareSize, squareSize,
\r
3469 backTextureSquareInfo[r][c].mode,
\r
3470 backTextureSquareInfo[r][c].x,
\r
3471 backTextureSquareInfo[r][c].y );
\r
3473 SelectObject( texture_hdc, hbm );
\r
3475 if (piece != EmptySquare) {
\r
3476 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3480 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3482 oldBrush = SelectObject(hdc, brush );
\r
3483 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3484 SelectObject(hdc, oldBrush);
\r
3485 if (piece != EmptySquare)
\r
3486 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3491 if( texture_hdc != NULL ) {
\r
3492 DeleteDC( texture_hdc );
\r
3496 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3497 void fputDW(FILE *f, int x)
\r
3499 fputc(x & 255, f);
\r
3500 fputc(x>>8 & 255, f);
\r
3501 fputc(x>>16 & 255, f);
\r
3502 fputc(x>>24 & 255, f);
\r
3505 #define MAX_CLIPS 200 /* more than enough */
\r
3508 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3510 // HBITMAP bufferBitmap;
\r
3515 int w = 100, h = 50;
\r
3517 if(logo == NULL) {
\r
3518 if(!logoHeight) return;
\r
3519 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3521 // GetClientRect(hwndMain, &Rect);
\r
3522 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3523 // Rect.bottom-Rect.top+1);
\r
3524 tmphdc = CreateCompatibleDC(hdc);
\r
3525 hbm = SelectObject(tmphdc, logo);
\r
3526 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3530 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3531 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3532 SelectObject(tmphdc, hbm);
\r
3540 HDC hdc = GetDC(hwndMain);
\r
3541 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3542 if(appData.autoLogo) {
\r
3544 switch(gameMode) { // pick logos based on game mode
\r
3545 case IcsObserving:
\r
3546 whiteLogo = second.programLogo; // ICS logo
\r
3547 blackLogo = second.programLogo;
\r
3550 case IcsPlayingWhite:
\r
3551 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3552 blackLogo = second.programLogo; // ICS logo
\r
3554 case IcsPlayingBlack:
\r
3555 whiteLogo = second.programLogo; // ICS logo
\r
3556 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3558 case TwoMachinesPlay:
\r
3559 if(first.twoMachinesColor[0] == 'b') {
\r
3560 whiteLogo = second.programLogo;
\r
3561 blackLogo = first.programLogo;
\r
3564 case MachinePlaysWhite:
\r
3565 blackLogo = userLogo;
\r
3567 case MachinePlaysBlack:
\r
3568 whiteLogo = userLogo;
\r
3569 blackLogo = first.programLogo;
\r
3572 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3573 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3574 ReleaseDC(hwndMain, hdc);
\r
3579 UpdateLogos(int display)
\r
3580 { // called after loading new engine(s), in tourney or from menu
\r
3581 LoadLogo(&first, 0, FALSE);
\r
3582 LoadLogo(&second, 1, appData.icsActive);
\r
3583 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3584 if(display) DisplayLogos();
\r
3587 static HDC hdcSeek;
\r
3589 // [HGM] seekgraph
\r
3590 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3593 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3594 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3595 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3596 SelectObject( hdcSeek, hp );
\r
3599 // front-end wrapper for drawing functions to do rectangles
\r
3600 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3605 if (hdcSeek == NULL) {
\r
3606 hdcSeek = GetDC(hwndMain);
\r
3607 if (!appData.monoMode) {
\r
3608 SelectPalette(hdcSeek, hPal, FALSE);
\r
3609 RealizePalette(hdcSeek);
\r
3612 hp = SelectObject( hdcSeek, gridPen );
\r
3613 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3614 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3615 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3616 SelectObject( hdcSeek, hp );
\r
3619 // front-end wrapper for putting text in graph
\r
3620 void DrawSeekText(char *buf, int x, int y)
\r
3623 SetBkMode( hdcSeek, TRANSPARENT );
\r
3624 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3625 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3628 void DrawSeekDot(int x, int y, int color)
\r
3630 int square = color & 0x80;
\r
3631 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3632 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3635 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3636 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3638 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3639 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3640 SelectObject(hdcSeek, oldBrush);
\r
3643 void DrawSeekOpen()
\r
3647 void DrawSeekClose()
\r
3652 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3654 static Board lastReq[2], lastDrawn[2];
\r
3655 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3656 static int lastDrawnFlipView = 0;
\r
3657 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3658 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3661 HBITMAP bufferBitmap;
\r
3662 HBITMAP oldBitmap;
\r
3664 HRGN clips[MAX_CLIPS];
\r
3665 ChessSquare dragged_piece = EmptySquare;
\r
3666 int nr = twoBoards*partnerUp;
\r
3668 /* I'm undecided on this - this function figures out whether a full
\r
3669 * repaint is necessary on its own, so there's no real reason to have the
\r
3670 * caller tell it that. I think this can safely be set to FALSE - but
\r
3671 * if we trust the callers not to request full repaints unnessesarily, then
\r
3672 * we could skip some clipping work. In other words, only request a full
\r
3673 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3674 * gamestart and similar) --Hawk
\r
3676 Boolean fullrepaint = repaint;
\r
3678 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3680 if( DrawPositionNeedsFullRepaint() ) {
\r
3681 fullrepaint = TRUE;
\r
3684 if (board == NULL) {
\r
3685 if (!lastReqValid[nr]) {
\r
3688 board = lastReq[nr];
\r
3690 CopyBoard(lastReq[nr], board);
\r
3691 lastReqValid[nr] = 1;
\r