2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
96 #define DATADIR "~~"
\r
98 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
100 int myrandom(void);
\r
101 void mysrandom(unsigned int seed);
\r
103 extern int whiteFlag, blackFlag;
\r
104 Boolean flipClock = FALSE;
\r
105 extern HANDLE chatHandle[];
\r
106 extern enum ICS_TYPE ics_type;
\r
108 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
109 int MyGetFullPathName P((char *name, char *fullname));
\r
110 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
111 VOID NewVariantPopup(HWND hwnd);
\r
112 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
113 /*char*/int promoChar));
\r
114 void DisplayMove P((int moveNumber));
\r
115 void ChatPopUp P((char *s));
\r
117 ChessSquare piece;
\r
118 POINT pos; /* window coordinates of current pos */
\r
119 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
120 POINT from; /* board coordinates of the piece's orig pos */
\r
121 POINT to; /* board coordinates of the piece's new pos */
\r
124 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
127 POINT start; /* window coordinates of start pos */
\r
128 POINT pos; /* window coordinates of current pos */
\r
129 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
130 POINT from; /* board coordinates of the piece's orig pos */
\r
134 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
137 POINT sq[2]; /* board coordinates of from, to squares */
\r
140 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
145 typedef struct { // [HGM] atomic
\r
146 int fromX, fromY, toX, toY, radius;
\r
149 static ExplodeInfo explodeInfo;
\r
151 /* Window class names */
\r
152 char szAppName[] = "WinBoard";
\r
153 char szConsoleName[] = "WBConsole";
\r
155 /* Title bar text */
\r
156 char szTitle[] = "WinBoard";
\r
157 char szConsoleTitle[] = "I C S Interaction";
\r
160 char *settingsFileName;
\r
161 Boolean saveSettingsOnExit;
\r
162 char installDir[MSG_SIZ];
\r
163 int errorExitStatus;
\r
165 BoardSize boardSize;
\r
166 Boolean chessProgram;
\r
167 //static int boardX, boardY;
\r
168 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
169 int squareSize, lineGap, minorSize;
\r
170 static int winW, winH;
\r
171 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
172 static int logoHeight = 0;
\r
173 static char messageText[MESSAGE_TEXT_MAX];
\r
174 static int clockTimerEvent = 0;
\r
175 static int loadGameTimerEvent = 0;
\r
176 static int analysisTimerEvent = 0;
\r
177 static DelayedEventCallback delayedTimerCallback;
\r
178 static int delayedTimerEvent = 0;
\r
179 static int buttonCount = 2;
\r
180 char *icsTextMenuString;
\r
182 char *firstChessProgramNames;
\r
183 char *secondChessProgramNames;
\r
185 #define PALETTESIZE 256
\r
187 HINSTANCE hInst; /* current instance */
\r
188 Boolean alwaysOnTop = FALSE;
\r
190 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
191 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
192 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
194 ColorClass currentColorClass;
\r
196 static HWND savedHwnd;
\r
197 HWND hCommPort = NULL; /* currently open comm port */
\r
198 static HWND hwndPause; /* pause button */
\r
199 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
200 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
201 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
202 explodeBrush, /* [HGM] atomic */
\r
203 markerBrush[8], /* [HGM] markers */
\r
204 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
205 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
206 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
207 static HPEN gridPen = NULL;
\r
208 static HPEN highlightPen = NULL;
\r
209 static HPEN premovePen = NULL;
\r
210 static NPLOGPALETTE pLogPal;
\r
211 static BOOL paletteChanged = FALSE;
\r
212 static HICON iconWhite, iconBlack, iconCurrent;
\r
213 static int doingSizing = FALSE;
\r
214 static int lastSizing = 0;
\r
215 static int prevStderrPort;
\r
216 static HBITMAP userLogo;
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
229 #if defined(_winmajor)
\r
230 #define oldDialog (_winmajor < 4)
\r
232 #define oldDialog 0
\r
236 #define INTERNATIONAL
\r
238 #ifdef INTERNATIONAL
\r
239 # define _(s) T_(s)
\r
245 # define Translate(x, y)
\r
246 # define LoadLanguageFile(s)
\r
249 #ifdef INTERNATIONAL
\r
251 Boolean barbaric; // flag indicating if translation is needed
\r
253 // list of item numbers used in each dialog (used to alter language at run time)
\r
255 #define ABOUTBOX -1 /* not sure why these are needed */
\r
256 #define ABOUTBOX2 -1
\r
258 int dialogItems[][42] = {
\r
259 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
260 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
261 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
262 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
263 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds,
\r
264 OPT_Ranget, IDOK, IDCANCEL },
\r
265 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
266 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
267 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
268 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
269 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
270 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
271 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
272 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
273 { ABOUTBOX2, IDC_ChessBoard },
\r
274 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
275 OPT_GameListClose, IDC_GameListDoFilter },
\r
276 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
277 { DLG_Error, IDOK },
\r
278 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
279 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
280 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
281 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
282 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
283 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
284 { DLG_IndexNumber, IDC_Index },
\r
285 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
286 { DLG_TypeInName, IDOK, IDCANCEL },
\r
287 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
288 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
289 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
290 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
291 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
292 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
293 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
294 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
295 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
296 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
297 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
298 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
299 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
300 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
301 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
302 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
303 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
304 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
305 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
306 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
307 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
308 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
309 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
310 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
311 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
312 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
313 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
314 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
315 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
316 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
317 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
318 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
319 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
320 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
321 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
322 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
323 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
324 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
325 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
326 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
327 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
328 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
329 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
330 { DLG_MoveHistory },
\r
331 { DLG_EvalGraph },
\r
332 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
333 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
334 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
335 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
336 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
337 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
338 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
339 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
340 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
344 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
345 static int lastChecked;
\r
346 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
347 extern int tinyLayout;
\r
348 extern char * menuBarText[][10];
\r
351 LoadLanguageFile(char *name)
\r
352 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
354 int i=0, j=0, n=0, k;
\r
357 if(!name || name[0] == NULLCHAR) return;
\r
358 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
359 appData.language = oldLanguage;
\r
360 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
361 if((f = fopen(buf, "r")) == NULL) return;
\r
362 while((k = fgetc(f)) != EOF) {
\r
363 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
364 languageBuf[i] = k;
\r
366 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
368 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
369 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
370 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
371 english[j] = languageBuf + n + 1; *p = 0;
\r
372 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
373 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
378 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
380 case 'n': k = '\n'; break;
\r
381 case 'r': k = '\r'; break;
\r
382 case 't': k = '\t'; break;
\r
384 languageBuf[--i] = k;
\r
389 barbaric = (j != 0);
\r
390 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
395 { // return the translation of the given string
\r
396 // efficiency can be improved a lot...
\r
398 static char buf[MSG_SIZ];
\r
399 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
400 if(!barbaric) return s;
\r
401 if(!s) return ""; // sanity
\r
402 while(english[i]) {
\r
403 if(!strcmp(s, english[i])) return foreign[i];
\r
404 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
405 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
414 Translate(HWND hDlg, int dialogID)
\r
415 { // translate all text items in the given dialog
\r
417 char buf[MSG_SIZ], *s;
\r
418 if(!barbaric) return;
\r
419 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
420 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
421 GetWindowText( hDlg, buf, MSG_SIZ );
\r
423 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
424 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
425 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
426 if(strlen(buf) == 0) continue;
\r
428 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
433 TranslateOneMenu(int i, HMENU subMenu)
\r
436 static MENUITEMINFO info;
\r
438 info.cbSize = sizeof(MENUITEMINFO);
\r
439 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
440 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
442 info.dwTypeData = buf;
\r
443 info.cch = sizeof(buf);
\r
444 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
446 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
447 else menuText[i][j] = strdup(buf); // remember original on first change
\r
449 if(buf[0] == NULLCHAR) continue;
\r
450 info.dwTypeData = T_(buf);
\r
451 info.cch = strlen(buf)+1;
\r
452 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
458 TranslateMenus(int addLanguage)
\r
461 WIN32_FIND_DATA fileData;
\r
463 #define IDM_English 1970
\r
465 HMENU mainMenu = GetMenu(hwndMain);
\r
466 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
467 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
468 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
469 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
470 TranslateOneMenu(i, subMenu);
\r
472 DrawMenuBar(hwndMain);
\r
475 if(!addLanguage) return;
\r
476 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
477 HMENU mainMenu = GetMenu(hwndMain);
\r
478 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
479 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
480 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
481 i = 0; lastChecked = IDM_English;
\r
483 char *p, *q = fileData.cFileName;
\r
484 int checkFlag = MF_UNCHECKED;
\r
485 languageFile[i] = strdup(q);
\r
486 if(barbaric && !strcmp(oldLanguage, q)) {
\r
487 checkFlag = MF_CHECKED;
\r
488 lastChecked = IDM_English + i + 1;
\r
489 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
491 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
492 p = strstr(fileData.cFileName, ".lng");
\r
494 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
495 } while(FindNextFile(hFind, &fileData));
\r
502 #define IDM_RecentEngines 3000
\r
505 RecentEngineMenu (char *s)
\r
507 if(appData.icsActive) return;
\r
508 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
509 HMENU mainMenu = GetMenu(hwndMain);
\r
510 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
511 int i=IDM_RecentEngines;
\r
512 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
513 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
515 char *p = strchr(s, '\n');
\r
516 if(p == NULL) return; // malformed!
\r
518 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
532 int cliWidth, cliHeight;
\r
535 SizeInfo sizeInfo[] =
\r
537 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
540 { "petite", 33, 1, 1, 1, 0, 0 },
\r
541 { "slim", 37, 2, 1, 0, 0, 0 },
\r
542 { "small", 40, 2, 1, 0, 0, 0 },
\r
543 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
544 { "middling", 49, 2, 0, 0, 0, 0 },
\r
545 { "average", 54, 2, 0, 0, 0, 0 },
\r
546 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
547 { "medium", 64, 3, 0, 0, 0, 0 },
\r
548 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
549 { "large", 80, 3, 0, 0, 0, 0 },
\r
550 { "big", 87, 3, 0, 0, 0, 0 },
\r
551 { "huge", 95, 3, 0, 0, 0, 0 },
\r
552 { "giant", 108, 3, 0, 0, 0, 0 },
\r
553 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
554 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
555 { NULL, 0, 0, 0, 0, 0, 0 }
\r
558 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
559 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
561 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
562 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
578 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
581 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
590 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
591 #define N_BUTTONS 5
\r
593 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
595 {"<<", IDM_ToStart, NULL, NULL},
\r
596 {"<", IDM_Backward, NULL, NULL},
\r
597 {"P", IDM_Pause, NULL, NULL},
\r
598 {">", IDM_Forward, NULL, NULL},
\r
599 {">>", IDM_ToEnd, NULL, NULL},
\r
602 int tinyLayout = 0, smallLayout = 0;
\r
603 #define MENU_BAR_ITEMS 9
\r
604 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
605 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
606 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
610 MySound sounds[(int)NSoundClasses];
\r
611 MyTextAttribs textAttribs[(int)NColorClasses];
\r
613 MyColorizeAttribs colorizeAttribs[] = {
\r
614 { (COLORREF)0, 0, N_("Shout Text") },
\r
615 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
616 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
617 { (COLORREF)0, 0, N_("Channel Text") },
\r
618 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
619 { (COLORREF)0, 0, N_("Tell Text") },
\r
620 { (COLORREF)0, 0, N_("Challenge Text") },
\r
621 { (COLORREF)0, 0, N_("Request Text") },
\r
622 { (COLORREF)0, 0, N_("Seek Text") },
\r
623 { (COLORREF)0, 0, N_("Normal Text") },
\r
624 { (COLORREF)0, 0, N_("None") }
\r
629 static char *commentTitle;
\r
630 static char *commentText;
\r
631 static int commentIndex;
\r
632 static Boolean editComment = FALSE;
\r
635 char errorTitle[MSG_SIZ];
\r
636 char errorMessage[2*MSG_SIZ];
\r
637 HWND errorDialog = NULL;
\r
638 BOOLEAN moveErrorMessageUp = FALSE;
\r
639 BOOLEAN consoleEcho = TRUE;
\r
640 CHARFORMAT consoleCF;
\r
641 COLORREF consoleBackgroundColor;
\r
643 char *programVersion;
\r
649 typedef int CPKind;
\r
658 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
661 #define INPUT_SOURCE_BUF_SIZE 4096
\r
663 typedef struct _InputSource {
\r
670 char buf[INPUT_SOURCE_BUF_SIZE];
\r
674 InputCallback func;
\r
675 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
679 InputSource *consoleInputSource;
\r
684 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
685 VOID ConsoleCreate();
\r
687 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
689 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
690 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
692 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
693 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
694 void ParseIcsTextMenu(char *icsTextMenuString);
\r
695 VOID PopUpNameDialog(char firstchar);
\r
696 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
700 int GameListOptions();
\r
702 int dummy; // [HGM] for obsolete args
\r
704 HWND hwndMain = NULL; /* root window*/
\r
705 HWND hwndConsole = NULL;
\r
706 HWND commentDialog = NULL;
\r
707 HWND moveHistoryDialog = NULL;
\r
708 HWND evalGraphDialog = NULL;
\r
709 HWND engineOutputDialog = NULL;
\r
710 HWND gameListDialog = NULL;
\r
711 HWND editTagsDialog = NULL;
\r
713 int commentUp = FALSE;
\r
715 WindowPlacement wpMain;
\r
716 WindowPlacement wpConsole;
\r
717 WindowPlacement wpComment;
\r
718 WindowPlacement wpMoveHistory;
\r
719 WindowPlacement wpEvalGraph;
\r
720 WindowPlacement wpEngineOutput;
\r
721 WindowPlacement wpGameList;
\r
722 WindowPlacement wpTags;
\r
724 VOID EngineOptionsPopup(); // [HGM] settings
\r
726 VOID GothicPopUp(char *title, VariantClass variant);
\r
728 * Setting "frozen" should disable all user input other than deleting
\r
729 * the window. We do this while engines are initializing themselves.
\r
731 static int frozen = 0;
\r
732 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
738 if (frozen) return;
\r
740 hmenu = GetMenu(hwndMain);
\r
741 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
742 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
744 DrawMenuBar(hwndMain);
\r
747 /* Undo a FreezeUI */
\r
753 if (!frozen) return;
\r
755 hmenu = GetMenu(hwndMain);
\r
756 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
757 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
759 DrawMenuBar(hwndMain);
\r
762 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
764 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
770 #define JAWS_ALT_INTERCEPT
\r
771 #define JAWS_KBUP_NAVIGATION
\r
772 #define JAWS_KBDOWN_NAVIGATION
\r
773 #define JAWS_MENU_ITEMS
\r
774 #define JAWS_SILENCE
\r
775 #define JAWS_REPLAY
\r
777 #define JAWS_COPYRIGHT
\r
778 #define JAWS_DELETE(X) X
\r
779 #define SAYMACHINEMOVE()
\r
783 /*---------------------------------------------------------------------------*\
\r
787 \*---------------------------------------------------------------------------*/
\r
789 static void HandleMessage P((MSG *message));
\r
790 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
793 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
794 LPSTR lpCmdLine, int nCmdShow)
\r
797 // INITCOMMONCONTROLSEX ex;
\r
801 LoadLibrary("RICHED32.DLL");
\r
802 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
804 if (!InitApplication(hInstance)) {
\r
807 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
814 // InitCommonControlsEx(&ex);
\r
815 InitCommonControls();
\r
817 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
818 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
819 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
821 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
823 while (GetMessage(&msg, /* message structure */
\r
824 NULL, /* handle of window receiving the message */
\r
825 0, /* lowest message to examine */
\r
826 0)) /* highest message to examine */
\r
828 HandleMessage(&msg);
\r
832 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
836 HandleMessage (MSG *message)
\r
838 MSG msg = *message;
\r
840 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
841 // [HGM] navigate: switch between all windows with tab
\r
842 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
843 int i, currentElement = 0;
\r
845 // first determine what element of the chain we come from (if any)
\r
846 if(appData.icsActive) {
\r
847 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
848 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
850 if(engineOutputDialog && EngineOutputIsUp()) {
\r
851 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
852 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
854 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
855 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
857 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
858 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
859 if(msg.hwnd == e1) currentElement = 2; else
\r
860 if(msg.hwnd == e2) currentElement = 3; else
\r
861 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
862 if(msg.hwnd == mh) currentElement = 4; else
\r
863 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
864 if(msg.hwnd == hText) currentElement = 5; else
\r
865 if(msg.hwnd == hInput) currentElement = 6; else
\r
866 for (i = 0; i < N_BUTTONS; i++) {
\r
867 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
870 // determine where to go to
\r
871 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
873 currentElement = (currentElement + direction) % 7;
\r
874 switch(currentElement) {
\r
876 h = hwndMain; break; // passing this case always makes the loop exit
\r
878 h = buttonDesc[0].hwnd; break; // could be NULL
\r
880 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
883 if(!EngineOutputIsUp()) continue;
\r
886 if(!MoveHistoryIsUp()) continue;
\r
888 // case 6: // input to eval graph does not seem to get here!
\r
889 // if(!EvalGraphIsUp()) continue;
\r
890 // h = evalGraphDialog; break;
\r
892 if(!appData.icsActive) continue;
\r
896 if(!appData.icsActive) continue;
\r
902 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
903 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
906 return; // this message now has been processed
\r
910 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
911 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
912 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
913 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
914 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
915 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
916 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
917 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
918 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
920 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
921 for(i=0; i<MAX_CHAT; i++)
\r
922 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
925 if(done) return; // [HGM] chat: end patch
\r
926 TranslateMessage(&msg); /* Translates virtual key codes */
\r
927 DispatchMessage(&msg); /* Dispatches message to window */
\r
933 { /* Dispatch pending messages */
\r
935 while (PeekMessage(&msg, /* message structure */
\r
936 NULL, /* handle of window receiving the message */
\r
937 0, /* lowest message to examine */
\r
938 0, /* highest message to examine */
\r
941 HandleMessage(&msg);
\r
945 /*---------------------------------------------------------------------------*\
\r
947 * Initialization functions
\r
949 \*---------------------------------------------------------------------------*/
\r
953 { // update user logo if necessary
\r
954 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
956 if(appData.autoLogo) {
\r
957 curName = UserName();
\r
958 if(strcmp(curName, oldUserName)) {
\r
959 GetCurrentDirectory(MSG_SIZ, dir);
\r
960 SetCurrentDirectory(installDir);
\r
961 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
962 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
963 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
964 if(userLogo == NULL)
\r
965 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
966 SetCurrentDirectory(dir); /* return to prev directory */
\r
972 InitApplication(HINSTANCE hInstance)
\r
976 /* Fill in window class structure with parameters that describe the */
\r
979 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
980 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
981 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
982 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
983 wc.hInstance = hInstance; /* Owner of this class */
\r
984 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
985 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
986 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
987 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
988 wc.lpszClassName = szAppName; /* Name to register as */
\r
990 /* Register the window class and return success/failure code. */
\r
991 if (!RegisterClass(&wc)) return FALSE;
\r
993 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
994 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
996 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
997 wc.hInstance = hInstance;
\r
998 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
999 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1000 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1001 wc.lpszMenuName = NULL;
\r
1002 wc.lpszClassName = szConsoleName;
\r
1004 if (!RegisterClass(&wc)) return FALSE;
\r
1009 /* Set by InitInstance, used by EnsureOnScreen */
\r
1010 int screenHeight, screenWidth;
\r
1011 RECT screenGeometry;
\r
1014 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1016 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1017 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1018 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1019 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1020 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1021 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1025 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1027 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1028 GetCurrentDirectory(MSG_SIZ, dir);
\r
1029 SetCurrentDirectory(installDir);
\r
1030 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1031 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1033 if (cps->programLogo == NULL && appData.debugMode) {
\r
1034 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1036 } else if(appData.autoLogo) {
\r
1037 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1038 char *opponent = "";
\r
1039 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1040 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1041 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1042 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1043 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1044 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1047 if(appData.directory[n] && appData.directory[n][0]) {
\r
1048 SetCurrentDirectory(appData.directory[n]);
\r
1049 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1052 SetCurrentDirectory(dir); /* return to prev directory */
\r
1058 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1059 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1061 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1062 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1063 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1064 liteBackTextureMode = appData.liteBackTextureMode;
\r
1066 if (liteBackTexture == NULL && appData.debugMode) {
\r
1067 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1071 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1072 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1073 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1074 darkBackTextureMode = appData.darkBackTextureMode;
\r
1076 if (darkBackTexture == NULL && appData.debugMode) {
\r
1077 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1082 #ifndef SM_CXVIRTUALSCREEN
\r
1083 #define SM_CXVIRTUALSCREEN 78
\r
1085 #ifndef SM_CYVIRTUALSCREEN
\r
1086 #define SM_CYVIRTUALSCREEN 79
\r
1088 #ifndef SM_XVIRTUALSCREEN
\r
1089 #define SM_XVIRTUALSCREEN 76
\r
1091 #ifndef SM_YVIRTUALSCREEN
\r
1092 #define SM_YVIRTUALSCREEN 77
\r
1098 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1099 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1100 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1101 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1102 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1103 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1104 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1105 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1109 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1111 HWND hwnd; /* Main window handle. */
\r
1113 WINDOWPLACEMENT wp;
\r
1116 hInst = hInstance; /* Store instance handle in our global variable */
\r
1117 programName = szAppName;
\r
1119 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1120 *filepart = NULLCHAR;
\r
1121 SetCurrentDirectory(installDir);
\r
1123 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1125 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1127 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1128 /* xboard, and older WinBoards, controlled the move sound with the
\r
1129 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1130 always turn the option on (so that the backend will call us),
\r
1131 then let the user turn the sound off by setting it to silence if
\r
1132 desired. To accommodate old winboard.ini files saved by old
\r
1133 versions of WinBoard, we also turn off the sound if the option
\r
1134 was initially set to false. [HGM] taken out of InitAppData */
\r
1135 if (!appData.ringBellAfterMoves) {
\r
1136 sounds[(int)SoundMove].name = strdup("");
\r
1137 appData.ringBellAfterMoves = TRUE;
\r
1139 if (appData.debugMode) {
\r
1140 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1141 setbuf(debugFP, NULL);
\r
1144 LoadLanguageFile(appData.language);
\r
1148 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1149 // InitEngineUCI( installDir, &second );
\r
1151 /* Create a main window for this application instance. */
\r
1152 hwnd = CreateWindow(szAppName, szTitle,
\r
1153 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1154 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1155 NULL, NULL, hInstance, NULL);
\r
1158 /* If window could not be created, return "failure" */
\r
1163 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1164 LoadLogo(&first, 0, FALSE);
\r
1165 LoadLogo(&second, 1, appData.icsActive);
\r
1169 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1170 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1171 iconCurrent = iconWhite;
\r
1172 InitDrawingColors();
\r
1174 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1175 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1176 /* Compute window size for each board size, and use the largest
\r
1177 size that fits on this screen as the default. */
\r
1178 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1179 if (boardSize == (BoardSize)-1 &&
\r
1180 winH <= screenHeight
\r
1181 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1182 && winW <= screenWidth) {
\r
1183 boardSize = (BoardSize)ibs;
\r
1187 InitDrawingSizes(boardSize, 0);
\r
1188 RecentEngineMenu(appData.recentEngineList);
\r
1190 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1192 /* [AS] Load textures if specified */
\r
1195 mysrandom( (unsigned) time(NULL) );
\r
1197 /* [AS] Restore layout */
\r
1198 if( wpMoveHistory.visible ) {
\r
1199 MoveHistoryPopUp();
\r
1202 if( wpEvalGraph.visible ) {
\r
1206 if( wpEngineOutput.visible ) {
\r
1207 EngineOutputPopUp();
\r
1210 /* Make the window visible; update its client area; and return "success" */
\r
1211 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1212 wp.length = sizeof(WINDOWPLACEMENT);
\r
1214 wp.showCmd = nCmdShow;
\r
1215 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1216 wp.rcNormalPosition.left = wpMain.x;
\r
1217 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1218 wp.rcNormalPosition.top = wpMain.y;
\r
1219 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1220 SetWindowPlacement(hwndMain, &wp);
\r
1222 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1224 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1225 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1227 if (hwndConsole) {
\r
1229 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1230 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1232 ShowWindow(hwndConsole, nCmdShow);
\r
1233 SetActiveWindow(hwndConsole);
\r
1235 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1236 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1245 HMENU hmenu = GetMenu(hwndMain);
\r
1247 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1248 MF_BYCOMMAND|((appData.icsActive &&
\r
1249 *appData.icsCommPort != NULLCHAR) ?
\r
1250 MF_ENABLED : MF_GRAYED));
\r
1251 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1252 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1253 MF_CHECKED : MF_UNCHECKED));
\r
1254 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1257 //---------------------------------------------------------------------------------------------------------
\r
1259 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1260 #define XBOARD FALSE
\r
1262 #define OPTCHAR "/"
\r
1263 #define SEPCHAR "="
\r
1264 #define TOPLEVEL 0
\r
1268 // front-end part of option handling
\r
1271 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1273 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1274 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1277 lf->lfEscapement = 0;
\r
1278 lf->lfOrientation = 0;
\r
1279 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1280 lf->lfItalic = mfp->italic;
\r
1281 lf->lfUnderline = mfp->underline;
\r
1282 lf->lfStrikeOut = mfp->strikeout;
\r
1283 lf->lfCharSet = mfp->charset;
\r
1284 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1286 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1287 lf->lfQuality = DEFAULT_QUALITY;
\r
1288 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1289 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1293 CreateFontInMF(MyFont *mf)
\r
1295 LFfromMFP(&mf->lf, &mf->mfp);
\r
1296 if (mf->hf) DeleteObject(mf->hf);
\r
1297 mf->hf = CreateFontIndirect(&mf->lf);
\r
1300 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1302 colorVariable[] = {
\r
1303 &whitePieceColor,
\r
1304 &blackPieceColor,
\r
1305 &lightSquareColor,
\r
1306 &darkSquareColor,
\r
1307 &highlightSquareColor,
\r
1308 &premoveHighlightColor,
\r
1310 &consoleBackgroundColor,
\r
1311 &appData.fontForeColorWhite,
\r
1312 &appData.fontBackColorWhite,
\r
1313 &appData.fontForeColorBlack,
\r
1314 &appData.fontBackColorBlack,
\r
1315 &appData.evalHistColorWhite,
\r
1316 &appData.evalHistColorBlack,
\r
1317 &appData.highlightArrowColor,
\r
1320 /* Command line font name parser. NULL name means do nothing.
\r
1321 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1322 For backward compatibility, syntax without the colon is also
\r
1323 accepted, but font names with digits in them won't work in that case.
\r
1326 ParseFontName(char *name, MyFontParams *mfp)
\r
1329 if (name == NULL) return;
\r
1331 q = strchr(p, ':');
\r
1333 if (q - p >= sizeof(mfp->faceName))
\r
1334 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1335 memcpy(mfp->faceName, p, q - p);
\r
1336 mfp->faceName[q - p] = NULLCHAR;
\r
1339 q = mfp->faceName;
\r
1341 while (*p && !isdigit(*p)) {
\r
1343 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1344 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1346 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1349 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1350 mfp->pointSize = (float) atof(p);
\r
1351 mfp->bold = (strchr(p, 'b') != NULL);
\r
1352 mfp->italic = (strchr(p, 'i') != NULL);
\r
1353 mfp->underline = (strchr(p, 'u') != NULL);
\r
1354 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1355 mfp->charset = DEFAULT_CHARSET;
\r
1356 q = strchr(p, 'c');
\r
1358 mfp->charset = (BYTE) atoi(q+1);
\r
1362 ParseFont(char *name, int number)
\r
1363 { // wrapper to shield back-end from 'font'
\r
1364 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1369 { // in WB we have a 2D array of fonts; this initializes their description
\r
1371 /* Point font array elements to structures and
\r
1372 parse default font names */
\r
1373 for (i=0; i<NUM_FONTS; i++) {
\r
1374 for (j=0; j<NUM_SIZES; j++) {
\r
1375 font[j][i] = &fontRec[j][i];
\r
1376 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1383 { // here we create the actual fonts from the selected descriptions
\r
1385 for (i=0; i<NUM_FONTS; i++) {
\r
1386 for (j=0; j<NUM_SIZES; j++) {
\r
1387 CreateFontInMF(font[j][i]);
\r
1391 /* Color name parser.
\r
1392 X version accepts X color names, but this one
\r
1393 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1395 ParseColorName(char *name)
\r
1397 int red, green, blue, count;
\r
1398 char buf[MSG_SIZ];
\r
1400 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1402 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1403 &red, &green, &blue);
\r
1406 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1407 DisplayError(buf, 0);
\r
1408 return RGB(0, 0, 0);
\r
1410 return PALETTERGB(red, green, blue);
\r
1414 ParseColor(int n, char *name)
\r
1415 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1416 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1420 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1422 char *e = argValue;
\r
1426 if (*e == 'b') eff |= CFE_BOLD;
\r
1427 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1428 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1429 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1430 else if (*e == '#' || isdigit(*e)) break;
\r
1434 *color = ParseColorName(e);
\r
1438 ParseTextAttribs(ColorClass cc, char *s)
\r
1439 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1440 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1441 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1445 ParseBoardSize(void *addr, char *name)
\r
1446 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1447 BoardSize bs = SizeTiny;
\r
1448 while (sizeInfo[bs].name != NULL) {
\r
1449 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1450 *(BoardSize *)addr = bs;
\r
1455 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1460 { // [HGM] import name from appData first
\r
1463 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1464 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1465 textAttribs[cc].sound.data = NULL;
\r
1466 MyLoadSound(&textAttribs[cc].sound);
\r
1468 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1469 textAttribs[cc].sound.name = strdup("");
\r
1470 textAttribs[cc].sound.data = NULL;
\r
1472 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1473 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1474 sounds[sc].data = NULL;
\r
1475 MyLoadSound(&sounds[sc]);
\r
1480 SetCommPortDefaults()
\r
1482 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1483 dcb.DCBlength = sizeof(DCB);
\r
1484 dcb.BaudRate = 9600;
\r
1485 dcb.fBinary = TRUE;
\r
1486 dcb.fParity = FALSE;
\r
1487 dcb.fOutxCtsFlow = FALSE;
\r
1488 dcb.fOutxDsrFlow = FALSE;
\r
1489 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1490 dcb.fDsrSensitivity = FALSE;
\r
1491 dcb.fTXContinueOnXoff = TRUE;
\r
1492 dcb.fOutX = FALSE;
\r
1494 dcb.fNull = FALSE;
\r
1495 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1496 dcb.fAbortOnError = FALSE;
\r
1498 dcb.Parity = SPACEPARITY;
\r
1499 dcb.StopBits = ONESTOPBIT;
\r
1502 // [HGM] args: these three cases taken out to stay in front-end
\r
1504 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1505 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1506 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1507 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1509 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1510 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1511 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1512 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1513 ad->argName, mfp->faceName, mfp->pointSize,
\r
1514 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1515 mfp->bold ? "b" : "",
\r
1516 mfp->italic ? "i" : "",
\r
1517 mfp->underline ? "u" : "",
\r
1518 mfp->strikeout ? "s" : "",
\r
1519 (int)mfp->charset);
\r
1525 { // [HGM] copy the names from the internal WB variables to appData
\r
1528 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1529 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1530 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1531 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1535 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1536 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1537 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1538 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1539 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1540 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1541 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1542 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1543 (ta->effects) ? " " : "",
\r
1544 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1548 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1549 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1550 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1551 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1552 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1556 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1557 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1558 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1562 ParseCommPortSettings(char *s)
\r
1563 { // wrapper to keep dcb from back-end
\r
1564 ParseCommSettings(s, &dcb);
\r
1569 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1570 GetActualPlacement(hwndMain, &wpMain);
\r
1571 GetActualPlacement(hwndConsole, &wpConsole);
\r
1572 GetActualPlacement(commentDialog, &wpComment);
\r
1573 GetActualPlacement(editTagsDialog, &wpTags);
\r
1574 GetActualPlacement(gameListDialog, &wpGameList);
\r
1575 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1576 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1577 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1581 PrintCommPortSettings(FILE *f, char *name)
\r
1582 { // wrapper to shield back-end from DCB
\r
1583 PrintCommSettings(f, name, &dcb);
\r
1587 MySearchPath(char *installDir, char *name, char *fullname)
\r
1589 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1590 if(name[0]== '%') {
\r
1591 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1592 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1593 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1594 *strchr(buf, '%') = 0;
\r
1595 strcat(fullname, getenv(buf));
\r
1596 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1598 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1599 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1600 return (int) strlen(fullname);
\r
1602 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1606 MyGetFullPathName(char *name, char *fullname)
\r
1609 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1614 { // [HGM] args: allows testing if main window is realized from back-end
\r
1615 return hwndMain != NULL;
\r
1619 PopUpStartupDialog()
\r
1623 LoadLanguageFile(appData.language);
\r
1624 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1625 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1626 FreeProcInstance(lpProc);
\r
1629 /*---------------------------------------------------------------------------*\
\r
1631 * GDI board drawing routines
\r
1633 \*---------------------------------------------------------------------------*/
\r
1635 /* [AS] Draw square using background texture */
\r
1636 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1641 return; /* Should never happen! */
\r
1644 SetGraphicsMode( dst, GM_ADVANCED );
\r
1651 /* X reflection */
\r
1656 x.eDx = (FLOAT) dw + dx - 1;
\r
1659 SetWorldTransform( dst, &x );
\r
1662 /* Y reflection */
\r
1668 x.eDy = (FLOAT) dh + dy - 1;
\r
1670 SetWorldTransform( dst, &x );
\r
1678 x.eDx = (FLOAT) dx;
\r
1679 x.eDy = (FLOAT) dy;
\r
1682 SetWorldTransform( dst, &x );
\r
1686 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1694 SetWorldTransform( dst, &x );
\r
1696 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1699 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1701 PM_WP = (int) WhitePawn,
\r
1702 PM_WN = (int) WhiteKnight,
\r
1703 PM_WB = (int) WhiteBishop,
\r
1704 PM_WR = (int) WhiteRook,
\r
1705 PM_WQ = (int) WhiteQueen,
\r
1706 PM_WF = (int) WhiteFerz,
\r
1707 PM_WW = (int) WhiteWazir,
\r
1708 PM_WE = (int) WhiteAlfil,
\r
1709 PM_WM = (int) WhiteMan,
\r
1710 PM_WO = (int) WhiteCannon,
\r
1711 PM_WU = (int) WhiteUnicorn,
\r
1712 PM_WH = (int) WhiteNightrider,
\r
1713 PM_WA = (int) WhiteAngel,
\r
1714 PM_WC = (int) WhiteMarshall,
\r
1715 PM_WAB = (int) WhiteCardinal,
\r
1716 PM_WD = (int) WhiteDragon,
\r
1717 PM_WL = (int) WhiteLance,
\r
1718 PM_WS = (int) WhiteCobra,
\r
1719 PM_WV = (int) WhiteFalcon,
\r
1720 PM_WSG = (int) WhiteSilver,
\r
1721 PM_WG = (int) WhiteGrasshopper,
\r
1722 PM_WK = (int) WhiteKing,
\r
1723 PM_BP = (int) BlackPawn,
\r
1724 PM_BN = (int) BlackKnight,
\r
1725 PM_BB = (int) BlackBishop,
\r
1726 PM_BR = (int) BlackRook,
\r
1727 PM_BQ = (int) BlackQueen,
\r
1728 PM_BF = (int) BlackFerz,
\r
1729 PM_BW = (int) BlackWazir,
\r
1730 PM_BE = (int) BlackAlfil,
\r
1731 PM_BM = (int) BlackMan,
\r
1732 PM_BO = (int) BlackCannon,
\r
1733 PM_BU = (int) BlackUnicorn,
\r
1734 PM_BH = (int) BlackNightrider,
\r
1735 PM_BA = (int) BlackAngel,
\r
1736 PM_BC = (int) BlackMarshall,
\r
1737 PM_BG = (int) BlackGrasshopper,
\r
1738 PM_BAB = (int) BlackCardinal,
\r
1739 PM_BD = (int) BlackDragon,
\r
1740 PM_BL = (int) BlackLance,
\r
1741 PM_BS = (int) BlackCobra,
\r
1742 PM_BV = (int) BlackFalcon,
\r
1743 PM_BSG = (int) BlackSilver,
\r
1744 PM_BK = (int) BlackKing
\r
1747 static HFONT hPieceFont = NULL;
\r
1748 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1749 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1750 static int fontBitmapSquareSize = 0;
\r
1751 static char pieceToFontChar[(int) EmptySquare] =
\r
1752 { 'p', 'n', 'b', 'r', 'q',
\r
1753 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1754 'k', 'o', 'm', 'v', 't', 'w',
\r
1755 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1758 extern BOOL SetCharTable( char *table, const char * map );
\r
1759 /* [HGM] moved to backend.c */
\r
1761 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1764 BYTE r1 = GetRValue( color );
\r
1765 BYTE g1 = GetGValue( color );
\r
1766 BYTE b1 = GetBValue( color );
\r
1772 /* Create a uniform background first */
\r
1773 hbrush = CreateSolidBrush( color );
\r
1774 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1775 FillRect( hdc, &rc, hbrush );
\r
1776 DeleteObject( hbrush );
\r
1779 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1780 int steps = squareSize / 2;
\r
1783 for( i=0; i<steps; i++ ) {
\r
1784 BYTE r = r1 - (r1-r2) * i / steps;
\r
1785 BYTE g = g1 - (g1-g2) * i / steps;
\r
1786 BYTE b = b1 - (b1-b2) * i / steps;
\r
1788 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1789 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1790 FillRect( hdc, &rc, hbrush );
\r
1791 DeleteObject(hbrush);
\r
1794 else if( mode == 2 ) {
\r
1795 /* Diagonal gradient, good more or less for every piece */
\r
1796 POINT triangle[3];
\r
1797 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1798 HBRUSH hbrush_old;
\r
1799 int steps = squareSize;
\r
1802 triangle[0].x = squareSize - steps;
\r
1803 triangle[0].y = squareSize;
\r
1804 triangle[1].x = squareSize;
\r
1805 triangle[1].y = squareSize;
\r
1806 triangle[2].x = squareSize;
\r
1807 triangle[2].y = squareSize - steps;
\r
1809 for( i=0; i<steps; i++ ) {
\r
1810 BYTE r = r1 - (r1-r2) * i / steps;
\r
1811 BYTE g = g1 - (g1-g2) * i / steps;
\r
1812 BYTE b = b1 - (b1-b2) * i / steps;
\r
1814 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1815 hbrush_old = SelectObject( hdc, hbrush );
\r
1816 Polygon( hdc, triangle, 3 );
\r
1817 SelectObject( hdc, hbrush_old );
\r
1818 DeleteObject(hbrush);
\r
1823 SelectObject( hdc, hpen );
\r
1828 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1829 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1830 piece: follow the steps as explained below.
\r
1832 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1836 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1842 int backColor = whitePieceColor;
\r
1843 int foreColor = blackPieceColor;
\r
1845 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1846 backColor = appData.fontBackColorWhite;
\r
1847 foreColor = appData.fontForeColorWhite;
\r
1849 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1850 backColor = appData.fontBackColorBlack;
\r
1851 foreColor = appData.fontForeColorBlack;
\r
1855 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1857 hbm_old = SelectObject( hdc, hbm );
\r
1861 rc.right = squareSize;
\r
1862 rc.bottom = squareSize;
\r
1864 /* Step 1: background is now black */
\r
1865 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1867 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1869 pt.x = (squareSize - sz.cx) / 2;
\r
1870 pt.y = (squareSize - sz.cy) / 2;
\r
1872 SetBkMode( hdc, TRANSPARENT );
\r
1873 SetTextColor( hdc, chroma );
\r
1874 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1875 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1877 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1878 /* Step 3: the area outside the piece is filled with white */
\r
1879 // FloodFill( hdc, 0, 0, chroma );
\r
1880 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1881 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1882 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1883 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1884 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1886 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1887 but if the start point is not inside the piece we're lost!
\r
1888 There should be a better way to do this... if we could create a region or path
\r
1889 from the fill operation we would be fine for example.
\r
1891 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1892 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1894 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1895 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1896 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1898 SelectObject( dc2, bm2 );
\r
1899 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1900 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1901 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1902 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1903 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1906 DeleteObject( bm2 );
\r
1909 SetTextColor( hdc, 0 );
\r
1911 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1912 draw the piece again in black for safety.
\r
1914 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1916 SelectObject( hdc, hbm_old );
\r
1918 if( hPieceMask[index] != NULL ) {
\r
1919 DeleteObject( hPieceMask[index] );
\r
1922 hPieceMask[index] = hbm;
\r
1925 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1927 SelectObject( hdc, hbm );
\r
1930 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1931 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1932 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1934 SelectObject( dc1, hPieceMask[index] );
\r
1935 SelectObject( dc2, bm2 );
\r
1936 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1937 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1940 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1941 the piece background and deletes (makes transparent) the rest.
\r
1942 Thanks to that mask, we are free to paint the background with the greates
\r
1943 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1944 We use this, to make gradients and give the pieces a "roundish" look.
\r
1946 SetPieceBackground( hdc, backColor, 2 );
\r
1947 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1951 DeleteObject( bm2 );
\r
1954 SetTextColor( hdc, foreColor );
\r
1955 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1957 SelectObject( hdc, hbm_old );
\r
1959 if( hPieceFace[index] != NULL ) {
\r
1960 DeleteObject( hPieceFace[index] );
\r
1963 hPieceFace[index] = hbm;
\r
1966 static int TranslatePieceToFontPiece( int piece )
\r
1996 case BlackMarshall:
\r
2000 case BlackNightrider:
\r
2006 case BlackUnicorn:
\r
2010 case BlackGrasshopper:
\r
2022 case BlackCardinal:
\r
2029 case WhiteMarshall:
\r
2033 case WhiteNightrider:
\r
2039 case WhiteUnicorn:
\r
2043 case WhiteGrasshopper:
\r
2055 case WhiteCardinal:
\r
2064 void CreatePiecesFromFont()
\r
2067 HDC hdc_window = NULL;
\r
2073 if( fontBitmapSquareSize < 0 ) {
\r
2074 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2078 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2079 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2080 fontBitmapSquareSize = -1;
\r
2084 if( fontBitmapSquareSize != squareSize ) {
\r
2085 hdc_window = GetDC( hwndMain );
\r
2086 hdc = CreateCompatibleDC( hdc_window );
\r
2088 if( hPieceFont != NULL ) {
\r
2089 DeleteObject( hPieceFont );
\r
2092 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2093 hPieceMask[i] = NULL;
\r
2094 hPieceFace[i] = NULL;
\r
2100 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2101 fontHeight = appData.fontPieceSize;
\r
2104 fontHeight = (fontHeight * squareSize) / 100;
\r
2106 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2108 lf.lfEscapement = 0;
\r
2109 lf.lfOrientation = 0;
\r
2110 lf.lfWeight = FW_NORMAL;
\r
2112 lf.lfUnderline = 0;
\r
2113 lf.lfStrikeOut = 0;
\r
2114 lf.lfCharSet = DEFAULT_CHARSET;
\r
2115 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2116 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2117 lf.lfQuality = PROOF_QUALITY;
\r
2118 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2119 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2120 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2122 hPieceFont = CreateFontIndirect( &lf );
\r
2124 if( hPieceFont == NULL ) {
\r
2125 fontBitmapSquareSize = -2;
\r
2128 /* Setup font-to-piece character table */
\r
2129 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2130 /* No (or wrong) global settings, try to detect the font */
\r
2131 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2133 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2135 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2136 /* DiagramTT* family */
\r
2137 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2139 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2140 /* Fairy symbols */
\r
2141 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2143 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2144 /* Good Companion (Some characters get warped as literal :-( */
\r
2145 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2146 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2147 SetCharTable(pieceToFontChar, s);
\r
2150 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2151 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2155 /* Create bitmaps */
\r
2156 hfont_old = SelectObject( hdc, hPieceFont );
\r
2157 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2158 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2159 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2161 SelectObject( hdc, hfont_old );
\r
2163 fontBitmapSquareSize = squareSize;
\r
2167 if( hdc != NULL ) {
\r
2171 if( hdc_window != NULL ) {
\r
2172 ReleaseDC( hwndMain, hdc_window );
\r
2177 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2179 char name[128], buf[MSG_SIZ];
\r
2181 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2182 if(appData.pieceDirectory[0]) {
\r
2184 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2185 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2186 if(res) return res;
\r
2188 if (gameInfo.event &&
\r
2189 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2190 strcmp(name, "k80s") == 0) {
\r
2191 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2193 return LoadBitmap(hinst, name);
\r
2197 /* Insert a color into the program's logical palette
\r
2198 structure. This code assumes the given color is
\r
2199 the result of the RGB or PALETTERGB macro, and it
\r
2200 knows how those macros work (which is documented).
\r
2203 InsertInPalette(COLORREF color)
\r
2205 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2207 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2208 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2209 pLogPal->palNumEntries--;
\r
2213 pe->peFlags = (char) 0;
\r
2214 pe->peRed = (char) (0xFF & color);
\r
2215 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2216 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2222 InitDrawingColors()
\r
2225 if (pLogPal == NULL) {
\r
2226 /* Allocate enough memory for a logical palette with
\r
2227 * PALETTESIZE entries and set the size and version fields
\r
2228 * of the logical palette structure.
\r
2230 pLogPal = (NPLOGPALETTE)
\r
2231 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2232 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2233 pLogPal->palVersion = 0x300;
\r
2235 pLogPal->palNumEntries = 0;
\r
2237 InsertInPalette(lightSquareColor);
\r
2238 InsertInPalette(darkSquareColor);
\r
2239 InsertInPalette(whitePieceColor);
\r
2240 InsertInPalette(blackPieceColor);
\r
2241 InsertInPalette(highlightSquareColor);
\r
2242 InsertInPalette(premoveHighlightColor);
\r
2244 /* create a logical color palette according the information
\r
2245 * in the LOGPALETTE structure.
\r
2247 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2249 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2250 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2251 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2252 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2253 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2254 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2255 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2256 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2258 /* [AS] Force rendering of the font-based pieces */
\r
2259 if( fontBitmapSquareSize > 0 ) {
\r
2260 fontBitmapSquareSize = 0;
\r
2266 BoardWidth(int boardSize, int n)
\r
2267 { /* [HGM] argument n added to allow different width and height */
\r
2268 int lineGap = sizeInfo[boardSize].lineGap;
\r
2270 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2271 lineGap = appData.overrideLineGap;
\r
2274 return (n + 1) * lineGap +
\r
2275 n * sizeInfo[boardSize].squareSize;
\r
2278 /* Respond to board resize by dragging edge */
\r
2280 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2282 BoardSize newSize = NUM_SIZES - 1;
\r
2283 static int recurse = 0;
\r
2284 if (IsIconic(hwndMain)) return;
\r
2285 if (recurse > 0) return;
\r
2287 while (newSize > 0) {
\r
2288 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2289 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2290 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2293 boardSize = newSize;
\r
2294 InitDrawingSizes(boardSize, flags);
\r
2299 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2302 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2304 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2305 ChessSquare piece;
\r
2306 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2308 SIZE clockSize, messageSize;
\r
2310 char buf[MSG_SIZ];
\r
2312 HMENU hmenu = GetMenu(hwndMain);
\r
2313 RECT crect, wrect, oldRect;
\r
2315 LOGBRUSH logbrush;
\r
2316 VariantClass v = gameInfo.variant;
\r
2318 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2319 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2321 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2322 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2323 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2324 oldBoardSize = boardSize;
\r
2326 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2327 { // correct board size to one where built-in pieces exist
\r
2328 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2329 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2331 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2332 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2333 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2334 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2335 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2336 boardSize = SizeMiddling;
\r
2339 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2341 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2342 oldRect.top = wpMain.y;
\r
2343 oldRect.right = wpMain.x + wpMain.width;
\r
2344 oldRect.bottom = wpMain.y + wpMain.height;
\r
2346 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2347 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2348 squareSize = sizeInfo[boardSize].squareSize;
\r
2349 lineGap = sizeInfo[boardSize].lineGap;
\r
2350 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2351 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2353 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2354 lineGap = appData.overrideLineGap;
\r
2357 if (tinyLayout != oldTinyLayout) {
\r
2358 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2360 style &= ~WS_SYSMENU;
\r
2361 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2362 "&Minimize\tCtrl+F4");
\r
2364 style |= WS_SYSMENU;
\r
2365 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2367 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2369 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2370 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2371 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2373 DrawMenuBar(hwndMain);
\r
2376 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2377 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2379 /* Get text area sizes */
\r
2380 hdc = GetDC(hwndMain);
\r
2381 if (appData.clockMode) {
\r
2382 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2384 snprintf(buf, MSG_SIZ, _("White"));
\r
2386 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2387 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2388 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2389 str = _("We only care about the height here");
\r
2390 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2391 SelectObject(hdc, oldFont);
\r
2392 ReleaseDC(hwndMain, hdc);
\r
2394 /* Compute where everything goes */
\r
2395 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2396 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2397 logoHeight = 2*clockSize.cy;
\r
2398 leftLogoRect.left = OUTER_MARGIN;
\r
2399 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2400 leftLogoRect.top = OUTER_MARGIN;
\r
2401 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2403 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2404 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2405 rightLogoRect.top = OUTER_MARGIN;
\r
2406 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2409 whiteRect.left = leftLogoRect.right;
\r
2410 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2411 whiteRect.top = OUTER_MARGIN;
\r
2412 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2414 blackRect.right = rightLogoRect.left;
\r
2415 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2416 blackRect.top = whiteRect.top;
\r
2417 blackRect.bottom = whiteRect.bottom;
\r
2419 whiteRect.left = OUTER_MARGIN;
\r
2420 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2421 whiteRect.top = OUTER_MARGIN;
\r
2422 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2424 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2425 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2426 blackRect.top = whiteRect.top;
\r
2427 blackRect.bottom = whiteRect.bottom;
\r
2429 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2432 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2433 if (appData.showButtonBar) {
\r
2434 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2435 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2437 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2439 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2440 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2442 boardRect.left = OUTER_MARGIN;
\r
2443 boardRect.right = boardRect.left + boardWidth;
\r
2444 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2445 boardRect.bottom = boardRect.top + boardHeight;
\r
2447 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2448 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2449 oldTinyLayout = tinyLayout;
\r
2450 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2451 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2452 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2453 winW *= 1 + twoBoards;
\r
2454 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2455 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2456 wpMain.height = winH; // without disturbing window attachments
\r
2457 GetWindowRect(hwndMain, &wrect);
\r
2458 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2459 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2461 // [HGM] placement: let attached windows follow size change.
\r
2462 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2463 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2464 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2465 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2466 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2468 /* compensate if menu bar wrapped */
\r
2469 GetClientRect(hwndMain, &crect);
\r
2470 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2471 wpMain.height += offby;
\r
2473 case WMSZ_TOPLEFT:
\r
2474 SetWindowPos(hwndMain, NULL,
\r
2475 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2476 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2479 case WMSZ_TOPRIGHT:
\r
2481 SetWindowPos(hwndMain, NULL,
\r
2482 wrect.left, wrect.bottom - wpMain.height,
\r
2483 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2486 case WMSZ_BOTTOMLEFT:
\r
2488 SetWindowPos(hwndMain, NULL,
\r
2489 wrect.right - wpMain.width, wrect.top,
\r
2490 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2493 case WMSZ_BOTTOMRIGHT:
\r
2497 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2498 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2503 for (i = 0; i < N_BUTTONS; i++) {
\r
2504 if (buttonDesc[i].hwnd != NULL) {
\r
2505 DestroyWindow(buttonDesc[i].hwnd);
\r
2506 buttonDesc[i].hwnd = NULL;
\r
2508 if (appData.showButtonBar) {
\r
2509 buttonDesc[i].hwnd =
\r
2510 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2511 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2512 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2513 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2514 (HMENU) buttonDesc[i].id,
\r
2515 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2517 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2518 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2519 MAKELPARAM(FALSE, 0));
\r
2521 if (buttonDesc[i].id == IDM_Pause)
\r
2522 hwndPause = buttonDesc[i].hwnd;
\r
2523 buttonDesc[i].wndproc = (WNDPROC)
\r
2524 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2527 if (gridPen != NULL) DeleteObject(gridPen);
\r
2528 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2529 if (premovePen != NULL) DeleteObject(premovePen);
\r
2530 if (lineGap != 0) {
\r
2531 logbrush.lbStyle = BS_SOLID;
\r
2532 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2534 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2535 lineGap, &logbrush, 0, NULL);
\r
2536 logbrush.lbColor = highlightSquareColor;
\r
2538 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2539 lineGap, &logbrush, 0, NULL);
\r
2541 logbrush.lbColor = premoveHighlightColor;
\r
2543 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2544 lineGap, &logbrush, 0, NULL);
\r
2546 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2547 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2548 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2549 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2550 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2551 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2552 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2553 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2555 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2556 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2557 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2558 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2559 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2560 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2561 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2562 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2566 /* [HGM] Licensing requirement */
\r
2568 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2571 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2573 GothicPopUp( "", VariantNormal);
\r
2576 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2578 /* Load piece bitmaps for this board size */
\r
2579 for (i=0; i<=2; i++) {
\r
2580 for (piece = WhitePawn;
\r
2581 (int) piece < (int) BlackPawn;
\r
2582 piece = (ChessSquare) ((int) piece + 1)) {
\r
2583 if (pieceBitmap[i][piece] != NULL)
\r
2584 DeleteObject(pieceBitmap[i][piece]);
\r
2588 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2589 // Orthodox Chess pieces
\r
2590 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2591 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2592 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2593 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2594 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2595 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2596 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2597 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2598 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2599 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2600 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2601 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2602 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2603 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2604 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2605 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2606 // in Shogi, Hijack the unused Queen for Lance
\r
2607 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2608 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2609 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2611 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2612 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2613 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2616 if(squareSize <= 72 && squareSize >= 33) {
\r
2617 /* A & C are available in most sizes now */
\r
2618 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2619 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2620 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2621 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2622 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2623 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2624 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2625 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2626 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2627 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2628 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2629 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2630 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2631 } else { // Smirf-like
\r
2632 if(gameInfo.variant == VariantSChess) {
\r
2633 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2634 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2635 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2637 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2638 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2639 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2642 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2643 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2644 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2645 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2646 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2647 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2648 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2649 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2650 } else { // WinBoard standard
\r
2651 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2652 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2653 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2658 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2659 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2660 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2661 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2662 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2663 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2664 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2665 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2666 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2667 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2668 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2669 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2670 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2671 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2672 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2673 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2674 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2677 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2678 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2679 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2680 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2681 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2682 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2683 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2684 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2685 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2686 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2687 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2688 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2689 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2690 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2691 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2693 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2694 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2695 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2696 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2697 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2698 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2699 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2700 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2701 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2702 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2703 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2704 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2705 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2707 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2708 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2709 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2710 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2711 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2712 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2713 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2714 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2715 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2716 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2717 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2718 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2721 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2722 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2723 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2724 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2725 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2726 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2727 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2728 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2729 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2730 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2731 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2732 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2733 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2734 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2735 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2739 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2740 /* special Shogi support in this size */
\r
2741 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2742 for (piece = WhitePawn;
\r
2743 (int) piece < (int) BlackPawn;
\r
2744 piece = (ChessSquare) ((int) piece + 1)) {
\r
2745 if (pieceBitmap[i][piece] != NULL)
\r
2746 DeleteObject(pieceBitmap[i][piece]);
\r
2749 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2750 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2751 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2752 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2753 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2754 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2755 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2756 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2757 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2758 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2762 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2763 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2764 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2765 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2766 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2767 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2768 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2769 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2770 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2771 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2772 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2776 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2777 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2778 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2779 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2780 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2781 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2782 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2783 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2784 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2785 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2786 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2790 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2796 PieceBitmap(ChessSquare p, int kind)
\r
2798 if ((int) p >= (int) BlackPawn)
\r
2799 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2801 return pieceBitmap[kind][(int) p];
\r
2804 /***************************************************************/
\r
2806 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2807 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2809 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2810 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2814 SquareToPos(int row, int column, int * x, int * y)
\r
2817 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2818 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2820 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2821 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2826 DrawCoordsOnDC(HDC hdc)
\r
2828 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2829 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2830 char str[2] = { NULLCHAR, NULLCHAR };
\r
2831 int oldMode, oldAlign, x, y, start, i;
\r
2835 if (!appData.showCoords)
\r
2838 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2840 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2841 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2842 oldAlign = GetTextAlign(hdc);
\r
2843 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2845 y = boardRect.top + lineGap;
\r
2846 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2849 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2850 x += border - lineGap - 4; y += squareSize - 6;
\r
2852 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2853 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2854 str[0] = files[start + i];
\r
2855 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2856 y += squareSize + lineGap;
\r
2859 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2862 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2863 x += -border + 4; y += border - squareSize + 6;
\r
2865 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2866 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2867 str[0] = ranks[start + i];
\r
2868 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2869 x += squareSize + lineGap;
\r
2872 SelectObject(hdc, oldBrush);
\r
2873 SetBkMode(hdc, oldMode);
\r
2874 SetTextAlign(hdc, oldAlign);
\r
2875 SelectObject(hdc, oldFont);
\r
2879 DrawGridOnDC(HDC hdc)
\r
2883 if (lineGap != 0) {
\r
2884 oldPen = SelectObject(hdc, gridPen);
\r
2885 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2886 SelectObject(hdc, oldPen);
\r
2890 #define HIGHLIGHT_PEN 0
\r
2891 #define PREMOVE_PEN 1
\r
2894 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2897 HPEN oldPen, hPen;
\r
2898 if (lineGap == 0) return;
\r
2900 x1 = boardRect.left +
\r
2901 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2902 y1 = boardRect.top +
\r
2903 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2905 x1 = boardRect.left +
\r
2906 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2907 y1 = boardRect.top +
\r
2908 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2910 hPen = pen ? premovePen : highlightPen;
\r
2911 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2912 MoveToEx(hdc, x1, y1, NULL);
\r
2913 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2914 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2915 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2916 LineTo(hdc, x1, y1);
\r
2917 SelectObject(hdc, oldPen);
\r
2921 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2924 for (i=0; i<2; i++) {
\r
2925 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2926 DrawHighlightOnDC(hdc, TRUE,
\r
2927 h->sq[i].x, h->sq[i].y,
\r
2932 /* Note: sqcolor is used only in monoMode */
\r
2933 /* Note that this code is largely duplicated in woptions.c,
\r
2934 function DrawSampleSquare, so that needs to be updated too */
\r
2936 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2938 HBITMAP oldBitmap;
\r
2942 if (appData.blindfold) return;
\r
2944 /* [AS] Use font-based pieces if needed */
\r
2945 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2946 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2947 CreatePiecesFromFont();
\r
2949 if( fontBitmapSquareSize == squareSize ) {
\r
2950 int index = TranslatePieceToFontPiece(piece);
\r
2952 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2954 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2955 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2959 squareSize, squareSize,
\r
2964 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2966 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2967 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2971 squareSize, squareSize,
\r
2980 if (appData.monoMode) {
\r
2981 SelectObject(tmphdc, PieceBitmap(piece,
\r
2982 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2983 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2984 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2986 HBRUSH xBrush = whitePieceBrush;
\r
2987 tmpSize = squareSize;
\r
2988 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2990 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2991 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2992 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2993 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2994 x += (squareSize - minorSize)>>1;
\r
2995 y += squareSize - minorSize - 2;
\r
2996 tmpSize = minorSize;
\r
2998 if (color || appData.allWhite ) {
\r
2999 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3001 oldBrush = SelectObject(hdc, xBrush);
\r
3002 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3003 if(appData.upsideDown && color==flipView)
\r
3004 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3006 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3007 /* Use black for outline of white pieces */
\r
3008 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3009 if(appData.upsideDown && color==flipView)
\r
3010 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3012 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3013 } else if(appData.pieceDirectory[0]) {
\r
3014 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3015 oldBrush = SelectObject(hdc, xBrush);
\r
3016 if(appData.upsideDown && color==flipView)
\r
3017 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3019 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3020 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3021 if(appData.upsideDown && color==flipView)
\r
3022 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3024 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3026 /* Use square color for details of black pieces */
\r
3027 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3028 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3029 if(appData.upsideDown && !flipView)
\r
3030 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3032 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3034 SelectObject(hdc, oldBrush);
\r
3035 SelectObject(tmphdc, oldBitmap);
\r
3039 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3040 int GetBackTextureMode( int algo )
\r
3042 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3046 case BACK_TEXTURE_MODE_PLAIN:
\r
3047 result = 1; /* Always use identity map */
\r
3049 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3050 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3058 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3059 to handle redraws cleanly (as random numbers would always be different).
\r
3061 VOID RebuildTextureSquareInfo()
\r
3071 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3073 if( liteBackTexture != NULL ) {
\r
3074 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3075 lite_w = bi.bmWidth;
\r
3076 lite_h = bi.bmHeight;
\r
3080 if( darkBackTexture != NULL ) {
\r
3081 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3082 dark_w = bi.bmWidth;
\r
3083 dark_h = bi.bmHeight;
\r
3087 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3088 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3089 if( (col + row) & 1 ) {
\r
3091 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3092 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3093 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3095 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3096 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3097 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3099 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3100 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3105 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3106 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3107 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3109 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3110 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3111 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3113 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3114 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3121 /* [AS] Arrow highlighting support */
\r
3123 static double A_WIDTH = 5; /* Width of arrow body */
\r
3125 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3126 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3128 static double Sqr( double x )
\r
3133 static int Round( double x )
\r
3135 return (int) (x + 0.5);
\r
3138 /* Draw an arrow between two points using current settings */
\r
3139 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3142 double dx, dy, j, k, x, y;
\r
3144 if( d_x == s_x ) {
\r
3145 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3147 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3150 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3151 arrow[1].y = d_y - h;
\r
3153 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3154 arrow[2].y = d_y - h;
\r
3159 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3160 arrow[5].y = d_y - h;
\r
3162 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3163 arrow[4].y = d_y - h;
\r
3165 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3168 else if( d_y == s_y ) {
\r
3169 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3172 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3174 arrow[1].x = d_x - w;
\r
3175 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3177 arrow[2].x = d_x - w;
\r
3178 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3183 arrow[5].x = d_x - w;
\r
3184 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3186 arrow[4].x = d_x - w;
\r
3187 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3190 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3193 /* [AS] Needed a lot of paper for this! :-) */
\r
3194 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3195 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3197 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3199 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3204 arrow[0].x = Round(x - j);
\r
3205 arrow[0].y = Round(y + j*dx);
\r
3207 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3208 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3211 x = (double) d_x - k;
\r
3212 y = (double) d_y - k*dy;
\r
3215 x = (double) d_x + k;
\r
3216 y = (double) d_y + k*dy;
\r
3219 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3221 arrow[6].x = Round(x - j);
\r
3222 arrow[6].y = Round(y + j*dx);
\r
3224 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3225 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3227 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3228 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3233 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3234 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3237 Polygon( hdc, arrow, 7 );
\r
3240 /* [AS] Draw an arrow between two squares */
\r
3241 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3243 int s_x, s_y, d_x, d_y;
\r
3250 if( s_col == d_col && s_row == d_row ) {
\r
3254 /* Get source and destination points */
\r
3255 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3256 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3259 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3261 else if( d_y < s_y ) {
\r
3262 d_y += squareSize / 2 + squareSize / 4;
\r
3265 d_y += squareSize / 2;
\r
3269 d_x += squareSize / 2 - squareSize / 4;
\r
3271 else if( d_x < s_x ) {
\r
3272 d_x += squareSize / 2 + squareSize / 4;
\r
3275 d_x += squareSize / 2;
\r
3278 s_x += squareSize / 2;
\r
3279 s_y += squareSize / 2;
\r
3281 /* Adjust width */
\r
3282 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3285 stLB.lbStyle = BS_SOLID;
\r
3286 stLB.lbColor = appData.highlightArrowColor;
\r
3289 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3290 holdpen = SelectObject( hdc, hpen );
\r
3291 hbrush = CreateBrushIndirect( &stLB );
\r
3292 holdbrush = SelectObject( hdc, hbrush );
\r
3294 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3296 SelectObject( hdc, holdpen );
\r
3297 SelectObject( hdc, holdbrush );
\r
3298 DeleteObject( hpen );
\r
3299 DeleteObject( hbrush );
\r
3302 BOOL HasHighlightInfo()
\r
3304 BOOL result = FALSE;
\r
3306 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3307 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3318 BOOL IsDrawArrowEnabled()
\r
3320 BOOL result = FALSE;
\r
3322 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3329 VOID DrawArrowHighlight( HDC hdc )
\r
3331 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3332 DrawArrowBetweenSquares( hdc,
\r
3333 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3334 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3338 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3340 HRGN result = NULL;
\r
3342 if( HasHighlightInfo() ) {
\r
3343 int x1, y1, x2, y2;
\r
3344 int sx, sy, dx, dy;
\r
3346 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3347 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3349 sx = MIN( x1, x2 );
\r
3350 sy = MIN( y1, y2 );
\r
3351 dx = MAX( x1, x2 ) + squareSize;
\r
3352 dy = MAX( y1, y2 ) + squareSize;
\r
3354 result = CreateRectRgn( sx, sy, dx, dy );
\r
3361 Warning: this function modifies the behavior of several other functions.
\r
3363 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3364 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3365 repaint is scattered all over the place, which is not good for features such as
\r
3366 "arrow highlighting" that require a full repaint of the board.
\r
3368 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3369 user interaction, when speed is not so important) but especially to avoid errors
\r
3370 in the displayed graphics.
\r
3372 In such patched places, I always try refer to this function so there is a single
\r
3373 place to maintain knowledge.
\r
3375 To restore the original behavior, just return FALSE unconditionally.
\r
3377 BOOL IsFullRepaintPreferrable()
\r
3379 BOOL result = FALSE;
\r
3381 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3382 /* Arrow may appear on the board */
\r
3390 This function is called by DrawPosition to know whether a full repaint must
\r
3393 Only DrawPosition may directly call this function, which makes use of
\r
3394 some state information. Other function should call DrawPosition specifying
\r
3395 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3397 BOOL DrawPositionNeedsFullRepaint()
\r
3399 BOOL result = FALSE;
\r
3402 Probably a slightly better policy would be to trigger a full repaint
\r
3403 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3404 but animation is fast enough that it's difficult to notice.
\r
3406 if( animInfo.piece == EmptySquare ) {
\r
3407 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3415 static HBITMAP borderBitmap;
\r
3418 DrawBackgroundOnDC(HDC hdc)
\r
3424 static char oldBorder[MSG_SIZ];
\r
3425 int w = 600, h = 600, mode;
\r
3427 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3428 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3429 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3431 if(borderBitmap == NULL) { // loading failed, use white
\r
3432 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3435 tmphdc = CreateCompatibleDC(hdc);
\r
3436 hbm = SelectObject(tmphdc, borderBitmap);
\r
3437 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3441 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3442 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3443 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3444 SetStretchBltMode(hdc, mode);
\r
3445 SelectObject(tmphdc, hbm);
\r
3450 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3452 int row, column, x, y, square_color, piece_color;
\r
3453 ChessSquare piece;
\r
3455 HDC texture_hdc = NULL;
\r
3457 /* [AS] Initialize background textures if needed */
\r
3458 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3459 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3460 if( backTextureSquareSize != squareSize
\r
3461 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3462 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3463 backTextureSquareSize = squareSize;
\r
3464 RebuildTextureSquareInfo();
\r
3467 texture_hdc = CreateCompatibleDC( hdc );
\r
3470 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3471 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3473 SquareToPos(row, column, &x, &y);
\r
3475 piece = board[row][column];
\r
3477 square_color = ((column + row) % 2) == 1;
\r
3478 if( gameInfo.variant == VariantXiangqi ) {
\r
3479 square_color = !InPalace(row, column);
\r
3480 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3481 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3483 piece_color = (int) piece < (int) BlackPawn;
\r
3486 /* [HGM] holdings file: light square or black */
\r
3487 if(column == BOARD_LEFT-2) {
\r
3488 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3491 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3495 if(column == BOARD_RGHT + 1 ) {
\r
3496 if( row < gameInfo.holdingsSize )
\r
3499 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3503 if(column == BOARD_LEFT-1 ) /* left align */
\r
3504 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3505 else if( column == BOARD_RGHT) /* right align */
\r
3506 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3507 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3509 if (appData.monoMode) {
\r
3510 if (piece == EmptySquare) {
\r
3511 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3512 square_color ? WHITENESS : BLACKNESS);
\r
3514 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3517 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3518 /* [AS] Draw the square using a texture bitmap */
\r
3519 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3520 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3521 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3524 squareSize, squareSize,
\r
3527 backTextureSquareInfo[r][c].mode,
\r
3528 backTextureSquareInfo[r][c].x,
\r
3529 backTextureSquareInfo[r][c].y );
\r
3531 SelectObject( texture_hdc, hbm );
\r
3533 if (piece != EmptySquare) {
\r
3534 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3538 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3540 oldBrush = SelectObject(hdc, brush );
\r
3541 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3542 SelectObject(hdc, oldBrush);
\r
3543 if (piece != EmptySquare)
\r
3544 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3549 if( texture_hdc != NULL ) {
\r
3550 DeleteDC( texture_hdc );
\r
3554 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3555 void fputDW(FILE *f, int x)
\r
3557 fputc(x & 255, f);
\r
3558 fputc(x>>8 & 255, f);
\r
3559 fputc(x>>16 & 255, f);
\r
3560 fputc(x>>24 & 255, f);
\r
3563 #define MAX_CLIPS 200 /* more than enough */
\r
3566 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3568 // HBITMAP bufferBitmap;
\r
3573 int w = 100, h = 50;
\r
3575 if(logo == NULL) {
\r
3576 if(!logoHeight) return;
\r
3577 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3579 // GetClientRect(hwndMain, &Rect);
\r
3580 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3581 // Rect.bottom-Rect.top+1);
\r
3582 tmphdc = CreateCompatibleDC(hdc);
\r
3583 hbm = SelectObject(tmphdc, logo);
\r
3584 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3588 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3589 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3590 SelectObject(tmphdc, hbm);
\r
3598 HDC hdc = GetDC(hwndMain);
\r
3599 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3600 if(appData.autoLogo) {
\r
3602 switch(gameMode) { // pick logos based on game mode
\r
3603 case IcsObserving:
\r
3604 whiteLogo = second.programLogo; // ICS logo
\r
3605 blackLogo = second.programLogo;
\r
3608 case IcsPlayingWhite:
\r
3609 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3610 blackLogo = second.programLogo; // ICS logo
\r
3612 case IcsPlayingBlack:
\r
3613 whiteLogo = second.programLogo; // ICS logo
\r
3614 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3616 case TwoMachinesPlay:
\r
3617 if(first.twoMachinesColor[0] == 'b') {
\r
3618 whiteLogo = second.programLogo;
\r
3619 blackLogo = first.programLogo;
\r
3622 case MachinePlaysWhite:
\r
3623 blackLogo = userLogo;
\r
3625 case MachinePlaysBlack:
\r
3626 whiteLogo = userLogo;
\r
3627 blackLogo = first.programLogo;
\r
3630 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3631 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3632 ReleaseDC(hwndMain, hdc);
\r
3637 UpdateLogos(int display)
\r
3638 { // called after loading new engine(s), in tourney or from menu
\r
3639 LoadLogo(&first, 0, FALSE);
\r
3640 LoadLogo(&second, 1, appData.icsActive);
\r
3641 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3642 if(display) DisplayLogos();
\r
3645 static HDC hdcSeek;
\r
3647 // [HGM] seekgraph
\r
3648 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3651 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3652 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3653 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3654 SelectObject( hdcSeek, hp );
\r
3657 // front-end wrapper for drawing functions to do rectangles
\r
3658 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3663 if (hdcSeek == NULL) {
\r
3664 hdcSeek = GetDC(hwndMain);
\r
3665 if (!appData.monoMode) {
\r
3666 SelectPalette(hdcSeek, hPal, FALSE);
\r
3667 RealizePalette(hdcSeek);
\r
3670 hp = SelectObject( hdcSeek, gridPen );
\r
3671 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3672 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3673 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3674 SelectObject( hdcSeek, hp );
\r
3677 // front-end wrapper for putting text in graph
\r
3678 void DrawSeekText(char *buf, int x, int y)
\r
3681 SetBkMode( hdcSeek, TRANSPARENT );
\r
3682 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3683 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3686 void DrawSeekDot(int x, int y, int color)
\r
3688 int square = color & 0x80;
\r
3689 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3690 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3693 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3694 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3696 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3697 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3698 SelectObject(hdcSeek, oldBrush);
\r
3701 void DrawSeekOpen()
\r
3705 void DrawSeekClose()
\r
3710 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3712 static Board lastReq[2], lastDrawn[2];
\r
3713 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3714 static int lastDrawnFlipView = 0;
\r
3715 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3716 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3719 HBITMAP bufferBitmap;
\r
3720 HBITMAP oldBitmap;
\r
3722 HRGN clips[MAX_CLIPS];
\r
3723 ChessSquare dragged_piece = EmptySquare;
\r
3724 int nr = twoBoards*partnerUp;
\r
3726 /* I'm undecided on this - this function figures out whether a full
\r
3727 * repaint is necessary on its own, so there's no real reason to have the
\r
3728 * caller tell it that. I think this can safely be set to FALSE - but
\r
3729 * if we trust the callers not to request full repaints unnessesarily, then
\r
3730 * we could skip some clipping work. In other words, only request a full
\r
3731 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3732 * gamestart and similar) --Hawk
\r
3734 Boolean fullrepaint = repaint;
\r
3736 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3738 if( DrawPositionNeedsFullRepaint() ) {
\r
3739 fullrepaint = TRUE;
\r
3742 if (board == NULL) {
\r
3743 if (!lastReqValid[nr]) {
\r
3746 board = lastReq[nr];
\r
3748 CopyBoard(lastReq[nr], board);
\r
3749 lastReqValid[nr] = 1;
\r
3752 if (doingSizing) {
\r
3756 if (IsIconic(hwndMain)) {
\r
3760 if (hdc == NULL) {
\r
3761 hdc = GetDC(hwndMain);
\r
3762 if (!appData.monoMode) {
\r
3763 SelectPalette(hdc, hPal, FALSE);
\r
3764 RealizePalette(hdc);
\r
3768 releaseDC = FALSE;
\r
3771 /* Create some work-DCs */
\r
3772 hdcmem = CreateCompatibleDC(hdc);
\r
3773 tmphdc = CreateCompatibleDC(hdc);
\r
3775 /* If dragging is in progress, we temporarely remove the piece */
\r
3776 /* [HGM] or temporarily decrease count if stacked */
\r
3777 /* !! Moved to before board compare !! */
\r
3778 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3779 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3780 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3781 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3782 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3784 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3785 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3786 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3788 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3791 /* Figure out which squares need updating by comparing the
\r
3792 * newest board with the last drawn board and checking if
\r
3793 * flipping has changed.
\r
3795 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3796 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3797 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3798 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3799 SquareToPos(row, column, &x, &y);
\r
3800 clips[num_clips++] =
\r
3801 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3805 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3806 for (i=0; i<2; i++) {
\r
3807 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3808 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3809 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3810 lastDrawnHighlight.sq[i].y >= 0) {
\r
3811 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3812 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3813 clips[num_clips++] =
\r
3814 CreateRectRgn(x - lineGap, y - lineGap,
\r
3815 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3817 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3818 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3819 clips[num_clips++] =
\r
3820 CreateRectRgn(x - lineGap, y - lineGap,
\r
3821 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3825 for (i=0; i<2; i++) {
\r
3826 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3827 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3828 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3829 lastDrawnPremove.sq[i].y >= 0) {
\r
3830 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3831 lastDrawnPremove.sq[i].x, &x, &y);
\r
3832 clips[num_clips++] =
\r
3833 CreateRectRgn(x - lineGap, y - lineGap,
\r
3834 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3836 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3837 premoveHighlightInfo.sq[i].y >= 0) {
\r
3838 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3839 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3840 clips[num_clips++] =
\r
3841 CreateRectRgn(x - lineGap, y - lineGap,
\r
3842 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3846 } else { // nr == 1
\r
3847 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3848 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3849 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3850 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3851 for (i=0; i<2; i++) {
\r
3852 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3853 partnerHighlightInfo.sq[i].y >= 0) {
\r
3854 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3855 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3856 clips[num_clips++] =
\r
3857 CreateRectRgn(x - lineGap, y - lineGap,
\r
3858 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3860 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3861 oldPartnerHighlight.sq[i].y >= 0) {
\r
3862 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3863 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3864 clips[num_clips++] =
\r
3865 CreateRectRgn(x - lineGap, y - lineGap,
\r
3866 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3871 fullrepaint = TRUE;
\r
3874 /* Create a buffer bitmap - this is the actual bitmap
\r
3875 * being written to. When all the work is done, we can
\r
3876 * copy it to the real DC (the screen). This avoids
\r
3877 * the problems with flickering.
\r
3879 GetClientRect(hwndMain, &Rect);
\r
3880 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3881 Rect.bottom-Rect.top+1);
\r
3882 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3883 if (!appData.monoMode) {
\r
3884 SelectPalette(hdcmem, hPal, FALSE);
\r
3887 /* Create clips for dragging */
\r
3888 if (!fullrepaint) {
\r
3889 if (dragInfo.from.x >= 0) {
\r
3890 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3891 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3893 if (dragInfo.start.x >= 0) {
\r
3894 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3895 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3897 if (dragInfo.pos.x >= 0) {
\r
3898 x = dragInfo.pos.x - squareSize / 2;
\r
3899 y = dragInfo.pos.y - squareSize / 2;
\r
3900 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3902 if (dragInfo.lastpos.x >= 0) {
\r
3903 x = dragInfo.lastpos.x - squareSize / 2;
\r
3904 y = dragInfo.lastpos.y - squareSize / 2;
\r
3905 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3909 /* Are we animating a move?
\r
3911 * - remove the piece from the board (temporarely)
\r
3912 * - calculate the clipping region
\r
3914 if (!fullrepaint) {
\r
3915 if (animInfo.piece != EmptySquare) {
\r
3916 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3917 x = boardRect.left + animInfo.lastpos.x;
\r
3918 y = boardRect.top + animInfo.lastpos.y;
\r
3919 x2 = boardRect.left + animInfo.pos.x;
\r
3920 y2 = boardRect.top + animInfo.pos.y;
\r
3921 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3922 /* Slight kludge. The real problem is that after AnimateMove is
\r
3923 done, the position on the screen does not match lastDrawn.
\r
3924 This currently causes trouble only on e.p. captures in
\r
3925 atomic, where the piece moves to an empty square and then
\r
3926 explodes. The old and new positions both had an empty square
\r
3927 at the destination, but animation has drawn a piece there and
\r
3928 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3929 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3933 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3934 if (num_clips == 0)
\r
3935 fullrepaint = TRUE;
\r
3937 /* Set clipping on the memory DC */
\r
3938 if (!fullrepaint) {
\r
3939 SelectClipRgn(hdcmem, clips[0]);
\r
3940 for (x = 1; x < num_clips; x++) {
\r
3941 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3942 abort(); // this should never ever happen!
\r
3946 /* Do all the drawing to the memory DC */
\r
3947 if(explodeInfo.radius) { // [HGM] atomic
\r
3949 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3950 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3951 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3952 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3953 x += squareSize/2;
\r
3954 y += squareSize/2;
\r
3955 if(!fullrepaint) {
\r
3956 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3957 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3959 DrawGridOnDC(hdcmem);
\r
3960 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3961 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3962 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3963 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3964 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3965 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3966 SelectObject(hdcmem, oldBrush);
\r
3968 if(border) DrawBackgroundOnDC(hdcmem);
\r
3969 DrawGridOnDC(hdcmem);
\r
3970 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3971 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3972 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3974 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3975 oldPartnerHighlight = partnerHighlightInfo;
\r
3977 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3979 if(nr == 0) // [HGM] dual: markers only on left board
\r
3980 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3981 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3982 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3983 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
3984 SquareToPos(row, column, &x, &y);
\r
3985 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3986 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3987 SelectObject(hdcmem, oldBrush);
\r
3992 if( appData.highlightMoveWithArrow ) {
\r
3993 DrawArrowHighlight(hdcmem);
\r
3996 DrawCoordsOnDC(hdcmem);
\r
3998 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
3999 /* to make sure lastDrawn contains what is actually drawn */
\r
4001 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4002 if (dragged_piece != EmptySquare) {
\r
4003 /* [HGM] or restack */
\r
4004 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4005 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4007 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4008 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4010 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4011 x = dragInfo.pos.x - squareSize / 2;
\r
4012 y = dragInfo.pos.y - squareSize / 2;
\r
4013 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
4014 ((int) dragInfo.piece < (int) BlackPawn),
\r
4015 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4018 /* Put the animated piece back into place and draw it */
\r
4019 if (animInfo.piece != EmptySquare) {
\r
4020 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4021 x = boardRect.left + animInfo.pos.x;
\r
4022 y = boardRect.top + animInfo.pos.y;
\r
4023 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4024 ((int) animInfo.piece < (int) BlackPawn),
\r
4025 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4028 /* Release the bufferBitmap by selecting in the old bitmap
\r
4029 * and delete the memory DC
\r
4031 SelectObject(hdcmem, oldBitmap);
\r
4034 /* Set clipping on the target DC */
\r
4035 if (!fullrepaint) {
\r
4036 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4038 GetRgnBox(clips[x], &rect);
\r
4039 DeleteObject(clips[x]);
\r
4040 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4041 rect.right + wpMain.width/2, rect.bottom);
\r
4043 SelectClipRgn(hdc, clips[0]);
\r
4044 for (x = 1; x < num_clips; x++) {
\r
4045 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4046 abort(); // this should never ever happen!
\r
4050 /* Copy the new bitmap onto the screen in one go.
\r
4051 * This way we avoid any flickering
\r
4053 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4054 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4055 boardRect.right - boardRect.left,
\r
4056 boardRect.bottom - boardRect.top,
\r
4057 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4058 if(saveDiagFlag) {
\r
4059 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4060 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4062 GetObject(bufferBitmap, sizeof(b), &b);
\r
4063 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4064 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4065 bih.biWidth = b.bmWidth;
\r
4066 bih.biHeight = b.bmHeight;
\r
4068 bih.biBitCount = b.bmBitsPixel;
\r
4069 bih.biCompression = 0;
\r
4070 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4071 bih.biXPelsPerMeter = 0;
\r
4072 bih.biYPelsPerMeter = 0;
\r
4073 bih.biClrUsed = 0;
\r
4074 bih.biClrImportant = 0;
\r
4075 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4076 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4077 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4078 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4080 wb = b.bmWidthBytes;
\r
4082 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4083 int k = ((int*) pData)[i];
\r
4084 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4085 if(j >= 16) break;
\r
4087 if(j >= nrColors) nrColors = j+1;
\r
4089 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4091 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4092 for(w=0; w<(wb>>2); w+=2) {
\r
4093 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4094 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4095 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4096 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4097 pData[p++] = m | j<<4;
\r
4099 while(p&3) pData[p++] = 0;
\r
4102 wb = ((wb+31)>>5)<<2;
\r
4104 // write BITMAPFILEHEADER
\r
4105 fprintf(diagFile, "BM");
\r
4106 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4107 fputDW(diagFile, 0);
\r
4108 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4109 // write BITMAPINFOHEADER
\r
4110 fputDW(diagFile, 40);
\r
4111 fputDW(diagFile, b.bmWidth);
\r
4112 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4113 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4114 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4115 fputDW(diagFile, 0);
\r
4116 fputDW(diagFile, 0);
\r
4117 fputDW(diagFile, 0);
\r
4118 fputDW(diagFile, 0);
\r
4119 fputDW(diagFile, 0);
\r
4120 fputDW(diagFile, 0);
\r
4121 // write color table
\r
4123 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4124 // write bitmap data
\r
4125 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4126 fputc(pData[i], diagFile);
\r
4131 SelectObject(tmphdc, oldBitmap);
\r
4133 /* Massive cleanup */
\r
4134 for (x = 0; x < num_clips; x++)
\r
4135 DeleteObject(clips[x]);
\r
4138 DeleteObject(bufferBitmap);
\r
4141 ReleaseDC(hwndMain, hdc);
\r
4143 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4145 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4147 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4150 /* CopyBoard(lastDrawn, board);*/
\r
4151 lastDrawnHighlight = highlightInfo;
\r
4152 lastDrawnPremove = premoveHighlightInfo;
\r
4153 lastDrawnFlipView = flipView;
\r
4154 lastDrawnValid[nr] = 1;
\r
4157 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4162 saveDiagFlag = 1; diagFile = f;
\r
4163 HDCDrawPosition(NULL, TRUE, NULL);
\r
4171 /*---------------------------------------------------------------------------*\
\r
4172 | CLIENT PAINT PROCEDURE
\r
4173 | This is the main event-handler for the WM_PAINT message.
\r
4175 \*---------------------------------------------------------------------------*/
\r
4177 PaintProc(HWND hwnd)
\r
4183 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4184 if (IsIconic(hwnd)) {
\r
4185 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4187 if (!appData.monoMode) {
\r
4188 SelectPalette(hdc, hPal, FALSE);
\r
4189 RealizePalette(hdc);
\r
4191 HDCDrawPosition(hdc, 1, NULL);
\r
4192 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4193 flipView = !flipView; partnerUp = !partnerUp;
\r
4194 HDCDrawPosition(hdc, 1, NULL);
\r
4195 flipView = !flipView; partnerUp = !partnerUp;
\r
4198 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4199 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4200 ETO_CLIPPED|ETO_OPAQUE,
\r
4201 &messageRect, messageText, strlen(messageText), NULL);
\r
4202 SelectObject(hdc, oldFont);
\r
4203 DisplayBothClocks();
\r
4206 EndPaint(hwnd,&ps);
\r
4214 * If the user selects on a border boundary, return -1; if off the board,
\r
4215 * return -2. Otherwise map the event coordinate to the square.
\r
4216 * The offset boardRect.left or boardRect.top must already have been
\r
4217 * subtracted from x.
\r
4219 int EventToSquare(x, limit)
\r
4224 if (x < lineGap + border)
\r
4226 x -= lineGap + border;
\r
4227 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4229 x /= (squareSize + lineGap);
\r
4241 DropEnable dropEnables[] = {
\r
4242 { 'P', DP_Pawn, N_("Pawn") },
\r
4243 { 'N', DP_Knight, N_("Knight") },
\r
4244 { 'B', DP_Bishop, N_("Bishop") },
\r
4245 { 'R', DP_Rook, N_("Rook") },
\r
4246 { 'Q', DP_Queen, N_("Queen") },
\r
4250 SetupDropMenu(HMENU hmenu)
\r
4252 int i, count, enable;
\r
4254 extern char white_holding[], black_holding[];
\r
4255 char item[MSG_SIZ];
\r
4257 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4258 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4259 dropEnables[i].piece);
\r
4261 while (p && *p++ == dropEnables[i].piece) count++;
\r
4262 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4263 enable = count > 0 || !appData.testLegality
\r
4264 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4265 && !appData.icsActive);
\r
4266 ModifyMenu(hmenu, dropEnables[i].command,
\r
4267 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4268 dropEnables[i].command, item);
\r
4272 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4274 dragInfo.lastpos.x = boardRect.left + x;
\r
4275 dragInfo.lastpos.y = boardRect.top + y;
\r
4276 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4277 dragInfo.from.x = fromX;
\r
4278 dragInfo.from.y = fromY;
\r
4279 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4280 dragInfo.start = dragInfo.from;
\r
4281 SetCapture(hwndMain);
\r
4284 void DragPieceEnd(int x, int y)
\r
4287 dragInfo.start.x = dragInfo.start.y = -1;
\r
4288 dragInfo.from = dragInfo.start;
\r
4289 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4292 void ChangeDragPiece(ChessSquare piece)
\r
4294 dragInfo.piece = piece;
\r
4297 /* Event handler for mouse messages */
\r
4299 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4303 static int recursive = 0;
\r
4305 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4308 if (message == WM_MBUTTONUP) {
\r
4309 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4310 to the middle button: we simulate pressing the left button too!
\r
4312 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4313 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4319 pt.x = LOWORD(lParam);
\r
4320 pt.y = HIWORD(lParam);
\r
4321 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4322 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4323 if (!flipView && y >= 0) {
\r
4324 y = BOARD_HEIGHT - 1 - y;
\r
4326 if (flipView && x >= 0) {
\r
4327 x = BOARD_WIDTH - 1 - x;
\r
4330 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4331 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4333 switch (message) {
\r
4334 case WM_LBUTTONDOWN:
\r
4335 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4336 ClockClick(flipClock); break;
\r
4337 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4338 ClockClick(!flipClock); break;
\r
4340 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4341 dragInfo.start.x = dragInfo.start.y = -1;
\r
4342 dragInfo.from = dragInfo.start;
\r
4344 if(fromX == -1 && frozen) { // not sure where this is for
\r
4345 fromX = fromY = -1;
\r
4346 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4349 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4350 DrawPosition(TRUE, NULL);
\r
4353 case WM_LBUTTONUP:
\r
4354 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4355 DrawPosition(TRUE, NULL);
\r
4358 case WM_MOUSEMOVE:
\r
4359 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4360 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4361 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4362 if ((appData.animateDragging || appData.highlightDragging)
\r
4363 && (wParam & MK_LBUTTON || dragging == 2)
\r
4364 && dragInfo.from.x >= 0)
\r
4366 BOOL full_repaint = FALSE;
\r
4368 if (appData.animateDragging) {
\r
4369 dragInfo.pos = pt;
\r
4371 if (appData.highlightDragging) {
\r
4372 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4373 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4374 full_repaint = TRUE;
\r
4378 DrawPosition( full_repaint, NULL);
\r
4380 dragInfo.lastpos = dragInfo.pos;
\r
4384 case WM_MOUSEWHEEL: // [DM]
\r
4385 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4386 /* Mouse Wheel is being rolled forward
\r
4387 * Play moves forward
\r
4389 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4390 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4391 /* Mouse Wheel is being rolled backward
\r
4392 * Play moves backward
\r
4394 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4395 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4399 case WM_MBUTTONUP:
\r
4400 case WM_RBUTTONUP:
\r
4402 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4405 case WM_MBUTTONDOWN:
\r
4406 case WM_RBUTTONDOWN:
\r
4409 fromX = fromY = -1;
\r
4410 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4411 dragInfo.start.x = dragInfo.start.y = -1;
\r
4412 dragInfo.from = dragInfo.start;
\r
4413 dragInfo.lastpos = dragInfo.pos;
\r
4414 if (appData.highlightDragging) {
\r
4415 ClearHighlights();
\r
4418 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4419 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4420 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4421 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4422 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4426 DrawPosition(TRUE, NULL);
\r
4428 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4431 if (message == WM_MBUTTONDOWN) {
\r
4432 buttonCount = 3; /* even if system didn't think so */
\r
4433 if (wParam & MK_SHIFT)
\r
4434 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4436 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4437 } else { /* message == WM_RBUTTONDOWN */
\r
4438 /* Just have one menu, on the right button. Windows users don't
\r
4439 think to try the middle one, and sometimes other software steals
\r
4440 it, or it doesn't really exist. */
\r
4441 if(gameInfo.variant != VariantShogi)
\r
4442 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4444 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4448 SetCapture(hwndMain);
\r
4451 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4452 SetupDropMenu(hmenu);
\r
4453 MenuPopup(hwnd, pt, hmenu, -1);
\r
4463 /* Preprocess messages for buttons in main window */
\r
4465 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4467 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4470 for (i=0; i<N_BUTTONS; i++) {
\r
4471 if (buttonDesc[i].id == id) break;
\r
4473 if (i == N_BUTTONS) return 0;
\r
4474 switch (message) {
\r
4479 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4480 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4487 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4490 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4491 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4492 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4493 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4495 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4497 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4498 TypeInEvent((char)wParam);
\r
4504 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4507 static int promoStyle;
\r
4509 /* Process messages for Promotion dialog box */
\r
4511 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4515 switch (message) {
\r
4517 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4518 /* Center the dialog over the application window */
\r
4519 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4520 Translate(hDlg, DLG_PromotionKing);
\r
4521 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4522 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4523 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4524 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4525 SW_SHOW : SW_HIDE);
\r
4526 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4527 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4528 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4529 PieceToChar(WhiteAngel) != '~') ||
\r
4530 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4531 PieceToChar(BlackAngel) != '~') ) ?
\r
4532 SW_SHOW : SW_HIDE);
\r
4533 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4534 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4535 PieceToChar(WhiteMarshall) != '~') ||
\r
4536 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4537 PieceToChar(BlackMarshall) != '~') ) ?
\r
4538 SW_SHOW : SW_HIDE);
\r
4539 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4540 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4541 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4543 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4544 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4545 SetWindowText(hDlg, "Promote?");
\r
4547 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4548 gameInfo.variant == VariantSuper ?
\r
4549 SW_SHOW : SW_HIDE);
\r
4552 case WM_COMMAND: /* message: received a command */
\r
4553 switch (LOWORD(wParam)) {
\r
4555 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4556 ClearHighlights();
\r
4557 DrawPosition(FALSE, NULL);
\r
4560 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4563 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4566 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4567 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4570 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4571 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4573 case PB_Chancellor:
\r
4574 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4576 case PB_Archbishop:
\r
4577 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4580 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4581 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4586 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4587 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4588 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4589 fromX = fromY = -1;
\r
4590 if (!appData.highlightLastMove) {
\r
4591 ClearHighlights();
\r
4592 DrawPosition(FALSE, NULL);
\r
4599 /* Pop up promotion dialog */
\r
4601 PromotionPopup(HWND hwnd)
\r
4605 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4606 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4607 hwnd, (DLGPROC)lpProc);
\r
4608 FreeProcInstance(lpProc);
\r
4612 PromotionPopUp(char choice)
\r
4614 promoStyle = (choice == '+');
\r
4615 DrawPosition(TRUE, NULL);
\r
4616 PromotionPopup(hwndMain);
\r
4620 LoadGameDialog(HWND hwnd, char* title)
\r
4624 char fileTitle[MSG_SIZ];
\r
4625 f = OpenFileDialog(hwnd, "rb", "",
\r
4626 appData.oldSaveStyle ? "gam" : "pgn",
\r
4628 title, &number, fileTitle, NULL);
\r
4630 cmailMsgLoaded = FALSE;
\r
4631 if (number == 0) {
\r
4632 int error = GameListBuild(f);
\r
4634 DisplayError(_("Cannot build game list"), error);
\r
4635 } else if (!ListEmpty(&gameList) &&
\r
4636 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4637 GameListPopUp(f, fileTitle);
\r
4640 GameListDestroy();
\r
4643 LoadGame(f, number, fileTitle, FALSE);
\r
4647 int get_term_width()
\r
4652 HFONT hfont, hold_font;
\r
4657 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4661 // get the text metrics
\r
4662 hdc = GetDC(hText);
\r
4663 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4664 if (consoleCF.dwEffects & CFE_BOLD)
\r
4665 lf.lfWeight = FW_BOLD;
\r
4666 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4667 lf.lfItalic = TRUE;
\r
4668 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4669 lf.lfStrikeOut = TRUE;
\r
4670 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4671 lf.lfUnderline = TRUE;
\r
4672 hfont = CreateFontIndirect(&lf);
\r
4673 hold_font = SelectObject(hdc, hfont);
\r
4674 GetTextMetrics(hdc, &tm);
\r
4675 SelectObject(hdc, hold_font);
\r
4676 DeleteObject(hfont);
\r
4677 ReleaseDC(hText, hdc);
\r
4679 // get the rectangle
\r
4680 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4682 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4685 void UpdateICSWidth(HWND hText)
\r
4687 LONG old_width, new_width;
\r
4689 new_width = get_term_width(hText, FALSE);
\r
4690 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4691 if (new_width != old_width)
\r
4693 ics_update_width(new_width);
\r
4694 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4699 ChangedConsoleFont()
\r
4702 CHARRANGE tmpsel, sel;
\r
4703 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4704 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4705 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4708 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4709 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4710 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4711 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4712 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4713 * size. This was undocumented in the version of MSVC++ that I had
\r
4714 * when I wrote the code, but is apparently documented now.
\r
4716 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4717 cfmt.bCharSet = f->lf.lfCharSet;
\r
4718 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4719 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4720 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4721 /* Why are the following seemingly needed too? */
\r
4722 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4723 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4724 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4726 tmpsel.cpMax = -1; /*999999?*/
\r
4727 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4728 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4729 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4730 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4732 paraf.cbSize = sizeof(paraf);
\r
4733 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4734 paraf.dxStartIndent = 0;
\r
4735 paraf.dxOffset = WRAP_INDENT;
\r
4736 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4737 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4738 UpdateICSWidth(hText);
\r
4741 /*---------------------------------------------------------------------------*\
\r
4743 * Window Proc for main window
\r
4745 \*---------------------------------------------------------------------------*/
\r
4747 /* Process messages for main window, etc. */
\r
4749 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4756 char fileTitle[MSG_SIZ];
\r
4757 static SnapData sd;
\r
4758 static int peek=0;
\r
4760 switch (message) {
\r
4762 case WM_PAINT: /* message: repaint portion of window */
\r
4766 case WM_ERASEBKGND:
\r
4767 if (IsIconic(hwnd)) {
\r
4768 /* Cheat; change the message */
\r
4769 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4771 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4775 case WM_LBUTTONDOWN:
\r
4776 case WM_MBUTTONDOWN:
\r
4777 case WM_RBUTTONDOWN:
\r
4778 case WM_LBUTTONUP:
\r
4779 case WM_MBUTTONUP:
\r
4780 case WM_RBUTTONUP:
\r
4781 case WM_MOUSEMOVE:
\r
4782 case WM_MOUSEWHEEL:
\r
4783 MouseEvent(hwnd, message, wParam, lParam);
\r
4787 if((char)wParam == '\b') {
\r
4788 ForwardEvent(); peek = 0;
\r
4791 JAWS_KBUP_NAVIGATION
\r
4796 if((char)wParam == '\b') {
\r
4797 if(!peek) BackwardEvent(), peek = 1;
\r
4800 JAWS_KBDOWN_NAVIGATION
\r
4806 JAWS_ALT_INTERCEPT
\r
4808 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4809 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4810 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4811 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4813 SendMessage(h, message, wParam, lParam);
\r
4814 } else if(lParam != KF_REPEAT) {
\r
4815 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4816 TypeInEvent((char)wParam);
\r
4817 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4818 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4823 case WM_PALETTECHANGED:
\r
4824 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4826 HDC hdc = GetDC(hwndMain);
\r
4827 SelectPalette(hdc, hPal, TRUE);
\r
4828 nnew = RealizePalette(hdc);
\r
4830 paletteChanged = TRUE;
\r
4832 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4834 ReleaseDC(hwnd, hdc);
\r
4838 case WM_QUERYNEWPALETTE:
\r
4839 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4841 HDC hdc = GetDC(hwndMain);
\r
4842 paletteChanged = FALSE;
\r
4843 SelectPalette(hdc, hPal, FALSE);
\r
4844 nnew = RealizePalette(hdc);
\r
4846 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4848 ReleaseDC(hwnd, hdc);
\r
4853 case WM_COMMAND: /* message: command from application menu */
\r
4854 wmId = LOWORD(wParam);
\r
4859 SAY("new game enter a move to play against the computer with white");
\r
4862 case IDM_NewGameFRC:
\r
4863 if( NewGameFRC() == 0 ) {
\r
4868 case IDM_NewVariant:
\r
4869 NewVariantPopup(hwnd);
\r
4872 case IDM_LoadGame:
\r
4873 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4876 case IDM_LoadNextGame:
\r
4880 case IDM_LoadPrevGame:
\r
4884 case IDM_ReloadGame:
\r
4888 case IDM_LoadPosition:
\r
4889 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4890 Reset(FALSE, TRUE);
\r
4893 f = OpenFileDialog(hwnd, "rb", "",
\r
4894 appData.oldSaveStyle ? "pos" : "fen",
\r
4896 _("Load Position from File"), &number, fileTitle, NULL);
\r
4898 LoadPosition(f, number, fileTitle);
\r
4902 case IDM_LoadNextPosition:
\r
4903 ReloadPosition(1);
\r
4906 case IDM_LoadPrevPosition:
\r
4907 ReloadPosition(-1);
\r
4910 case IDM_ReloadPosition:
\r
4911 ReloadPosition(0);
\r
4914 case IDM_SaveGame:
\r
4915 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4916 f = OpenFileDialog(hwnd, "a", defName,
\r
4917 appData.oldSaveStyle ? "gam" : "pgn",
\r
4919 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4921 SaveGame(f, 0, "");
\r
4925 case IDM_SavePosition:
\r
4926 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4927 f = OpenFileDialog(hwnd, "a", defName,
\r
4928 appData.oldSaveStyle ? "pos" : "fen",
\r
4930 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4932 SavePosition(f, 0, "");
\r
4936 case IDM_SaveDiagram:
\r
4937 defName = "diagram";
\r
4938 f = OpenFileDialog(hwnd, "wb", defName,
\r
4941 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4947 case IDM_SaveSelected:
\r
4948 f = OpenFileDialog(hwnd, "a", "",
\r
4951 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4953 SaveSelected(f, 0, "");
\r
4957 case IDM_CreateBook:
\r
4958 CreateBookEvent();
\r
4961 case IDM_CopyGame:
\r
4962 CopyGameToClipboard();
\r
4965 case IDM_PasteGame:
\r
4966 PasteGameFromClipboard();
\r
4969 case IDM_CopyGameListToClipboard:
\r
4970 CopyGameListToClipboard();
\r
4973 /* [AS] Autodetect FEN or PGN data */
\r
4974 case IDM_PasteAny:
\r
4975 PasteGameOrFENFromClipboard();
\r
4978 /* [AS] Move history */
\r
4979 case IDM_ShowMoveHistory:
\r
4980 if( MoveHistoryIsUp() ) {
\r
4981 MoveHistoryPopDown();
\r
4984 MoveHistoryPopUp();
\r
4988 /* [AS] Eval graph */
\r
4989 case IDM_ShowEvalGraph:
\r
4990 if( EvalGraphIsUp() ) {
\r
4991 EvalGraphPopDown();
\r
4995 SetFocus(hwndMain);
\r
4999 /* [AS] Engine output */
\r
5000 case IDM_ShowEngineOutput:
\r
5001 if( EngineOutputIsUp() ) {
\r
5002 EngineOutputPopDown();
\r
5005 EngineOutputPopUp();
\r
5009 /* [AS] User adjudication */
\r
5010 case IDM_UserAdjudication_White:
\r
5011 UserAdjudicationEvent( +1 );
\r
5014 case IDM_UserAdjudication_Black:
\r
5015 UserAdjudicationEvent( -1 );
\r
5018 case IDM_UserAdjudication_Draw:
\r
5019 UserAdjudicationEvent( 0 );
\r
5022 /* [AS] Game list options dialog */
\r
5023 case IDM_GameListOptions:
\r
5024 GameListOptions();
\r
5031 case IDM_CopyPosition:
\r
5032 CopyFENToClipboard();
\r
5035 case IDM_PastePosition:
\r
5036 PasteFENFromClipboard();
\r
5039 case IDM_MailMove:
\r
5043 case IDM_ReloadCMailMsg:
\r
5044 Reset(TRUE, TRUE);
\r
5045 ReloadCmailMsgEvent(FALSE);
\r
5048 case IDM_Minimize:
\r
5049 ShowWindow(hwnd, SW_MINIMIZE);
\r
5056 case IDM_MachineWhite:
\r
5057 MachineWhiteEvent();
\r
5059 * refresh the tags dialog only if it's visible
\r
5061 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5063 tags = PGNTags(&gameInfo);
\r
5064 TagsPopUp(tags, CmailMsg());
\r
5067 SAY("computer starts playing white");
\r
5070 case IDM_MachineBlack:
\r
5071 MachineBlackEvent();
\r
5073 * refresh the tags dialog only if it's visible
\r
5075 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5077 tags = PGNTags(&gameInfo);
\r
5078 TagsPopUp(tags, CmailMsg());
\r
5081 SAY("computer starts playing black");
\r
5084 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5085 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5088 case IDM_TwoMachines:
\r
5089 TwoMachinesEvent();
\r
5091 * refresh the tags dialog only if it's visible
\r
5093 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5095 tags = PGNTags(&gameInfo);
\r
5096 TagsPopUp(tags, CmailMsg());
\r
5099 SAY("computer starts playing both sides");
\r
5102 case IDM_AnalysisMode:
\r
5103 if(AnalyzeModeEvent()) {
\r
5104 SAY("analyzing current position");
\r
5108 case IDM_AnalyzeFile:
\r
5109 AnalyzeFileEvent();
\r
5112 case IDM_IcsClient:
\r
5116 case IDM_EditGame:
\r
5117 case IDM_EditGame2:
\r
5122 case IDM_EditPosition:
\r
5123 case IDM_EditPosition2:
\r
5124 EditPositionEvent();
\r
5125 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5128 case IDM_Training:
\r
5132 case IDM_ShowGameList:
\r
5133 ShowGameListProc();
\r
5136 case IDM_EditProgs1:
\r
5137 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5140 case IDM_LoadProg1:
\r
5141 LoadEnginePopUp(hwndMain, 0);
\r
5144 case IDM_LoadProg2:
\r
5145 LoadEnginePopUp(hwndMain, 1);
\r
5148 case IDM_EditServers:
\r
5149 EditTagsPopUp(icsNames, &icsNames);
\r
5152 case IDM_EditTags:
\r
5157 case IDM_EditBook:
\r
5161 case IDM_EditComment:
\r
5163 if (commentUp && editComment) {
\r
5166 EditCommentEvent();
\r
5187 case IDM_CallFlag:
\r
5207 case IDM_StopObserving:
\r
5208 StopObservingEvent();
\r
5211 case IDM_StopExamining:
\r
5212 StopExaminingEvent();
\r
5216 UploadGameEvent();
\r
5219 case IDM_TypeInMove:
\r
5220 TypeInEvent('\000');
\r
5223 case IDM_TypeInName:
\r
5224 PopUpNameDialog('\000');
\r
5227 case IDM_Backward:
\r
5229 SetFocus(hwndMain);
\r
5236 SetFocus(hwndMain);
\r
5241 SetFocus(hwndMain);
\r
5246 SetFocus(hwndMain);
\r
5249 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5250 case OPT_GameListPrev:
\r
5251 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5255 RevertEvent(FALSE);
\r
5258 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5259 RevertEvent(TRUE);
\r
5262 case IDM_TruncateGame:
\r
5263 TruncateGameEvent();
\r
5270 case IDM_RetractMove:
\r
5271 RetractMoveEvent();
\r
5274 case IDM_FlipView:
\r
5275 flipView = !flipView;
\r
5276 DrawPosition(FALSE, NULL);
\r
5279 case IDM_FlipClock:
\r
5280 flipClock = !flipClock;
\r
5281 DisplayBothClocks();
\r
5285 case IDM_MuteSounds:
\r
5286 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5287 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5288 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5291 case IDM_GeneralOptions:
\r
5292 GeneralOptionsPopup(hwnd);
\r
5293 DrawPosition(TRUE, NULL);
\r
5296 case IDM_BoardOptions:
\r
5297 BoardOptionsPopup(hwnd);
\r
5300 case IDM_ThemeOptions:
\r
5301 ThemeOptionsPopup(hwnd);
\r
5304 case IDM_EnginePlayOptions:
\r
5305 EnginePlayOptionsPopup(hwnd);
\r
5308 case IDM_Engine1Options:
\r
5309 EngineOptionsPopup(hwnd, &first);
\r
5312 case IDM_Engine2Options:
\r
5314 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5315 EngineOptionsPopup(hwnd, &second);
\r
5318 case IDM_OptionsUCI:
\r
5319 UciOptionsPopup(hwnd);
\r
5323 TourneyPopup(hwnd);
\r
5326 case IDM_IcsOptions:
\r
5327 IcsOptionsPopup(hwnd);
\r
5331 FontsOptionsPopup(hwnd);
\r
5335 SoundOptionsPopup(hwnd);
\r
5338 case IDM_CommPort:
\r
5339 CommPortOptionsPopup(hwnd);
\r
5342 case IDM_LoadOptions:
\r
5343 LoadOptionsPopup(hwnd);
\r
5346 case IDM_SaveOptions:
\r
5347 SaveOptionsPopup(hwnd);
\r
5350 case IDM_TimeControl:
\r
5351 TimeControlOptionsPopup(hwnd);
\r
5354 case IDM_SaveSettings:
\r
5355 SaveSettings(settingsFileName);
\r
5358 case IDM_SaveSettingsOnExit:
\r
5359 saveSettingsOnExit = !saveSettingsOnExit;
\r
5360 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5361 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5362 MF_CHECKED : MF_UNCHECKED));
\r
5373 case IDM_AboutGame:
\r
5378 appData.debugMode = !appData.debugMode;
\r
5379 if (appData.debugMode) {
\r
5380 char dir[MSG_SIZ];
\r
5381 GetCurrentDirectory(MSG_SIZ, dir);
\r
5382 SetCurrentDirectory(installDir);
\r
5383 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5384 SetCurrentDirectory(dir);
\r
5385 setbuf(debugFP, NULL);
\r
5392 case IDM_HELPCONTENTS:
\r
5393 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5394 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5395 MessageBox (GetFocus(),
\r
5396 _("Unable to activate help"),
\r
5397 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5401 case IDM_HELPSEARCH:
\r
5402 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5403 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5404 MessageBox (GetFocus(),
\r
5405 _("Unable to activate help"),
\r
5406 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5410 case IDM_HELPHELP:
\r
5411 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5412 MessageBox (GetFocus(),
\r
5413 _("Unable to activate help"),
\r
5414 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5419 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5421 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5422 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5423 FreeProcInstance(lpProc);
\r
5426 case IDM_DirectCommand1:
\r
5427 AskQuestionEvent(_("Direct Command"),
\r
5428 _("Send to chess program:"), "", "1");
\r
5430 case IDM_DirectCommand2:
\r
5431 AskQuestionEvent(_("Direct Command"),
\r
5432 _("Send to second chess program:"), "", "2");
\r
5435 case EP_WhitePawn:
\r
5436 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5437 fromX = fromY = -1;
\r
5440 case EP_WhiteKnight:
\r
5441 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5442 fromX = fromY = -1;
\r
5445 case EP_WhiteBishop:
\r
5446 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5447 fromX = fromY = -1;
\r
5450 case EP_WhiteRook:
\r
5451 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5452 fromX = fromY = -1;
\r
5455 case EP_WhiteQueen:
\r
5456 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5457 fromX = fromY = -1;
\r
5460 case EP_WhiteFerz:
\r
5461 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5462 fromX = fromY = -1;
\r
5465 case EP_WhiteWazir:
\r
5466 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5467 fromX = fromY = -1;
\r
5470 case EP_WhiteAlfil:
\r
5471 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5472 fromX = fromY = -1;
\r
5475 case EP_WhiteCannon:
\r
5476 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5477 fromX = fromY = -1;
\r
5480 case EP_WhiteCardinal:
\r
5481 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5482 fromX = fromY = -1;
\r
5485 case EP_WhiteMarshall:
\r
5486 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5487 fromX = fromY = -1;
\r
5490 case EP_WhiteKing:
\r
5491 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5492 fromX = fromY = -1;
\r
5495 case EP_BlackPawn:
\r
5496 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5497 fromX = fromY = -1;
\r
5500 case EP_BlackKnight:
\r
5501 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5502 fromX = fromY = -1;
\r
5505 case EP_BlackBishop:
\r
5506 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5507 fromX = fromY = -1;
\r
5510 case EP_BlackRook:
\r
5511 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5512 fromX = fromY = -1;
\r
5515 case EP_BlackQueen:
\r
5516 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5517 fromX = fromY = -1;
\r
5520 case EP_BlackFerz:
\r
5521 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5522 fromX = fromY = -1;
\r
5525 case EP_BlackWazir:
\r
5526 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5527 fromX = fromY = -1;
\r
5530 case EP_BlackAlfil:
\r
5531 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5532 fromX = fromY = -1;
\r
5535 case EP_BlackCannon:
\r
5536 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5537 fromX = fromY = -1;
\r
5540 case EP_BlackCardinal:
\r
5541 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5542 fromX = fromY = -1;
\r
5545 case EP_BlackMarshall:
\r
5546 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5547 fromX = fromY = -1;
\r
5550 case EP_BlackKing:
\r
5551 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5552 fromX = fromY = -1;
\r
5555 case EP_EmptySquare:
\r
5556 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5557 fromX = fromY = -1;
\r
5560 case EP_ClearBoard:
\r
5561 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5562 fromX = fromY = -1;
\r
5566 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5567 fromX = fromY = -1;
\r
5571 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5572 fromX = fromY = -1;
\r
5576 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5577 fromX = fromY = -1;
\r
5581 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5582 fromX = fromY = -1;
\r
5586 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5587 fromX = fromY = -1;
\r
5591 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5592 fromX = fromY = -1;
\r
5596 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5597 fromX = fromY = -1;
\r
5601 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5602 fromX = fromY = -1;
\r
5606 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5607 fromX = fromY = -1;
\r
5611 barbaric = 0; appData.language = "";
\r
5612 TranslateMenus(0);
\r
5613 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5614 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5615 lastChecked = wmId;
\r
5619 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5620 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5622 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5623 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5624 TranslateMenus(0);
\r
5625 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5626 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5627 lastChecked = wmId;
\r
5630 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5636 case CLOCK_TIMER_ID:
\r
5637 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5638 clockTimerEvent = 0;
\r
5639 DecrementClocks(); /* call into back end */
\r
5641 case LOAD_GAME_TIMER_ID:
\r
5642 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5643 loadGameTimerEvent = 0;
\r
5644 AutoPlayGameLoop(); /* call into back end */
\r
5646 case ANALYSIS_TIMER_ID:
\r
5647 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5648 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5649 AnalysisPeriodicEvent(0);
\r
5651 KillTimer(hwnd, analysisTimerEvent);
\r
5652 analysisTimerEvent = 0;
\r
5655 case DELAYED_TIMER_ID:
\r
5656 KillTimer(hwnd, delayedTimerEvent);
\r
5657 delayedTimerEvent = 0;
\r
5658 delayedTimerCallback();
\r
5663 case WM_USER_Input:
\r
5664 InputEvent(hwnd, message, wParam, lParam);
\r
5667 /* [AS] Also move "attached" child windows */
\r
5668 case WM_WINDOWPOSCHANGING:
\r
5670 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5671 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5673 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5674 /* Window is moving */
\r
5677 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5678 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5679 rcMain.right = wpMain.x + wpMain.width;
\r
5680 rcMain.top = wpMain.y;
\r
5681 rcMain.bottom = wpMain.y + wpMain.height;
\r
5683 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5684 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5685 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5686 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5687 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5688 wpMain.x = lpwp->x;
\r
5689 wpMain.y = lpwp->y;
\r
5694 /* [AS] Snapping */
\r
5695 case WM_ENTERSIZEMOVE:
\r
5696 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5697 if (hwnd == hwndMain) {
\r
5698 doingSizing = TRUE;
\r
5701 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5705 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5706 if (hwnd == hwndMain) {
\r
5707 lastSizing = wParam;
\r
5712 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5713 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5715 case WM_EXITSIZEMOVE:
\r
5716 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5717 if (hwnd == hwndMain) {
\r
5719 doingSizing = FALSE;
\r
5720 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5721 GetClientRect(hwnd, &client);
\r
5722 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5724 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5726 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5729 case WM_DESTROY: /* message: window being destroyed */
\r
5730 PostQuitMessage(0);
\r
5734 if (hwnd == hwndMain) {
\r
5739 default: /* Passes it on if unprocessed */
\r
5740 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5747 /*---------------------------------------------------------------------------*\
\r
5749 * Misc utility routines
\r
5751 \*---------------------------------------------------------------------------*/
\r
5754 * Decent random number generator, at least not as bad as Windows
\r
5755 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5757 unsigned int randstate;
\r
5762 randstate = randstate * 1664525 + 1013904223;
\r
5763 return (int) randstate & 0x7fffffff;
\r
5767 mysrandom(unsigned int seed)
\r
5774 * returns TRUE if user selects a different color, FALSE otherwise
\r
5778 ChangeColor(HWND hwnd, COLORREF *which)
\r
5780 static BOOL firstTime = TRUE;
\r
5781 static DWORD customColors[16];
\r
5783 COLORREF newcolor;
\r
5788 /* Make initial colors in use available as custom colors */
\r
5789 /* Should we put the compiled-in defaults here instead? */
\r
5791 customColors[i++] = lightSquareColor & 0xffffff;
\r
5792 customColors[i++] = darkSquareColor & 0xffffff;
\r
5793 customColors[i++] = whitePieceColor & 0xffffff;
\r
5794 customColors[i++] = blackPieceColor & 0xffffff;
\r
5795 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5796 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5798 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5799 customColors[i++] = textAttribs[ccl].color;
\r
5801 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5802 firstTime = FALSE;
\r
5805 cc.lStructSize = sizeof(cc);
\r
5806 cc.hwndOwner = hwnd;
\r
5807 cc.hInstance = NULL;
\r
5808 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5809 cc.lpCustColors = (LPDWORD) customColors;
\r
5810 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5812 if (!ChooseColor(&cc)) return FALSE;
\r
5814 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5815 if (newcolor == *which) return FALSE;
\r
5816 *which = newcolor;
\r
5820 InitDrawingColors();
\r
5821 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5826 MyLoadSound(MySound *ms)
\r
5832 if (ms->data && ms->flag) free(ms->data);
\r
5835 switch (ms->name[0]) {
\r
5841 /* System sound from Control Panel. Don't preload here. */
\r
5845 if (ms->name[1] == NULLCHAR) {
\r
5846 /* "!" alone = silence */
\r
5849 /* Builtin wave resource. Error if not found. */
\r
5850 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5851 if (h == NULL) break;
\r
5852 ms->data = (void *)LoadResource(hInst, h);
\r
5853 ms->flag = 0; // not maloced, so cannot be freed!
\r
5854 if (h == NULL) break;
\r
5859 /* .wav file. Error if not found. */
\r
5860 f = fopen(ms->name, "rb");
\r
5861 if (f == NULL) break;
\r
5862 if (fstat(fileno(f), &st) < 0) break;
\r
5863 ms->data = malloc(st.st_size);
\r
5865 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5871 char buf[MSG_SIZ];
\r
5872 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5873 DisplayError(buf, GetLastError());
\r
5879 MyPlaySound(MySound *ms)
\r
5881 BOOLEAN ok = FALSE;
\r
5883 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5884 switch (ms->name[0]) {
\r
5886 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5891 /* System sound from Control Panel (deprecated feature).
\r
5892 "$" alone or an unset sound name gets default beep (still in use). */
\r
5893 if (ms->name[1]) {
\r
5894 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5896 if (!ok) ok = MessageBeep(MB_OK);
\r
5899 /* Builtin wave resource, or "!" alone for silence */
\r
5900 if (ms->name[1]) {
\r
5901 if (ms->data == NULL) return FALSE;
\r
5902 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5908 /* .wav file. Error if not found. */
\r
5909 if (ms->data == NULL) return FALSE;
\r
5910 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5913 /* Don't print an error: this can happen innocently if the sound driver
\r
5914 is busy; for instance, if another instance of WinBoard is playing
\r
5915 a sound at about the same time. */
\r
5921 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5924 OPENFILENAME *ofn;
\r
5925 static UINT *number; /* gross that this is static */
\r
5927 switch (message) {
\r
5928 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5929 /* Center the dialog over the application window */
\r
5930 ofn = (OPENFILENAME *) lParam;
\r
5931 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5932 number = (UINT *) ofn->lCustData;
\r
5933 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5937 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5938 Translate(hDlg, 1536);
\r
5939 return FALSE; /* Allow for further processing */
\r
5942 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5943 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5945 return FALSE; /* Allow for further processing */
\r
5951 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5953 static UINT *number;
\r
5954 OPENFILENAME *ofname;
\r
5957 case WM_INITDIALOG:
\r
5958 Translate(hdlg, DLG_IndexNumber);
\r
5959 ofname = (OPENFILENAME *)lParam;
\r
5960 number = (UINT *)(ofname->lCustData);
\r
5963 ofnot = (OFNOTIFY *)lParam;
\r
5964 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5965 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5974 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5975 char *nameFilt, char *dlgTitle, UINT *number,
\r
5976 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5978 OPENFILENAME openFileName;
\r
5979 char buf1[MSG_SIZ];
\r
5982 if (fileName == NULL) fileName = buf1;
\r
5983 if (defName == NULL) {
\r
5984 safeStrCpy(fileName, "*.", 3 );
\r
5985 strcat(fileName, defExt);
\r
5987 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5989 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5990 if (number) *number = 0;
\r
5992 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5993 openFileName.hwndOwner = hwnd;
\r
5994 openFileName.hInstance = (HANDLE) hInst;
\r
5995 openFileName.lpstrFilter = nameFilt;
\r
5996 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5997 openFileName.nMaxCustFilter = 0L;
\r
5998 openFileName.nFilterIndex = 1L;
\r
5999 openFileName.lpstrFile = fileName;
\r
6000 openFileName.nMaxFile = MSG_SIZ;
\r
6001 openFileName.lpstrFileTitle = fileTitle;
\r
6002 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6003 openFileName.lpstrInitialDir = NULL;
\r
6004 openFileName.lpstrTitle = dlgTitle;
\r
6005 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6006 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6007 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6008 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6009 openFileName.nFileOffset = 0;
\r
6010 openFileName.nFileExtension = 0;
\r
6011 openFileName.lpstrDefExt = defExt;
\r
6012 openFileName.lCustData = (LONG) number;
\r
6013 openFileName.lpfnHook = oldDialog ?
\r
6014 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6015 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6017 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6018 GetOpenFileName(&openFileName)) {
\r
6019 /* open the file */
\r
6020 f = fopen(openFileName.lpstrFile, write);
\r
6022 MessageBox(hwnd, _("File open failed"), NULL,
\r
6023 MB_OK|MB_ICONEXCLAMATION);
\r
6027 int err = CommDlgExtendedError();
\r
6028 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6037 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6039 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6042 * Get the first pop-up menu in the menu template. This is the
\r
6043 * menu that TrackPopupMenu displays.
\r
6045 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6046 TranslateOneMenu(10, hmenuTrackPopup);
\r
6048 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6051 * TrackPopup uses screen coordinates, so convert the
\r
6052 * coordinates of the mouse click to screen coordinates.
\r
6054 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6056 /* Draw and track the floating pop-up menu. */
\r
6057 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6058 pt.x, pt.y, 0, hwnd, NULL);
\r
6060 /* Destroy the menu.*/
\r
6061 DestroyMenu(hmenu);
\r
6066 int sizeX, sizeY, newSizeX, newSizeY;
\r
6068 } ResizeEditPlusButtonsClosure;
\r
6071 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6073 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6077 if (hChild == cl->hText) return TRUE;
\r
6078 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6079 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6080 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6081 ScreenToClient(cl->hDlg, &pt);
\r
6082 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6083 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6087 /* Resize a dialog that has a (rich) edit field filling most of
\r
6088 the top, with a row of buttons below */
\r
6090 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6093 int newTextHeight, newTextWidth;
\r
6094 ResizeEditPlusButtonsClosure cl;
\r
6096 /*if (IsIconic(hDlg)) return;*/
\r
6097 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6099 cl.hdwp = BeginDeferWindowPos(8);
\r
6101 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6102 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6103 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6104 if (newTextHeight < 0) {
\r
6105 newSizeY += -newTextHeight;
\r
6106 newTextHeight = 0;
\r
6108 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6109 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6115 cl.newSizeX = newSizeX;
\r
6116 cl.newSizeY = newSizeY;
\r
6117 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6119 EndDeferWindowPos(cl.hdwp);
\r
6122 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6124 RECT rChild, rParent;
\r
6125 int wChild, hChild, wParent, hParent;
\r
6126 int wScreen, hScreen, xNew, yNew;
\r
6129 /* Get the Height and Width of the child window */
\r
6130 GetWindowRect (hwndChild, &rChild);
\r
6131 wChild = rChild.right - rChild.left;
\r
6132 hChild = rChild.bottom - rChild.top;
\r
6134 /* Get the Height and Width of the parent window */
\r
6135 GetWindowRect (hwndParent, &rParent);
\r
6136 wParent = rParent.right - rParent.left;
\r
6137 hParent = rParent.bottom - rParent.top;
\r
6139 /* Get the display limits */
\r
6140 hdc = GetDC (hwndChild);
\r
6141 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6142 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6143 ReleaseDC(hwndChild, hdc);
\r
6145 /* Calculate new X position, then adjust for screen */
\r
6146 xNew = rParent.left + ((wParent - wChild) /2);
\r
6149 } else if ((xNew+wChild) > wScreen) {
\r
6150 xNew = wScreen - wChild;
\r
6153 /* Calculate new Y position, then adjust for screen */
\r
6155 yNew = rParent.top + ((hParent - hChild) /2);
\r
6158 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6163 } else if ((yNew+hChild) > hScreen) {
\r
6164 yNew = hScreen - hChild;
\r
6167 /* Set it, and return */
\r
6168 return SetWindowPos (hwndChild, NULL,
\r
6169 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6172 /* Center one window over another */
\r
6173 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6175 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6178 /*---------------------------------------------------------------------------*\
\r
6180 * Startup Dialog functions
\r
6182 \*---------------------------------------------------------------------------*/
\r
6184 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6186 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6188 while (*cd != NULL) {
\r
6189 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6195 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6197 char buf1[MAX_ARG_LEN];
\r
6200 if (str[0] == '@') {
\r
6201 FILE* f = fopen(str + 1, "r");
\r
6203 DisplayFatalError(str + 1, errno, 2);
\r
6206 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6208 buf1[len] = NULLCHAR;
\r
6212 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6215 char buf[MSG_SIZ];
\r
6216 char *end = strchr(str, '\n');
\r
6217 if (end == NULL) return;
\r
6218 memcpy(buf, str, end - str);
\r
6219 buf[end - str] = NULLCHAR;
\r
6220 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6226 SetStartupDialogEnables(HWND hDlg)
\r
6228 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6229 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6230 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6231 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6232 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6233 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6234 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6235 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6236 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6237 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6238 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6239 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6240 IsDlgButtonChecked(hDlg, OPT_View));
\r
6244 QuoteForFilename(char *filename)
\r
6246 int dquote, space;
\r
6247 dquote = strchr(filename, '"') != NULL;
\r
6248 space = strchr(filename, ' ') != NULL;
\r
6249 if (dquote || space) {
\r
6261 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6263 char buf[MSG_SIZ];
\r
6266 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6267 q = QuoteForFilename(nthcp);
\r
6268 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6269 if (*nthdir != NULLCHAR) {
\r
6270 q = QuoteForFilename(nthdir);
\r
6271 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6273 if (*nthcp == NULLCHAR) {
\r
6274 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6275 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6276 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6277 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6282 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6284 char buf[MSG_SIZ];
\r
6288 switch (message) {
\r
6289 case WM_INITDIALOG:
\r
6290 /* Center the dialog */
\r
6291 CenterWindow (hDlg, GetDesktopWindow());
\r
6292 Translate(hDlg, DLG_Startup);
\r
6293 /* Initialize the dialog items */
\r
6294 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6295 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6296 firstChessProgramNames);
\r
6297 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6298 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6299 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6300 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6301 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6302 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6303 if (*appData.icsHelper != NULLCHAR) {
\r
6304 char *q = QuoteForFilename(appData.icsHelper);
\r
6305 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6307 if (*appData.icsHost == NULLCHAR) {
\r
6308 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6309 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6310 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6311 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6312 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6315 if (appData.icsActive) {
\r
6316 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6318 else if (appData.noChessProgram) {
\r
6319 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6322 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6325 SetStartupDialogEnables(hDlg);
\r
6329 switch (LOWORD(wParam)) {
\r
6331 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6332 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6333 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6335 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6336 ParseArgs(StringGet, &p);
\r
6337 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6338 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6340 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6341 ParseArgs(StringGet, &p);
\r
6342 SwapEngines(singleList); // ... and then make it 'second'
\r
6344 appData.noChessProgram = FALSE;
\r
6345 appData.icsActive = FALSE;
\r
6346 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6347 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6348 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6350 ParseArgs(StringGet, &p);
\r
6351 if (appData.zippyPlay) {
\r
6352 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6353 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6355 ParseArgs(StringGet, &p);
\r
6357 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6358 appData.noChessProgram = TRUE;
\r
6359 appData.icsActive = FALSE;
\r
6361 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6362 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6365 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6366 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6368 ParseArgs(StringGet, &p);
\r
6370 EndDialog(hDlg, TRUE);
\r
6377 case IDM_HELPCONTENTS:
\r
6378 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6379 MessageBox (GetFocus(),
\r
6380 _("Unable to activate help"),
\r
6381 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6386 SetStartupDialogEnables(hDlg);
\r
6394 /*---------------------------------------------------------------------------*\
\r
6396 * About box dialog functions
\r
6398 \*---------------------------------------------------------------------------*/
\r
6400 /* Process messages for "About" dialog box */
\r
6402 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6404 switch (message) {
\r
6405 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6406 /* Center the dialog over the application window */
\r
6407 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6408 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6409 Translate(hDlg, ABOUTBOX);
\r
6413 case WM_COMMAND: /* message: received a command */
\r
6414 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6415 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6416 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6424 /*---------------------------------------------------------------------------*\
\r
6426 * Comment Dialog functions
\r
6428 \*---------------------------------------------------------------------------*/
\r
6431 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6433 static HANDLE hwndText = NULL;
\r
6434 int len, newSizeX, newSizeY;
\r
6435 static int sizeX, sizeY;
\r
6440 switch (message) {
\r
6441 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6442 /* Initialize the dialog items */
\r
6443 Translate(hDlg, DLG_EditComment);
\r
6444 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6445 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6446 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6447 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6448 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6449 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6450 SetWindowText(hDlg, commentTitle);
\r
6451 if (editComment) {
\r
6452 SetFocus(hwndText);
\r
6454 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6456 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6457 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6458 MAKELPARAM(FALSE, 0));
\r
6459 /* Size and position the dialog */
\r
6460 if (!commentDialog) {
\r
6461 commentDialog = hDlg;
\r
6462 GetClientRect(hDlg, &rect);
\r
6463 sizeX = rect.right;
\r
6464 sizeY = rect.bottom;
\r
6465 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6466 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6467 WINDOWPLACEMENT wp;
\r
6468 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6469 wp.length = sizeof(WINDOWPLACEMENT);
\r
6471 wp.showCmd = SW_SHOW;
\r
6472 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6473 wp.rcNormalPosition.left = wpComment.x;
\r
6474 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6475 wp.rcNormalPosition.top = wpComment.y;
\r
6476 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6477 SetWindowPlacement(hDlg, &wp);
\r
6479 GetClientRect(hDlg, &rect);
\r
6480 newSizeX = rect.right;
\r
6481 newSizeY = rect.bottom;
\r
6482 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6483 newSizeX, newSizeY);
\r
6488 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6491 case WM_COMMAND: /* message: received a command */
\r
6492 switch (LOWORD(wParam)) {
\r
6494 if (editComment) {
\r
6496 /* Read changed options from the dialog box */
\r
6497 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6498 len = GetWindowTextLength(hwndText);
\r
6499 str = (char *) malloc(len + 1);
\r
6500 GetWindowText(hwndText, str, len + 1);
\r
6509 ReplaceComment(commentIndex, str);
\r
6516 case OPT_CancelComment:
\r
6520 case OPT_ClearComment:
\r
6521 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6524 case OPT_EditComment:
\r
6525 EditCommentEvent();
\r
6533 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6534 if( wParam == OPT_CommentText ) {
\r
6535 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6537 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6538 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6542 pt.x = LOWORD( lpMF->lParam );
\r
6543 pt.y = HIWORD( lpMF->lParam );
\r
6545 if(lpMF->msg == WM_CHAR) {
\r
6547 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6548 index = sel.cpMin;
\r
6550 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6552 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6553 len = GetWindowTextLength(hwndText);
\r
6554 str = (char *) malloc(len + 1);
\r
6555 GetWindowText(hwndText, str, len + 1);
\r
6556 ReplaceComment(commentIndex, str);
\r
6557 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6558 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6561 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6562 lpMF->msg = WM_USER;
\r
6570 newSizeX = LOWORD(lParam);
\r
6571 newSizeY = HIWORD(lParam);
\r
6572 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6577 case WM_GETMINMAXINFO:
\r
6578 /* Prevent resizing window too small */
\r
6579 mmi = (MINMAXINFO *) lParam;
\r
6580 mmi->ptMinTrackSize.x = 100;
\r
6581 mmi->ptMinTrackSize.y = 100;
\r
6588 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6593 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6595 if (str == NULL) str = "";
\r
6596 p = (char *) malloc(2 * strlen(str) + 2);
\r
6599 if (*str == '\n') *q++ = '\r';
\r
6603 if (commentText != NULL) free(commentText);
\r
6605 commentIndex = index;
\r
6606 commentTitle = title;
\r
6608 editComment = edit;
\r
6610 if (commentDialog) {
\r
6611 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6612 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6614 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6615 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6616 hwndMain, (DLGPROC)lpProc);
\r
6617 FreeProcInstance(lpProc);
\r
6623 /*---------------------------------------------------------------------------*\
\r
6625 * Type-in move dialog functions
\r
6627 \*---------------------------------------------------------------------------*/
\r
6630 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6632 char move[MSG_SIZ];
\r
6635 switch (message) {
\r
6636 case WM_INITDIALOG:
\r
6637 move[0] = (char) lParam;
\r
6638 move[1] = NULLCHAR;
\r
6639 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6640 Translate(hDlg, DLG_TypeInMove);
\r
6641 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6642 SetWindowText(hInput, move);
\r
6644 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6648 switch (LOWORD(wParam)) {
\r
6651 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6652 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6653 TypeInDoneEvent(move);
\r
6654 EndDialog(hDlg, TRUE);
\r
6657 EndDialog(hDlg, FALSE);
\r
6668 PopUpMoveDialog(char firstchar)
\r
6672 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6673 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6674 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6675 FreeProcInstance(lpProc);
\r
6678 /*---------------------------------------------------------------------------*\
\r
6680 * Type-in name dialog functions
\r
6682 \*---------------------------------------------------------------------------*/
\r
6685 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6687 char move[MSG_SIZ];
\r
6690 switch (message) {
\r
6691 case WM_INITDIALOG:
\r
6692 move[0] = (char) lParam;
\r
6693 move[1] = NULLCHAR;
\r
6694 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6695 Translate(hDlg, DLG_TypeInName);
\r
6696 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6697 SetWindowText(hInput, move);
\r
6699 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6703 switch (LOWORD(wParam)) {
\r
6705 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6706 appData.userName = strdup(move);
\r
6709 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6710 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6711 DisplayTitle(move);
\r
6715 EndDialog(hDlg, TRUE);
\r
6718 EndDialog(hDlg, FALSE);
\r
6729 PopUpNameDialog(char firstchar)
\r
6733 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6734 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6735 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6736 FreeProcInstance(lpProc);
\r
6739 /*---------------------------------------------------------------------------*\
\r
6743 \*---------------------------------------------------------------------------*/
\r
6745 /* Nonmodal error box */
\r
6746 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6747 WPARAM wParam, LPARAM lParam);
\r
6750 ErrorPopUp(char *title, char *content)
\r
6754 BOOLEAN modal = hwndMain == NULL;
\r
6772 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6773 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6776 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6778 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6779 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6780 hwndMain, (DLGPROC)lpProc);
\r
6781 FreeProcInstance(lpProc);
\r
6788 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6789 if (errorDialog == NULL) return;
\r
6790 DestroyWindow(errorDialog);
\r
6791 errorDialog = NULL;
\r
6792 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6796 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6800 switch (message) {
\r
6801 case WM_INITDIALOG:
\r
6802 GetWindowRect(hDlg, &rChild);
\r
6805 SetWindowPos(hDlg, NULL, rChild.left,
\r
6806 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6807 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6811 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6812 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6813 and it doesn't work when you resize the dialog.
\r
6814 For now, just give it a default position.
\r
6816 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6817 Translate(hDlg, DLG_Error);
\r
6819 errorDialog = hDlg;
\r
6820 SetWindowText(hDlg, errorTitle);
\r
6821 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6825 switch (LOWORD(wParam)) {
\r
6828 if (errorDialog == hDlg) errorDialog = NULL;
\r
6829 DestroyWindow(hDlg);
\r
6841 HWND gothicDialog = NULL;
\r
6844 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6847 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6849 switch (message) {
\r
6850 case WM_INITDIALOG:
\r
6851 GetWindowRect(hDlg, &rChild);
\r
6853 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6857 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6858 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6859 and it doesn't work when you resize the dialog.
\r
6860 For now, just give it a default position.
\r
6862 gothicDialog = hDlg;
\r
6863 SetWindowText(hDlg, errorTitle);
\r
6864 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6868 switch (LOWORD(wParam)) {
\r
6871 if (errorDialog == hDlg) errorDialog = NULL;
\r
6872 DestroyWindow(hDlg);
\r
6884 GothicPopUp(char *title, VariantClass variant)
\r
6887 static char *lastTitle;
\r
6889 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6890 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6892 if(lastTitle != title && gothicDialog != NULL) {
\r
6893 DestroyWindow(gothicDialog);
\r
6894 gothicDialog = NULL;
\r
6896 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6897 title = lastTitle;
\r
6898 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6899 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6900 hwndMain, (DLGPROC)lpProc);
\r
6901 FreeProcInstance(lpProc);
\r
6906 /*---------------------------------------------------------------------------*\
\r
6908 * Ics Interaction console functions
\r
6910 \*---------------------------------------------------------------------------*/
\r
6912 #define HISTORY_SIZE 64
\r
6913 static char *history[HISTORY_SIZE];
\r
6914 int histIn = 0, histP = 0;
\r
6918 SaveInHistory(char *cmd)
\r
6920 if (history[histIn] != NULL) {
\r
6921 free(history[histIn]);
\r
6922 history[histIn] = NULL;
\r
6924 if (*cmd == NULLCHAR) return;
\r
6925 history[histIn] = StrSave(cmd);
\r
6926 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6927 if (history[histIn] != NULL) {
\r
6928 free(history[histIn]);
\r
6930 history[histIn] = NULL;
\r
6936 PrevInHistory(char *cmd)
\r
6939 if (histP == histIn) {
\r
6940 if (history[histIn] != NULL) free(history[histIn]);
\r
6941 history[histIn] = StrSave(cmd);
\r
6943 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6944 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6946 return history[histP];
\r
6952 if (histP == histIn) return NULL;
\r
6953 histP = (histP + 1) % HISTORY_SIZE;
\r
6954 return history[histP];
\r
6958 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6962 hmenu = LoadMenu(hInst, "TextMenu");
\r
6963 h = GetSubMenu(hmenu, 0);
\r
6965 if (strcmp(e->item, "-") == 0) {
\r
6966 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6967 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6968 int flags = MF_STRING, j = 0;
\r
6969 if (e->item[0] == '|') {
\r
6970 flags |= MF_MENUBARBREAK;
\r
6973 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6974 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6982 WNDPROC consoleTextWindowProc;
\r
6985 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6987 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6988 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6992 SetWindowText(hInput, command);
\r
6994 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6996 sel.cpMin = 999999;
\r
6997 sel.cpMax = 999999;
\r
6998 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7003 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7004 if (sel.cpMin == sel.cpMax) {
\r
7005 /* Expand to surrounding word */
\r
7008 tr.chrg.cpMax = sel.cpMin;
\r
7009 tr.chrg.cpMin = --sel.cpMin;
\r
7010 if (sel.cpMin < 0) break;
\r
7011 tr.lpstrText = name;
\r
7012 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7013 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7017 tr.chrg.cpMin = sel.cpMax;
\r
7018 tr.chrg.cpMax = ++sel.cpMax;
\r
7019 tr.lpstrText = name;
\r
7020 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7021 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7024 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7025 MessageBeep(MB_ICONEXCLAMATION);
\r
7029 tr.lpstrText = name;
\r
7030 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7032 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7033 MessageBeep(MB_ICONEXCLAMATION);
\r
7036 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7039 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7040 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7041 SetWindowText(hInput, buf);
\r
7042 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7044 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7045 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7046 SetWindowText(hInput, buf);
\r
7047 sel.cpMin = 999999;
\r
7048 sel.cpMax = 999999;
\r
7049 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7055 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7060 switch (message) {
\r
7062 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7063 if(wParam=='R') return 0;
\r
7066 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7069 sel.cpMin = 999999;
\r
7070 sel.cpMax = 999999;
\r
7071 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7072 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7077 if(wParam != '\022') {
\r
7078 if (wParam == '\t') {
\r
7079 if (GetKeyState(VK_SHIFT) < 0) {
\r
7081 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7082 if (buttonDesc[0].hwnd) {
\r
7083 SetFocus(buttonDesc[0].hwnd);
\r
7085 SetFocus(hwndMain);
\r
7089 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7092 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7093 JAWS_DELETE( SetFocus(hInput); )
\r
7094 SendMessage(hInput, message, wParam, lParam);
\r
7097 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7099 case WM_RBUTTONDOWN:
\r
7100 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7101 /* Move selection here if it was empty */
\r
7103 pt.x = LOWORD(lParam);
\r
7104 pt.y = HIWORD(lParam);
\r
7105 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7106 if (sel.cpMin == sel.cpMax) {
\r
7107 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7108 sel.cpMax = sel.cpMin;
\r
7109 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7111 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7112 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7114 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7115 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7116 if (sel.cpMin == sel.cpMax) {
\r
7117 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7118 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7120 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7121 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7123 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7124 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7125 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7126 MenuPopup(hwnd, pt, hmenu, -1);
\r
7130 case WM_RBUTTONUP:
\r
7131 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7132 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7133 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7137 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7139 return SendMessage(hInput, message, wParam, lParam);
\r
7140 case WM_MBUTTONDOWN:
\r
7141 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7143 switch (LOWORD(wParam)) {
\r
7144 case IDM_QuickPaste:
\r
7146 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7147 if (sel.cpMin == sel.cpMax) {
\r
7148 MessageBeep(MB_ICONEXCLAMATION);
\r
7151 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7152 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7153 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7158 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7161 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7164 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7168 int i = LOWORD(wParam) - IDM_CommandX;
\r
7169 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7170 icsTextMenuEntry[i].command != NULL) {
\r
7171 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7172 icsTextMenuEntry[i].getname,
\r
7173 icsTextMenuEntry[i].immediate);
\r
7181 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7184 WNDPROC consoleInputWindowProc;
\r
7187 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7189 char buf[MSG_SIZ];
\r
7191 static BOOL sendNextChar = FALSE;
\r
7192 static BOOL quoteNextChar = FALSE;
\r
7193 InputSource *is = consoleInputSource;
\r
7197 switch (message) {
\r
7199 if (!appData.localLineEditing || sendNextChar) {
\r
7200 is->buf[0] = (CHAR) wParam;
\r
7202 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7203 sendNextChar = FALSE;
\r
7206 if (quoteNextChar) {
\r
7207 buf[0] = (char) wParam;
\r
7208 buf[1] = NULLCHAR;
\r
7209 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7210 quoteNextChar = FALSE;
\r
7214 case '\r': /* Enter key */
\r
7215 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7216 if (consoleEcho) SaveInHistory(is->buf);
\r
7217 is->buf[is->count++] = '\n';
\r
7218 is->buf[is->count] = NULLCHAR;
\r
7219 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7220 if (consoleEcho) {
\r
7221 ConsoleOutput(is->buf, is->count, TRUE);
\r
7222 } else if (appData.localLineEditing) {
\r
7223 ConsoleOutput("\n", 1, TRUE);
\r
7226 case '\033': /* Escape key */
\r
7227 SetWindowText(hwnd, "");
\r
7228 cf.cbSize = sizeof(CHARFORMAT);
\r
7229 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7230 if (consoleEcho) {
\r
7231 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7233 cf.crTextColor = COLOR_ECHOOFF;
\r
7235 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7236 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7238 case '\t': /* Tab key */
\r
7239 if (GetKeyState(VK_SHIFT) < 0) {
\r
7241 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7244 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7245 if (buttonDesc[0].hwnd) {
\r
7246 SetFocus(buttonDesc[0].hwnd);
\r
7248 SetFocus(hwndMain);
\r
7252 case '\023': /* Ctrl+S */
\r
7253 sendNextChar = TRUE;
\r
7255 case '\021': /* Ctrl+Q */
\r
7256 quoteNextChar = TRUE;
\r
7266 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7267 p = PrevInHistory(buf);
\r
7269 SetWindowText(hwnd, p);
\r
7270 sel.cpMin = 999999;
\r
7271 sel.cpMax = 999999;
\r
7272 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7277 p = NextInHistory();
\r
7279 SetWindowText(hwnd, p);
\r
7280 sel.cpMin = 999999;
\r
7281 sel.cpMax = 999999;
\r
7282 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7288 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7292 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7296 case WM_MBUTTONDOWN:
\r
7297 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7298 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7300 case WM_RBUTTONUP:
\r
7301 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7302 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7303 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7307 hmenu = LoadMenu(hInst, "InputMenu");
\r
7308 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7309 if (sel.cpMin == sel.cpMax) {
\r
7310 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7311 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7313 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7314 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7316 pt.x = LOWORD(lParam);
\r
7317 pt.y = HIWORD(lParam);
\r
7318 MenuPopup(hwnd, pt, hmenu, -1);
\r
7322 switch (LOWORD(wParam)) {
\r
7324 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7326 case IDM_SelectAll:
\r
7328 sel.cpMax = -1; /*999999?*/
\r
7329 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7332 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7335 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7338 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7343 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7346 #define CO_MAX 100000
\r
7347 #define CO_TRIM 1000
\r
7350 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7352 static SnapData sd;
\r
7353 HWND hText, hInput;
\r
7355 static int sizeX, sizeY;
\r
7356 int newSizeX, newSizeY;
\r
7360 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7361 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7363 switch (message) {
\r
7365 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7367 ENLINK *pLink = (ENLINK*)lParam;
\r
7368 if (pLink->msg == WM_LBUTTONUP)
\r
7372 tr.chrg = pLink->chrg;
\r
7373 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7374 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7375 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7376 free(tr.lpstrText);
\r
7380 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7381 hwndConsole = hDlg;
\r
7383 consoleTextWindowProc = (WNDPROC)
\r
7384 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7385 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7386 consoleInputWindowProc = (WNDPROC)
\r
7387 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7388 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7389 Colorize(ColorNormal, TRUE);
\r
7390 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7391 ChangedConsoleFont();
\r
7392 GetClientRect(hDlg, &rect);
\r
7393 sizeX = rect.right;
\r
7394 sizeY = rect.bottom;
\r
7395 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7396 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7397 WINDOWPLACEMENT wp;
\r
7398 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7399 wp.length = sizeof(WINDOWPLACEMENT);
\r
7401 wp.showCmd = SW_SHOW;
\r
7402 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7403 wp.rcNormalPosition.left = wpConsole.x;
\r
7404 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7405 wp.rcNormalPosition.top = wpConsole.y;
\r
7406 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7407 SetWindowPlacement(hDlg, &wp);
\r
7410 // [HGM] Chessknight's change 2004-07-13
\r
7411 else { /* Determine Defaults */
\r
7412 WINDOWPLACEMENT wp;
\r
7413 wpConsole.x = wpMain.width + 1;
\r
7414 wpConsole.y = wpMain.y;
\r
7415 wpConsole.width = screenWidth - wpMain.width;
\r
7416 wpConsole.height = wpMain.height;
\r
7417 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7418 wp.length = sizeof(WINDOWPLACEMENT);
\r
7420 wp.showCmd = SW_SHOW;
\r
7421 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7422 wp.rcNormalPosition.left = wpConsole.x;
\r
7423 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7424 wp.rcNormalPosition.top = wpConsole.y;
\r
7425 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7426 SetWindowPlacement(hDlg, &wp);
\r
7429 // Allow hText to highlight URLs and send notifications on them
\r
7430 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7431 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7432 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7433 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7447 if (IsIconic(hDlg)) break;
\r
7448 newSizeX = LOWORD(lParam);
\r
7449 newSizeY = HIWORD(lParam);
\r
7450 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7451 RECT rectText, rectInput;
\r
7453 int newTextHeight, newTextWidth;
\r
7454 GetWindowRect(hText, &rectText);
\r
7455 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7456 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7457 if (newTextHeight < 0) {
\r
7458 newSizeY += -newTextHeight;
\r
7459 newTextHeight = 0;
\r
7461 SetWindowPos(hText, NULL, 0, 0,
\r
7462 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7463 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7464 pt.x = rectInput.left;
\r
7465 pt.y = rectInput.top + newSizeY - sizeY;
\r
7466 ScreenToClient(hDlg, &pt);
\r
7467 SetWindowPos(hInput, NULL,
\r
7468 pt.x, pt.y, /* needs client coords */
\r
7469 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7470 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7476 case WM_GETMINMAXINFO:
\r
7477 /* Prevent resizing window too small */
\r
7478 mmi = (MINMAXINFO *) lParam;
\r
7479 mmi->ptMinTrackSize.x = 100;
\r
7480 mmi->ptMinTrackSize.y = 100;
\r
7483 /* [AS] Snapping */
\r
7484 case WM_ENTERSIZEMOVE:
\r
7485 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7488 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7491 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7493 case WM_EXITSIZEMOVE:
\r
7494 UpdateICSWidth(hText);
\r
7495 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7498 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7506 if (hwndConsole) return;
\r
7507 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7508 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7513 ConsoleOutput(char* data, int length, int forceVisible)
\r
7518 char buf[CO_MAX+1];
\r
7521 static int delayLF = 0;
\r
7522 CHARRANGE savesel, sel;
\r
7524 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7532 while (length--) {
\r
7540 } else if (*p == '\007') {
\r
7541 MyPlaySound(&sounds[(int)SoundBell]);
\r
7548 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7549 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7550 /* Save current selection */
\r
7551 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7552 exlen = GetWindowTextLength(hText);
\r
7553 /* Find out whether current end of text is visible */
\r
7554 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7555 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7556 /* Trim existing text if it's too long */
\r
7557 if (exlen + (q - buf) > CO_MAX) {
\r
7558 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7561 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7562 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7564 savesel.cpMin -= trim;
\r
7565 savesel.cpMax -= trim;
\r
7566 if (exlen < 0) exlen = 0;
\r
7567 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7568 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7570 /* Append the new text */
\r
7571 sel.cpMin = exlen;
\r
7572 sel.cpMax = exlen;
\r
7573 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7574 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7575 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7576 if (forceVisible || exlen == 0 ||
\r
7577 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7578 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7579 /* Scroll to make new end of text visible if old end of text
\r
7580 was visible or new text is an echo of user typein */
\r
7581 sel.cpMin = 9999999;
\r
7582 sel.cpMax = 9999999;
\r
7583 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7584 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7585 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7586 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7588 if (savesel.cpMax == exlen || forceVisible) {
\r
7589 /* Move insert point to new end of text if it was at the old
\r
7590 end of text or if the new text is an echo of user typein */
\r
7591 sel.cpMin = 9999999;
\r
7592 sel.cpMax = 9999999;
\r
7593 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7595 /* Restore previous selection */
\r
7596 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7598 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7605 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7609 COLORREF oldFg, oldBg;
\r
7613 if(copyNumber > 1)
\r
7614 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7616 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7617 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7618 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7621 rect.right = x + squareSize;
\r
7623 rect.bottom = y + squareSize;
\r
7626 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7627 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7628 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7629 &rect, str, strlen(str), NULL);
\r
7631 (void) SetTextColor(hdc, oldFg);
\r
7632 (void) SetBkColor(hdc, oldBg);
\r
7633 (void) SelectObject(hdc, oldFont);
\r
7637 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7638 RECT *rect, char *color, char *flagFell)
\r
7642 COLORREF oldFg, oldBg;
\r
7645 if (twoBoards && partnerUp) return;
\r
7646 if (appData.clockMode) {
\r
7648 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7650 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7657 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7658 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7660 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7661 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7663 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7667 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7668 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7669 rect, str, strlen(str), NULL);
\r
7670 if(logoHeight > 0 && appData.clockMode) {
\r
7672 str += strlen(color)+2;
\r
7673 r.top = rect->top + logoHeight/2;
\r
7674 r.left = rect->left;
\r
7675 r.right = rect->right;
\r
7676 r.bottom = rect->bottom;
\r
7677 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7678 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7679 &r, str, strlen(str), NULL);
\r
7681 (void) SetTextColor(hdc, oldFg);
\r
7682 (void) SetBkColor(hdc, oldBg);
\r
7683 (void) SelectObject(hdc, oldFont);
\r
7688 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7694 if( count <= 0 ) {
\r
7695 if (appData.debugMode) {
\r
7696 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7699 return ERROR_INVALID_USER_BUFFER;
\r
7702 ResetEvent(ovl->hEvent);
\r
7703 ovl->Offset = ovl->OffsetHigh = 0;
\r
7704 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7708 err = GetLastError();
\r
7709 if (err == ERROR_IO_PENDING) {
\r
7710 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7714 err = GetLastError();
\r
7721 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7726 ResetEvent(ovl->hEvent);
\r
7727 ovl->Offset = ovl->OffsetHigh = 0;
\r
7728 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7732 err = GetLastError();
\r
7733 if (err == ERROR_IO_PENDING) {
\r
7734 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7738 err = GetLastError();
\r
7745 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7746 void CheckForInputBufferFull( InputSource * is )
\r
7748 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7749 /* Look for end of line */
\r
7750 char * p = is->buf;
\r
7752 while( p < is->next && *p != '\n' ) {
\r
7756 if( p >= is->next ) {
\r
7757 if (appData.debugMode) {
\r
7758 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7761 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7762 is->count = (DWORD) -1;
\r
7763 is->next = is->buf;
\r
7769 InputThread(LPVOID arg)
\r
7774 is = (InputSource *) arg;
\r
7775 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7776 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7777 while (is->hThread != NULL) {
\r
7778 is->error = DoReadFile(is->hFile, is->next,
\r
7779 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7780 &is->count, &ovl);
\r
7781 if (is->error == NO_ERROR) {
\r
7782 is->next += is->count;
\r
7784 if (is->error == ERROR_BROKEN_PIPE) {
\r
7785 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7788 is->count = (DWORD) -1;
\r
7789 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7794 CheckForInputBufferFull( is );
\r
7796 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7798 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7800 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7803 CloseHandle(ovl.hEvent);
\r
7804 CloseHandle(is->hFile);
\r
7806 if (appData.debugMode) {
\r
7807 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7814 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7816 NonOvlInputThread(LPVOID arg)
\r
7823 is = (InputSource *) arg;
\r
7824 while (is->hThread != NULL) {
\r
7825 is->error = ReadFile(is->hFile, is->next,
\r
7826 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7827 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7828 if (is->error == NO_ERROR) {
\r
7829 /* Change CRLF to LF */
\r
7830 if (is->next > is->buf) {
\r
7832 i = is->count + 1;
\r
7840 if (prev == '\r' && *p == '\n') {
\r
7852 if (is->error == ERROR_BROKEN_PIPE) {
\r
7853 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7856 is->count = (DWORD) -1;
\r
7860 CheckForInputBufferFull( is );
\r
7862 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7864 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7866 if (is->count < 0) break; /* Quit on error */
\r
7868 CloseHandle(is->hFile);
\r
7873 SocketInputThread(LPVOID arg)
\r
7877 is = (InputSource *) arg;
\r
7878 while (is->hThread != NULL) {
\r
7879 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7880 if ((int)is->count == SOCKET_ERROR) {
\r
7881 is->count = (DWORD) -1;
\r
7882 is->error = WSAGetLastError();
\r
7884 is->error = NO_ERROR;
\r
7885 is->next += is->count;
\r
7886 if (is->count == 0 && is->second == is) {
\r
7887 /* End of file on stderr; quit with no message */
\r
7891 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7893 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7895 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7901 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7905 is = (InputSource *) lParam;
\r
7906 if (is->lineByLine) {
\r
7907 /* Feed in lines one by one */
\r
7908 char *p = is->buf;
\r
7910 while (q < is->next) {
\r
7911 if (*q++ == '\n') {
\r
7912 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7917 /* Move any partial line to the start of the buffer */
\r
7919 while (p < is->next) {
\r
7924 if (is->error != NO_ERROR || is->count == 0) {
\r
7925 /* Notify backend of the error. Note: If there was a partial
\r
7926 line at the end, it is not flushed through. */
\r
7927 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7930 /* Feed in the whole chunk of input at once */
\r
7931 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7932 is->next = is->buf;
\r
7936 /*---------------------------------------------------------------------------*\
\r
7938 * Menu enables. Used when setting various modes.
\r
7940 \*---------------------------------------------------------------------------*/
\r
7948 GreyRevert(Boolean grey)
\r
7949 { // [HGM] vari: for retracting variations in local mode
\r
7950 HMENU hmenu = GetMenu(hwndMain);
\r
7951 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7952 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7956 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7958 while (enab->item > 0) {
\r
7959 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7964 Enables gnuEnables[] = {
\r
7965 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7966 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7967 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7968 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7969 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7970 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7971 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7972 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7979 // Needed to switch from ncp to GNU mode on Engine Load
\r
7980 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7981 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7982 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7983 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7984 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7985 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7986 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7987 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7990 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7991 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7992 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7993 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7997 Enables icsEnables[] = {
\r
7998 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7999 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8000 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8001 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8002 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8003 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8004 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8005 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8006 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8007 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8008 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8014 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8022 Enables zippyEnables[] = {
\r
8023 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8024 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8025 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8026 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8031 Enables ncpEnables[] = {
\r
8032 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8033 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8034 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8035 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8036 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8037 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8038 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8039 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8040 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8041 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8042 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8043 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8044 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8045 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8046 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8047 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8048 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8053 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8057 Enables trainingOnEnables[] = {
\r
8058 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8059 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8060 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8062 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8063 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8064 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8065 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8066 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8070 Enables trainingOffEnables[] = {
\r
8071 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8072 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8073 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8074 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8075 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8076 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8077 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8078 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8079 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8083 /* These modify either ncpEnables or gnuEnables */
\r
8084 Enables cmailEnables[] = {
\r
8085 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8086 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8087 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8088 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8089 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8090 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8091 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8095 Enables machineThinkingEnables[] = {
\r
8096 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8097 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8098 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8099 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8100 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8101 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8102 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8103 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8104 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8105 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8106 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8107 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8109 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8110 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8111 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8115 Enables userThinkingEnables[] = {
\r
8116 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8117 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8118 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8119 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8120 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8121 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8122 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8123 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8124 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8125 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8126 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8127 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8129 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8130 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8131 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8135 /*---------------------------------------------------------------------------*\
\r
8137 * Front-end interface functions exported by XBoard.
\r
8138 * Functions appear in same order as prototypes in frontend.h.
\r
8140 \*---------------------------------------------------------------------------*/
\r
8142 CheckMark(UINT item, int state)
\r
8144 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8150 static UINT prevChecked = 0;
\r
8151 static int prevPausing = 0;
\r
8154 if (pausing != prevPausing) {
\r
8155 prevPausing = pausing;
\r
8156 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8157 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8158 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8161 switch (gameMode) {
\r
8162 case BeginningOfGame:
\r
8163 if (appData.icsActive)
\r
8164 nowChecked = IDM_IcsClient;
\r
8165 else if (appData.noChessProgram)
\r
8166 nowChecked = IDM_EditGame;
\r
8168 nowChecked = IDM_MachineBlack;
\r
8170 case MachinePlaysBlack:
\r
8171 nowChecked = IDM_MachineBlack;
\r
8173 case MachinePlaysWhite:
\r
8174 nowChecked = IDM_MachineWhite;
\r
8176 case TwoMachinesPlay:
\r
8177 nowChecked = IDM_TwoMachines;
\r
8180 nowChecked = IDM_AnalysisMode;
\r
8183 nowChecked = IDM_AnalyzeFile;
\r
8186 nowChecked = IDM_EditGame;
\r
8188 case PlayFromGameFile:
\r
8189 nowChecked = IDM_LoadGame;
\r
8191 case EditPosition:
\r
8192 nowChecked = IDM_EditPosition;
\r
8195 nowChecked = IDM_Training;
\r
8197 case IcsPlayingWhite:
\r
8198 case IcsPlayingBlack:
\r
8199 case IcsObserving:
\r
8201 nowChecked = IDM_IcsClient;
\r
8208 CheckMark(prevChecked, MF_UNCHECKED);
\r
8209 CheckMark(nowChecked, MF_CHECKED);
\r
8210 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8212 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8213 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8214 MF_BYCOMMAND|MF_ENABLED);
\r
8216 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8217 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8220 prevChecked = nowChecked;
\r
8222 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8223 if (appData.icsActive) {
\r
8224 if (appData.icsEngineAnalyze) {
\r
8225 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8227 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8230 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8236 HMENU hmenu = GetMenu(hwndMain);
\r
8237 SetMenuEnables(hmenu, icsEnables);
\r
8238 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8239 MF_BYCOMMAND|MF_ENABLED);
\r
8241 if (appData.zippyPlay) {
\r
8242 SetMenuEnables(hmenu, zippyEnables);
\r
8243 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8244 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8245 MF_BYCOMMAND|MF_ENABLED);
\r
8253 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8259 HMENU hmenu = GetMenu(hwndMain);
\r
8260 SetMenuEnables(hmenu, ncpEnables);
\r
8261 DrawMenuBar(hwndMain);
\r
8267 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8271 SetTrainingModeOn()
\r
8274 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8275 for (i = 0; i < N_BUTTONS; i++) {
\r
8276 if (buttonDesc[i].hwnd != NULL)
\r
8277 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8282 VOID SetTrainingModeOff()
\r
8285 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8286 for (i = 0; i < N_BUTTONS; i++) {
\r
8287 if (buttonDesc[i].hwnd != NULL)
\r
8288 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8294 SetUserThinkingEnables()
\r
8296 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8300 SetMachineThinkingEnables()
\r
8302 HMENU hMenu = GetMenu(hwndMain);
\r
8303 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8305 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8307 if (gameMode == MachinePlaysBlack) {
\r
8308 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8309 } else if (gameMode == MachinePlaysWhite) {
\r
8310 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8311 } else if (gameMode == TwoMachinesPlay) {
\r
8312 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8318 DisplayTitle(char *str)
\r
8320 char title[MSG_SIZ], *host;
\r
8321 if (str[0] != NULLCHAR) {
\r
8322 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8323 } else if (appData.icsActive) {
\r
8324 if (appData.icsCommPort[0] != NULLCHAR)
\r
8327 host = appData.icsHost;
\r
8328 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8329 } else if (appData.noChessProgram) {
\r
8330 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8332 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8333 strcat(title, ": ");
\r
8334 strcat(title, first.tidy);
\r
8336 SetWindowText(hwndMain, title);
\r
8341 DisplayMessage(char *str1, char *str2)
\r
8345 int remain = MESSAGE_TEXT_MAX - 1;
\r
8348 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8349 messageText[0] = NULLCHAR;
\r
8351 len = strlen(str1);
\r
8352 if (len > remain) len = remain;
\r
8353 strncpy(messageText, str1, len);
\r
8354 messageText[len] = NULLCHAR;
\r
8357 if (*str2 && remain >= 2) {
\r
8359 strcat(messageText, " ");
\r
8362 len = strlen(str2);
\r
8363 if (len > remain) len = remain;
\r
8364 strncat(messageText, str2, len);
\r
8366 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8367 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8369 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8373 hdc = GetDC(hwndMain);
\r
8374 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8375 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8376 &messageRect, messageText, strlen(messageText), NULL);
\r
8377 (void) SelectObject(hdc, oldFont);
\r
8378 (void) ReleaseDC(hwndMain, hdc);
\r
8382 DisplayError(char *str, int error)
\r
8384 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8388 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8390 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8391 NULL, error, LANG_NEUTRAL,
\r
8392 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8394 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8396 ErrorMap *em = errmap;
\r
8397 while (em->err != 0 && em->err != error) em++;
\r
8398 if (em->err != 0) {
\r
8399 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8401 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8406 ErrorPopUp(_("Error"), buf);
\r
8411 DisplayMoveError(char *str)
\r
8413 fromX = fromY = -1;
\r
8414 ClearHighlights();
\r
8415 DrawPosition(FALSE, NULL);
\r
8416 if (appData.popupMoveErrors) {
\r
8417 ErrorPopUp(_("Error"), str);
\r
8419 DisplayMessage(str, "");
\r
8420 moveErrorMessageUp = TRUE;
\r
8425 DisplayFatalError(char *str, int error, int exitStatus)
\r
8427 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8429 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8432 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8433 NULL, error, LANG_NEUTRAL,
\r
8434 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8436 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8438 ErrorMap *em = errmap;
\r
8439 while (em->err != 0 && em->err != error) em++;
\r
8440 if (em->err != 0) {
\r
8441 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8443 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8448 if (appData.debugMode) {
\r
8449 fprintf(debugFP, "%s: %s\n", label, str);
\r
8451 if (appData.popupExitMessage) {
\r
8452 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8453 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8455 ExitEvent(exitStatus);
\r
8460 DisplayInformation(char *str)
\r
8462 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8467 DisplayNote(char *str)
\r
8469 ErrorPopUp(_("Note"), str);
\r
8474 char *title, *question, *replyPrefix;
\r
8479 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8481 static QuestionParams *qp;
\r
8482 char reply[MSG_SIZ];
\r
8485 switch (message) {
\r
8486 case WM_INITDIALOG:
\r
8487 qp = (QuestionParams *) lParam;
\r
8488 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8489 Translate(hDlg, DLG_Question);
\r
8490 SetWindowText(hDlg, qp->title);
\r
8491 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8492 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8496 switch (LOWORD(wParam)) {
\r
8498 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8499 if (*reply) strcat(reply, " ");
\r
8500 len = strlen(reply);
\r
8501 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8502 strcat(reply, "\n");
\r
8503 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8504 EndDialog(hDlg, TRUE);
\r
8505 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8508 EndDialog(hDlg, FALSE);
\r
8519 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8521 QuestionParams qp;
\r
8525 qp.question = question;
\r
8526 qp.replyPrefix = replyPrefix;
\r
8528 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8529 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8530 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8531 FreeProcInstance(lpProc);
\r
8534 /* [AS] Pick FRC position */
\r
8535 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8537 static int * lpIndexFRC;
\r
8543 case WM_INITDIALOG:
\r
8544 lpIndexFRC = (int *) lParam;
\r
8546 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8547 Translate(hDlg, DLG_NewGameFRC);
\r
8549 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8550 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8551 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8552 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8557 switch( LOWORD(wParam) ) {
\r
8559 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8560 EndDialog( hDlg, 0 );
\r
8561 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8564 EndDialog( hDlg, 1 );
\r
8566 case IDC_NFG_Edit:
\r
8567 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8568 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8570 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8573 case IDC_NFG_Random:
\r
8574 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8575 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8588 int index = appData.defaultFrcPosition;
\r
8589 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8591 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8593 if( result == 0 ) {
\r
8594 appData.defaultFrcPosition = index;
\r
8600 /* [AS] Game list options. Refactored by HGM */
\r
8602 HWND gameListOptionsDialog;
\r
8604 // low-level front-end: clear text edit / list widget
\r
8609 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8612 // low-level front-end: clear text edit / list widget
\r
8614 GLT_DeSelectList()
\r
8616 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8619 // low-level front-end: append line to text edit / list widget
\r
8621 GLT_AddToList( char *name )
\r
8624 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8628 // low-level front-end: get line from text edit / list widget
\r
8630 GLT_GetFromList( int index, char *name )
\r
8633 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8639 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8641 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8642 int idx2 = idx1 + delta;
\r
8643 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8645 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8648 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8649 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8650 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8651 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8655 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8659 case WM_INITDIALOG:
\r
8660 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8662 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8663 Translate(hDlg, DLG_GameListOptions);
\r
8665 /* Initialize list */
\r
8666 GLT_TagsToList( lpUserGLT );
\r
8668 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8673 switch( LOWORD(wParam) ) {
\r
8676 EndDialog( hDlg, 0 );
\r
8679 EndDialog( hDlg, 1 );
\r
8682 case IDC_GLT_Default:
\r
8683 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8686 case IDC_GLT_Restore:
\r
8687 GLT_TagsToList( appData.gameListTags );
\r
8691 GLT_MoveSelection( hDlg, -1 );
\r
8694 case IDC_GLT_Down:
\r
8695 GLT_MoveSelection( hDlg, +1 );
\r
8705 int GameListOptions()
\r
8708 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8710 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8712 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8714 if( result == 0 ) {
\r
8715 char *oldTags = appData.gameListTags;
\r
8716 /* [AS] Memory leak here! */
\r
8717 appData.gameListTags = strdup( lpUserGLT );
\r
8718 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8719 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8726 DisplayIcsInteractionTitle(char *str)
\r
8728 char consoleTitle[MSG_SIZ];
\r
8730 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8731 SetWindowText(hwndConsole, consoleTitle);
\r
8733 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8734 char buf[MSG_SIZ], *p = buf, *q;
\r
8735 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8737 q = strchr(p, ';');
\r
8739 if(*p) ChatPopUp(p);
\r
8743 SetActiveWindow(hwndMain);
\r
8747 DrawPosition(int fullRedraw, Board board)
\r
8749 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8752 void NotifyFrontendLogin()
\r
8755 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8761 fromX = fromY = -1;
\r
8762 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8763 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8764 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8765 dragInfo.lastpos = dragInfo.pos;
\r
8766 dragInfo.start.x = dragInfo.start.y = -1;
\r
8767 dragInfo.from = dragInfo.start;
\r
8769 DrawPosition(TRUE, NULL);
\r
8776 CommentPopUp(char *title, char *str)
\r
8778 HWND hwnd = GetActiveWindow();
\r
8779 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8781 SetActiveWindow(hwnd);
\r
8785 CommentPopDown(void)
\r
8787 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8788 if (commentDialog) {
\r
8789 ShowWindow(commentDialog, SW_HIDE);
\r
8791 commentUp = FALSE;
\r
8795 EditCommentPopUp(int index, char *title, char *str)
\r
8797 EitherCommentPopUp(index, title, str, TRUE);
\r
8804 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8811 MyPlaySound(&sounds[(int)SoundMove]);
\r
8814 VOID PlayIcsWinSound()
\r
8816 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8819 VOID PlayIcsLossSound()
\r
8821 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8824 VOID PlayIcsDrawSound()
\r
8826 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8829 VOID PlayIcsUnfinishedSound()
\r
8831 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8837 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8843 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8851 consoleEcho = TRUE;
\r
8852 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8853 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8854 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8863 consoleEcho = FALSE;
\r
8864 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8865 /* This works OK: set text and background both to the same color */
\r
8867 cf.crTextColor = COLOR_ECHOOFF;
\r
8868 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8869 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8872 /* No Raw()...? */
\r
8874 void Colorize(ColorClass cc, int continuation)
\r
8876 currentColorClass = cc;
\r
8877 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8878 consoleCF.crTextColor = textAttribs[cc].color;
\r
8879 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8880 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8886 static char buf[MSG_SIZ];
\r
8887 DWORD bufsiz = MSG_SIZ;
\r
8889 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8890 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8892 if (!GetUserName(buf, &bufsiz)) {
\r
8893 /*DisplayError("Error getting user name", GetLastError());*/
\r
8894 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8902 static char buf[MSG_SIZ];
\r
8903 DWORD bufsiz = MSG_SIZ;
\r
8905 if (!GetComputerName(buf, &bufsiz)) {
\r
8906 /*DisplayError("Error getting host name", GetLastError());*/
\r
8907 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8914 ClockTimerRunning()
\r
8916 return clockTimerEvent != 0;
\r
8922 if (clockTimerEvent == 0) return FALSE;
\r
8923 KillTimer(hwndMain, clockTimerEvent);
\r
8924 clockTimerEvent = 0;
\r
8929 StartClockTimer(long millisec)
\r
8931 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8932 (UINT) millisec, NULL);
\r
8936 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8939 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8941 if(appData.noGUI) return;
\r
8942 hdc = GetDC(hwndMain);
\r
8943 if (!IsIconic(hwndMain)) {
\r
8944 DisplayAClock(hdc, timeRemaining, highlight,
\r
8945 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8947 if (highlight && iconCurrent == iconBlack) {
\r
8948 iconCurrent = iconWhite;
\r
8949 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8950 if (IsIconic(hwndMain)) {
\r
8951 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8954 (void) ReleaseDC(hwndMain, hdc);
\r
8956 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8960 DisplayBlackClock(long timeRemaining, int highlight)
\r
8963 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8966 if(appData.noGUI) return;
\r
8967 hdc = GetDC(hwndMain);
\r
8968 if (!IsIconic(hwndMain)) {
\r
8969 DisplayAClock(hdc, timeRemaining, highlight,
\r
8970 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8972 if (highlight && iconCurrent == iconWhite) {
\r
8973 iconCurrent = iconBlack;
\r
8974 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8975 if (IsIconic(hwndMain)) {
\r
8976 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8979 (void) ReleaseDC(hwndMain, hdc);
\r
8981 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8986 LoadGameTimerRunning()
\r
8988 return loadGameTimerEvent != 0;
\r
8992 StopLoadGameTimer()
\r
8994 if (loadGameTimerEvent == 0) return FALSE;
\r
8995 KillTimer(hwndMain, loadGameTimerEvent);
\r
8996 loadGameTimerEvent = 0;
\r
9001 StartLoadGameTimer(long millisec)
\r
9003 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9004 (UINT) millisec, NULL);
\r
9012 char fileTitle[MSG_SIZ];
\r
9014 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9015 f = OpenFileDialog(hwndMain, "a", defName,
\r
9016 appData.oldSaveStyle ? "gam" : "pgn",
\r
9018 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9020 SaveGame(f, 0, "");
\r
9027 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9029 if (delayedTimerEvent != 0) {
\r
9030 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9031 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9033 KillTimer(hwndMain, delayedTimerEvent);
\r
9034 delayedTimerEvent = 0;
\r
9035 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9036 delayedTimerCallback();
\r
9038 delayedTimerCallback = cb;
\r
9039 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9040 (UINT) millisec, NULL);
\r
9043 DelayedEventCallback
\r
9046 if (delayedTimerEvent) {
\r
9047 return delayedTimerCallback;
\r
9054 CancelDelayedEvent()
\r
9056 if (delayedTimerEvent) {
\r
9057 KillTimer(hwndMain, delayedTimerEvent);
\r
9058 delayedTimerEvent = 0;
\r
9062 DWORD GetWin32Priority(int nice)
\r
9063 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9065 REALTIME_PRIORITY_CLASS 0x00000100
\r
9066 HIGH_PRIORITY_CLASS 0x00000080
\r
9067 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9068 NORMAL_PRIORITY_CLASS 0x00000020
\r
9069 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9070 IDLE_PRIORITY_CLASS 0x00000040
\r
9072 if (nice < -15) return 0x00000080;
\r
9073 if (nice < 0) return 0x00008000;
\r
9074 if (nice == 0) return 0x00000020;
\r
9075 if (nice < 15) return 0x00004000;
\r
9076 return 0x00000040;
\r
9079 void RunCommand(char *cmdLine)
\r
9081 /* Now create the child process. */
\r
9082 STARTUPINFO siStartInfo;
\r
9083 PROCESS_INFORMATION piProcInfo;
\r
9085 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9086 siStartInfo.lpReserved = NULL;
\r
9087 siStartInfo.lpDesktop = NULL;
\r
9088 siStartInfo.lpTitle = NULL;
\r
9089 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9090 siStartInfo.cbReserved2 = 0;
\r
9091 siStartInfo.lpReserved2 = NULL;
\r
9092 siStartInfo.hStdInput = NULL;
\r
9093 siStartInfo.hStdOutput = NULL;
\r
9094 siStartInfo.hStdError = NULL;
\r
9096 CreateProcess(NULL,
\r
9097 cmdLine, /* command line */
\r
9098 NULL, /* process security attributes */
\r
9099 NULL, /* primary thread security attrs */
\r
9100 TRUE, /* handles are inherited */
\r
9101 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9102 NULL, /* use parent's environment */
\r
9104 &siStartInfo, /* STARTUPINFO pointer */
\r
9105 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9107 CloseHandle(piProcInfo.hThread);
\r
9110 /* Start a child process running the given program.
\r
9111 The process's standard output can be read from "from", and its
\r
9112 standard input can be written to "to".
\r
9113 Exit with fatal error if anything goes wrong.
\r
9114 Returns an opaque pointer that can be used to destroy the process
\r
9118 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9120 #define BUFSIZE 4096
\r
9122 HANDLE hChildStdinRd, hChildStdinWr,
\r
9123 hChildStdoutRd, hChildStdoutWr;
\r
9124 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9125 SECURITY_ATTRIBUTES saAttr;
\r
9127 PROCESS_INFORMATION piProcInfo;
\r
9128 STARTUPINFO siStartInfo;
\r
9130 char buf[MSG_SIZ];
\r
9133 if (appData.debugMode) {
\r
9134 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9139 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9140 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9141 saAttr.bInheritHandle = TRUE;
\r
9142 saAttr.lpSecurityDescriptor = NULL;
\r
9145 * The steps for redirecting child's STDOUT:
\r
9146 * 1. Create anonymous pipe to be STDOUT for child.
\r
9147 * 2. Create a noninheritable duplicate of read handle,
\r
9148 * and close the inheritable read handle.
\r
9151 /* Create a pipe for the child's STDOUT. */
\r
9152 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9153 return GetLastError();
\r
9156 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9157 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9158 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9159 FALSE, /* not inherited */
\r
9160 DUPLICATE_SAME_ACCESS);
\r
9162 return GetLastError();
\r
9164 CloseHandle(hChildStdoutRd);
\r
9167 * The steps for redirecting child's STDIN:
\r
9168 * 1. Create anonymous pipe to be STDIN for child.
\r
9169 * 2. Create a noninheritable duplicate of write handle,
\r
9170 * and close the inheritable write handle.
\r
9173 /* Create a pipe for the child's STDIN. */
\r
9174 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9175 return GetLastError();
\r
9178 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9179 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9180 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9181 FALSE, /* not inherited */
\r
9182 DUPLICATE_SAME_ACCESS);
\r
9184 return GetLastError();
\r
9186 CloseHandle(hChildStdinWr);
\r
9188 /* Arrange to (1) look in dir for the child .exe file, and
\r
9189 * (2) have dir be the child's working directory. Interpret
\r
9190 * dir relative to the directory WinBoard loaded from. */
\r
9191 GetCurrentDirectory(MSG_SIZ, buf);
\r
9192 SetCurrentDirectory(installDir);
\r
9193 SetCurrentDirectory(dir);
\r
9195 /* Now create the child process. */
\r
9197 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9198 siStartInfo.lpReserved = NULL;
\r
9199 siStartInfo.lpDesktop = NULL;
\r
9200 siStartInfo.lpTitle = NULL;
\r
9201 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9202 siStartInfo.cbReserved2 = 0;
\r
9203 siStartInfo.lpReserved2 = NULL;
\r
9204 siStartInfo.hStdInput = hChildStdinRd;
\r
9205 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9206 siStartInfo.hStdError = hChildStdoutWr;
\r
9208 fSuccess = CreateProcess(NULL,
\r
9209 cmdLine, /* command line */
\r
9210 NULL, /* process security attributes */
\r
9211 NULL, /* primary thread security attrs */
\r
9212 TRUE, /* handles are inherited */
\r
9213 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9214 NULL, /* use parent's environment */
\r
9216 &siStartInfo, /* STARTUPINFO pointer */
\r
9217 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9219 err = GetLastError();
\r
9220 SetCurrentDirectory(buf); /* return to prev directory */
\r
9225 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9226 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9227 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9230 /* Close the handles we don't need in the parent */
\r
9231 CloseHandle(piProcInfo.hThread);
\r
9232 CloseHandle(hChildStdinRd);
\r
9233 CloseHandle(hChildStdoutWr);
\r
9235 /* Prepare return value */
\r
9236 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9237 cp->kind = CPReal;
\r
9238 cp->hProcess = piProcInfo.hProcess;
\r
9239 cp->pid = piProcInfo.dwProcessId;
\r
9240 cp->hFrom = hChildStdoutRdDup;
\r
9241 cp->hTo = hChildStdinWrDup;
\r
9243 *pr = (void *) cp;
\r
9245 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9246 2000 where engines sometimes don't see the initial command(s)
\r
9247 from WinBoard and hang. I don't understand how that can happen,
\r
9248 but the Sleep is harmless, so I've put it in. Others have also
\r
9249 reported what may be the same problem, so hopefully this will fix
\r
9250 it for them too. */
\r
9258 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9260 ChildProc *cp; int result;
\r
9262 cp = (ChildProc *) pr;
\r
9263 if (cp == NULL) return;
\r
9265 switch (cp->kind) {
\r
9267 /* TerminateProcess is considered harmful, so... */
\r
9268 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9269 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9270 /* The following doesn't work because the chess program
\r
9271 doesn't "have the same console" as WinBoard. Maybe
\r
9272 we could arrange for this even though neither WinBoard
\r
9273 nor the chess program uses a console for stdio? */
\r
9274 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9276 /* [AS] Special termination modes for misbehaving programs... */
\r
9277 if( signal & 8 ) {
\r
9278 result = TerminateProcess( cp->hProcess, 0 );
\r
9280 if ( appData.debugMode) {
\r
9281 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9284 else if( signal & 4 ) {
\r
9285 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9287 if( dw != WAIT_OBJECT_0 ) {
\r
9288 result = TerminateProcess( cp->hProcess, 0 );
\r
9290 if ( appData.debugMode) {
\r
9291 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9297 CloseHandle(cp->hProcess);
\r
9301 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9305 closesocket(cp->sock);
\r
9310 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9311 closesocket(cp->sock);
\r
9312 closesocket(cp->sock2);
\r
9320 InterruptChildProcess(ProcRef pr)
\r
9324 cp = (ChildProc *) pr;
\r
9325 if (cp == NULL) return;
\r
9326 switch (cp->kind) {
\r
9328 /* The following doesn't work because the chess program
\r
9329 doesn't "have the same console" as WinBoard. Maybe
\r
9330 we could arrange for this even though neither WinBoard
\r
9331 nor the chess program uses a console for stdio */
\r
9332 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9337 /* Can't interrupt */
\r
9341 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9348 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9350 char cmdLine[MSG_SIZ];
\r
9352 if (port[0] == NULLCHAR) {
\r
9353 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9355 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9357 return StartChildProcess(cmdLine, "", pr);
\r
9361 /* Code to open TCP sockets */
\r
9364 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9370 struct sockaddr_in sa, mysa;
\r
9371 struct hostent FAR *hp;
\r
9372 unsigned short uport;
\r
9373 WORD wVersionRequested;
\r
9376 /* Initialize socket DLL */
\r
9377 wVersionRequested = MAKEWORD(1, 1);
\r
9378 err = WSAStartup(wVersionRequested, &wsaData);
\r
9379 if (err != 0) return err;
\r
9382 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9383 err = WSAGetLastError();
\r
9388 /* Bind local address using (mostly) don't-care values.
\r
9390 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9391 mysa.sin_family = AF_INET;
\r
9392 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9393 uport = (unsigned short) 0;
\r
9394 mysa.sin_port = htons(uport);
\r
9395 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9396 == SOCKET_ERROR) {
\r
9397 err = WSAGetLastError();
\r
9402 /* Resolve remote host name */
\r
9403 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9404 if (!(hp = gethostbyname(host))) {
\r
9405 unsigned int b0, b1, b2, b3;
\r
9407 err = WSAGetLastError();
\r
9409 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9410 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9411 hp->h_addrtype = AF_INET;
\r
9413 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9414 hp->h_addr_list[0] = (char *) malloc(4);
\r
9415 hp->h_addr_list[0][0] = (char) b0;
\r
9416 hp->h_addr_list[0][1] = (char) b1;
\r
9417 hp->h_addr_list[0][2] = (char) b2;
\r
9418 hp->h_addr_list[0][3] = (char) b3;
\r
9424 sa.sin_family = hp->h_addrtype;
\r
9425 uport = (unsigned short) atoi(port);
\r
9426 sa.sin_port = htons(uport);
\r
9427 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9429 /* Make connection */
\r
9430 if (connect(s, (struct sockaddr *) &sa,
\r
9431 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9432 err = WSAGetLastError();
\r
9437 /* Prepare return value */
\r
9438 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9439 cp->kind = CPSock;
\r
9441 *pr = (ProcRef *) cp;
\r
9447 OpenCommPort(char *name, ProcRef *pr)
\r
9452 char fullname[MSG_SIZ];
\r
9454 if (*name != '\\')
\r
9455 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9457 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9459 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9460 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9461 if (h == (HANDLE) -1) {
\r
9462 return GetLastError();
\r
9466 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9468 /* Accumulate characters until a 100ms pause, then parse */
\r
9469 ct.ReadIntervalTimeout = 100;
\r
9470 ct.ReadTotalTimeoutMultiplier = 0;
\r
9471 ct.ReadTotalTimeoutConstant = 0;
\r
9472 ct.WriteTotalTimeoutMultiplier = 0;
\r
9473 ct.WriteTotalTimeoutConstant = 0;
\r
9474 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9476 /* Prepare return value */
\r
9477 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9478 cp->kind = CPComm;
\r
9481 *pr = (ProcRef *) cp;
\r
9487 OpenLoopback(ProcRef *pr)
\r
9489 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9495 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9500 struct sockaddr_in sa, mysa;
\r
9501 struct hostent FAR *hp;
\r
9502 unsigned short uport;
\r
9503 WORD wVersionRequested;
\r
9506 char stderrPortStr[MSG_SIZ];
\r
9508 /* Initialize socket DLL */
\r
9509 wVersionRequested = MAKEWORD(1, 1);
\r
9510 err = WSAStartup(wVersionRequested, &wsaData);
\r
9511 if (err != 0) return err;
\r
9513 /* Resolve remote host name */
\r
9514 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9515 if (!(hp = gethostbyname(host))) {
\r
9516 unsigned int b0, b1, b2, b3;
\r
9518 err = WSAGetLastError();
\r
9520 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9521 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9522 hp->h_addrtype = AF_INET;
\r
9524 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9525 hp->h_addr_list[0] = (char *) malloc(4);
\r
9526 hp->h_addr_list[0][0] = (char) b0;
\r
9527 hp->h_addr_list[0][1] = (char) b1;
\r
9528 hp->h_addr_list[0][2] = (char) b2;
\r
9529 hp->h_addr_list[0][3] = (char) b3;
\r
9535 sa.sin_family = hp->h_addrtype;
\r
9536 uport = (unsigned short) 514;
\r
9537 sa.sin_port = htons(uport);
\r
9538 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9540 /* Bind local socket to unused "privileged" port address
\r
9542 s = INVALID_SOCKET;
\r
9543 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9544 mysa.sin_family = AF_INET;
\r
9545 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9546 for (fromPort = 1023;; fromPort--) {
\r
9547 if (fromPort < 0) {
\r
9549 return WSAEADDRINUSE;
\r
9551 if (s == INVALID_SOCKET) {
\r
9552 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9553 err = WSAGetLastError();
\r
9558 uport = (unsigned short) fromPort;
\r
9559 mysa.sin_port = htons(uport);
\r
9560 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9561 == SOCKET_ERROR) {
\r
9562 err = WSAGetLastError();
\r
9563 if (err == WSAEADDRINUSE) continue;
\r
9567 if (connect(s, (struct sockaddr *) &sa,
\r
9568 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9569 err = WSAGetLastError();
\r
9570 if (err == WSAEADDRINUSE) {
\r
9581 /* Bind stderr local socket to unused "privileged" port address
\r
9583 s2 = INVALID_SOCKET;
\r
9584 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9585 mysa.sin_family = AF_INET;
\r
9586 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9587 for (fromPort = 1023;; fromPort--) {
\r
9588 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9589 if (fromPort < 0) {
\r
9590 (void) closesocket(s);
\r
9592 return WSAEADDRINUSE;
\r
9594 if (s2 == INVALID_SOCKET) {
\r
9595 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9596 err = WSAGetLastError();
\r
9602 uport = (unsigned short) fromPort;
\r
9603 mysa.sin_port = htons(uport);
\r
9604 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9605 == SOCKET_ERROR) {
\r
9606 err = WSAGetLastError();
\r
9607 if (err == WSAEADDRINUSE) continue;
\r
9608 (void) closesocket(s);
\r
9612 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9613 err = WSAGetLastError();
\r
9614 if (err == WSAEADDRINUSE) {
\r
9616 s2 = INVALID_SOCKET;
\r
9619 (void) closesocket(s);
\r
9620 (void) closesocket(s2);
\r
9626 prevStderrPort = fromPort; // remember port used
\r
9627 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9629 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9630 err = WSAGetLastError();
\r
9631 (void) closesocket(s);
\r
9632 (void) closesocket(s2);
\r
9637 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9638 err = WSAGetLastError();
\r
9639 (void) closesocket(s);
\r
9640 (void) closesocket(s2);
\r
9644 if (*user == NULLCHAR) user = UserName();
\r
9645 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9646 err = WSAGetLastError();
\r
9647 (void) closesocket(s);
\r
9648 (void) closesocket(s2);
\r
9652 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9653 err = WSAGetLastError();
\r
9654 (void) closesocket(s);
\r
9655 (void) closesocket(s2);
\r
9660 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9661 err = WSAGetLastError();
\r
9662 (void) closesocket(s);
\r
9663 (void) closesocket(s2);
\r
9667 (void) closesocket(s2); /* Stop listening */
\r
9669 /* Prepare return value */
\r
9670 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9671 cp->kind = CPRcmd;
\r
9674 *pr = (ProcRef *) cp;
\r
9681 AddInputSource(ProcRef pr, int lineByLine,
\r
9682 InputCallback func, VOIDSTAR closure)
\r
9684 InputSource *is, *is2 = NULL;
\r
9685 ChildProc *cp = (ChildProc *) pr;
\r
9687 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9688 is->lineByLine = lineByLine;
\r
9690 is->closure = closure;
\r
9691 is->second = NULL;
\r
9692 is->next = is->buf;
\r
9693 if (pr == NoProc) {
\r
9694 is->kind = CPReal;
\r
9695 consoleInputSource = is;
\r
9697 is->kind = cp->kind;
\r
9699 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9700 we create all threads suspended so that the is->hThread variable can be
\r
9701 safely assigned, then let the threads start with ResumeThread.
\r
9703 switch (cp->kind) {
\r
9705 is->hFile = cp->hFrom;
\r
9706 cp->hFrom = NULL; /* now owned by InputThread */
\r
9708 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9709 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9713 is->hFile = cp->hFrom;
\r
9714 cp->hFrom = NULL; /* now owned by InputThread */
\r
9716 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9717 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9721 is->sock = cp->sock;
\r
9723 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9724 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9728 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9730 is->sock = cp->sock;
\r
9732 is2->sock = cp->sock2;
\r
9733 is2->second = is2;
\r
9735 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9736 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9738 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9739 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9743 if( is->hThread != NULL ) {
\r
9744 ResumeThread( is->hThread );
\r
9747 if( is2 != NULL && is2->hThread != NULL ) {
\r
9748 ResumeThread( is2->hThread );
\r
9752 return (InputSourceRef) is;
\r
9756 RemoveInputSource(InputSourceRef isr)
\r
9760 is = (InputSource *) isr;
\r
9761 is->hThread = NULL; /* tell thread to stop */
\r
9762 CloseHandle(is->hThread);
\r
9763 if (is->second != NULL) {
\r
9764 is->second->hThread = NULL;
\r
9765 CloseHandle(is->second->hThread);
\r
9769 int no_wrap(char *message, int count)
\r
9771 ConsoleOutput(message, count, FALSE);
\r
9776 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9779 int outCount = SOCKET_ERROR;
\r
9780 ChildProc *cp = (ChildProc *) pr;
\r
9781 static OVERLAPPED ovl;
\r
9783 static int line = 0;
\r
9787 if (appData.noJoin || !appData.useInternalWrap)
\r
9788 return no_wrap(message, count);
\r
9791 int width = get_term_width();
\r
9792 int len = wrap(NULL, message, count, width, &line);
\r
9793 char *msg = malloc(len);
\r
9797 return no_wrap(message, count);
\r
9800 dbgchk = wrap(msg, message, count, width, &line);
\r
9801 if (dbgchk != len && appData.debugMode)
\r
9802 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9803 ConsoleOutput(msg, len, FALSE);
\r
9810 if (ovl.hEvent == NULL) {
\r
9811 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9813 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9815 switch (cp->kind) {
\r
9818 outCount = send(cp->sock, message, count, 0);
\r
9819 if (outCount == SOCKET_ERROR) {
\r
9820 *outError = WSAGetLastError();
\r
9822 *outError = NO_ERROR;
\r
9827 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9828 &dOutCount, NULL)) {
\r
9829 *outError = NO_ERROR;
\r
9830 outCount = (int) dOutCount;
\r
9832 *outError = GetLastError();
\r
9837 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9838 &dOutCount, &ovl);
\r
9839 if (*outError == NO_ERROR) {
\r
9840 outCount = (int) dOutCount;
\r
9850 if(n != 0) Sleep(n);
\r
9854 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9857 /* Ignore delay, not implemented for WinBoard */
\r
9858 return OutputToProcess(pr, message, count, outError);
\r
9863 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9864 char *buf, int count, int error)
\r
9866 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9869 /* see wgamelist.c for Game List functions */
\r
9870 /* see wedittags.c for Edit Tags functions */
\r
9877 char buf[MSG_SIZ];
\r
9880 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9881 f = fopen(buf, "r");
\r
9883 ProcessICSInitScript(f);
\r
9893 StartAnalysisClock()
\r
9895 if (analysisTimerEvent) return;
\r
9896 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9897 (UINT) 2000, NULL);
\r
9901 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9903 highlightInfo.sq[0].x = fromX;
\r
9904 highlightInfo.sq[0].y = fromY;
\r
9905 highlightInfo.sq[1].x = toX;
\r
9906 highlightInfo.sq[1].y = toY;
\r
9912 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9913 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9917 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9919 premoveHighlightInfo.sq[0].x = fromX;
\r
9920 premoveHighlightInfo.sq[0].y = fromY;
\r
9921 premoveHighlightInfo.sq[1].x = toX;
\r
9922 premoveHighlightInfo.sq[1].y = toY;
\r
9926 ClearPremoveHighlights()
\r
9928 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9929 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9933 ShutDownFrontEnd()
\r
9935 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9936 DeleteClipboardTempFiles();
\r
9942 if (IsIconic(hwndMain))
\r
9943 ShowWindow(hwndMain, SW_RESTORE);
\r
9945 SetActiveWindow(hwndMain);
\r
9949 * Prototypes for animation support routines
\r
9951 static void ScreenSquare(int column, int row, POINT * pt);
\r
9952 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9953 POINT frames[], int * nFrames);
\r
9959 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9960 { // [HGM] atomic: animate blast wave
\r
9963 explodeInfo.fromX = fromX;
\r
9964 explodeInfo.fromY = fromY;
\r
9965 explodeInfo.toX = toX;
\r
9966 explodeInfo.toY = toY;
\r
9967 for(i=1; i<4*kFactor; i++) {
\r
9968 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9969 DrawPosition(FALSE, board);
\r
9970 Sleep(appData.animSpeed);
\r
9972 explodeInfo.radius = 0;
\r
9973 DrawPosition(TRUE, board);
\r
9977 AnimateMove(board, fromX, fromY, toX, toY)
\r
9984 ChessSquare piece;
\r
9985 int x = toX, y = toY;
\r
9986 POINT start, finish, mid;
\r
9987 POINT frames[kFactor * 2 + 1];
\r
9990 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
9992 if (!appData.animate) return;
\r
9993 if (doingSizing) return;
\r
9994 if (fromY < 0 || fromX < 0) return;
\r
9995 piece = board[fromY][fromX];
\r
9996 if (piece >= EmptySquare) return;
\r
9998 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10002 ScreenSquare(fromX, fromY, &start);
\r
10003 ScreenSquare(toX, toY, &finish);
\r
10005 /* All moves except knight jumps move in straight line */
\r
10006 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10007 mid.x = start.x + (finish.x - start.x) / 2;
\r
10008 mid.y = start.y + (finish.y - start.y) / 2;
\r
10010 /* Knight: make straight movement then diagonal */
\r
10011 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10012 mid.x = start.x + (finish.x - start.x) / 2;
\r
10016 mid.y = start.y + (finish.y - start.y) / 2;
\r
10020 /* Don't use as many frames for very short moves */
\r
10021 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10022 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10024 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10026 animInfo.from.x = fromX;
\r
10027 animInfo.from.y = fromY;
\r
10028 animInfo.to.x = toX;
\r
10029 animInfo.to.y = toY;
\r
10030 animInfo.lastpos = start;
\r
10031 animInfo.piece = piece;
\r
10032 for (n = 0; n < nFrames; n++) {
\r
10033 animInfo.pos = frames[n];
\r
10034 DrawPosition(FALSE, NULL);
\r
10035 animInfo.lastpos = animInfo.pos;
\r
10036 Sleep(appData.animSpeed);
\r
10038 animInfo.pos = finish;
\r
10039 DrawPosition(FALSE, NULL);
\r
10041 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10043 animInfo.piece = EmptySquare;
\r
10044 Explode(board, fromX, fromY, toX, toY);
\r
10047 /* Convert board position to corner of screen rect and color */
\r
10050 ScreenSquare(column, row, pt)
\r
10051 int column; int row; POINT * pt;
\r
10054 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10055 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10057 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10058 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10062 /* Generate a series of frame coords from start->mid->finish.
\r
10063 The movement rate doubles until the half way point is
\r
10064 reached, then halves back down to the final destination,
\r
10065 which gives a nice slow in/out effect. The algorithmn
\r
10066 may seem to generate too many intermediates for short
\r
10067 moves, but remember that the purpose is to attract the
\r
10068 viewers attention to the piece about to be moved and
\r
10069 then to where it ends up. Too few frames would be less
\r
10073 Tween(start, mid, finish, factor, frames, nFrames)
\r
10074 POINT * start; POINT * mid;
\r
10075 POINT * finish; int factor;
\r
10076 POINT frames[]; int * nFrames;
\r
10078 int n, fraction = 1, count = 0;
\r
10080 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10081 for (n = 0; n < factor; n++)
\r
10083 for (n = 0; n < factor; n++) {
\r
10084 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10085 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10087 fraction = fraction / 2;
\r
10091 frames[count] = *mid;
\r
10094 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10096 for (n = 0; n < factor; n++) {
\r
10097 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10098 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10100 fraction = fraction * 2;
\r
10102 *nFrames = count;
\r
10106 SettingsPopUp(ChessProgramState *cps)
\r
10107 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10108 EngineOptionsPopup(savedHwnd, cps);
\r
10111 int flock(int fid, int code)
\r
10113 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10115 ov.hEvent = NULL;
\r
10117 ov.OffsetHigh = 0;
\r
10119 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10121 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10122 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10123 default: return -1;
\r
10132 static char col[8][20];
\r
10133 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10135 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10140 ActivateTheme (int new)
\r
10141 { // Redo initialization of features depending on options that can occur in themes
\r
10143 if(new) InitDrawingColors();
\r
10144 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10145 InitDrawingSizes(boardSize, 0);
\r
10146 InvalidateRect(hwndMain, NULL, TRUE);
\r