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, 2016 Free
\r
9 * Software Foundation, Inc.
\r
11 * Enhancements Copyright 2005 Alessandro Scotti
\r
13 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
14 * which was written and is copyrighted by Wayne Christopher.
\r
16 * The following terms apply to Digital Equipment Corporation's copyright
\r
17 * interest in XBoard:
\r
18 * ------------------------------------------------------------------------
\r
19 * All Rights Reserved
\r
21 * Permission to use, copy, modify, and distribute this software and its
\r
22 * documentation for any purpose and without fee is hereby granted,
\r
23 * provided that the above copyright notice appear in all copies and that
\r
24 * both that copyright notice and this permission notice appear in
\r
25 * supporting documentation, and that the name of Digital not be
\r
26 * used in advertising or publicity pertaining to distribution of the
\r
27 * software without specific, written prior permission.
\r
29 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
30 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
31 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
32 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
33 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
34 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
36 * ------------------------------------------------------------------------
\r
38 * The following terms apply to the enhanced version of XBoard
\r
39 * distributed by the Free Software Foundation:
\r
40 * ------------------------------------------------------------------------
\r
42 * GNU XBoard is free software: you can redistribute it and/or modify
\r
43 * it under the terms of the GNU General Public License as published by
\r
44 * the Free Software Foundation, either version 3 of the License, or (at
\r
45 * your option) any later version.
\r
47 * GNU XBoard is distributed in the hope that it will be useful, but
\r
48 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
49 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
50 * General Public License for more details.
\r
52 * You should have received a copy of the GNU General Public License
\r
53 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
55 *------------------------------------------------------------------------
\r
56 ** See the file ChangeLog for a revision history. */
\r
60 #include <windows.h>
\r
61 #include <winuser.h>
\r
62 #include <winsock.h>
\r
63 #include <commctrl.h>
\r
69 #include <sys/stat.h>
\r
72 #include <commdlg.h>
\r
74 #include <richedit.h>
\r
75 #include <mmsystem.h>
\r
85 #include "frontend.h"
\r
86 #include "backend.h"
\r
87 #include "winboard.h"
\r
89 #include "wclipbrd.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
97 #define DATADIR "~~"
\r
99 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
101 int myrandom(void);
\r
102 void mysrandom(unsigned int seed);
\r
104 extern int whiteFlag, blackFlag;
\r
105 Boolean flipClock = FALSE;
\r
106 extern HANDLE chatHandle[];
\r
107 extern enum ICS_TYPE ics_type;
\r
109 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
110 int MyGetFullPathName P((char *name, char *fullname));
\r
111 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
112 VOID NewVariantPopup(HWND hwnd);
\r
113 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
114 /*char*/int promoChar));
\r
115 void DisplayMove P((int moveNumber));
\r
116 void ChatPopUp P((char *s));
\r
118 ChessSquare piece;
\r
119 POINT pos; /* window coordinates of current pos */
\r
120 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
121 POINT from; /* board coordinates of the piece's orig pos */
\r
122 POINT to; /* board coordinates of the piece's new pos */
\r
125 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
128 POINT start; /* window coordinates of start pos */
\r
129 POINT pos; /* window coordinates of current pos */
\r
130 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
131 POINT from; /* board coordinates of the piece's orig pos */
\r
135 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
138 POINT sq[2]; /* board coordinates of from, to squares */
\r
141 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
144 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
146 typedef struct { // [HGM] atomic
\r
147 int fromX, fromY, toX, toY, radius;
\r
150 static ExplodeInfo explodeInfo;
\r
152 /* Window class names */
\r
153 char szAppName[] = "WinBoard";
\r
154 char szConsoleName[] = "WBConsole";
\r
156 /* Title bar text */
\r
157 char szTitle[] = "WinBoard";
\r
158 char szConsoleTitle[] = "I C S Interaction";
\r
161 char *settingsFileName;
\r
162 Boolean saveSettingsOnExit;
\r
163 char installDir[MSG_SIZ];
\r
164 int errorExitStatus;
\r
166 BoardSize boardSize;
\r
167 Boolean chessProgram;
\r
168 //static int boardX, boardY;
\r
169 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
170 int squareSize, lineGap, minorSize;
\r
171 static int winW, winH;
\r
172 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
173 static int logoHeight = 0;
\r
174 static char messageText[MESSAGE_TEXT_MAX];
\r
175 static int clockTimerEvent = 0;
\r
176 static int loadGameTimerEvent = 0;
\r
177 static int analysisTimerEvent = 0;
\r
178 static DelayedEventCallback delayedTimerCallback;
\r
179 static int delayedTimerEvent = 0;
\r
180 static int buttonCount = 2;
\r
181 char *icsTextMenuString;
\r
183 char *firstChessProgramNames;
\r
184 char *secondChessProgramNames;
\r
186 #define PALETTESIZE 256
\r
188 HINSTANCE hInst; /* current instance */
\r
189 Boolean alwaysOnTop = FALSE;
\r
191 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
192 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
193 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
195 ColorClass currentColorClass;
\r
197 static HWND savedHwnd;
\r
198 HWND hCommPort = NULL; /* currently open comm port */
\r
199 static HWND hwndPause; /* pause button */
\r
200 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
201 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
202 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
203 explodeBrush, /* [HGM] atomic */
\r
204 markerBrush[8], /* [HGM] markers */
\r
205 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
206 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
207 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
208 static HPEN gridPen = NULL;
\r
209 static HPEN highlightPen = NULL;
\r
210 static HPEN premovePen = NULL;
\r
211 static NPLOGPALETTE pLogPal;
\r
212 static BOOL paletteChanged = FALSE;
\r
213 static HICON iconWhite, iconBlack, iconCurrent;
\r
214 static int doingSizing = FALSE;
\r
215 static int lastSizing = 0;
\r
216 static int prevStderrPort;
\r
217 static HBITMAP userLogo;
\r
219 static HBITMAP liteBackTexture = NULL;
\r
220 static HBITMAP darkBackTexture = NULL;
\r
221 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
223 static int backTextureSquareSize = 0;
\r
224 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
226 #if __GNUC__ && !defined(_winmajor)
\r
227 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
230 #if defined(_winmajor)
\r
231 #define oldDialog (_winmajor < 4)
\r
233 #define oldDialog 0
\r
237 #define INTERNATIONAL
\r
239 #ifdef INTERNATIONAL
\r
240 # define _(s) T_(s)
\r
246 # define Translate(x, y)
\r
247 # define LoadLanguageFile(s)
\r
250 #ifdef INTERNATIONAL
\r
252 Boolean barbaric; // flag indicating if translation is needed
\r
254 // list of item numbers used in each dialog (used to alter language at run time)
\r
256 #define ABOUTBOX -1 /* not sure why these are needed */
\r
257 #define ABOUTBOX2 -1
\r
259 int dialogItems[][42] = {
\r
260 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
261 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
262 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
263 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
264 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds,
\r
265 OPT_Ranget, IDOK, IDCANCEL },
\r
266 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
267 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
268 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
269 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
270 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
271 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
272 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
273 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
274 { ABOUTBOX2, IDC_ChessBoard },
\r
275 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
276 OPT_GameListClose, IDC_GameListDoFilter },
\r
277 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
278 { DLG_Error, IDOK },
\r
279 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
280 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
281 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
282 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
283 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
284 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
285 { DLG_IndexNumber, IDC_Index },
\r
286 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
287 { DLG_TypeInName, IDOK, IDCANCEL },
\r
288 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
289 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
290 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
291 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
292 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
293 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
294 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
295 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
296 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
297 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
298 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
299 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
300 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
301 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
302 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
303 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
304 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
305 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
306 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
307 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
308 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
309 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
310 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
311 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
312 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
313 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
314 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
315 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
316 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
317 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
318 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
319 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
320 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
321 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
322 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
323 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
324 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
325 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
326 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
327 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
328 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
329 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
330 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
331 { DLG_MoveHistory },
\r
332 { DLG_EvalGraph },
\r
333 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
334 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
335 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
336 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
337 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
338 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
339 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
340 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
341 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
345 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
346 static int lastChecked;
\r
347 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
348 extern int tinyLayout;
\r
349 extern char * menuBarText[][10];
\r
352 LoadLanguageFile(char *name)
\r
353 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
355 int i=0, j=0, n=0, k;
\r
358 if(!name || name[0] == NULLCHAR) return;
\r
359 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
360 appData.language = oldLanguage;
\r
361 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
362 if((f = fopen(buf, "r")) == NULL) return;
\r
363 while((k = fgetc(f)) != EOF) {
\r
364 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
365 languageBuf[i] = k;
\r
367 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
369 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
370 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
371 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
372 english[j] = languageBuf + n + 1; *p = 0;
\r
373 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
374 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
379 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
381 case 'n': k = '\n'; break;
\r
382 case 'r': k = '\r'; break;
\r
383 case 't': k = '\t'; break;
\r
385 languageBuf[--i] = k;
\r
390 barbaric = (j != 0);
\r
391 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
396 { // return the translation of the given string
\r
397 // efficiency can be improved a lot...
\r
399 static char buf[MSG_SIZ];
\r
400 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
401 if(!barbaric) return s;
\r
402 if(!s) return ""; // sanity
\r
403 while(english[i]) {
\r
404 if(!strcmp(s, english[i])) return foreign[i];
\r
405 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
406 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
415 Translate(HWND hDlg, int dialogID)
\r
416 { // translate all text items in the given dialog
\r
418 char buf[MSG_SIZ], *s;
\r
419 if(!barbaric) return;
\r
420 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
421 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
422 GetWindowText( hDlg, buf, MSG_SIZ );
\r
424 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
425 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
426 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
427 if(strlen(buf) == 0) continue;
\r
429 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
434 TranslateOneMenu(int i, HMENU subMenu)
\r
437 static MENUITEMINFO info;
\r
439 info.cbSize = sizeof(MENUITEMINFO);
\r
440 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
441 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
443 info.dwTypeData = buf;
\r
444 info.cch = sizeof(buf);
\r
445 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
447 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
448 else menuText[i][j] = strdup(buf); // remember original on first change
\r
450 if(buf[0] == NULLCHAR) continue;
\r
451 info.dwTypeData = T_(buf);
\r
452 info.cch = strlen(buf)+1;
\r
453 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
459 TranslateMenus(int addLanguage)
\r
462 WIN32_FIND_DATA fileData;
\r
464 #define IDM_English 1970
\r
466 HMENU mainMenu = GetMenu(hwndMain);
\r
467 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
468 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
469 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
470 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
471 TranslateOneMenu(i, subMenu);
\r
473 DrawMenuBar(hwndMain);
\r
476 if(!addLanguage) return;
\r
477 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
478 HMENU mainMenu = GetMenu(hwndMain);
\r
479 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
480 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
481 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
482 i = 0; lastChecked = IDM_English;
\r
484 char *p, *q = fileData.cFileName;
\r
485 int checkFlag = MF_UNCHECKED;
\r
486 languageFile[i] = strdup(q);
\r
487 if(barbaric && !strcmp(oldLanguage, q)) {
\r
488 checkFlag = MF_CHECKED;
\r
489 lastChecked = IDM_English + i + 1;
\r
490 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
492 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
493 p = strstr(fileData.cFileName, ".lng");
\r
495 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
496 } while(FindNextFile(hFind, &fileData));
\r
503 #define IDM_RecentEngines 3000
\r
506 RecentEngineMenu (char *s)
\r
508 if(appData.icsActive) return;
\r
509 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
510 HMENU mainMenu = GetMenu(hwndMain);
\r
511 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
512 int i=IDM_RecentEngines;
\r
513 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
514 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
516 char *p = strchr(s, '\n');
\r
517 if(p == NULL) return; // malformed!
\r
519 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
533 int cliWidth, cliHeight;
\r
536 SizeInfo sizeInfo[] =
\r
538 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
539 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
540 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
541 { "petite", 33, 1, 1, 1, 0, 0 },
\r
542 { "slim", 37, 2, 1, 0, 0, 0 },
\r
543 { "small", 40, 2, 1, 0, 0, 0 },
\r
544 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
545 { "middling", 49, 2, 0, 0, 0, 0 },
\r
546 { "average", 54, 2, 0, 0, 0, 0 },
\r
547 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
548 { "medium", 64, 3, 0, 0, 0, 0 },
\r
549 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
550 { "large", 80, 3, 0, 0, 0, 0 },
\r
551 { "big", 87, 3, 0, 0, 0, 0 },
\r
552 { "huge", 95, 3, 0, 0, 0, 0 },
\r
553 { "giant", 108, 3, 0, 0, 0, 0 },
\r
554 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
555 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
556 { NULL, 0, 0, 0, 0, 0, 0 }
\r
559 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
560 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
575 { 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
576 { 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
577 { 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
578 { 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
579 { 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
582 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
591 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
592 #define N_BUTTONS 5
\r
594 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
596 {"<<", IDM_ToStart, NULL, NULL},
\r
597 {"<", IDM_Backward, NULL, NULL},
\r
598 {"P", IDM_Pause, NULL, NULL},
\r
599 {">", IDM_Forward, NULL, NULL},
\r
600 {">>", IDM_ToEnd, NULL, NULL},
\r
603 int tinyLayout = 0, smallLayout = 0;
\r
604 #define MENU_BAR_ITEMS 9
\r
605 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
606 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
607 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
611 MySound sounds[(int)NSoundClasses];
\r
612 MyTextAttribs textAttribs[(int)NColorClasses];
\r
614 MyColorizeAttribs colorizeAttribs[] = {
\r
615 { (COLORREF)0, 0, N_("Shout Text") },
\r
616 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
617 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
618 { (COLORREF)0, 0, N_("Channel Text") },
\r
619 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
620 { (COLORREF)0, 0, N_("Tell Text") },
\r
621 { (COLORREF)0, 0, N_("Challenge Text") },
\r
622 { (COLORREF)0, 0, N_("Request Text") },
\r
623 { (COLORREF)0, 0, N_("Seek Text") },
\r
624 { (COLORREF)0, 0, N_("Normal Text") },
\r
625 { (COLORREF)0, 0, N_("None") }
\r
630 static char *commentTitle;
\r
631 static char *commentText;
\r
632 static int commentIndex;
\r
633 static Boolean editComment = FALSE;
\r
636 char errorTitle[MSG_SIZ];
\r
637 char errorMessage[2*MSG_SIZ];
\r
638 HWND errorDialog = NULL;
\r
639 BOOLEAN moveErrorMessageUp = FALSE;
\r
640 BOOLEAN consoleEcho = TRUE;
\r
641 CHARFORMAT consoleCF;
\r
642 COLORREF consoleBackgroundColor;
\r
644 char *programVersion;
\r
650 typedef int CPKind;
\r
659 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
662 #define INPUT_SOURCE_BUF_SIZE 4096
\r
664 typedef struct _InputSource {
\r
671 char buf[INPUT_SOURCE_BUF_SIZE];
\r
675 InputCallback func;
\r
676 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
680 InputSource *consoleInputSource;
\r
685 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
686 VOID ConsoleCreate();
\r
688 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
689 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
690 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
691 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
693 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
694 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
695 void ParseIcsTextMenu(char *icsTextMenuString);
\r
696 VOID PopUpNameDialog(char firstchar);
\r
697 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
701 int GameListOptions();
\r
703 int dummy; // [HGM] for obsolete args
\r
705 HWND hwndMain = NULL; /* root window*/
\r
706 HWND hwndConsole = NULL;
\r
707 HWND commentDialog = NULL;
\r
708 HWND moveHistoryDialog = NULL;
\r
709 HWND evalGraphDialog = NULL;
\r
710 HWND engineOutputDialog = NULL;
\r
711 HWND gameListDialog = NULL;
\r
712 HWND editTagsDialog = NULL;
\r
714 int commentUp = FALSE;
\r
716 WindowPlacement wpMain;
\r
717 WindowPlacement wpConsole;
\r
718 WindowPlacement wpComment;
\r
719 WindowPlacement wpMoveHistory;
\r
720 WindowPlacement wpEvalGraph;
\r
721 WindowPlacement wpEngineOutput;
\r
722 WindowPlacement wpGameList;
\r
723 WindowPlacement wpTags;
\r
725 VOID EngineOptionsPopup(); // [HGM] settings
\r
727 VOID GothicPopUp(char *title, VariantClass variant);
\r
729 * Setting "frozen" should disable all user input other than deleting
\r
730 * the window. We do this while engines are initializing themselves.
\r
732 static int frozen = 0;
\r
733 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
739 if (frozen) return;
\r
741 hmenu = GetMenu(hwndMain);
\r
742 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
743 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
745 DrawMenuBar(hwndMain);
\r
748 /* Undo a FreezeUI */
\r
754 if (!frozen) return;
\r
756 hmenu = GetMenu(hwndMain);
\r
757 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
758 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
760 DrawMenuBar(hwndMain);
\r
763 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
765 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
771 #define JAWS_ALT_INTERCEPT
\r
772 #define JAWS_KBUP_NAVIGATION
\r
773 #define JAWS_KBDOWN_NAVIGATION
\r
774 #define JAWS_MENU_ITEMS
\r
775 #define JAWS_SILENCE
\r
776 #define JAWS_REPLAY
\r
778 #define JAWS_COPYRIGHT
\r
779 #define JAWS_DELETE(X) X
\r
780 #define SAYMACHINEMOVE()
\r
784 /*---------------------------------------------------------------------------*\
\r
788 \*---------------------------------------------------------------------------*/
\r
790 static void HandleMessage P((MSG *message));
\r
791 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
794 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
795 LPSTR lpCmdLine, int nCmdShow)
\r
798 // INITCOMMONCONTROLSEX ex;
\r
802 LoadLibrary("RICHED32.DLL");
\r
803 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
805 if (!InitApplication(hInstance)) {
\r
808 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
815 // InitCommonControlsEx(&ex);
\r
816 InitCommonControls();
\r
818 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
819 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
820 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
822 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
824 while (GetMessage(&msg, /* message structure */
\r
825 NULL, /* handle of window receiving the message */
\r
826 0, /* lowest message to examine */
\r
827 0)) /* highest message to examine */
\r
829 HandleMessage(&msg);
\r
833 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
837 HandleMessage (MSG *message)
\r
839 MSG msg = *message;
\r
841 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
842 // [HGM] navigate: switch between all windows with tab
\r
843 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
844 int i, currentElement = 0;
\r
846 // first determine what element of the chain we come from (if any)
\r
847 if(appData.icsActive) {
\r
848 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
849 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
851 if(engineOutputDialog && EngineOutputIsUp()) {
\r
852 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
853 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
855 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
856 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
858 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
859 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
860 if(msg.hwnd == e1) currentElement = 2; else
\r
861 if(msg.hwnd == e2) currentElement = 3; else
\r
862 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
863 if(msg.hwnd == mh) currentElement = 4; else
\r
864 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
865 if(msg.hwnd == hText) currentElement = 5; else
\r
866 if(msg.hwnd == hInput) currentElement = 6; else
\r
867 for (i = 0; i < N_BUTTONS; i++) {
\r
868 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
871 // determine where to go to
\r
872 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
874 currentElement = (currentElement + direction) % 7;
\r
875 switch(currentElement) {
\r
877 h = hwndMain; break; // passing this case always makes the loop exit
\r
879 h = buttonDesc[0].hwnd; break; // could be NULL
\r
881 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
884 if(!EngineOutputIsUp()) continue;
\r
887 if(!MoveHistoryIsUp()) continue;
\r
889 // case 6: // input to eval graph does not seem to get here!
\r
890 // if(!EvalGraphIsUp()) continue;
\r
891 // h = evalGraphDialog; break;
\r
893 if(!appData.icsActive) continue;
\r
897 if(!appData.icsActive) continue;
\r
903 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
904 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
907 return; // this message now has been processed
\r
911 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
912 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
913 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
914 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
915 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
916 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
917 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
918 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
920 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
921 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
922 for(i=0; i<MAX_CHAT; i++)
\r
923 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
926 if(done) return; // [HGM] chat: end patch
\r
927 TranslateMessage(&msg); /* Translates virtual key codes */
\r
928 DispatchMessage(&msg); /* Dispatches message to window */
\r
934 { /* Dispatch pending messages */
\r
936 while (PeekMessage(&msg, /* message structure */
\r
937 NULL, /* handle of window receiving the message */
\r
938 0, /* lowest message to examine */
\r
939 0, /* highest message to examine */
\r
942 HandleMessage(&msg);
\r
946 /*---------------------------------------------------------------------------*\
\r
948 * Initialization functions
\r
950 \*---------------------------------------------------------------------------*/
\r
954 { // update user logo if necessary
\r
955 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
957 if(appData.autoLogo) {
\r
958 curName = UserName();
\r
959 if(strcmp(curName, oldUserName)) {
\r
960 GetCurrentDirectory(MSG_SIZ, dir);
\r
961 SetCurrentDirectory(installDir);
\r
962 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
963 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
964 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
965 if(userLogo == NULL)
\r
966 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
967 SetCurrentDirectory(dir); /* return to prev directory */
\r
973 InitApplication(HINSTANCE hInstance)
\r
977 /* Fill in window class structure with parameters that describe the */
\r
980 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
981 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
982 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
983 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
984 wc.hInstance = hInstance; /* Owner of this class */
\r
985 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
986 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
987 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
988 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
989 wc.lpszClassName = szAppName; /* Name to register as */
\r
991 /* Register the window class and return success/failure code. */
\r
992 if (!RegisterClass(&wc)) return FALSE;
\r
994 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
995 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
997 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
998 wc.hInstance = hInstance;
\r
999 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
1000 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1001 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1002 wc.lpszMenuName = NULL;
\r
1003 wc.lpszClassName = szConsoleName;
\r
1005 if (!RegisterClass(&wc)) return FALSE;
\r
1010 /* Set by InitInstance, used by EnsureOnScreen */
\r
1011 int screenHeight, screenWidth;
\r
1012 RECT screenGeometry;
\r
1015 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1017 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1018 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1019 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1020 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1021 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1022 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1026 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1028 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1029 GetCurrentDirectory(MSG_SIZ, dir);
\r
1030 SetCurrentDirectory(installDir);
\r
1031 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1032 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1034 if (cps->programLogo == NULL && appData.debugMode) {
\r
1035 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1037 } else if(appData.autoLogo) {
\r
1038 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1039 char *opponent = "";
\r
1040 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1041 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1042 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1043 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1044 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1045 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1048 if(appData.directory[n] && appData.directory[n][0]) {
\r
1049 SetCurrentDirectory(appData.directory[n]);
\r
1050 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1053 SetCurrentDirectory(dir); /* return to prev directory */
\r
1059 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1060 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1062 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1063 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1064 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1065 liteBackTextureMode = appData.liteBackTextureMode;
\r
1067 if (liteBackTexture == NULL && appData.debugMode) {
\r
1068 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1072 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1073 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1074 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1075 darkBackTextureMode = appData.darkBackTextureMode;
\r
1077 if (darkBackTexture == NULL && appData.debugMode) {
\r
1078 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1083 #ifndef SM_CXVIRTUALSCREEN
\r
1084 #define SM_CXVIRTUALSCREEN 78
\r
1086 #ifndef SM_CYVIRTUALSCREEN
\r
1087 #define SM_CYVIRTUALSCREEN 79
\r
1089 #ifndef SM_XVIRTUALSCREEN
\r
1090 #define SM_XVIRTUALSCREEN 76
\r
1092 #ifndef SM_YVIRTUALSCREEN
\r
1093 #define SM_YVIRTUALSCREEN 77
\r
1099 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1100 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1101 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1102 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1103 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1104 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1105 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1106 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1110 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1112 HWND hwnd; /* Main window handle. */
\r
1114 WINDOWPLACEMENT wp;
\r
1117 hInst = hInstance; /* Store instance handle in our global variable */
\r
1118 programName = szAppName;
\r
1120 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1121 *filepart = NULLCHAR;
\r
1122 SetCurrentDirectory(installDir);
\r
1124 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1126 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1128 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1129 /* xboard, and older WinBoards, controlled the move sound with the
\r
1130 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1131 always turn the option on (so that the backend will call us),
\r
1132 then let the user turn the sound off by setting it to silence if
\r
1133 desired. To accommodate old winboard.ini files saved by old
\r
1134 versions of WinBoard, we also turn off the sound if the option
\r
1135 was initially set to false. [HGM] taken out of InitAppData */
\r
1136 if (!appData.ringBellAfterMoves) {
\r
1137 sounds[(int)SoundMove].name = strdup("");
\r
1138 appData.ringBellAfterMoves = TRUE;
\r
1140 if (appData.debugMode) {
\r
1141 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1142 setbuf(debugFP, NULL);
\r
1145 LoadLanguageFile(appData.language);
\r
1149 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1150 // InitEngineUCI( installDir, &second );
\r
1152 /* Create a main window for this application instance. */
\r
1153 hwnd = CreateWindow(szAppName, szTitle,
\r
1154 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1155 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1156 NULL, NULL, hInstance, NULL);
\r
1159 /* If window could not be created, return "failure" */
\r
1164 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1165 LoadLogo(&first, 0, FALSE);
\r
1166 LoadLogo(&second, 1, appData.icsActive);
\r
1170 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1171 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1172 iconCurrent = iconWhite;
\r
1173 InitDrawingColors();
\r
1175 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1176 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1177 /* Compute window size for each board size, and use the largest
\r
1178 size that fits on this screen as the default. */
\r
1179 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1180 if (boardSize == (BoardSize)-1 &&
\r
1181 winH <= screenHeight
\r
1182 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1183 && winW <= screenWidth) {
\r
1184 boardSize = (BoardSize)ibs;
\r
1188 InitDrawingSizes(boardSize, 0);
\r
1189 RecentEngineMenu(appData.recentEngineList);
\r
1191 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1193 /* [AS] Load textures if specified */
\r
1196 mysrandom( (unsigned) time(NULL) );
\r
1198 /* [AS] Restore layout */
\r
1199 if( wpMoveHistory.visible ) {
\r
1200 MoveHistoryPopUp();
\r
1203 if( wpEvalGraph.visible ) {
\r
1207 if( wpEngineOutput.visible ) {
\r
1208 EngineOutputPopUp();
\r
1211 /* Make the window visible; update its client area; and return "success" */
\r
1212 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1213 wp.length = sizeof(WINDOWPLACEMENT);
\r
1215 wp.showCmd = nCmdShow;
\r
1216 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1217 wp.rcNormalPosition.left = wpMain.x;
\r
1218 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1219 wp.rcNormalPosition.top = wpMain.y;
\r
1220 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1221 SetWindowPlacement(hwndMain, &wp);
\r
1223 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1225 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1226 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1228 if (hwndConsole) {
\r
1230 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1231 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1233 ShowWindow(hwndConsole, nCmdShow);
\r
1234 SetActiveWindow(hwndConsole);
\r
1236 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1237 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1246 HMENU hmenu = GetMenu(hwndMain);
\r
1248 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1249 MF_BYCOMMAND|((appData.icsActive &&
\r
1250 *appData.icsCommPort != NULLCHAR) ?
\r
1251 MF_ENABLED : MF_GRAYED));
\r
1252 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1253 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1254 MF_CHECKED : MF_UNCHECKED));
\r
1255 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1258 //---------------------------------------------------------------------------------------------------------
\r
1260 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1261 #define XBOARD FALSE
\r
1263 #define OPTCHAR "/"
\r
1264 #define SEPCHAR "="
\r
1265 #define TOPLEVEL 0
\r
1269 // front-end part of option handling
\r
1272 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1274 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1275 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1278 lf->lfEscapement = 0;
\r
1279 lf->lfOrientation = 0;
\r
1280 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1281 lf->lfItalic = mfp->italic;
\r
1282 lf->lfUnderline = mfp->underline;
\r
1283 lf->lfStrikeOut = mfp->strikeout;
\r
1284 lf->lfCharSet = mfp->charset;
\r
1285 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1287 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1288 lf->lfQuality = DEFAULT_QUALITY;
\r
1289 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1290 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1294 CreateFontInMF(MyFont *mf)
\r
1296 LFfromMFP(&mf->lf, &mf->mfp);
\r
1297 if (mf->hf) DeleteObject(mf->hf);
\r
1298 mf->hf = CreateFontIndirect(&mf->lf);
\r
1301 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1303 colorVariable[] = {
\r
1304 &whitePieceColor,
\r
1305 &blackPieceColor,
\r
1306 &lightSquareColor,
\r
1307 &darkSquareColor,
\r
1308 &highlightSquareColor,
\r
1309 &premoveHighlightColor,
\r
1311 &consoleBackgroundColor,
\r
1312 &appData.fontForeColorWhite,
\r
1313 &appData.fontBackColorWhite,
\r
1314 &appData.fontForeColorBlack,
\r
1315 &appData.fontBackColorBlack,
\r
1316 &appData.evalHistColorWhite,
\r
1317 &appData.evalHistColorBlack,
\r
1318 &appData.highlightArrowColor,
\r
1321 /* Command line font name parser. NULL name means do nothing.
\r
1322 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1323 For backward compatibility, syntax without the colon is also
\r
1324 accepted, but font names with digits in them won't work in that case.
\r
1327 ParseFontName(char *name, MyFontParams *mfp)
\r
1330 if (name == NULL) return;
\r
1332 q = strchr(p, ':');
\r
1334 if (q - p >= sizeof(mfp->faceName))
\r
1335 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1336 memcpy(mfp->faceName, p, q - p);
\r
1337 mfp->faceName[q - p] = NULLCHAR;
\r
1340 q = mfp->faceName;
\r
1342 while (*p && !isdigit(*p)) {
\r
1344 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1345 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1347 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1350 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1351 mfp->pointSize = (float) atof(p);
\r
1352 mfp->bold = (strchr(p, 'b') != NULL);
\r
1353 mfp->italic = (strchr(p, 'i') != NULL);
\r
1354 mfp->underline = (strchr(p, 'u') != NULL);
\r
1355 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1356 mfp->charset = DEFAULT_CHARSET;
\r
1357 q = strchr(p, 'c');
\r
1359 mfp->charset = (BYTE) atoi(q+1);
\r
1363 ParseFont(char *name, int number)
\r
1364 { // wrapper to shield back-end from 'font'
\r
1365 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1370 { // in WB we have a 2D array of fonts; this initializes their description
\r
1372 /* Point font array elements to structures and
\r
1373 parse default font names */
\r
1374 for (i=0; i<NUM_FONTS; i++) {
\r
1375 for (j=0; j<NUM_SIZES; j++) {
\r
1376 font[j][i] = &fontRec[j][i];
\r
1377 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1384 { // here we create the actual fonts from the selected descriptions
\r
1386 for (i=0; i<NUM_FONTS; i++) {
\r
1387 for (j=0; j<NUM_SIZES; j++) {
\r
1388 CreateFontInMF(font[j][i]);
\r
1392 /* Color name parser.
\r
1393 X version accepts X color names, but this one
\r
1394 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1396 ParseColorName(char *name)
\r
1398 int red, green, blue, count;
\r
1399 char buf[MSG_SIZ];
\r
1401 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1403 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1404 &red, &green, &blue);
\r
1407 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1408 DisplayError(buf, 0);
\r
1409 return RGB(0, 0, 0);
\r
1411 return PALETTERGB(red, green, blue);
\r
1415 ParseColor(int n, char *name)
\r
1416 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1417 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1421 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1423 char *e = argValue;
\r
1427 if (*e == 'b') eff |= CFE_BOLD;
\r
1428 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1429 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1430 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1431 else if (*e == '#' || isdigit(*e)) break;
\r
1435 *color = ParseColorName(e);
\r
1439 ParseTextAttribs(ColorClass cc, char *s)
\r
1440 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1441 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1442 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1446 ParseBoardSize(void *addr, char *name)
\r
1447 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1448 BoardSize bs = SizeTiny;
\r
1449 while (sizeInfo[bs].name != NULL) {
\r
1450 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1451 *(BoardSize *)addr = bs;
\r
1456 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1461 { // [HGM] import name from appData first
\r
1464 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1465 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1466 textAttribs[cc].sound.data = NULL;
\r
1467 MyLoadSound(&textAttribs[cc].sound);
\r
1469 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1470 textAttribs[cc].sound.name = strdup("");
\r
1471 textAttribs[cc].sound.data = NULL;
\r
1473 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1474 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1475 sounds[sc].data = NULL;
\r
1476 MyLoadSound(&sounds[sc]);
\r
1481 SetCommPortDefaults()
\r
1483 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1484 dcb.DCBlength = sizeof(DCB);
\r
1485 dcb.BaudRate = 9600;
\r
1486 dcb.fBinary = TRUE;
\r
1487 dcb.fParity = FALSE;
\r
1488 dcb.fOutxCtsFlow = FALSE;
\r
1489 dcb.fOutxDsrFlow = FALSE;
\r
1490 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1491 dcb.fDsrSensitivity = FALSE;
\r
1492 dcb.fTXContinueOnXoff = TRUE;
\r
1493 dcb.fOutX = FALSE;
\r
1495 dcb.fNull = FALSE;
\r
1496 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1497 dcb.fAbortOnError = FALSE;
\r
1499 dcb.Parity = SPACEPARITY;
\r
1500 dcb.StopBits = ONESTOPBIT;
\r
1503 // [HGM] args: these three cases taken out to stay in front-end
\r
1505 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1506 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1507 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1508 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1510 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1511 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1512 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1513 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1514 ad->argName, mfp->faceName, mfp->pointSize,
\r
1515 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1516 mfp->bold ? "b" : "",
\r
1517 mfp->italic ? "i" : "",
\r
1518 mfp->underline ? "u" : "",
\r
1519 mfp->strikeout ? "s" : "",
\r
1520 (int)mfp->charset);
\r
1526 { // [HGM] copy the names from the internal WB variables to appData
\r
1529 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1530 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1531 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1532 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1536 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1537 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1538 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1539 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1540 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1541 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1542 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1543 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1544 (ta->effects) ? " " : "",
\r
1545 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1549 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1550 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1551 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1552 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1553 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1557 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1558 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1559 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1563 ParseCommPortSettings(char *s)
\r
1564 { // wrapper to keep dcb from back-end
\r
1565 ParseCommSettings(s, &dcb);
\r
1570 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1571 GetActualPlacement(hwndMain, &wpMain);
\r
1572 GetActualPlacement(hwndConsole, &wpConsole);
\r
1573 GetActualPlacement(commentDialog, &wpComment);
\r
1574 GetActualPlacement(editTagsDialog, &wpTags);
\r
1575 GetActualPlacement(gameListDialog, &wpGameList);
\r
1576 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1577 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1578 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1582 PrintCommPortSettings(FILE *f, char *name)
\r
1583 { // wrapper to shield back-end from DCB
\r
1584 PrintCommSettings(f, name, &dcb);
\r
1588 MySearchPath(char *installDir, char *name, char *fullname)
\r
1590 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1591 if(name[0]== '%') {
\r
1592 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1593 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1594 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1595 *strchr(buf, '%') = 0;
\r
1596 strcat(fullname, getenv(buf));
\r
1597 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1599 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1600 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1601 return (int) strlen(fullname);
\r
1603 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1607 MyGetFullPathName(char *name, char *fullname)
\r
1610 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1615 { // [HGM] args: allows testing if main window is realized from back-end
\r
1616 return hwndMain != NULL;
\r
1620 PopUpStartupDialog()
\r
1624 LoadLanguageFile(appData.language);
\r
1625 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1626 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1627 FreeProcInstance(lpProc);
\r
1630 /*---------------------------------------------------------------------------*\
\r
1632 * GDI board drawing routines
\r
1634 \*---------------------------------------------------------------------------*/
\r
1636 /* [AS] Draw square using background texture */
\r
1637 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1642 return; /* Should never happen! */
\r
1645 SetGraphicsMode( dst, GM_ADVANCED );
\r
1652 /* X reflection */
\r
1657 x.eDx = (FLOAT) dw + dx - 1;
\r
1660 SetWorldTransform( dst, &x );
\r
1663 /* Y reflection */
\r
1669 x.eDy = (FLOAT) dh + dy - 1;
\r
1671 SetWorldTransform( dst, &x );
\r
1679 x.eDx = (FLOAT) dx;
\r
1680 x.eDy = (FLOAT) dy;
\r
1683 SetWorldTransform( dst, &x );
\r
1687 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1695 SetWorldTransform( dst, &x );
\r
1697 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1700 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1702 PM_WP = (int) WhitePawn,
\r
1703 PM_WN = (int) WhiteKnight,
\r
1704 PM_WB = (int) WhiteBishop,
\r
1705 PM_WR = (int) WhiteRook,
\r
1706 PM_WQ = (int) WhiteQueen,
\r
1707 PM_WF = (int) WhiteFerz,
\r
1708 PM_WW = (int) WhiteWazir,
\r
1709 PM_WE = (int) WhiteAlfil,
\r
1710 PM_WM = (int) WhiteMan,
\r
1711 PM_WO = (int) WhiteCannon,
\r
1712 PM_WU = (int) WhiteUnicorn,
\r
1713 PM_WH = (int) WhiteNightrider,
\r
1714 PM_WA = (int) WhiteAngel,
\r
1715 PM_WC = (int) WhiteMarshall,
\r
1716 PM_WAB = (int) WhiteCardinal,
\r
1717 PM_WD = (int) WhiteDragon,
\r
1718 PM_WL = (int) WhiteLance,
\r
1719 PM_WS = (int) WhiteCobra,
\r
1720 PM_WV = (int) WhiteFalcon,
\r
1721 PM_WSG = (int) WhiteSilver,
\r
1722 PM_WG = (int) WhiteGrasshopper,
\r
1723 PM_WK = (int) WhiteKing,
\r
1724 PM_BP = (int) BlackPawn,
\r
1725 PM_BN = (int) BlackKnight,
\r
1726 PM_BB = (int) BlackBishop,
\r
1727 PM_BR = (int) BlackRook,
\r
1728 PM_BQ = (int) BlackQueen,
\r
1729 PM_BF = (int) BlackFerz,
\r
1730 PM_BW = (int) BlackWazir,
\r
1731 PM_BE = (int) BlackAlfil,
\r
1732 PM_BM = (int) BlackMan,
\r
1733 PM_BO = (int) BlackCannon,
\r
1734 PM_BU = (int) BlackUnicorn,
\r
1735 PM_BH = (int) BlackNightrider,
\r
1736 PM_BA = (int) BlackAngel,
\r
1737 PM_BC = (int) BlackMarshall,
\r
1738 PM_BG = (int) BlackGrasshopper,
\r
1739 PM_BAB = (int) BlackCardinal,
\r
1740 PM_BD = (int) BlackDragon,
\r
1741 PM_BL = (int) BlackLance,
\r
1742 PM_BS = (int) BlackCobra,
\r
1743 PM_BV = (int) BlackFalcon,
\r
1744 PM_BSG = (int) BlackSilver,
\r
1745 PM_BK = (int) BlackKing
\r
1748 static HFONT hPieceFont = NULL;
\r
1749 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1750 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1751 static int fontBitmapSquareSize = 0;
\r
1752 static char pieceToFontChar[(int) EmptySquare] =
\r
1753 { 'p', 'n', 'b', 'r', 'q',
\r
1754 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1755 'k', 'o', 'm', 'v', 't', 'w',
\r
1756 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1759 extern BOOL SetCharTable( char *table, const char * map );
\r
1760 /* [HGM] moved to backend.c */
\r
1762 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1765 BYTE r1 = GetRValue( color );
\r
1766 BYTE g1 = GetGValue( color );
\r
1767 BYTE b1 = GetBValue( color );
\r
1773 /* Create a uniform background first */
\r
1774 hbrush = CreateSolidBrush( color );
\r
1775 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1776 FillRect( hdc, &rc, hbrush );
\r
1777 DeleteObject( hbrush );
\r
1780 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1781 int steps = squareSize / 2;
\r
1784 for( i=0; i<steps; i++ ) {
\r
1785 BYTE r = r1 - (r1-r2) * i / steps;
\r
1786 BYTE g = g1 - (g1-g2) * i / steps;
\r
1787 BYTE b = b1 - (b1-b2) * i / steps;
\r
1789 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1790 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1791 FillRect( hdc, &rc, hbrush );
\r
1792 DeleteObject(hbrush);
\r
1795 else if( mode == 2 ) {
\r
1796 /* Diagonal gradient, good more or less for every piece */
\r
1797 POINT triangle[3];
\r
1798 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1799 HBRUSH hbrush_old;
\r
1800 int steps = squareSize;
\r
1803 triangle[0].x = squareSize - steps;
\r
1804 triangle[0].y = squareSize;
\r
1805 triangle[1].x = squareSize;
\r
1806 triangle[1].y = squareSize;
\r
1807 triangle[2].x = squareSize;
\r
1808 triangle[2].y = squareSize - steps;
\r
1810 for( i=0; i<steps; i++ ) {
\r
1811 BYTE r = r1 - (r1-r2) * i / steps;
\r
1812 BYTE g = g1 - (g1-g2) * i / steps;
\r
1813 BYTE b = b1 - (b1-b2) * i / steps;
\r
1815 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1816 hbrush_old = SelectObject( hdc, hbrush );
\r
1817 Polygon( hdc, triangle, 3 );
\r
1818 SelectObject( hdc, hbrush_old );
\r
1819 DeleteObject(hbrush);
\r
1824 SelectObject( hdc, hpen );
\r
1829 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1830 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1831 piece: follow the steps as explained below.
\r
1833 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1837 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1843 int backColor = whitePieceColor;
\r
1844 int foreColor = blackPieceColor;
\r
1846 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1847 backColor = appData.fontBackColorWhite;
\r
1848 foreColor = appData.fontForeColorWhite;
\r
1850 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1851 backColor = appData.fontBackColorBlack;
\r
1852 foreColor = appData.fontForeColorBlack;
\r
1856 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1858 hbm_old = SelectObject( hdc, hbm );
\r
1862 rc.right = squareSize;
\r
1863 rc.bottom = squareSize;
\r
1865 /* Step 1: background is now black */
\r
1866 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1868 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1870 pt.x = (squareSize - sz.cx) / 2;
\r
1871 pt.y = (squareSize - sz.cy) / 2;
\r
1873 SetBkMode( hdc, TRANSPARENT );
\r
1874 SetTextColor( hdc, chroma );
\r
1875 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1876 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1878 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1879 /* Step 3: the area outside the piece is filled with white */
\r
1880 // FloodFill( hdc, 0, 0, chroma );
\r
1881 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1882 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1883 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1884 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1885 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1887 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1888 but if the start point is not inside the piece we're lost!
\r
1889 There should be a better way to do this... if we could create a region or path
\r
1890 from the fill operation we would be fine for example.
\r
1892 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1893 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1895 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1896 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1897 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1899 SelectObject( dc2, bm2 );
\r
1900 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1901 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1902 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1903 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1904 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1907 DeleteObject( bm2 );
\r
1910 SetTextColor( hdc, 0 );
\r
1912 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1913 draw the piece again in black for safety.
\r
1915 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1917 SelectObject( hdc, hbm_old );
\r
1919 if( hPieceMask[index] != NULL ) {
\r
1920 DeleteObject( hPieceMask[index] );
\r
1923 hPieceMask[index] = hbm;
\r
1926 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1928 SelectObject( hdc, hbm );
\r
1931 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1932 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1933 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1935 SelectObject( dc1, hPieceMask[index] );
\r
1936 SelectObject( dc2, bm2 );
\r
1937 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1938 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1941 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1942 the piece background and deletes (makes transparent) the rest.
\r
1943 Thanks to that mask, we are free to paint the background with the greates
\r
1944 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1945 We use this, to make gradients and give the pieces a "roundish" look.
\r
1947 SetPieceBackground( hdc, backColor, 2 );
\r
1948 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1952 DeleteObject( bm2 );
\r
1955 SetTextColor( hdc, foreColor );
\r
1956 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1958 SelectObject( hdc, hbm_old );
\r
1960 if( hPieceFace[index] != NULL ) {
\r
1961 DeleteObject( hPieceFace[index] );
\r
1964 hPieceFace[index] = hbm;
\r
1967 static int TranslatePieceToFontPiece( int piece )
\r
1997 case BlackMarshall:
\r
2001 case BlackNightrider:
\r
2007 case BlackUnicorn:
\r
2011 case BlackGrasshopper:
\r
2023 case BlackCardinal:
\r
2030 case WhiteMarshall:
\r
2034 case WhiteNightrider:
\r
2040 case WhiteUnicorn:
\r
2044 case WhiteGrasshopper:
\r
2056 case WhiteCardinal:
\r
2065 void CreatePiecesFromFont()
\r
2068 HDC hdc_window = NULL;
\r
2074 if( fontBitmapSquareSize < 0 ) {
\r
2075 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2079 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2080 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2081 fontBitmapSquareSize = -1;
\r
2085 if( fontBitmapSquareSize != squareSize ) {
\r
2086 hdc_window = GetDC( hwndMain );
\r
2087 hdc = CreateCompatibleDC( hdc_window );
\r
2089 if( hPieceFont != NULL ) {
\r
2090 DeleteObject( hPieceFont );
\r
2093 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2094 hPieceMask[i] = NULL;
\r
2095 hPieceFace[i] = NULL;
\r
2101 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2102 fontHeight = appData.fontPieceSize;
\r
2105 fontHeight = (fontHeight * squareSize) / 100;
\r
2107 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2109 lf.lfEscapement = 0;
\r
2110 lf.lfOrientation = 0;
\r
2111 lf.lfWeight = FW_NORMAL;
\r
2113 lf.lfUnderline = 0;
\r
2114 lf.lfStrikeOut = 0;
\r
2115 lf.lfCharSet = DEFAULT_CHARSET;
\r
2116 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2117 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2118 lf.lfQuality = PROOF_QUALITY;
\r
2119 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2120 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2121 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2123 hPieceFont = CreateFontIndirect( &lf );
\r
2125 if( hPieceFont == NULL ) {
\r
2126 fontBitmapSquareSize = -2;
\r
2129 /* Setup font-to-piece character table */
\r
2130 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2131 /* No (or wrong) global settings, try to detect the font */
\r
2132 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2134 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2136 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2137 /* DiagramTT* family */
\r
2138 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2140 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2141 /* Fairy symbols */
\r
2142 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2144 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2145 /* Good Companion (Some characters get warped as literal :-( */
\r
2146 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2147 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2148 SetCharTable(pieceToFontChar, s);
\r
2151 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2152 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2156 /* Create bitmaps */
\r
2157 hfont_old = SelectObject( hdc, hPieceFont );
\r
2158 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2159 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2160 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2162 SelectObject( hdc, hfont_old );
\r
2164 fontBitmapSquareSize = squareSize;
\r
2168 if( hdc != NULL ) {
\r
2172 if( hdc_window != NULL ) {
\r
2173 ReleaseDC( hwndMain, hdc_window );
\r
2178 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2180 char name[128], buf[MSG_SIZ];
\r
2182 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2183 if(appData.pieceDirectory[0]) {
\r
2185 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2186 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2187 if(res) return res;
\r
2189 if (gameInfo.event &&
\r
2190 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2191 strcmp(name, "k80s") == 0) {
\r
2192 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2194 return LoadBitmap(hinst, name);
\r
2198 /* Insert a color into the program's logical palette
\r
2199 structure. This code assumes the given color is
\r
2200 the result of the RGB or PALETTERGB macro, and it
\r
2201 knows how those macros work (which is documented).
\r
2204 InsertInPalette(COLORREF color)
\r
2206 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2208 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2209 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2210 pLogPal->palNumEntries--;
\r
2214 pe->peFlags = (char) 0;
\r
2215 pe->peRed = (char) (0xFF & color);
\r
2216 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2217 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2223 InitDrawingColors()
\r
2226 if (pLogPal == NULL) {
\r
2227 /* Allocate enough memory for a logical palette with
\r
2228 * PALETTESIZE entries and set the size and version fields
\r
2229 * of the logical palette structure.
\r
2231 pLogPal = (NPLOGPALETTE)
\r
2232 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2233 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2234 pLogPal->palVersion = 0x300;
\r
2236 pLogPal->palNumEntries = 0;
\r
2238 InsertInPalette(lightSquareColor);
\r
2239 InsertInPalette(darkSquareColor);
\r
2240 InsertInPalette(whitePieceColor);
\r
2241 InsertInPalette(blackPieceColor);
\r
2242 InsertInPalette(highlightSquareColor);
\r
2243 InsertInPalette(premoveHighlightColor);
\r
2245 /* create a logical color palette according the information
\r
2246 * in the LOGPALETTE structure.
\r
2248 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2250 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2251 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2252 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2253 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2254 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2255 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2256 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2257 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2259 /* [AS] Force rendering of the font-based pieces */
\r
2260 if( fontBitmapSquareSize > 0 ) {
\r
2261 fontBitmapSquareSize = 0;
\r
2267 BoardWidth(int boardSize, int n)
\r
2268 { /* [HGM] argument n added to allow different width and height */
\r
2269 int lineGap = sizeInfo[boardSize].lineGap;
\r
2271 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2272 lineGap = appData.overrideLineGap;
\r
2275 return (n + 1) * lineGap +
\r
2276 n * sizeInfo[boardSize].squareSize;
\r
2279 /* Respond to board resize by dragging edge */
\r
2281 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2283 BoardSize newSize = NUM_SIZES - 1;
\r
2284 static int recurse = 0;
\r
2285 if (IsIconic(hwndMain)) return;
\r
2286 if (recurse > 0) return;
\r
2288 while (newSize > 0) {
\r
2289 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2290 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2291 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2294 boardSize = newSize;
\r
2295 InitDrawingSizes(boardSize, flags);
\r
2300 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2303 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2305 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2306 ChessSquare piece;
\r
2307 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2309 SIZE clockSize, messageSize;
\r
2311 char buf[MSG_SIZ];
\r
2313 HMENU hmenu = GetMenu(hwndMain);
\r
2314 RECT crect, wrect, oldRect;
\r
2316 LOGBRUSH logbrush;
\r
2317 VariantClass v = gameInfo.variant;
\r
2319 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2320 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2322 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2323 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2324 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2325 oldBoardSize = boardSize;
\r
2327 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2328 { // correct board size to one where built-in pieces exist
\r
2329 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2330 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2332 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2333 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2334 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2335 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2336 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2337 boardSize = SizeMiddling;
\r
2340 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2342 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2343 oldRect.top = wpMain.y;
\r
2344 oldRect.right = wpMain.x + wpMain.width;
\r
2345 oldRect.bottom = wpMain.y + wpMain.height;
\r
2347 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2348 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2349 squareSize = sizeInfo[boardSize].squareSize;
\r
2350 lineGap = sizeInfo[boardSize].lineGap;
\r
2351 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2352 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2354 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2355 lineGap = appData.overrideLineGap;
\r
2358 if (tinyLayout != oldTinyLayout) {
\r
2359 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2361 style &= ~WS_SYSMENU;
\r
2362 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2363 "&Minimize\tCtrl+F4");
\r
2365 style |= WS_SYSMENU;
\r
2366 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2368 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2370 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2371 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2372 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2374 DrawMenuBar(hwndMain);
\r
2377 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2378 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2380 /* Get text area sizes */
\r
2381 hdc = GetDC(hwndMain);
\r
2382 if (appData.clockMode) {
\r
2383 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2385 snprintf(buf, MSG_SIZ, _("White"));
\r
2387 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2388 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2389 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2390 str = _("We only care about the height here");
\r
2391 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2392 SelectObject(hdc, oldFont);
\r
2393 ReleaseDC(hwndMain, hdc);
\r
2395 /* Compute where everything goes */
\r
2396 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2397 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2398 logoHeight = 2*clockSize.cy;
\r
2399 leftLogoRect.left = OUTER_MARGIN;
\r
2400 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2401 leftLogoRect.top = OUTER_MARGIN;
\r
2402 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2404 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2405 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2406 rightLogoRect.top = OUTER_MARGIN;
\r
2407 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2410 whiteRect.left = leftLogoRect.right;
\r
2411 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2412 whiteRect.top = OUTER_MARGIN;
\r
2413 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2415 blackRect.right = rightLogoRect.left;
\r
2416 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2417 blackRect.top = whiteRect.top;
\r
2418 blackRect.bottom = whiteRect.bottom;
\r
2420 whiteRect.left = OUTER_MARGIN;
\r
2421 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2422 whiteRect.top = OUTER_MARGIN;
\r
2423 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2425 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2426 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2427 blackRect.top = whiteRect.top;
\r
2428 blackRect.bottom = whiteRect.bottom;
\r
2430 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2433 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2434 if (appData.showButtonBar) {
\r
2435 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2436 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2438 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2440 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2441 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2443 boardRect.left = OUTER_MARGIN;
\r
2444 boardRect.right = boardRect.left + boardWidth;
\r
2445 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2446 boardRect.bottom = boardRect.top + boardHeight;
\r
2448 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2449 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2450 oldTinyLayout = tinyLayout;
\r
2451 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2452 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2453 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2454 winW *= 1 + twoBoards;
\r
2455 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2456 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2457 wpMain.height = winH; // without disturbing window attachments
\r
2458 GetWindowRect(hwndMain, &wrect);
\r
2459 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2460 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2462 // [HGM] placement: let attached windows follow size change.
\r
2463 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2464 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2465 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2466 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2467 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2469 /* compensate if menu bar wrapped */
\r
2470 GetClientRect(hwndMain, &crect);
\r
2471 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2472 wpMain.height += offby;
\r
2474 case WMSZ_TOPLEFT:
\r
2475 SetWindowPos(hwndMain, NULL,
\r
2476 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2477 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2480 case WMSZ_TOPRIGHT:
\r
2482 SetWindowPos(hwndMain, NULL,
\r
2483 wrect.left, wrect.bottom - wpMain.height,
\r
2484 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2487 case WMSZ_BOTTOMLEFT:
\r
2489 SetWindowPos(hwndMain, NULL,
\r
2490 wrect.right - wpMain.width, wrect.top,
\r
2491 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2494 case WMSZ_BOTTOMRIGHT:
\r
2498 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2499 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2504 for (i = 0; i < N_BUTTONS; i++) {
\r
2505 if (buttonDesc[i].hwnd != NULL) {
\r
2506 DestroyWindow(buttonDesc[i].hwnd);
\r
2507 buttonDesc[i].hwnd = NULL;
\r
2509 if (appData.showButtonBar) {
\r
2510 buttonDesc[i].hwnd =
\r
2511 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2512 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2513 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2514 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2515 (HMENU) buttonDesc[i].id,
\r
2516 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2518 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2519 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2520 MAKELPARAM(FALSE, 0));
\r
2522 if (buttonDesc[i].id == IDM_Pause)
\r
2523 hwndPause = buttonDesc[i].hwnd;
\r
2524 buttonDesc[i].wndproc = (WNDPROC)
\r
2525 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2528 if (gridPen != NULL) DeleteObject(gridPen);
\r
2529 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2530 if (premovePen != NULL) DeleteObject(premovePen);
\r
2531 if (lineGap != 0) {
\r
2532 logbrush.lbStyle = BS_SOLID;
\r
2533 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2535 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2536 lineGap, &logbrush, 0, NULL);
\r
2537 logbrush.lbColor = highlightSquareColor;
\r
2539 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2540 lineGap, &logbrush, 0, NULL);
\r
2542 logbrush.lbColor = premoveHighlightColor;
\r
2544 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2545 lineGap, &logbrush, 0, NULL);
\r
2547 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2548 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2549 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2550 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2551 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2552 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2553 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2554 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2556 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2557 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2558 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2559 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2560 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2561 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2562 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2563 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2567 /* [HGM] Licensing requirement */
\r
2569 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2572 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2574 GothicPopUp( "", VariantNormal);
\r
2577 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2579 /* Load piece bitmaps for this board size */
\r
2580 for (i=0; i<=2; i++) {
\r
2581 for (piece = WhitePawn;
\r
2582 (int) piece < (int) BlackPawn;
\r
2583 piece = (ChessSquare) ((int) piece + 1)) {
\r
2584 if (pieceBitmap[i][piece] != NULL)
\r
2585 DeleteObject(pieceBitmap[i][piece]);
\r
2589 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2590 // Orthodox Chess pieces
\r
2591 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2592 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2593 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2594 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2595 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2596 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2597 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2598 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2599 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2600 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2601 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2602 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2603 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2604 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2605 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2606 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2607 // in Shogi, Hijack the unused Queen for Lance
\r
2608 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2609 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2610 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2612 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2613 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2614 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2617 if(squareSize <= 72 && squareSize >= 33) {
\r
2618 /* A & C are available in most sizes now */
\r
2619 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2620 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2621 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2622 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2623 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2624 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2625 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2626 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2627 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2628 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2629 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2630 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2631 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2632 } else { // Smirf-like
\r
2633 if(gameInfo.variant == VariantSChess) {
\r
2634 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2635 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2636 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2638 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2639 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2640 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2643 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2644 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2647 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2648 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2651 } else { // WinBoard standard
\r
2652 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2653 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2654 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2659 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2660 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2663 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2664 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2665 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2666 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2667 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2668 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2669 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2670 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2671 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2672 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2673 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2674 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2675 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2676 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2677 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2678 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2679 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2680 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2681 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2682 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2683 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2684 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2685 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2686 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2687 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2688 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2689 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2690 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2691 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2692 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2694 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2695 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2696 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2697 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2698 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2699 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2700 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2701 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2702 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2703 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2704 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2705 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2706 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2708 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2709 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2710 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2711 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2712 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2713 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2714 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2715 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2716 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2717 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2718 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2719 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2722 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2723 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2724 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2725 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2726 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2727 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2728 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2729 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2730 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2731 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2732 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2733 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2734 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2735 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2736 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2740 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2741 /* special Shogi support in this size */
\r
2742 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2743 for (piece = WhitePawn;
\r
2744 (int) piece < (int) BlackPawn;
\r
2745 piece = (ChessSquare) ((int) piece + 1)) {
\r
2746 if (pieceBitmap[i][piece] != NULL)
\r
2747 DeleteObject(pieceBitmap[i][piece]);
\r
2750 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2751 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2752 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2753 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2754 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2755 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2756 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2757 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2758 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2762 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2763 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2764 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2765 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2766 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2767 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2768 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2769 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2770 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2771 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2772 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2776 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2777 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2778 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2779 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2780 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2781 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2782 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2783 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2784 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2785 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2786 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2790 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2791 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2797 PieceBitmap(ChessSquare p, int kind)
\r
2799 if ((int) p >= (int) BlackPawn)
\r
2800 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2802 return pieceBitmap[kind][(int) p];
\r
2805 /***************************************************************/
\r
2807 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2808 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2810 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2811 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2815 SquareToPos(int row, int column, int * x, int * y)
\r
2818 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2819 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2821 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2822 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2827 DrawCoordsOnDC(HDC hdc)
\r
2829 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2830 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2831 char str[2] = { NULLCHAR, NULLCHAR };
\r
2832 int oldMode, oldAlign, x, y, start, i;
\r
2836 if (!appData.showCoords)
\r
2839 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2841 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2842 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2843 oldAlign = GetTextAlign(hdc);
\r
2844 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2846 y = boardRect.top + lineGap;
\r
2847 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2850 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2851 x += border - lineGap - 4; y += squareSize - 6;
\r
2853 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2854 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2855 str[0] = files[start + i];
\r
2856 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2857 y += squareSize + lineGap;
\r
2860 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2863 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2864 x += -border + 4; y += border - squareSize + 6;
\r
2866 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2867 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2868 str[0] = ranks[start + i];
\r
2869 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2870 x += squareSize + lineGap;
\r
2873 SelectObject(hdc, oldBrush);
\r
2874 SetBkMode(hdc, oldMode);
\r
2875 SetTextAlign(hdc, oldAlign);
\r
2876 SelectObject(hdc, oldFont);
\r
2880 DrawGridOnDC(HDC hdc)
\r
2884 if (lineGap != 0) {
\r
2885 oldPen = SelectObject(hdc, gridPen);
\r
2886 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2887 SelectObject(hdc, oldPen);
\r
2891 #define HIGHLIGHT_PEN 0
\r
2892 #define PREMOVE_PEN 1
\r
2895 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2898 HPEN oldPen, hPen;
\r
2899 if (lineGap == 0) return;
\r
2901 x1 = boardRect.left +
\r
2902 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2903 y1 = boardRect.top +
\r
2904 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2906 x1 = boardRect.left +
\r
2907 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2908 y1 = boardRect.top +
\r
2909 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2911 hPen = pen ? premovePen : highlightPen;
\r
2912 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2913 MoveToEx(hdc, x1, y1, NULL);
\r
2914 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2915 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2916 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2917 LineTo(hdc, x1, y1);
\r
2918 SelectObject(hdc, oldPen);
\r
2922 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2925 for (i=0; i<2; i++) {
\r
2926 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2927 DrawHighlightOnDC(hdc, TRUE,
\r
2928 h->sq[i].x, h->sq[i].y,
\r
2933 /* Note: sqcolor is used only in monoMode */
\r
2934 /* Note that this code is largely duplicated in woptions.c,
\r
2935 function DrawSampleSquare, so that needs to be updated too */
\r
2937 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2939 HBITMAP oldBitmap;
\r
2943 if (appData.blindfold) return;
\r
2945 /* [AS] Use font-based pieces if needed */
\r
2946 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2947 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2948 CreatePiecesFromFont();
\r
2950 if( fontBitmapSquareSize == squareSize ) {
\r
2951 int index = TranslatePieceToFontPiece(piece);
\r
2953 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2955 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2956 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2960 squareSize, squareSize,
\r
2965 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2967 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2968 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2972 squareSize, squareSize,
\r
2981 if (appData.monoMode) {
\r
2982 SelectObject(tmphdc, PieceBitmap(piece,
\r
2983 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2984 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2985 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2987 HBRUSH xBrush = whitePieceBrush;
\r
2988 tmpSize = squareSize;
\r
2989 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2991 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2992 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2993 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2994 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2995 x += (squareSize - minorSize)>>1;
\r
2996 y += squareSize - minorSize - 2;
\r
2997 tmpSize = minorSize;
\r
2999 if (color || appData.allWhite ) {
\r
3000 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3002 oldBrush = SelectObject(hdc, xBrush);
\r
3003 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3004 if(appData.upsideDown && color==flipView)
\r
3005 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3007 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3008 /* Use black for outline of white pieces */
\r
3009 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3010 if(appData.upsideDown && color==flipView)
\r
3011 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3013 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3014 } else if(appData.pieceDirectory[0]) {
\r
3015 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3016 oldBrush = SelectObject(hdc, xBrush);
\r
3017 if(appData.upsideDown && color==flipView)
\r
3018 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3020 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3021 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3022 if(appData.upsideDown && color==flipView)
\r
3023 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3025 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3027 /* Use square color for details of black pieces */
\r
3028 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3029 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3030 if(appData.upsideDown && !flipView)
\r
3031 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3033 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3035 SelectObject(hdc, oldBrush);
\r
3036 SelectObject(tmphdc, oldBitmap);
\r
3040 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3041 int GetBackTextureMode( int algo )
\r
3043 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3047 case BACK_TEXTURE_MODE_PLAIN:
\r
3048 result = 1; /* Always use identity map */
\r
3050 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3051 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3059 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3060 to handle redraws cleanly (as random numbers would always be different).
\r
3062 VOID RebuildTextureSquareInfo()
\r
3072 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3074 if( liteBackTexture != NULL ) {
\r
3075 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3076 lite_w = bi.bmWidth;
\r
3077 lite_h = bi.bmHeight;
\r
3081 if( darkBackTexture != NULL ) {
\r
3082 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3083 dark_w = bi.bmWidth;
\r
3084 dark_h = bi.bmHeight;
\r
3088 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3089 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3090 if( (col + row) & 1 ) {
\r
3092 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3093 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3094 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3096 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3097 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3098 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3100 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3101 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3106 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3107 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3108 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3110 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3111 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3112 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3114 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3115 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3122 /* [AS] Arrow highlighting support */
\r
3124 static double A_WIDTH = 5; /* Width of arrow body */
\r
3126 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3127 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3129 static double Sqr( double x )
\r
3134 static int Round( double x )
\r
3136 return (int) (x + 0.5);
\r
3139 /* Draw an arrow between two points using current settings */
\r
3140 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3143 double dx, dy, j, k, x, y;
\r
3145 if( d_x == s_x ) {
\r
3146 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3148 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3151 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3152 arrow[1].y = d_y - h;
\r
3154 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3155 arrow[2].y = d_y - h;
\r
3160 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3161 arrow[5].y = d_y - h;
\r
3163 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3164 arrow[4].y = d_y - h;
\r
3166 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3169 else if( d_y == s_y ) {
\r
3170 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3173 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3175 arrow[1].x = d_x - w;
\r
3176 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3178 arrow[2].x = d_x - w;
\r
3179 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3184 arrow[5].x = d_x - w;
\r
3185 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3187 arrow[4].x = d_x - w;
\r
3188 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3191 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3194 /* [AS] Needed a lot of paper for this! :-) */
\r
3195 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3196 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3198 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3200 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3205 arrow[0].x = Round(x - j);
\r
3206 arrow[0].y = Round(y + j*dx);
\r
3208 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3209 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3212 x = (double) d_x - k;
\r
3213 y = (double) d_y - k*dy;
\r
3216 x = (double) d_x + k;
\r
3217 y = (double) d_y + k*dy;
\r
3220 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3222 arrow[6].x = Round(x - j);
\r
3223 arrow[6].y = Round(y + j*dx);
\r
3225 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3226 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3228 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3229 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3234 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3235 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3238 Polygon( hdc, arrow, 7 );
\r
3241 /* [AS] Draw an arrow between two squares */
\r
3242 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3244 int s_x, s_y, d_x, d_y;
\r
3251 if( s_col == d_col && s_row == d_row ) {
\r
3255 /* Get source and destination points */
\r
3256 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3257 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3260 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3262 else if( d_y < s_y ) {
\r
3263 d_y += squareSize / 2 + squareSize / 4;
\r
3266 d_y += squareSize / 2;
\r
3270 d_x += squareSize / 2 - squareSize / 4;
\r
3272 else if( d_x < s_x ) {
\r
3273 d_x += squareSize / 2 + squareSize / 4;
\r
3276 d_x += squareSize / 2;
\r
3279 s_x += squareSize / 2;
\r
3280 s_y += squareSize / 2;
\r
3282 /* Adjust width */
\r
3283 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3286 stLB.lbStyle = BS_SOLID;
\r
3287 stLB.lbColor = appData.highlightArrowColor;
\r
3290 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3291 holdpen = SelectObject( hdc, hpen );
\r
3292 hbrush = CreateBrushIndirect( &stLB );
\r
3293 holdbrush = SelectObject( hdc, hbrush );
\r
3295 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3297 SelectObject( hdc, holdpen );
\r
3298 SelectObject( hdc, holdbrush );
\r
3299 DeleteObject( hpen );
\r
3300 DeleteObject( hbrush );
\r
3303 BOOL HasHighlightInfo()
\r
3305 BOOL result = FALSE;
\r
3307 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3308 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3319 BOOL IsDrawArrowEnabled()
\r
3321 BOOL result = FALSE;
\r
3323 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3330 VOID DrawArrowHighlight( HDC hdc )
\r
3332 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3333 DrawArrowBetweenSquares( hdc,
\r
3334 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3335 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3339 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3341 HRGN result = NULL;
\r
3343 if( HasHighlightInfo() ) {
\r
3344 int x1, y1, x2, y2;
\r
3345 int sx, sy, dx, dy;
\r
3347 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3348 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3350 sx = MIN( x1, x2 );
\r
3351 sy = MIN( y1, y2 );
\r
3352 dx = MAX( x1, x2 ) + squareSize;
\r
3353 dy = MAX( y1, y2 ) + squareSize;
\r
3355 result = CreateRectRgn( sx, sy, dx, dy );
\r
3362 Warning: this function modifies the behavior of several other functions.
\r
3364 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3365 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3366 repaint is scattered all over the place, which is not good for features such as
\r
3367 "arrow highlighting" that require a full repaint of the board.
\r
3369 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3370 user interaction, when speed is not so important) but especially to avoid errors
\r
3371 in the displayed graphics.
\r
3373 In such patched places, I always try refer to this function so there is a single
\r
3374 place to maintain knowledge.
\r
3376 To restore the original behavior, just return FALSE unconditionally.
\r
3378 BOOL IsFullRepaintPreferrable()
\r
3380 BOOL result = FALSE;
\r
3382 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3383 /* Arrow may appear on the board */
\r
3391 This function is called by DrawPosition to know whether a full repaint must
\r
3394 Only DrawPosition may directly call this function, which makes use of
\r
3395 some state information. Other function should call DrawPosition specifying
\r
3396 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3398 BOOL DrawPositionNeedsFullRepaint()
\r
3400 BOOL result = FALSE;
\r
3403 Probably a slightly better policy would be to trigger a full repaint
\r
3404 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3405 but animation is fast enough that it's difficult to notice.
\r
3407 if( animInfo.piece == EmptySquare ) {
\r
3408 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3416 static HBITMAP borderBitmap;
\r
3419 DrawBackgroundOnDC(HDC hdc)
\r
3425 static char oldBorder[MSG_SIZ];
\r
3426 int w = 600, h = 600, mode;
\r
3428 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3429 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3430 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3432 if(borderBitmap == NULL) { // loading failed, use white
\r
3433 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3436 tmphdc = CreateCompatibleDC(hdc);
\r
3437 hbm = SelectObject(tmphdc, borderBitmap);
\r
3438 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3442 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3443 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3444 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3445 SetStretchBltMode(hdc, mode);
\r
3446 SelectObject(tmphdc, hbm);
\r
3451 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3453 int row, column, x, y, square_color, piece_color;
\r
3454 ChessSquare piece;
\r
3456 HDC texture_hdc = NULL;
\r
3458 /* [AS] Initialize background textures if needed */
\r
3459 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3460 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3461 if( backTextureSquareSize != squareSize
\r
3462 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3463 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3464 backTextureSquareSize = squareSize;
\r
3465 RebuildTextureSquareInfo();
\r
3468 texture_hdc = CreateCompatibleDC( hdc );
\r
3471 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3472 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3474 SquareToPos(row, column, &x, &y);
\r
3476 piece = board[row][column];
\r
3478 square_color = ((column + row) % 2) == 1;
\r
3479 if( gameInfo.variant == VariantXiangqi ) {
\r
3480 square_color = !InPalace(row, column);
\r
3481 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3482 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3484 piece_color = (int) piece < (int) BlackPawn;
\r
3487 /* [HGM] holdings file: light square or black */
\r
3488 if(column == BOARD_LEFT-2) {
\r
3489 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3492 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3496 if(column == BOARD_RGHT + 1 ) {
\r
3497 if( row < gameInfo.holdingsSize )
\r
3500 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3504 if(column == BOARD_LEFT-1 ) /* left align */
\r
3505 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3506 else if( column == BOARD_RGHT) /* right align */
\r
3507 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3508 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3510 if (appData.monoMode) {
\r
3511 if (piece == EmptySquare) {
\r
3512 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3513 square_color ? WHITENESS : BLACKNESS);
\r
3515 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3518 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3519 /* [AS] Draw the square using a texture bitmap */
\r
3520 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3521 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3522 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3525 squareSize, squareSize,
\r
3528 backTextureSquareInfo[r][c].mode,
\r
3529 backTextureSquareInfo[r][c].x,
\r
3530 backTextureSquareInfo[r][c].y );
\r
3532 SelectObject( texture_hdc, hbm );
\r
3534 if (piece != EmptySquare) {
\r
3535 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3539 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3541 oldBrush = SelectObject(hdc, brush );
\r
3542 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3543 SelectObject(hdc, oldBrush);
\r
3544 if (piece != EmptySquare)
\r
3545 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3550 if( texture_hdc != NULL ) {
\r
3551 DeleteDC( texture_hdc );
\r
3555 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3556 void fputDW(FILE *f, int x)
\r
3558 fputc(x & 255, f);
\r
3559 fputc(x>>8 & 255, f);
\r
3560 fputc(x>>16 & 255, f);
\r
3561 fputc(x>>24 & 255, f);
\r
3564 #define MAX_CLIPS 200 /* more than enough */
\r
3567 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3569 // HBITMAP bufferBitmap;
\r
3574 int w = 100, h = 50;
\r
3576 if(logo == NULL) {
\r
3577 if(!logoHeight) return;
\r
3578 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3580 // GetClientRect(hwndMain, &Rect);
\r
3581 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3582 // Rect.bottom-Rect.top+1);
\r
3583 tmphdc = CreateCompatibleDC(hdc);
\r
3584 hbm = SelectObject(tmphdc, logo);
\r
3585 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3589 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3590 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3591 SelectObject(tmphdc, hbm);
\r
3599 HDC hdc = GetDC(hwndMain);
\r
3600 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3601 if(appData.autoLogo) {
\r
3603 switch(gameMode) { // pick logos based on game mode
\r
3604 case IcsObserving:
\r
3605 whiteLogo = second.programLogo; // ICS logo
\r
3606 blackLogo = second.programLogo;
\r
3609 case IcsPlayingWhite:
\r
3610 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3611 blackLogo = second.programLogo; // ICS logo
\r
3613 case IcsPlayingBlack:
\r
3614 whiteLogo = second.programLogo; // ICS logo
\r
3615 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3617 case TwoMachinesPlay:
\r
3618 if(first.twoMachinesColor[0] == 'b') {
\r
3619 whiteLogo = second.programLogo;
\r
3620 blackLogo = first.programLogo;
\r
3623 case MachinePlaysWhite:
\r
3624 blackLogo = userLogo;
\r
3626 case MachinePlaysBlack:
\r
3627 whiteLogo = userLogo;
\r
3628 blackLogo = first.programLogo;
\r
3631 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3632 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3633 ReleaseDC(hwndMain, hdc);
\r
3638 UpdateLogos(int display)
\r
3639 { // called after loading new engine(s), in tourney or from menu
\r
3640 LoadLogo(&first, 0, FALSE);
\r
3641 LoadLogo(&second, 1, appData.icsActive);
\r
3642 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3643 if(display) DisplayLogos();
\r
3646 static HDC hdcSeek;
\r
3648 // [HGM] seekgraph
\r
3649 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3652 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3653 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3654 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3655 SelectObject( hdcSeek, hp );
\r
3658 // front-end wrapper for drawing functions to do rectangles
\r
3659 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3664 if (hdcSeek == NULL) {
\r
3665 hdcSeek = GetDC(hwndMain);
\r
3666 if (!appData.monoMode) {
\r
3667 SelectPalette(hdcSeek, hPal, FALSE);
\r
3668 RealizePalette(hdcSeek);
\r
3671 hp = SelectObject( hdcSeek, gridPen );
\r
3672 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3673 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3674 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3675 SelectObject( hdcSeek, hp );
\r
3678 // front-end wrapper for putting text in graph
\r
3679 void DrawSeekText(char *buf, int x, int y)
\r
3682 SetBkMode( hdcSeek, TRANSPARENT );
\r
3683 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3684 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3687 void DrawSeekDot(int x, int y, int color)
\r
3689 int square = color & 0x80;
\r
3690 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3691 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3694 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3695 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3697 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3698 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3699 SelectObject(hdcSeek, oldBrush);
\r
3702 void DrawSeekOpen()
\r
3706 void DrawSeekClose()
\r
3711 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3713 static Board lastReq[2], lastDrawn[2];
\r
3714 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3715 static int lastDrawnFlipView = 0;
\r
3716 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3717 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3720 HBITMAP bufferBitmap;
\r
3721 HBITMAP oldBitmap;
\r
3723 HRGN clips[MAX_CLIPS];
\r
3724 ChessSquare dragged_piece = EmptySquare;
\r
3725 int nr = twoBoards*partnerUp;
\r
3727 /* I'm undecided on this - this function figures out whether a full
\r
3728 * repaint is necessary on its own, so there's no real reason to have the
\r
3729 * caller tell it that. I think this can safely be set to FALSE - but
\r
3730 * if we trust the callers not to request full repaints unnessesarily, then
\r
3731 * we could skip some clipping work. In other words, only request a full
\r
3732 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3733 * gamestart and similar) --Hawk
\r
3735 Boolean fullrepaint = repaint;
\r
3737 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3739 if( DrawPositionNeedsFullRepaint() ) {
\r
3740 fullrepaint = TRUE;
\r
3743 if (board == NULL) {
\r
3744 if (!lastReqValid[nr]) {
\r
3747 board = lastReq[nr];
\r
3749 CopyBoard(lastReq[nr], board);
\r
3750 lastReqValid[nr] = 1;
\r
3753 if (doingSizing) {
\r
3757 if (IsIconic(hwndMain)) {
\r
3761 if (hdc == NULL) {
\r
3762 hdc = GetDC(hwndMain);
\r
3763 if (!appData.monoMode) {
\r
3764 SelectPalette(hdc, hPal, FALSE);
\r
3765 RealizePalette(hdc);
\r
3769 releaseDC = FALSE;
\r
3772 /* Create some work-DCs */
\r
3773 hdcmem = CreateCompatibleDC(hdc);
\r
3774 tmphdc = CreateCompatibleDC(hdc);
\r
3776 /* If dragging is in progress, we temporarely remove the piece */
\r
3777 /* [HGM] or temporarily decrease count if stacked */
\r
3778 /* !! Moved to before board compare !! */
\r
3779 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3780 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3781 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3782 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3783 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3785 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3786 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3787 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3789 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3792 /* Figure out which squares need updating by comparing the
\r
3793 * newest board with the last drawn board and checking if
\r
3794 * flipping has changed.
\r
3796 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3797 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3798 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3799 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3800 SquareToPos(row, column, &x, &y);
\r
3801 clips[num_clips++] =
\r
3802 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3806 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3807 for (i=0; i<2; i++) {
\r
3808 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3809 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3810 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3811 lastDrawnHighlight.sq[i].y >= 0) {
\r
3812 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3813 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3814 clips[num_clips++] =
\r
3815 CreateRectRgn(x - lineGap, y - lineGap,
\r
3816 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3818 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3819 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3820 clips[num_clips++] =
\r
3821 CreateRectRgn(x - lineGap, y - lineGap,
\r
3822 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3826 for (i=0; i<2; i++) {
\r
3827 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3828 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3829 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3830 lastDrawnPremove.sq[i].y >= 0) {
\r
3831 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3832 lastDrawnPremove.sq[i].x, &x, &y);
\r
3833 clips[num_clips++] =
\r
3834 CreateRectRgn(x - lineGap, y - lineGap,
\r
3835 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3837 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3838 premoveHighlightInfo.sq[i].y >= 0) {
\r
3839 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3840 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3841 clips[num_clips++] =
\r
3842 CreateRectRgn(x - lineGap, y - lineGap,
\r
3843 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3847 } else { // nr == 1
\r
3848 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3849 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3850 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3851 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3852 for (i=0; i<2; i++) {
\r
3853 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3854 partnerHighlightInfo.sq[i].y >= 0) {
\r
3855 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3856 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3857 clips[num_clips++] =
\r
3858 CreateRectRgn(x - lineGap, y - lineGap,
\r
3859 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3861 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3862 oldPartnerHighlight.sq[i].y >= 0) {
\r
3863 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3864 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3865 clips[num_clips++] =
\r
3866 CreateRectRgn(x - lineGap, y - lineGap,
\r
3867 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3872 fullrepaint = TRUE;
\r
3875 /* Create a buffer bitmap - this is the actual bitmap
\r
3876 * being written to. When all the work is done, we can
\r
3877 * copy it to the real DC (the screen). This avoids
\r
3878 * the problems with flickering.
\r
3880 GetClientRect(hwndMain, &Rect);
\r
3881 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3882 Rect.bottom-Rect.top+1);
\r
3883 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3884 if (!appData.monoMode) {
\r
3885 SelectPalette(hdcmem, hPal, FALSE);
\r
3888 /* Create clips for dragging */
\r
3889 if (!fullrepaint) {
\r
3890 if (dragInfo.from.x >= 0) {
\r
3891 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3892 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3894 if (dragInfo.start.x >= 0) {
\r
3895 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3896 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3898 if (dragInfo.pos.x >= 0) {
\r
3899 x = dragInfo.pos.x - squareSize / 2;
\r
3900 y = dragInfo.pos.y - squareSize / 2;
\r
3901 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3903 if (dragInfo.lastpos.x >= 0) {
\r
3904 x = dragInfo.lastpos.x - squareSize / 2;
\r
3905 y = dragInfo.lastpos.y - squareSize / 2;
\r
3906 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3910 /* Are we animating a move?
\r
3912 * - remove the piece from the board (temporarely)
\r
3913 * - calculate the clipping region
\r
3915 if (!fullrepaint) {
\r
3916 if (animInfo.piece != EmptySquare) {
\r
3917 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3918 x = boardRect.left + animInfo.lastpos.x;
\r
3919 y = boardRect.top + animInfo.lastpos.y;
\r
3920 x2 = boardRect.left + animInfo.pos.x;
\r
3921 y2 = boardRect.top + animInfo.pos.y;
\r
3922 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3923 /* Slight kludge. The real problem is that after AnimateMove is
\r
3924 done, the position on the screen does not match lastDrawn.
\r
3925 This currently causes trouble only on e.p. captures in
\r
3926 atomic, where the piece moves to an empty square and then
\r
3927 explodes. The old and new positions both had an empty square
\r
3928 at the destination, but animation has drawn a piece there and
\r
3929 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3930 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3934 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3935 if (num_clips == 0)
\r
3936 fullrepaint = TRUE;
\r
3938 /* Set clipping on the memory DC */
\r
3939 if (!fullrepaint) {
\r
3940 SelectClipRgn(hdcmem, clips[0]);
\r
3941 for (x = 1; x < num_clips; x++) {
\r
3942 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3943 abort(); // this should never ever happen!
\r
3947 /* Do all the drawing to the memory DC */
\r
3948 if(explodeInfo.radius) { // [HGM] atomic
\r
3950 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3951 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3952 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3953 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3954 x += squareSize/2;
\r
3955 y += squareSize/2;
\r
3956 if(!fullrepaint) {
\r
3957 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3958 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3960 DrawGridOnDC(hdcmem);
\r
3961 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3962 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3963 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3964 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3965 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3966 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3967 SelectObject(hdcmem, oldBrush);
\r
3969 if(border) DrawBackgroundOnDC(hdcmem);
\r
3970 DrawGridOnDC(hdcmem);
\r
3971 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3972 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3973 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3975 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3976 oldPartnerHighlight = partnerHighlightInfo;
\r
3978 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3980 if(nr == 0) // [HGM] dual: markers only on left board
\r
3981 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3982 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3983 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3984 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
3985 SquareToPos(row, column, &x, &y);
\r
3986 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3987 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3988 SelectObject(hdcmem, oldBrush);
\r
3993 if( appData.highlightMoveWithArrow ) {
\r
3994 DrawArrowHighlight(hdcmem);
\r
3997 DrawCoordsOnDC(hdcmem);
\r
3999 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
4000 /* to make sure lastDrawn contains what is actually drawn */
\r
4002 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4003 if (dragged_piece != EmptySquare) {
\r
4004 /* [HGM] or restack */
\r
4005 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4006 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4008 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4009 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4011 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4012 x = dragInfo.pos.x - squareSize / 2;
\r
4013 y = dragInfo.pos.y - squareSize / 2;
\r
4014 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
4015 ((int) dragInfo.piece < (int) BlackPawn),
\r
4016 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4019 /* Put the animated piece back into place and draw it */
\r
4020 if (animInfo.piece != EmptySquare) {
\r
4021 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4022 x = boardRect.left + animInfo.pos.x;
\r
4023 y = boardRect.top + animInfo.pos.y;
\r
4024 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4025 ((int) animInfo.piece < (int) BlackPawn),
\r
4026 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4029 /* Release the bufferBitmap by selecting in the old bitmap
\r
4030 * and delete the memory DC
\r
4032 SelectObject(hdcmem, oldBitmap);
\r
4035 /* Set clipping on the target DC */
\r
4036 if (!fullrepaint) {
\r
4037 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4039 GetRgnBox(clips[x], &rect);
\r
4040 DeleteObject(clips[x]);
\r
4041 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4042 rect.right + wpMain.width/2, rect.bottom);
\r
4044 SelectClipRgn(hdc, clips[0]);
\r
4045 for (x = 1; x < num_clips; x++) {
\r
4046 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4047 abort(); // this should never ever happen!
\r
4051 /* Copy the new bitmap onto the screen in one go.
\r
4052 * This way we avoid any flickering
\r
4054 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4055 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4056 boardRect.right - boardRect.left,
\r
4057 boardRect.bottom - boardRect.top,
\r
4058 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4059 if(saveDiagFlag) {
\r
4060 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4061 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4063 GetObject(bufferBitmap, sizeof(b), &b);
\r
4064 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4065 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4066 bih.biWidth = b.bmWidth;
\r
4067 bih.biHeight = b.bmHeight;
\r
4069 bih.biBitCount = b.bmBitsPixel;
\r
4070 bih.biCompression = 0;
\r
4071 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4072 bih.biXPelsPerMeter = 0;
\r
4073 bih.biYPelsPerMeter = 0;
\r
4074 bih.biClrUsed = 0;
\r
4075 bih.biClrImportant = 0;
\r
4076 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4077 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4078 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4079 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4081 wb = b.bmWidthBytes;
\r
4083 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4084 int k = ((int*) pData)[i];
\r
4085 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4086 if(j >= 16) break;
\r
4088 if(j >= nrColors) nrColors = j+1;
\r
4090 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4092 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4093 for(w=0; w<(wb>>2); w+=2) {
\r
4094 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4095 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4096 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4097 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4098 pData[p++] = m | j<<4;
\r
4100 while(p&3) pData[p++] = 0;
\r
4103 wb = ((wb+31)>>5)<<2;
\r
4105 // write BITMAPFILEHEADER
\r
4106 fprintf(diagFile, "BM");
\r
4107 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4108 fputDW(diagFile, 0);
\r
4109 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4110 // write BITMAPINFOHEADER
\r
4111 fputDW(diagFile, 40);
\r
4112 fputDW(diagFile, b.bmWidth);
\r
4113 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4114 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4115 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\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 fputDW(diagFile, 0);
\r
4122 // write color table
\r
4124 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4125 // write bitmap data
\r
4126 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4127 fputc(pData[i], diagFile);
\r
4132 SelectObject(tmphdc, oldBitmap);
\r
4134 /* Massive cleanup */
\r
4135 for (x = 0; x < num_clips; x++)
\r
4136 DeleteObject(clips[x]);
\r
4139 DeleteObject(bufferBitmap);
\r
4142 ReleaseDC(hwndMain, hdc);
\r
4144 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4146 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4148 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4151 /* CopyBoard(lastDrawn, board);*/
\r
4152 lastDrawnHighlight = highlightInfo;
\r
4153 lastDrawnPremove = premoveHighlightInfo;
\r
4154 lastDrawnFlipView = flipView;
\r
4155 lastDrawnValid[nr] = 1;
\r
4158 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4163 saveDiagFlag = 1; diagFile = f;
\r
4164 HDCDrawPosition(NULL, TRUE, NULL);
\r
4172 /*---------------------------------------------------------------------------*\
\r
4173 | CLIENT PAINT PROCEDURE
\r
4174 | This is the main event-handler for the WM_PAINT message.
\r
4176 \*---------------------------------------------------------------------------*/
\r
4178 PaintProc(HWND hwnd)
\r
4184 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4185 if (IsIconic(hwnd)) {
\r
4186 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4188 if (!appData.monoMode) {
\r
4189 SelectPalette(hdc, hPal, FALSE);
\r
4190 RealizePalette(hdc);
\r
4192 HDCDrawPosition(hdc, 1, NULL);
\r
4193 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4194 flipView = !flipView; partnerUp = !partnerUp;
\r
4195 HDCDrawPosition(hdc, 1, NULL);
\r
4196 flipView = !flipView; partnerUp = !partnerUp;
\r
4199 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4200 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4201 ETO_CLIPPED|ETO_OPAQUE,
\r
4202 &messageRect, messageText, strlen(messageText), NULL);
\r
4203 SelectObject(hdc, oldFont);
\r
4204 DisplayBothClocks();
\r
4207 EndPaint(hwnd,&ps);
\r
4215 * If the user selects on a border boundary, return -1; if off the board,
\r
4216 * return -2. Otherwise map the event coordinate to the square.
\r
4217 * The offset boardRect.left or boardRect.top must already have been
\r
4218 * subtracted from x.
\r
4220 int EventToSquare(x, limit)
\r
4225 if (x < lineGap + border)
\r
4227 x -= lineGap + border;
\r
4228 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4230 x /= (squareSize + lineGap);
\r
4242 DropEnable dropEnables[] = {
\r
4243 { 'P', DP_Pawn, N_("Pawn") },
\r
4244 { 'N', DP_Knight, N_("Knight") },
\r
4245 { 'B', DP_Bishop, N_("Bishop") },
\r
4246 { 'R', DP_Rook, N_("Rook") },
\r
4247 { 'Q', DP_Queen, N_("Queen") },
\r
4251 SetupDropMenu(HMENU hmenu)
\r
4253 int i, count, enable;
\r
4255 extern char white_holding[], black_holding[];
\r
4256 char item[MSG_SIZ];
\r
4258 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4259 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4260 dropEnables[i].piece);
\r
4262 while (p && *p++ == dropEnables[i].piece) count++;
\r
4263 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4264 enable = count > 0 || !appData.testLegality
\r
4265 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4266 && !appData.icsActive);
\r
4267 ModifyMenu(hmenu, dropEnables[i].command,
\r
4268 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4269 dropEnables[i].command, item);
\r
4273 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4275 dragInfo.lastpos.x = boardRect.left + x;
\r
4276 dragInfo.lastpos.y = boardRect.top + y;
\r
4277 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4278 dragInfo.from.x = fromX;
\r
4279 dragInfo.from.y = fromY;
\r
4280 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4281 dragInfo.start = dragInfo.from;
\r
4282 SetCapture(hwndMain);
\r
4285 void DragPieceEnd(int x, int y)
\r
4288 dragInfo.start.x = dragInfo.start.y = -1;
\r
4289 dragInfo.from = dragInfo.start;
\r
4290 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4293 void ChangeDragPiece(ChessSquare piece)
\r
4295 dragInfo.piece = piece;
\r
4298 /* Event handler for mouse messages */
\r
4300 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4304 static int recursive = 0;
\r
4306 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4309 if (message == WM_MBUTTONUP) {
\r
4310 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4311 to the middle button: we simulate pressing the left button too!
\r
4313 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4314 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4320 pt.x = LOWORD(lParam);
\r
4321 pt.y = HIWORD(lParam);
\r
4322 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4323 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4324 if (!flipView && y >= 0) {
\r
4325 y = BOARD_HEIGHT - 1 - y;
\r
4327 if (flipView && x >= 0) {
\r
4328 x = BOARD_WIDTH - 1 - x;
\r
4331 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4332 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4334 switch (message) {
\r
4335 case WM_LBUTTONDOWN:
\r
4336 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4337 ClockClick(flipClock); break;
\r
4338 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4339 ClockClick(!flipClock); break;
\r
4341 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4342 dragInfo.start.x = dragInfo.start.y = -1;
\r
4343 dragInfo.from = dragInfo.start;
\r
4345 if(fromX == -1 && frozen) { // not sure where this is for
\r
4346 fromX = fromY = -1;
\r
4347 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4350 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4351 DrawPosition(TRUE, NULL);
\r
4354 case WM_LBUTTONUP:
\r
4355 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4356 DrawPosition(TRUE, NULL);
\r
4359 case WM_MOUSEMOVE:
\r
4360 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4361 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4362 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4363 if ((appData.animateDragging || appData.highlightDragging)
\r
4364 && (wParam & MK_LBUTTON || dragging == 2)
\r
4365 && dragInfo.from.x >= 0)
\r
4367 BOOL full_repaint = FALSE;
\r
4369 if (appData.animateDragging) {
\r
4370 dragInfo.pos = pt;
\r
4372 if (appData.highlightDragging) {
\r
4373 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4374 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4375 full_repaint = TRUE;
\r
4379 DrawPosition( full_repaint, NULL);
\r
4381 dragInfo.lastpos = dragInfo.pos;
\r
4385 case WM_MOUSEWHEEL: // [DM]
\r
4386 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4387 /* Mouse Wheel is being rolled forward
\r
4388 * Play moves forward
\r
4390 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4391 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4392 /* Mouse Wheel is being rolled backward
\r
4393 * Play moves backward
\r
4395 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4396 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4400 case WM_MBUTTONUP:
\r
4401 case WM_RBUTTONUP:
\r
4403 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4406 case WM_MBUTTONDOWN:
\r
4407 case WM_RBUTTONDOWN:
\r
4410 fromX = fromY = -1;
\r
4411 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4412 dragInfo.start.x = dragInfo.start.y = -1;
\r
4413 dragInfo.from = dragInfo.start;
\r
4414 dragInfo.lastpos = dragInfo.pos;
\r
4415 if (appData.highlightDragging) {
\r
4416 ClearHighlights();
\r
4419 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4420 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4421 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4422 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4423 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4427 DrawPosition(TRUE, NULL);
\r
4429 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4432 if (message == WM_MBUTTONDOWN) {
\r
4433 buttonCount = 3; /* even if system didn't think so */
\r
4434 if (wParam & MK_SHIFT)
\r
4435 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4437 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4438 } else { /* message == WM_RBUTTONDOWN */
\r
4439 /* Just have one menu, on the right button. Windows users don't
\r
4440 think to try the middle one, and sometimes other software steals
\r
4441 it, or it doesn't really exist. */
\r
4442 if(gameInfo.variant != VariantShogi)
\r
4443 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4445 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4449 SetCapture(hwndMain);
\r
4452 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4453 SetupDropMenu(hmenu);
\r
4454 MenuPopup(hwnd, pt, hmenu, -1);
\r
4464 /* Preprocess messages for buttons in main window */
\r
4466 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4468 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4471 for (i=0; i<N_BUTTONS; i++) {
\r
4472 if (buttonDesc[i].id == id) break;
\r
4474 if (i == N_BUTTONS) return 0;
\r
4475 switch (message) {
\r
4480 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4481 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4488 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4491 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4492 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4493 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4494 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4496 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4498 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4499 TypeInEvent((char)wParam);
\r
4505 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4508 static int promoStyle;
\r
4510 /* Process messages for Promotion dialog box */
\r
4512 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4516 switch (message) {
\r
4518 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4519 /* Center the dialog over the application window */
\r
4520 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4521 Translate(hDlg, DLG_PromotionKing);
\r
4522 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4523 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4524 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4525 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4526 SW_SHOW : SW_HIDE);
\r
4527 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4528 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4529 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4530 PieceToChar(WhiteAngel) != '~') ||
\r
4531 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4532 PieceToChar(BlackAngel) != '~') ) ?
\r
4533 SW_SHOW : SW_HIDE);
\r
4534 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4535 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4536 PieceToChar(WhiteMarshall) != '~') ||
\r
4537 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4538 PieceToChar(BlackMarshall) != '~') ) ?
\r
4539 SW_SHOW : SW_HIDE);
\r
4540 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4541 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4542 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4544 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4545 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4546 SetWindowText(hDlg, "Promote?");
\r
4548 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4549 gameInfo.variant == VariantSuper ?
\r
4550 SW_SHOW : SW_HIDE);
\r
4553 case WM_COMMAND: /* message: received a command */
\r
4554 switch (LOWORD(wParam)) {
\r
4556 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4557 ClearHighlights();
\r
4558 DrawPosition(FALSE, NULL);
\r
4561 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4564 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4567 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4568 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4571 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4572 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4574 case PB_Chancellor:
\r
4575 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4577 case PB_Archbishop:
\r
4578 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4581 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4582 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4587 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4588 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4589 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4590 fromX = fromY = -1;
\r
4591 if (!appData.highlightLastMove) {
\r
4592 ClearHighlights();
\r
4593 DrawPosition(FALSE, NULL);
\r
4600 /* Pop up promotion dialog */
\r
4602 PromotionPopup(HWND hwnd)
\r
4606 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4607 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4608 hwnd, (DLGPROC)lpProc);
\r
4609 FreeProcInstance(lpProc);
\r
4613 PromotionPopUp(char choice)
\r
4615 promoStyle = (choice == '+');
\r
4616 DrawPosition(TRUE, NULL);
\r
4617 PromotionPopup(hwndMain);
\r
4621 LoadGameDialog(HWND hwnd, char* title)
\r
4625 char fileTitle[MSG_SIZ];
\r
4626 f = OpenFileDialog(hwnd, "rb", "",
\r
4627 appData.oldSaveStyle ? "gam" : "pgn",
\r
4629 title, &number, fileTitle, NULL);
\r
4631 cmailMsgLoaded = FALSE;
\r
4632 if (number == 0) {
\r
4633 int error = GameListBuild(f);
\r
4635 DisplayError(_("Cannot build game list"), error);
\r
4636 } else if (!ListEmpty(&gameList) &&
\r
4637 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4638 GameListPopUp(f, fileTitle);
\r
4641 GameListDestroy();
\r
4644 LoadGame(f, number, fileTitle, FALSE);
\r
4648 int get_term_width()
\r
4653 HFONT hfont, hold_font;
\r
4658 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4662 // get the text metrics
\r
4663 hdc = GetDC(hText);
\r
4664 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4665 if (consoleCF.dwEffects & CFE_BOLD)
\r
4666 lf.lfWeight = FW_BOLD;
\r
4667 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4668 lf.lfItalic = TRUE;
\r
4669 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4670 lf.lfStrikeOut = TRUE;
\r
4671 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4672 lf.lfUnderline = TRUE;
\r
4673 hfont = CreateFontIndirect(&lf);
\r
4674 hold_font = SelectObject(hdc, hfont);
\r
4675 GetTextMetrics(hdc, &tm);
\r
4676 SelectObject(hdc, hold_font);
\r
4677 DeleteObject(hfont);
\r
4678 ReleaseDC(hText, hdc);
\r
4680 // get the rectangle
\r
4681 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4683 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4686 void UpdateICSWidth(HWND hText)
\r
4688 LONG old_width, new_width;
\r
4690 new_width = get_term_width(hText, FALSE);
\r
4691 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4692 if (new_width != old_width)
\r
4694 ics_update_width(new_width);
\r
4695 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4700 ChangedConsoleFont()
\r
4703 CHARRANGE tmpsel, sel;
\r
4704 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4705 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4706 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4709 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4710 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4711 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4712 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4713 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4714 * size. This was undocumented in the version of MSVC++ that I had
\r
4715 * when I wrote the code, but is apparently documented now.
\r
4717 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4718 cfmt.bCharSet = f->lf.lfCharSet;
\r
4719 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4720 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4721 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4722 /* Why are the following seemingly needed too? */
\r
4723 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4724 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4725 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4727 tmpsel.cpMax = -1; /*999999?*/
\r
4728 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4729 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4730 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4731 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4733 paraf.cbSize = sizeof(paraf);
\r
4734 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4735 paraf.dxStartIndent = 0;
\r
4736 paraf.dxOffset = WRAP_INDENT;
\r
4737 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4738 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4739 UpdateICSWidth(hText);
\r
4742 /*---------------------------------------------------------------------------*\
\r
4744 * Window Proc for main window
\r
4746 \*---------------------------------------------------------------------------*/
\r
4748 /* Process messages for main window, etc. */
\r
4750 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4757 char fileTitle[MSG_SIZ];
\r
4758 static SnapData sd;
\r
4759 static int peek=0;
\r
4761 switch (message) {
\r
4763 case WM_PAINT: /* message: repaint portion of window */
\r
4767 case WM_ERASEBKGND:
\r
4768 if (IsIconic(hwnd)) {
\r
4769 /* Cheat; change the message */
\r
4770 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4772 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4776 case WM_LBUTTONDOWN:
\r
4777 case WM_MBUTTONDOWN:
\r
4778 case WM_RBUTTONDOWN:
\r
4779 case WM_LBUTTONUP:
\r
4780 case WM_MBUTTONUP:
\r
4781 case WM_RBUTTONUP:
\r
4782 case WM_MOUSEMOVE:
\r
4783 case WM_MOUSEWHEEL:
\r
4784 MouseEvent(hwnd, message, wParam, lParam);
\r
4788 if((char)wParam == '\b') {
\r
4789 ForwardEvent(); peek = 0;
\r
4792 JAWS_KBUP_NAVIGATION
\r
4797 if((char)wParam == '\b') {
\r
4798 if(!peek) BackwardEvent(), peek = 1;
\r
4801 JAWS_KBDOWN_NAVIGATION
\r
4807 JAWS_ALT_INTERCEPT
\r
4809 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4810 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4811 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4812 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4814 SendMessage(h, message, wParam, lParam);
\r
4815 } else if(lParam != KF_REPEAT) {
\r
4816 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4817 TypeInEvent((char)wParam);
\r
4818 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4819 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4824 case WM_PALETTECHANGED:
\r
4825 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4827 HDC hdc = GetDC(hwndMain);
\r
4828 SelectPalette(hdc, hPal, TRUE);
\r
4829 nnew = RealizePalette(hdc);
\r
4831 paletteChanged = TRUE;
\r
4833 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4835 ReleaseDC(hwnd, hdc);
\r
4839 case WM_QUERYNEWPALETTE:
\r
4840 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4842 HDC hdc = GetDC(hwndMain);
\r
4843 paletteChanged = FALSE;
\r
4844 SelectPalette(hdc, hPal, FALSE);
\r
4845 nnew = RealizePalette(hdc);
\r
4847 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4849 ReleaseDC(hwnd, hdc);
\r
4854 case WM_COMMAND: /* message: command from application menu */
\r
4855 wmId = LOWORD(wParam);
\r
4860 SAY("new game enter a move to play against the computer with white");
\r
4863 case IDM_NewGameFRC:
\r
4864 if( NewGameFRC() == 0 ) {
\r
4869 case IDM_NewVariant:
\r
4870 NewVariantPopup(hwnd);
\r
4873 case IDM_LoadGame:
\r
4874 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4877 case IDM_LoadNextGame:
\r
4881 case IDM_LoadPrevGame:
\r
4885 case IDM_ReloadGame:
\r
4889 case IDM_LoadPosition:
\r
4890 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4891 Reset(FALSE, TRUE);
\r
4894 f = OpenFileDialog(hwnd, "rb", "",
\r
4895 appData.oldSaveStyle ? "pos" : "fen",
\r
4897 _("Load Position from File"), &number, fileTitle, NULL);
\r
4899 LoadPosition(f, number, fileTitle);
\r
4903 case IDM_LoadNextPosition:
\r
4904 ReloadPosition(1);
\r
4907 case IDM_LoadPrevPosition:
\r
4908 ReloadPosition(-1);
\r
4911 case IDM_ReloadPosition:
\r
4912 ReloadPosition(0);
\r
4915 case IDM_SaveGame:
\r
4916 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4917 f = OpenFileDialog(hwnd, "a", defName,
\r
4918 appData.oldSaveStyle ? "gam" : "pgn",
\r
4920 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4922 SaveGame(f, 0, "");
\r
4926 case IDM_SavePosition:
\r
4927 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4928 f = OpenFileDialog(hwnd, "a", defName,
\r
4929 appData.oldSaveStyle ? "pos" : "fen",
\r
4931 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4933 SavePosition(f, 0, "");
\r
4937 case IDM_SaveDiagram:
\r
4938 defName = "diagram";
\r
4939 f = OpenFileDialog(hwnd, "wb", defName,
\r
4942 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4948 case IDM_SaveSelected:
\r
4949 f = OpenFileDialog(hwnd, "a", "",
\r
4952 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4954 SaveSelected(f, 0, "");
\r
4958 case IDM_CreateBook:
\r
4959 CreateBookEvent();
\r
4962 case IDM_CopyGame:
\r
4963 CopyGameToClipboard();
\r
4966 case IDM_PasteGame:
\r
4967 PasteGameFromClipboard();
\r
4970 case IDM_CopyGameListToClipboard:
\r
4971 CopyGameListToClipboard();
\r
4974 /* [AS] Autodetect FEN or PGN data */
\r
4975 case IDM_PasteAny:
\r
4976 PasteGameOrFENFromClipboard();
\r
4979 /* [AS] Move history */
\r
4980 case IDM_ShowMoveHistory:
\r
4981 if( MoveHistoryIsUp() ) {
\r
4982 MoveHistoryPopDown();
\r
4985 MoveHistoryPopUp();
\r
4989 /* [AS] Eval graph */
\r
4990 case IDM_ShowEvalGraph:
\r
4991 if( EvalGraphIsUp() ) {
\r
4992 EvalGraphPopDown();
\r
4996 SetFocus(hwndMain);
\r
5000 /* [AS] Engine output */
\r
5001 case IDM_ShowEngineOutput:
\r
5002 if( EngineOutputIsUp() ) {
\r
5003 EngineOutputPopDown();
\r
5006 EngineOutputPopUp();
\r
5010 /* [AS] User adjudication */
\r
5011 case IDM_UserAdjudication_White:
\r
5012 UserAdjudicationEvent( +1 );
\r
5015 case IDM_UserAdjudication_Black:
\r
5016 UserAdjudicationEvent( -1 );
\r
5019 case IDM_UserAdjudication_Draw:
\r
5020 UserAdjudicationEvent( 0 );
\r
5023 /* [AS] Game list options dialog */
\r
5024 case IDM_GameListOptions:
\r
5025 GameListOptions();
\r
5032 case IDM_CopyPosition:
\r
5033 CopyFENToClipboard();
\r
5036 case IDM_PastePosition:
\r
5037 PasteFENFromClipboard();
\r
5040 case IDM_MailMove:
\r
5044 case IDM_ReloadCMailMsg:
\r
5045 Reset(TRUE, TRUE);
\r
5046 ReloadCmailMsgEvent(FALSE);
\r
5049 case IDM_Minimize:
\r
5050 ShowWindow(hwnd, SW_MINIMIZE);
\r
5057 case IDM_MachineWhite:
\r
5058 MachineWhiteEvent();
\r
5060 * refresh the tags dialog only if it's visible
\r
5062 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5064 tags = PGNTags(&gameInfo);
\r
5065 TagsPopUp(tags, CmailMsg());
\r
5068 SAY("computer starts playing white");
\r
5071 case IDM_MachineBlack:
\r
5072 MachineBlackEvent();
\r
5074 * refresh the tags dialog only if it's visible
\r
5076 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5078 tags = PGNTags(&gameInfo);
\r
5079 TagsPopUp(tags, CmailMsg());
\r
5082 SAY("computer starts playing black");
\r
5085 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5086 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5089 case IDM_TwoMachines:
\r
5090 TwoMachinesEvent();
\r
5092 * refresh the tags dialog only if it's visible
\r
5094 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5096 tags = PGNTags(&gameInfo);
\r
5097 TagsPopUp(tags, CmailMsg());
\r
5100 SAY("computer starts playing both sides");
\r
5103 case IDM_AnalysisMode:
\r
5104 if(AnalyzeModeEvent()) {
\r
5105 SAY("analyzing current position");
\r
5109 case IDM_AnalyzeFile:
\r
5110 AnalyzeFileEvent();
\r
5113 case IDM_IcsClient:
\r
5117 case IDM_EditGame:
\r
5118 case IDM_EditGame2:
\r
5123 case IDM_EditPosition:
\r
5124 case IDM_EditPosition2:
\r
5125 EditPositionEvent();
\r
5126 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5129 case IDM_Training:
\r
5133 case IDM_ShowGameList:
\r
5134 ShowGameListProc();
\r
5137 case IDM_EditProgs1:
\r
5138 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5141 case IDM_LoadProg1:
\r
5142 LoadEnginePopUp(hwndMain, 0);
\r
5145 case IDM_LoadProg2:
\r
5146 LoadEnginePopUp(hwndMain, 1);
\r
5149 case IDM_EditServers:
\r
5150 EditTagsPopUp(icsNames, &icsNames);
\r
5153 case IDM_EditTags:
\r
5158 case IDM_EditBook:
\r
5162 case IDM_EditComment:
\r
5164 if (commentUp && editComment) {
\r
5167 EditCommentEvent();
\r
5188 case IDM_CallFlag:
\r
5208 case IDM_StopObserving:
\r
5209 StopObservingEvent();
\r
5212 case IDM_StopExamining:
\r
5213 StopExaminingEvent();
\r
5217 UploadGameEvent();
\r
5220 case IDM_TypeInMove:
\r
5221 TypeInEvent('\000');
\r
5224 case IDM_TypeInName:
\r
5225 PopUpNameDialog('\000');
\r
5228 case IDM_Backward:
\r
5230 SetFocus(hwndMain);
\r
5237 SetFocus(hwndMain);
\r
5242 SetFocus(hwndMain);
\r
5247 SetFocus(hwndMain);
\r
5250 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5251 case OPT_GameListPrev:
\r
5252 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5256 RevertEvent(FALSE);
\r
5259 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5260 RevertEvent(TRUE);
\r
5263 case IDM_TruncateGame:
\r
5264 TruncateGameEvent();
\r
5271 case IDM_RetractMove:
\r
5272 RetractMoveEvent();
\r
5275 case IDM_FlipView:
\r
5276 flipView = !flipView;
\r
5277 DrawPosition(FALSE, NULL);
\r
5280 case IDM_FlipClock:
\r
5281 flipClock = !flipClock;
\r
5282 DisplayBothClocks();
\r
5286 case IDM_MuteSounds:
\r
5287 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5288 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5289 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5292 case IDM_GeneralOptions:
\r
5293 GeneralOptionsPopup(hwnd);
\r
5294 DrawPosition(TRUE, NULL);
\r
5297 case IDM_BoardOptions:
\r
5298 BoardOptionsPopup(hwnd);
\r
5301 case IDM_ThemeOptions:
\r
5302 ThemeOptionsPopup(hwnd);
\r
5305 case IDM_EnginePlayOptions:
\r
5306 EnginePlayOptionsPopup(hwnd);
\r
5309 case IDM_Engine1Options:
\r
5310 EngineOptionsPopup(hwnd, &first);
\r
5313 case IDM_Engine2Options:
\r
5315 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5316 EngineOptionsPopup(hwnd, &second);
\r
5319 case IDM_OptionsUCI:
\r
5320 UciOptionsPopup(hwnd);
\r
5324 TourneyPopup(hwnd);
\r
5327 case IDM_IcsOptions:
\r
5328 IcsOptionsPopup(hwnd);
\r
5332 FontsOptionsPopup(hwnd);
\r
5336 SoundOptionsPopup(hwnd);
\r
5339 case IDM_CommPort:
\r
5340 CommPortOptionsPopup(hwnd);
\r
5343 case IDM_LoadOptions:
\r
5344 LoadOptionsPopup(hwnd);
\r
5347 case IDM_SaveOptions:
\r
5348 SaveOptionsPopup(hwnd);
\r
5351 case IDM_TimeControl:
\r
5352 TimeControlOptionsPopup(hwnd);
\r
5355 case IDM_SaveSettings:
\r
5356 SaveSettings(settingsFileName);
\r
5359 case IDM_SaveSettingsOnExit:
\r
5360 saveSettingsOnExit = !saveSettingsOnExit;
\r
5361 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5362 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5363 MF_CHECKED : MF_UNCHECKED));
\r
5374 case IDM_AboutGame:
\r
5379 appData.debugMode = !appData.debugMode;
\r
5380 if (appData.debugMode) {
\r
5381 char dir[MSG_SIZ];
\r
5382 GetCurrentDirectory(MSG_SIZ, dir);
\r
5383 SetCurrentDirectory(installDir);
\r
5384 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5385 SetCurrentDirectory(dir);
\r
5386 setbuf(debugFP, NULL);
\r
5393 case IDM_HELPCONTENTS:
\r
5394 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5395 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5396 MessageBox (GetFocus(),
\r
5397 _("Unable to activate help"),
\r
5398 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5402 case IDM_HELPSEARCH:
\r
5403 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5404 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5405 MessageBox (GetFocus(),
\r
5406 _("Unable to activate help"),
\r
5407 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5411 case IDM_HELPHELP:
\r
5412 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5413 MessageBox (GetFocus(),
\r
5414 _("Unable to activate help"),
\r
5415 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5420 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5422 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5423 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5424 FreeProcInstance(lpProc);
\r
5427 case IDM_DirectCommand1:
\r
5428 AskQuestionEvent(_("Direct Command"),
\r
5429 _("Send to chess program:"), "", "1");
\r
5431 case IDM_DirectCommand2:
\r
5432 AskQuestionEvent(_("Direct Command"),
\r
5433 _("Send to second chess program:"), "", "2");
\r
5436 case EP_WhitePawn:
\r
5437 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5438 fromX = fromY = -1;
\r
5441 case EP_WhiteKnight:
\r
5442 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5443 fromX = fromY = -1;
\r
5446 case EP_WhiteBishop:
\r
5447 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5448 fromX = fromY = -1;
\r
5451 case EP_WhiteRook:
\r
5452 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5453 fromX = fromY = -1;
\r
5456 case EP_WhiteQueen:
\r
5457 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5458 fromX = fromY = -1;
\r
5461 case EP_WhiteFerz:
\r
5462 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5463 fromX = fromY = -1;
\r
5466 case EP_WhiteWazir:
\r
5467 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5468 fromX = fromY = -1;
\r
5471 case EP_WhiteAlfil:
\r
5472 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5473 fromX = fromY = -1;
\r
5476 case EP_WhiteCannon:
\r
5477 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5478 fromX = fromY = -1;
\r
5481 case EP_WhiteCardinal:
\r
5482 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5483 fromX = fromY = -1;
\r
5486 case EP_WhiteMarshall:
\r
5487 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5488 fromX = fromY = -1;
\r
5491 case EP_WhiteKing:
\r
5492 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5493 fromX = fromY = -1;
\r
5496 case EP_BlackPawn:
\r
5497 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5498 fromX = fromY = -1;
\r
5501 case EP_BlackKnight:
\r
5502 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5503 fromX = fromY = -1;
\r
5506 case EP_BlackBishop:
\r
5507 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5508 fromX = fromY = -1;
\r
5511 case EP_BlackRook:
\r
5512 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5513 fromX = fromY = -1;
\r
5516 case EP_BlackQueen:
\r
5517 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5518 fromX = fromY = -1;
\r
5521 case EP_BlackFerz:
\r
5522 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5523 fromX = fromY = -1;
\r
5526 case EP_BlackWazir:
\r
5527 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5528 fromX = fromY = -1;
\r
5531 case EP_BlackAlfil:
\r
5532 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5533 fromX = fromY = -1;
\r
5536 case EP_BlackCannon:
\r
5537 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5538 fromX = fromY = -1;
\r
5541 case EP_BlackCardinal:
\r
5542 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5543 fromX = fromY = -1;
\r
5546 case EP_BlackMarshall:
\r
5547 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5548 fromX = fromY = -1;
\r
5551 case EP_BlackKing:
\r
5552 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5553 fromX = fromY = -1;
\r
5556 case EP_EmptySquare:
\r
5557 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5558 fromX = fromY = -1;
\r
5561 case EP_ClearBoard:
\r
5562 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5563 fromX = fromY = -1;
\r
5567 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5568 fromX = fromY = -1;
\r
5572 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5573 fromX = fromY = -1;
\r
5577 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5578 fromX = fromY = -1;
\r
5582 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5583 fromX = fromY = -1;
\r
5587 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5588 fromX = fromY = -1;
\r
5592 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5593 fromX = fromY = -1;
\r
5597 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5598 fromX = fromY = -1;
\r
5602 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5603 fromX = fromY = -1;
\r
5607 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5608 fromX = fromY = -1;
\r
5612 barbaric = 0; appData.language = "";
\r
5613 TranslateMenus(0);
\r
5614 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5615 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5616 lastChecked = wmId;
\r
5620 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5621 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5623 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5624 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5625 TranslateMenus(0);
\r
5626 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5627 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5628 lastChecked = wmId;
\r
5631 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5637 case CLOCK_TIMER_ID:
\r
5638 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5639 clockTimerEvent = 0;
\r
5640 DecrementClocks(); /* call into back end */
\r
5642 case LOAD_GAME_TIMER_ID:
\r
5643 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5644 loadGameTimerEvent = 0;
\r
5645 AutoPlayGameLoop(); /* call into back end */
\r
5647 case ANALYSIS_TIMER_ID:
\r
5648 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5649 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5650 AnalysisPeriodicEvent(0);
\r
5652 KillTimer(hwnd, analysisTimerEvent);
\r
5653 analysisTimerEvent = 0;
\r
5656 case DELAYED_TIMER_ID:
\r
5657 KillTimer(hwnd, delayedTimerEvent);
\r
5658 delayedTimerEvent = 0;
\r
5659 delayedTimerCallback();
\r
5664 case WM_USER_Input:
\r
5665 InputEvent(hwnd, message, wParam, lParam);
\r
5668 /* [AS] Also move "attached" child windows */
\r
5669 case WM_WINDOWPOSCHANGING:
\r
5671 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5672 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5674 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5675 /* Window is moving */
\r
5678 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5679 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5680 rcMain.right = wpMain.x + wpMain.width;
\r
5681 rcMain.top = wpMain.y;
\r
5682 rcMain.bottom = wpMain.y + wpMain.height;
\r
5684 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5685 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5686 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5687 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5688 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5689 wpMain.x = lpwp->x;
\r
5690 wpMain.y = lpwp->y;
\r
5695 /* [AS] Snapping */
\r
5696 case WM_ENTERSIZEMOVE:
\r
5697 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5698 if (hwnd == hwndMain) {
\r
5699 doingSizing = TRUE;
\r
5702 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5706 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5707 if (hwnd == hwndMain) {
\r
5708 lastSizing = wParam;
\r
5713 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5714 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5716 case WM_EXITSIZEMOVE:
\r
5717 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5718 if (hwnd == hwndMain) {
\r
5720 doingSizing = FALSE;
\r
5721 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5722 GetClientRect(hwnd, &client);
\r
5723 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5725 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5727 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5730 case WM_DESTROY: /* message: window being destroyed */
\r
5731 PostQuitMessage(0);
\r
5735 if (hwnd == hwndMain) {
\r
5740 default: /* Passes it on if unprocessed */
\r
5741 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5748 /*---------------------------------------------------------------------------*\
\r
5750 * Misc utility routines
\r
5752 \*---------------------------------------------------------------------------*/
\r
5755 * Decent random number generator, at least not as bad as Windows
\r
5756 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5758 unsigned int randstate;
\r
5763 randstate = randstate * 1664525 + 1013904223;
\r
5764 return (int) randstate & 0x7fffffff;
\r
5768 mysrandom(unsigned int seed)
\r
5775 * returns TRUE if user selects a different color, FALSE otherwise
\r
5779 ChangeColor(HWND hwnd, COLORREF *which)
\r
5781 static BOOL firstTime = TRUE;
\r
5782 static DWORD customColors[16];
\r
5784 COLORREF newcolor;
\r
5789 /* Make initial colors in use available as custom colors */
\r
5790 /* Should we put the compiled-in defaults here instead? */
\r
5792 customColors[i++] = lightSquareColor & 0xffffff;
\r
5793 customColors[i++] = darkSquareColor & 0xffffff;
\r
5794 customColors[i++] = whitePieceColor & 0xffffff;
\r
5795 customColors[i++] = blackPieceColor & 0xffffff;
\r
5796 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5797 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5799 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5800 customColors[i++] = textAttribs[ccl].color;
\r
5802 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5803 firstTime = FALSE;
\r
5806 cc.lStructSize = sizeof(cc);
\r
5807 cc.hwndOwner = hwnd;
\r
5808 cc.hInstance = NULL;
\r
5809 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5810 cc.lpCustColors = (LPDWORD) customColors;
\r
5811 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5813 if (!ChooseColor(&cc)) return FALSE;
\r
5815 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5816 if (newcolor == *which) return FALSE;
\r
5817 *which = newcolor;
\r
5821 InitDrawingColors();
\r
5822 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5827 MyLoadSound(MySound *ms)
\r
5833 if (ms->data && ms->flag) free(ms->data);
\r
5836 switch (ms->name[0]) {
\r
5842 /* System sound from Control Panel. Don't preload here. */
\r
5846 if (ms->name[1] == NULLCHAR) {
\r
5847 /* "!" alone = silence */
\r
5850 /* Builtin wave resource. Error if not found. */
\r
5851 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5852 if (h == NULL) break;
\r
5853 ms->data = (void *)LoadResource(hInst, h);
\r
5854 ms->flag = 0; // not maloced, so cannot be freed!
\r
5855 if (h == NULL) break;
\r
5860 /* .wav file. Error if not found. */
\r
5861 f = fopen(ms->name, "rb");
\r
5862 if (f == NULL) break;
\r
5863 if (fstat(fileno(f), &st) < 0) break;
\r
5864 ms->data = malloc(st.st_size);
\r
5866 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5872 char buf[MSG_SIZ];
\r
5873 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5874 DisplayError(buf, GetLastError());
\r
5880 MyPlaySound(MySound *ms)
\r
5882 BOOLEAN ok = FALSE;
\r
5884 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5885 switch (ms->name[0]) {
\r
5887 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5892 /* System sound from Control Panel (deprecated feature).
\r
5893 "$" alone or an unset sound name gets default beep (still in use). */
\r
5894 if (ms->name[1]) {
\r
5895 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5897 if (!ok) ok = MessageBeep(MB_OK);
\r
5900 /* Builtin wave resource, or "!" alone for silence */
\r
5901 if (ms->name[1]) {
\r
5902 if (ms->data == NULL) return FALSE;
\r
5903 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5909 /* .wav file. Error if not found. */
\r
5910 if (ms->data == NULL) return FALSE;
\r
5911 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5914 /* Don't print an error: this can happen innocently if the sound driver
\r
5915 is busy; for instance, if another instance of WinBoard is playing
\r
5916 a sound at about the same time. */
\r
5922 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5925 OPENFILENAME *ofn;
\r
5926 static UINT *number; /* gross that this is static */
\r
5928 switch (message) {
\r
5929 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5930 /* Center the dialog over the application window */
\r
5931 ofn = (OPENFILENAME *) lParam;
\r
5932 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5933 number = (UINT *) ofn->lCustData;
\r
5934 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5938 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5939 Translate(hDlg, 1536);
\r
5940 return FALSE; /* Allow for further processing */
\r
5943 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5944 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5946 return FALSE; /* Allow for further processing */
\r
5952 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5954 static UINT *number;
\r
5955 OPENFILENAME *ofname;
\r
5958 case WM_INITDIALOG:
\r
5959 Translate(hdlg, DLG_IndexNumber);
\r
5960 ofname = (OPENFILENAME *)lParam;
\r
5961 number = (UINT *)(ofname->lCustData);
\r
5964 ofnot = (OFNOTIFY *)lParam;
\r
5965 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5966 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5975 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5976 char *nameFilt, char *dlgTitle, UINT *number,
\r
5977 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5979 OPENFILENAME openFileName;
\r
5980 char buf1[MSG_SIZ];
\r
5983 if (fileName == NULL) fileName = buf1;
\r
5984 if (defName == NULL) {
\r
5985 safeStrCpy(fileName, "*.", 3 );
\r
5986 strcat(fileName, defExt);
\r
5988 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5990 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5991 if (number) *number = 0;
\r
5993 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5994 openFileName.hwndOwner = hwnd;
\r
5995 openFileName.hInstance = (HANDLE) hInst;
\r
5996 openFileName.lpstrFilter = nameFilt;
\r
5997 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5998 openFileName.nMaxCustFilter = 0L;
\r
5999 openFileName.nFilterIndex = 1L;
\r
6000 openFileName.lpstrFile = fileName;
\r
6001 openFileName.nMaxFile = MSG_SIZ;
\r
6002 openFileName.lpstrFileTitle = fileTitle;
\r
6003 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6004 openFileName.lpstrInitialDir = NULL;
\r
6005 openFileName.lpstrTitle = dlgTitle;
\r
6006 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6007 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6008 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6009 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6010 openFileName.nFileOffset = 0;
\r
6011 openFileName.nFileExtension = 0;
\r
6012 openFileName.lpstrDefExt = defExt;
\r
6013 openFileName.lCustData = (LONG) number;
\r
6014 openFileName.lpfnHook = oldDialog ?
\r
6015 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6016 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6018 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6019 GetOpenFileName(&openFileName)) {
\r
6020 /* open the file */
\r
6021 f = fopen(openFileName.lpstrFile, write);
\r
6023 MessageBox(hwnd, _("File open failed"), NULL,
\r
6024 MB_OK|MB_ICONEXCLAMATION);
\r
6028 int err = CommDlgExtendedError();
\r
6029 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6038 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6040 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6043 * Get the first pop-up menu in the menu template. This is the
\r
6044 * menu that TrackPopupMenu displays.
\r
6046 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6047 TranslateOneMenu(10, hmenuTrackPopup);
\r
6049 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6052 * TrackPopup uses screen coordinates, so convert the
\r
6053 * coordinates of the mouse click to screen coordinates.
\r
6055 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6057 /* Draw and track the floating pop-up menu. */
\r
6058 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6059 pt.x, pt.y, 0, hwnd, NULL);
\r
6061 /* Destroy the menu.*/
\r
6062 DestroyMenu(hmenu);
\r
6067 int sizeX, sizeY, newSizeX, newSizeY;
\r
6069 } ResizeEditPlusButtonsClosure;
\r
6072 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6074 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6078 if (hChild == cl->hText) return TRUE;
\r
6079 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6080 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6081 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6082 ScreenToClient(cl->hDlg, &pt);
\r
6083 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6084 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6088 /* Resize a dialog that has a (rich) edit field filling most of
\r
6089 the top, with a row of buttons below */
\r
6091 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6094 int newTextHeight, newTextWidth;
\r
6095 ResizeEditPlusButtonsClosure cl;
\r
6097 /*if (IsIconic(hDlg)) return;*/
\r
6098 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6100 cl.hdwp = BeginDeferWindowPos(8);
\r
6102 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6103 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6104 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6105 if (newTextHeight < 0) {
\r
6106 newSizeY += -newTextHeight;
\r
6107 newTextHeight = 0;
\r
6109 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6110 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6116 cl.newSizeX = newSizeX;
\r
6117 cl.newSizeY = newSizeY;
\r
6118 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6120 EndDeferWindowPos(cl.hdwp);
\r
6123 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6125 RECT rChild, rParent;
\r
6126 int wChild, hChild, wParent, hParent;
\r
6127 int wScreen, hScreen, xNew, yNew;
\r
6130 /* Get the Height and Width of the child window */
\r
6131 GetWindowRect (hwndChild, &rChild);
\r
6132 wChild = rChild.right - rChild.left;
\r
6133 hChild = rChild.bottom - rChild.top;
\r
6135 /* Get the Height and Width of the parent window */
\r
6136 GetWindowRect (hwndParent, &rParent);
\r
6137 wParent = rParent.right - rParent.left;
\r
6138 hParent = rParent.bottom - rParent.top;
\r
6140 /* Get the display limits */
\r
6141 hdc = GetDC (hwndChild);
\r
6142 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6143 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6144 ReleaseDC(hwndChild, hdc);
\r
6146 /* Calculate new X position, then adjust for screen */
\r
6147 xNew = rParent.left + ((wParent - wChild) /2);
\r
6150 } else if ((xNew+wChild) > wScreen) {
\r
6151 xNew = wScreen - wChild;
\r
6154 /* Calculate new Y position, then adjust for screen */
\r
6156 yNew = rParent.top + ((hParent - hChild) /2);
\r
6159 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6164 } else if ((yNew+hChild) > hScreen) {
\r
6165 yNew = hScreen - hChild;
\r
6168 /* Set it, and return */
\r
6169 return SetWindowPos (hwndChild, NULL,
\r
6170 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6173 /* Center one window over another */
\r
6174 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6176 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6179 /*---------------------------------------------------------------------------*\
\r
6181 * Startup Dialog functions
\r
6183 \*---------------------------------------------------------------------------*/
\r
6185 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6187 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6189 while (*cd != NULL) {
\r
6190 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6196 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6198 char buf1[MAX_ARG_LEN];
\r
6201 if (str[0] == '@') {
\r
6202 FILE* f = fopen(str + 1, "r");
\r
6204 DisplayFatalError(str + 1, errno, 2);
\r
6207 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6209 buf1[len] = NULLCHAR;
\r
6213 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6216 char buf[MSG_SIZ];
\r
6217 char *end = strchr(str, '\n');
\r
6218 if (end == NULL) return;
\r
6219 memcpy(buf, str, end - str);
\r
6220 buf[end - str] = NULLCHAR;
\r
6221 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6227 SetStartupDialogEnables(HWND hDlg)
\r
6229 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6230 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6231 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6232 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6233 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6234 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6235 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6236 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6237 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6238 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6239 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6240 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6241 IsDlgButtonChecked(hDlg, OPT_View));
\r
6245 QuoteForFilename(char *filename)
\r
6247 int dquote, space;
\r
6248 dquote = strchr(filename, '"') != NULL;
\r
6249 space = strchr(filename, ' ') != NULL;
\r
6250 if (dquote || space) {
\r
6262 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6264 char buf[MSG_SIZ];
\r
6267 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6268 q = QuoteForFilename(nthcp);
\r
6269 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6270 if (*nthdir != NULLCHAR) {
\r
6271 q = QuoteForFilename(nthdir);
\r
6272 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6274 if (*nthcp == NULLCHAR) {
\r
6275 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6276 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6277 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6278 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6283 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6285 char buf[MSG_SIZ];
\r
6289 switch (message) {
\r
6290 case WM_INITDIALOG:
\r
6291 /* Center the dialog */
\r
6292 CenterWindow (hDlg, GetDesktopWindow());
\r
6293 Translate(hDlg, DLG_Startup);
\r
6294 /* Initialize the dialog items */
\r
6295 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6296 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6297 firstChessProgramNames);
\r
6298 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6299 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6300 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6301 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6302 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6303 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6304 if (*appData.icsHelper != NULLCHAR) {
\r
6305 char *q = QuoteForFilename(appData.icsHelper);
\r
6306 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6308 if (*appData.icsHost == NULLCHAR) {
\r
6309 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6310 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6311 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6312 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6313 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6316 if (appData.icsActive) {
\r
6317 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6319 else if (appData.noChessProgram) {
\r
6320 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6323 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6326 SetStartupDialogEnables(hDlg);
\r
6330 switch (LOWORD(wParam)) {
\r
6332 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6333 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6334 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6336 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6337 ParseArgs(StringGet, &p);
\r
6338 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6339 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6341 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6342 ParseArgs(StringGet, &p);
\r
6343 SwapEngines(singleList); // ... and then make it 'second'
\r
6345 appData.noChessProgram = FALSE;
\r
6346 appData.icsActive = FALSE;
\r
6347 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6348 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6349 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6351 ParseArgs(StringGet, &p);
\r
6352 if (appData.zippyPlay) {
\r
6353 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6354 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6356 ParseArgs(StringGet, &p);
\r
6358 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6359 appData.noChessProgram = TRUE;
\r
6360 appData.icsActive = FALSE;
\r
6362 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6363 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6366 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6367 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6369 ParseArgs(StringGet, &p);
\r
6371 EndDialog(hDlg, TRUE);
\r
6378 case IDM_HELPCONTENTS:
\r
6379 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6380 MessageBox (GetFocus(),
\r
6381 _("Unable to activate help"),
\r
6382 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6387 SetStartupDialogEnables(hDlg);
\r
6395 /*---------------------------------------------------------------------------*\
\r
6397 * About box dialog functions
\r
6399 \*---------------------------------------------------------------------------*/
\r
6401 /* Process messages for "About" dialog box */
\r
6403 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6405 switch (message) {
\r
6406 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6407 /* Center the dialog over the application window */
\r
6408 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6409 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6410 Translate(hDlg, ABOUTBOX);
\r
6414 case WM_COMMAND: /* message: received a command */
\r
6415 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6416 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6417 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6425 /*---------------------------------------------------------------------------*\
\r
6427 * Comment Dialog functions
\r
6429 \*---------------------------------------------------------------------------*/
\r
6432 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6434 static HANDLE hwndText = NULL;
\r
6435 int len, newSizeX, newSizeY;
\r
6436 static int sizeX, sizeY;
\r
6441 switch (message) {
\r
6442 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6443 /* Initialize the dialog items */
\r
6444 Translate(hDlg, DLG_EditComment);
\r
6445 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6446 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6447 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6448 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6449 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6450 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6451 SetWindowText(hDlg, commentTitle);
\r
6452 if (editComment) {
\r
6453 SetFocus(hwndText);
\r
6455 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6457 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6458 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6459 MAKELPARAM(FALSE, 0));
\r
6460 /* Size and position the dialog */
\r
6461 if (!commentDialog) {
\r
6462 commentDialog = hDlg;
\r
6463 GetClientRect(hDlg, &rect);
\r
6464 sizeX = rect.right;
\r
6465 sizeY = rect.bottom;
\r
6466 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6467 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6468 WINDOWPLACEMENT wp;
\r
6469 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6470 wp.length = sizeof(WINDOWPLACEMENT);
\r
6472 wp.showCmd = SW_SHOW;
\r
6473 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6474 wp.rcNormalPosition.left = wpComment.x;
\r
6475 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6476 wp.rcNormalPosition.top = wpComment.y;
\r
6477 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6478 SetWindowPlacement(hDlg, &wp);
\r
6480 GetClientRect(hDlg, &rect);
\r
6481 newSizeX = rect.right;
\r
6482 newSizeY = rect.bottom;
\r
6483 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6484 newSizeX, newSizeY);
\r
6489 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6492 case WM_COMMAND: /* message: received a command */
\r
6493 switch (LOWORD(wParam)) {
\r
6495 if (editComment) {
\r
6497 /* Read changed options from the dialog box */
\r
6498 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6499 len = GetWindowTextLength(hwndText);
\r
6500 str = (char *) malloc(len + 1);
\r
6501 GetWindowText(hwndText, str, len + 1);
\r
6510 ReplaceComment(commentIndex, str);
\r
6517 case OPT_CancelComment:
\r
6521 case OPT_ClearComment:
\r
6522 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6525 case OPT_EditComment:
\r
6526 EditCommentEvent();
\r
6534 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6535 if( wParam == OPT_CommentText ) {
\r
6536 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6538 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6539 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6543 pt.x = LOWORD( lpMF->lParam );
\r
6544 pt.y = HIWORD( lpMF->lParam );
\r
6546 if(lpMF->msg == WM_CHAR) {
\r
6548 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6549 index = sel.cpMin;
\r
6551 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6553 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6554 len = GetWindowTextLength(hwndText);
\r
6555 str = (char *) malloc(len + 1);
\r
6556 GetWindowText(hwndText, str, len + 1);
\r
6557 ReplaceComment(commentIndex, str);
\r
6558 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6559 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6562 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6563 lpMF->msg = WM_USER;
\r
6571 newSizeX = LOWORD(lParam);
\r
6572 newSizeY = HIWORD(lParam);
\r
6573 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6578 case WM_GETMINMAXINFO:
\r
6579 /* Prevent resizing window too small */
\r
6580 mmi = (MINMAXINFO *) lParam;
\r
6581 mmi->ptMinTrackSize.x = 100;
\r
6582 mmi->ptMinTrackSize.y = 100;
\r
6589 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6594 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6596 if (str == NULL) str = "";
\r
6597 p = (char *) malloc(2 * strlen(str) + 2);
\r
6600 if (*str == '\n') *q++ = '\r';
\r
6604 if (commentText != NULL) free(commentText);
\r
6606 commentIndex = index;
\r
6607 commentTitle = title;
\r
6609 editComment = edit;
\r
6611 if (commentDialog) {
\r
6612 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6613 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6615 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6616 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6617 hwndMain, (DLGPROC)lpProc);
\r
6618 FreeProcInstance(lpProc);
\r
6624 /*---------------------------------------------------------------------------*\
\r
6626 * Type-in move dialog functions
\r
6628 \*---------------------------------------------------------------------------*/
\r
6631 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6633 char move[MSG_SIZ];
\r
6636 switch (message) {
\r
6637 case WM_INITDIALOG:
\r
6638 move[0] = (char) lParam;
\r
6639 move[1] = NULLCHAR;
\r
6640 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6641 Translate(hDlg, DLG_TypeInMove);
\r
6642 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6643 SetWindowText(hInput, move);
\r
6645 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6649 switch (LOWORD(wParam)) {
\r
6652 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6653 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6654 TypeInDoneEvent(move);
\r
6655 EndDialog(hDlg, TRUE);
\r
6658 EndDialog(hDlg, FALSE);
\r
6669 PopUpMoveDialog(char firstchar)
\r
6673 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6674 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6675 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6676 FreeProcInstance(lpProc);
\r
6679 /*---------------------------------------------------------------------------*\
\r
6681 * Type-in name dialog functions
\r
6683 \*---------------------------------------------------------------------------*/
\r
6686 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6688 char move[MSG_SIZ];
\r
6691 switch (message) {
\r
6692 case WM_INITDIALOG:
\r
6693 move[0] = (char) lParam;
\r
6694 move[1] = NULLCHAR;
\r
6695 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6696 Translate(hDlg, DLG_TypeInName);
\r
6697 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6698 SetWindowText(hInput, move);
\r
6700 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6704 switch (LOWORD(wParam)) {
\r
6706 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6707 appData.userName = strdup(move);
\r
6710 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6711 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6712 DisplayTitle(move);
\r
6716 EndDialog(hDlg, TRUE);
\r
6719 EndDialog(hDlg, FALSE);
\r
6730 PopUpNameDialog(char firstchar)
\r
6734 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6735 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6736 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6737 FreeProcInstance(lpProc);
\r
6740 /*---------------------------------------------------------------------------*\
\r
6744 \*---------------------------------------------------------------------------*/
\r
6746 /* Nonmodal error box */
\r
6747 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6748 WPARAM wParam, LPARAM lParam);
\r
6751 ErrorPopUp(char *title, char *content)
\r
6755 BOOLEAN modal = hwndMain == NULL;
\r
6773 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6774 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6777 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6779 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6780 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6781 hwndMain, (DLGPROC)lpProc);
\r
6782 FreeProcInstance(lpProc);
\r
6789 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6790 if (errorDialog == NULL) return;
\r
6791 DestroyWindow(errorDialog);
\r
6792 errorDialog = NULL;
\r
6793 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6797 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6801 switch (message) {
\r
6802 case WM_INITDIALOG:
\r
6803 GetWindowRect(hDlg, &rChild);
\r
6806 SetWindowPos(hDlg, NULL, rChild.left,
\r
6807 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6808 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6812 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6813 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6814 and it doesn't work when you resize the dialog.
\r
6815 For now, just give it a default position.
\r
6817 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6818 Translate(hDlg, DLG_Error);
\r
6820 errorDialog = hDlg;
\r
6821 SetWindowText(hDlg, errorTitle);
\r
6822 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6826 switch (LOWORD(wParam)) {
\r
6829 if (errorDialog == hDlg) errorDialog = NULL;
\r
6830 DestroyWindow(hDlg);
\r
6842 HWND gothicDialog = NULL;
\r
6845 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6848 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6850 switch (message) {
\r
6851 case WM_INITDIALOG:
\r
6852 GetWindowRect(hDlg, &rChild);
\r
6854 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6858 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6859 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6860 and it doesn't work when you resize the dialog.
\r
6861 For now, just give it a default position.
\r
6863 gothicDialog = hDlg;
\r
6864 SetWindowText(hDlg, errorTitle);
\r
6865 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6869 switch (LOWORD(wParam)) {
\r
6872 if (errorDialog == hDlg) errorDialog = NULL;
\r
6873 DestroyWindow(hDlg);
\r
6885 GothicPopUp(char *title, VariantClass variant)
\r
6888 static char *lastTitle;
\r
6890 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6891 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6893 if(lastTitle != title && gothicDialog != NULL) {
\r
6894 DestroyWindow(gothicDialog);
\r
6895 gothicDialog = NULL;
\r
6897 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6898 title = lastTitle;
\r
6899 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6900 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6901 hwndMain, (DLGPROC)lpProc);
\r
6902 FreeProcInstance(lpProc);
\r
6907 /*---------------------------------------------------------------------------*\
\r
6909 * Ics Interaction console functions
\r
6911 \*---------------------------------------------------------------------------*/
\r
6913 #define HISTORY_SIZE 64
\r
6914 static char *history[HISTORY_SIZE];
\r
6915 int histIn = 0, histP = 0;
\r
6919 SaveInHistory(char *cmd)
\r
6921 if (history[histIn] != NULL) {
\r
6922 free(history[histIn]);
\r
6923 history[histIn] = NULL;
\r
6925 if (*cmd == NULLCHAR) return;
\r
6926 history[histIn] = StrSave(cmd);
\r
6927 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6928 if (history[histIn] != NULL) {
\r
6929 free(history[histIn]);
\r
6931 history[histIn] = NULL;
\r
6937 PrevInHistory(char *cmd)
\r
6940 if (histP == histIn) {
\r
6941 if (history[histIn] != NULL) free(history[histIn]);
\r
6942 history[histIn] = StrSave(cmd);
\r
6944 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6945 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6947 return history[histP];
\r
6953 if (histP == histIn) return NULL;
\r
6954 histP = (histP + 1) % HISTORY_SIZE;
\r
6955 return history[histP];
\r
6959 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6963 hmenu = LoadMenu(hInst, "TextMenu");
\r
6964 h = GetSubMenu(hmenu, 0);
\r
6966 if (strcmp(e->item, "-") == 0) {
\r
6967 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6968 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6969 int flags = MF_STRING, j = 0;
\r
6970 if (e->item[0] == '|') {
\r
6971 flags |= MF_MENUBARBREAK;
\r
6974 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6975 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6983 WNDPROC consoleTextWindowProc;
\r
6986 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6988 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6989 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6993 SetWindowText(hInput, command);
\r
6995 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6997 sel.cpMin = 999999;
\r
6998 sel.cpMax = 999999;
\r
6999 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7004 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7005 if (sel.cpMin == sel.cpMax) {
\r
7006 /* Expand to surrounding word */
\r
7009 tr.chrg.cpMax = sel.cpMin;
\r
7010 tr.chrg.cpMin = --sel.cpMin;
\r
7011 if (sel.cpMin < 0) break;
\r
7012 tr.lpstrText = name;
\r
7013 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7014 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7018 tr.chrg.cpMin = sel.cpMax;
\r
7019 tr.chrg.cpMax = ++sel.cpMax;
\r
7020 tr.lpstrText = name;
\r
7021 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7022 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7025 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7026 MessageBeep(MB_ICONEXCLAMATION);
\r
7030 tr.lpstrText = name;
\r
7031 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7033 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7034 MessageBeep(MB_ICONEXCLAMATION);
\r
7037 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7040 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7041 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7042 SetWindowText(hInput, buf);
\r
7043 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7045 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7046 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7047 SetWindowText(hInput, buf);
\r
7048 sel.cpMin = 999999;
\r
7049 sel.cpMax = 999999;
\r
7050 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7056 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7061 switch (message) {
\r
7063 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7064 if(wParam=='R') return 0;
\r
7067 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7070 sel.cpMin = 999999;
\r
7071 sel.cpMax = 999999;
\r
7072 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7073 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7078 if(wParam != '\022') {
\r
7079 if (wParam == '\t') {
\r
7080 if (GetKeyState(VK_SHIFT) < 0) {
\r
7082 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7083 if (buttonDesc[0].hwnd) {
\r
7084 SetFocus(buttonDesc[0].hwnd);
\r
7086 SetFocus(hwndMain);
\r
7090 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7093 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7094 JAWS_DELETE( SetFocus(hInput); )
\r
7095 SendMessage(hInput, message, wParam, lParam);
\r
7098 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7100 case WM_RBUTTONDOWN:
\r
7101 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7102 /* Move selection here if it was empty */
\r
7104 pt.x = LOWORD(lParam);
\r
7105 pt.y = HIWORD(lParam);
\r
7106 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7107 if (sel.cpMin == sel.cpMax) {
\r
7108 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7109 sel.cpMax = sel.cpMin;
\r
7110 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7112 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7113 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7115 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7116 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7117 if (sel.cpMin == sel.cpMax) {
\r
7118 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7119 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7121 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7122 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7124 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7125 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7126 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7127 MenuPopup(hwnd, pt, hmenu, -1);
\r
7131 case WM_RBUTTONUP:
\r
7132 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7133 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7134 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7138 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7140 return SendMessage(hInput, message, wParam, lParam);
\r
7141 case WM_MBUTTONDOWN:
\r
7142 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7144 switch (LOWORD(wParam)) {
\r
7145 case IDM_QuickPaste:
\r
7147 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7148 if (sel.cpMin == sel.cpMax) {
\r
7149 MessageBeep(MB_ICONEXCLAMATION);
\r
7152 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7153 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7154 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7159 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7162 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7165 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7169 int i = LOWORD(wParam) - IDM_CommandX;
\r
7170 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7171 icsTextMenuEntry[i].command != NULL) {
\r
7172 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7173 icsTextMenuEntry[i].getname,
\r
7174 icsTextMenuEntry[i].immediate);
\r
7182 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7185 WNDPROC consoleInputWindowProc;
\r
7188 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7190 char buf[MSG_SIZ];
\r
7192 static BOOL sendNextChar = FALSE;
\r
7193 static BOOL quoteNextChar = FALSE;
\r
7194 InputSource *is = consoleInputSource;
\r
7198 switch (message) {
\r
7200 if (!appData.localLineEditing || sendNextChar) {
\r
7201 is->buf[0] = (CHAR) wParam;
\r
7203 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7204 sendNextChar = FALSE;
\r
7207 if (quoteNextChar) {
\r
7208 buf[0] = (char) wParam;
\r
7209 buf[1] = NULLCHAR;
\r
7210 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7211 quoteNextChar = FALSE;
\r
7215 case '\r': /* Enter key */
\r
7216 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7217 if (consoleEcho) SaveInHistory(is->buf);
\r
7218 is->buf[is->count++] = '\n';
\r
7219 is->buf[is->count] = NULLCHAR;
\r
7220 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7221 if (consoleEcho) {
\r
7222 ConsoleOutput(is->buf, is->count, TRUE);
\r
7223 } else if (appData.localLineEditing) {
\r
7224 ConsoleOutput("\n", 1, TRUE);
\r
7227 case '\033': /* Escape key */
\r
7228 SetWindowText(hwnd, "");
\r
7229 cf.cbSize = sizeof(CHARFORMAT);
\r
7230 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7231 if (consoleEcho) {
\r
7232 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7234 cf.crTextColor = COLOR_ECHOOFF;
\r
7236 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7237 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7239 case '\t': /* Tab key */
\r
7240 if (GetKeyState(VK_SHIFT) < 0) {
\r
7242 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7245 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7246 if (buttonDesc[0].hwnd) {
\r
7247 SetFocus(buttonDesc[0].hwnd);
\r
7249 SetFocus(hwndMain);
\r
7253 case '\023': /* Ctrl+S */
\r
7254 sendNextChar = TRUE;
\r
7256 case '\021': /* Ctrl+Q */
\r
7257 quoteNextChar = TRUE;
\r
7267 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7268 p = PrevInHistory(buf);
\r
7270 SetWindowText(hwnd, p);
\r
7271 sel.cpMin = 999999;
\r
7272 sel.cpMax = 999999;
\r
7273 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7278 p = NextInHistory();
\r
7280 SetWindowText(hwnd, p);
\r
7281 sel.cpMin = 999999;
\r
7282 sel.cpMax = 999999;
\r
7283 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7289 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7293 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7297 case WM_MBUTTONDOWN:
\r
7298 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7299 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7301 case WM_RBUTTONUP:
\r
7302 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7303 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7304 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7308 hmenu = LoadMenu(hInst, "InputMenu");
\r
7309 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7310 if (sel.cpMin == sel.cpMax) {
\r
7311 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7312 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7314 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7315 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7317 pt.x = LOWORD(lParam);
\r
7318 pt.y = HIWORD(lParam);
\r
7319 MenuPopup(hwnd, pt, hmenu, -1);
\r
7323 switch (LOWORD(wParam)) {
\r
7325 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7327 case IDM_SelectAll:
\r
7329 sel.cpMax = -1; /*999999?*/
\r
7330 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7333 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7336 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7339 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7344 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7347 #define CO_MAX 100000
\r
7348 #define CO_TRIM 1000
\r
7351 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7353 static SnapData sd;
\r
7354 HWND hText, hInput;
\r
7356 static int sizeX, sizeY;
\r
7357 int newSizeX, newSizeY;
\r
7361 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7362 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7364 switch (message) {
\r
7366 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7368 ENLINK *pLink = (ENLINK*)lParam;
\r
7369 if (pLink->msg == WM_LBUTTONUP)
\r
7373 tr.chrg = pLink->chrg;
\r
7374 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7375 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7376 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7377 free(tr.lpstrText);
\r
7381 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7382 hwndConsole = hDlg;
\r
7384 consoleTextWindowProc = (WNDPROC)
\r
7385 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7386 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7387 consoleInputWindowProc = (WNDPROC)
\r
7388 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7389 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7390 Colorize(ColorNormal, TRUE);
\r
7391 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7392 ChangedConsoleFont();
\r
7393 GetClientRect(hDlg, &rect);
\r
7394 sizeX = rect.right;
\r
7395 sizeY = rect.bottom;
\r
7396 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7397 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7398 WINDOWPLACEMENT wp;
\r
7399 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7400 wp.length = sizeof(WINDOWPLACEMENT);
\r
7402 wp.showCmd = SW_SHOW;
\r
7403 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7404 wp.rcNormalPosition.left = wpConsole.x;
\r
7405 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7406 wp.rcNormalPosition.top = wpConsole.y;
\r
7407 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7408 SetWindowPlacement(hDlg, &wp);
\r
7411 // [HGM] Chessknight's change 2004-07-13
\r
7412 else { /* Determine Defaults */
\r
7413 WINDOWPLACEMENT wp;
\r
7414 wpConsole.x = wpMain.width + 1;
\r
7415 wpConsole.y = wpMain.y;
\r
7416 wpConsole.width = screenWidth - wpMain.width;
\r
7417 wpConsole.height = wpMain.height;
\r
7418 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7419 wp.length = sizeof(WINDOWPLACEMENT);
\r
7421 wp.showCmd = SW_SHOW;
\r
7422 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7423 wp.rcNormalPosition.left = wpConsole.x;
\r
7424 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7425 wp.rcNormalPosition.top = wpConsole.y;
\r
7426 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7427 SetWindowPlacement(hDlg, &wp);
\r
7430 // Allow hText to highlight URLs and send notifications on them
\r
7431 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7432 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7433 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7434 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7448 if (IsIconic(hDlg)) break;
\r
7449 newSizeX = LOWORD(lParam);
\r
7450 newSizeY = HIWORD(lParam);
\r
7451 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7452 RECT rectText, rectInput;
\r
7454 int newTextHeight, newTextWidth;
\r
7455 GetWindowRect(hText, &rectText);
\r
7456 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7457 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7458 if (newTextHeight < 0) {
\r
7459 newSizeY += -newTextHeight;
\r
7460 newTextHeight = 0;
\r
7462 SetWindowPos(hText, NULL, 0, 0,
\r
7463 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7464 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7465 pt.x = rectInput.left;
\r
7466 pt.y = rectInput.top + newSizeY - sizeY;
\r
7467 ScreenToClient(hDlg, &pt);
\r
7468 SetWindowPos(hInput, NULL,
\r
7469 pt.x, pt.y, /* needs client coords */
\r
7470 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7471 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7477 case WM_GETMINMAXINFO:
\r
7478 /* Prevent resizing window too small */
\r
7479 mmi = (MINMAXINFO *) lParam;
\r
7480 mmi->ptMinTrackSize.x = 100;
\r
7481 mmi->ptMinTrackSize.y = 100;
\r
7484 /* [AS] Snapping */
\r
7485 case WM_ENTERSIZEMOVE:
\r
7486 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7489 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7492 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7494 case WM_EXITSIZEMOVE:
\r
7495 UpdateICSWidth(hText);
\r
7496 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7499 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7507 if (hwndConsole) return;
\r
7508 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7509 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7514 ConsoleOutput(char* data, int length, int forceVisible)
\r
7519 char buf[CO_MAX+1];
\r
7522 static int delayLF = 0;
\r
7523 CHARRANGE savesel, sel;
\r
7525 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7533 while (length--) {
\r
7541 } else if (*p == '\007') {
\r
7542 MyPlaySound(&sounds[(int)SoundBell]);
\r
7549 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7550 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7551 /* Save current selection */
\r
7552 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7553 exlen = GetWindowTextLength(hText);
\r
7554 /* Find out whether current end of text is visible */
\r
7555 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7556 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7557 /* Trim existing text if it's too long */
\r
7558 if (exlen + (q - buf) > CO_MAX) {
\r
7559 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7562 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7563 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7565 savesel.cpMin -= trim;
\r
7566 savesel.cpMax -= trim;
\r
7567 if (exlen < 0) exlen = 0;
\r
7568 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7569 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7571 /* Append the new text */
\r
7572 sel.cpMin = exlen;
\r
7573 sel.cpMax = exlen;
\r
7574 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7575 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7576 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7577 if (forceVisible || exlen == 0 ||
\r
7578 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7579 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7580 /* Scroll to make new end of text visible if old end of text
\r
7581 was visible or new text is an echo of user typein */
\r
7582 sel.cpMin = 9999999;
\r
7583 sel.cpMax = 9999999;
\r
7584 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7585 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7586 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7587 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7589 if (savesel.cpMax == exlen || forceVisible) {
\r
7590 /* Move insert point to new end of text if it was at the old
\r
7591 end of text or if the new text is an echo of user typein */
\r
7592 sel.cpMin = 9999999;
\r
7593 sel.cpMax = 9999999;
\r
7594 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7596 /* Restore previous selection */
\r
7597 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7599 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7606 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7610 COLORREF oldFg, oldBg;
\r
7614 if(copyNumber > 1)
\r
7615 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7617 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7618 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7619 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7622 rect.right = x + squareSize;
\r
7624 rect.bottom = y + squareSize;
\r
7627 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7628 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7629 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7630 &rect, str, strlen(str), NULL);
\r
7632 (void) SetTextColor(hdc, oldFg);
\r
7633 (void) SetBkColor(hdc, oldBg);
\r
7634 (void) SelectObject(hdc, oldFont);
\r
7638 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7639 RECT *rect, char *color, char *flagFell)
\r
7643 COLORREF oldFg, oldBg;
\r
7646 if (twoBoards && partnerUp) return;
\r
7647 if (appData.clockMode) {
\r
7649 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7651 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7658 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7659 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7661 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7662 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7664 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7668 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7669 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7670 rect, str, strlen(str), NULL);
\r
7671 if(logoHeight > 0 && appData.clockMode) {
\r
7673 str += strlen(color)+2;
\r
7674 r.top = rect->top + logoHeight/2;
\r
7675 r.left = rect->left;
\r
7676 r.right = rect->right;
\r
7677 r.bottom = rect->bottom;
\r
7678 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7679 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7680 &r, str, strlen(str), NULL);
\r
7682 (void) SetTextColor(hdc, oldFg);
\r
7683 (void) SetBkColor(hdc, oldBg);
\r
7684 (void) SelectObject(hdc, oldFont);
\r
7689 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7695 if( count <= 0 ) {
\r
7696 if (appData.debugMode) {
\r
7697 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7700 return ERROR_INVALID_USER_BUFFER;
\r
7703 ResetEvent(ovl->hEvent);
\r
7704 ovl->Offset = ovl->OffsetHigh = 0;
\r
7705 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7709 err = GetLastError();
\r
7710 if (err == ERROR_IO_PENDING) {
\r
7711 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7715 err = GetLastError();
\r
7722 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7727 ResetEvent(ovl->hEvent);
\r
7728 ovl->Offset = ovl->OffsetHigh = 0;
\r
7729 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7733 err = GetLastError();
\r
7734 if (err == ERROR_IO_PENDING) {
\r
7735 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7739 err = GetLastError();
\r
7746 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7747 void CheckForInputBufferFull( InputSource * is )
\r
7749 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7750 /* Look for end of line */
\r
7751 char * p = is->buf;
\r
7753 while( p < is->next && *p != '\n' ) {
\r
7757 if( p >= is->next ) {
\r
7758 if (appData.debugMode) {
\r
7759 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7762 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7763 is->count = (DWORD) -1;
\r
7764 is->next = is->buf;
\r
7770 InputThread(LPVOID arg)
\r
7775 is = (InputSource *) arg;
\r
7776 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7777 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7778 while (is->hThread != NULL) {
\r
7779 is->error = DoReadFile(is->hFile, is->next,
\r
7780 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7781 &is->count, &ovl);
\r
7782 if (is->error == NO_ERROR) {
\r
7783 is->next += is->count;
\r
7785 if (is->error == ERROR_BROKEN_PIPE) {
\r
7786 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7789 is->count = (DWORD) -1;
\r
7790 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7795 CheckForInputBufferFull( is );
\r
7797 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7799 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7801 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7804 CloseHandle(ovl.hEvent);
\r
7805 CloseHandle(is->hFile);
\r
7807 if (appData.debugMode) {
\r
7808 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7815 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7817 NonOvlInputThread(LPVOID arg)
\r
7824 is = (InputSource *) arg;
\r
7825 while (is->hThread != NULL) {
\r
7826 is->error = ReadFile(is->hFile, is->next,
\r
7827 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7828 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7829 if (is->error == NO_ERROR) {
\r
7830 /* Change CRLF to LF */
\r
7831 if (is->next > is->buf) {
\r
7833 i = is->count + 1;
\r
7841 if (prev == '\r' && *p == '\n') {
\r
7853 if (is->error == ERROR_BROKEN_PIPE) {
\r
7854 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7857 is->count = (DWORD) -1;
\r
7861 CheckForInputBufferFull( is );
\r
7863 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7865 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7867 if (is->count < 0) break; /* Quit on error */
\r
7869 CloseHandle(is->hFile);
\r
7874 SocketInputThread(LPVOID arg)
\r
7878 is = (InputSource *) arg;
\r
7879 while (is->hThread != NULL) {
\r
7880 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7881 if ((int)is->count == SOCKET_ERROR) {
\r
7882 is->count = (DWORD) -1;
\r
7883 is->error = WSAGetLastError();
\r
7885 is->error = NO_ERROR;
\r
7886 is->next += is->count;
\r
7887 if (is->count == 0 && is->second == is) {
\r
7888 /* End of file on stderr; quit with no message */
\r
7892 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7894 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7896 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7902 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7906 is = (InputSource *) lParam;
\r
7907 if (is->lineByLine) {
\r
7908 /* Feed in lines one by one */
\r
7909 char *p = is->buf;
\r
7911 while (q < is->next) {
\r
7912 if (*q++ == '\n') {
\r
7913 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7918 /* Move any partial line to the start of the buffer */
\r
7920 while (p < is->next) {
\r
7925 if (is->error != NO_ERROR || is->count == 0) {
\r
7926 /* Notify backend of the error. Note: If there was a partial
\r
7927 line at the end, it is not flushed through. */
\r
7928 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7931 /* Feed in the whole chunk of input at once */
\r
7932 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7933 is->next = is->buf;
\r
7937 /*---------------------------------------------------------------------------*\
\r
7939 * Menu enables. Used when setting various modes.
\r
7941 \*---------------------------------------------------------------------------*/
\r
7949 GreyRevert(Boolean grey)
\r
7950 { // [HGM] vari: for retracting variations in local mode
\r
7951 HMENU hmenu = GetMenu(hwndMain);
\r
7952 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7953 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7957 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7959 while (enab->item > 0) {
\r
7960 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7965 Enables gnuEnables[] = {
\r
7966 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7967 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7968 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7969 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7970 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7971 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7972 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7980 // Needed to switch from ncp to GNU mode on Engine Load
\r
7981 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7982 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7983 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7984 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7985 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7986 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7987 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7990 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7991 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7992 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7993 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7994 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7998 Enables icsEnables[] = {
\r
7999 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8000 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8001 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8002 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8003 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8004 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8005 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8006 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8007 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8008 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8015 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8023 Enables zippyEnables[] = {
\r
8024 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8025 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8026 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8027 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8032 Enables ncpEnables[] = {
\r
8033 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8034 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8035 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8036 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8037 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8038 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8039 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8040 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8041 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8042 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8043 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8044 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8045 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8046 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8047 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8048 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8053 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8058 Enables trainingOnEnables[] = {
\r
8059 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8060 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8062 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8063 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8064 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8065 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8066 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8067 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8071 Enables trainingOffEnables[] = {
\r
8072 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8073 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8074 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8075 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8076 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8077 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8078 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8079 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8080 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8084 /* These modify either ncpEnables or gnuEnables */
\r
8085 Enables cmailEnables[] = {
\r
8086 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8087 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8088 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8089 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8090 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8091 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8092 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8096 Enables machineThinkingEnables[] = {
\r
8097 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8098 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8099 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8100 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8101 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8102 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8103 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8104 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8105 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8106 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8107 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8109 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8110 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8111 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8112 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8116 Enables userThinkingEnables[] = {
\r
8117 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8118 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8119 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8120 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8121 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8122 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8123 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8124 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8125 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8126 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8127 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8129 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8130 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8131 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8132 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8136 /*---------------------------------------------------------------------------*\
\r
8138 * Front-end interface functions exported by XBoard.
\r
8139 * Functions appear in same order as prototypes in frontend.h.
\r
8141 \*---------------------------------------------------------------------------*/
\r
8143 CheckMark(UINT item, int state)
\r
8145 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8151 static UINT prevChecked = 0;
\r
8152 static int prevPausing = 0;
\r
8155 if (pausing != prevPausing) {
\r
8156 prevPausing = pausing;
\r
8157 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8158 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8159 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8162 switch (gameMode) {
\r
8163 case BeginningOfGame:
\r
8164 if (appData.icsActive)
\r
8165 nowChecked = IDM_IcsClient;
\r
8166 else if (appData.noChessProgram)
\r
8167 nowChecked = IDM_EditGame;
\r
8169 nowChecked = IDM_MachineBlack;
\r
8171 case MachinePlaysBlack:
\r
8172 nowChecked = IDM_MachineBlack;
\r
8174 case MachinePlaysWhite:
\r
8175 nowChecked = IDM_MachineWhite;
\r
8177 case TwoMachinesPlay:
\r
8178 nowChecked = IDM_TwoMachines;
\r
8181 nowChecked = IDM_AnalysisMode;
\r
8184 nowChecked = IDM_AnalyzeFile;
\r
8187 nowChecked = IDM_EditGame;
\r
8189 case PlayFromGameFile:
\r
8190 nowChecked = IDM_LoadGame;
\r
8192 case EditPosition:
\r
8193 nowChecked = IDM_EditPosition;
\r
8196 nowChecked = IDM_Training;
\r
8198 case IcsPlayingWhite:
\r
8199 case IcsPlayingBlack:
\r
8200 case IcsObserving:
\r
8202 nowChecked = IDM_IcsClient;
\r
8209 CheckMark(prevChecked, MF_UNCHECKED);
\r
8210 CheckMark(nowChecked, MF_CHECKED);
\r
8211 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8213 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8214 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8215 MF_BYCOMMAND|MF_ENABLED);
\r
8217 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8218 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8221 prevChecked = nowChecked;
\r
8223 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8224 if (appData.icsActive) {
\r
8225 if (appData.icsEngineAnalyze) {
\r
8226 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8228 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8231 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8237 HMENU hmenu = GetMenu(hwndMain);
\r
8238 SetMenuEnables(hmenu, icsEnables);
\r
8239 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8240 MF_BYCOMMAND|MF_ENABLED);
\r
8242 if (appData.zippyPlay) {
\r
8243 SetMenuEnables(hmenu, zippyEnables);
\r
8244 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8245 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8246 MF_BYCOMMAND|MF_ENABLED);
\r
8254 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8260 HMENU hmenu = GetMenu(hwndMain);
\r
8261 SetMenuEnables(hmenu, ncpEnables);
\r
8262 DrawMenuBar(hwndMain);
\r
8268 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8272 SetTrainingModeOn()
\r
8275 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8276 for (i = 0; i < N_BUTTONS; i++) {
\r
8277 if (buttonDesc[i].hwnd != NULL)
\r
8278 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8283 VOID SetTrainingModeOff()
\r
8286 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8287 for (i = 0; i < N_BUTTONS; i++) {
\r
8288 if (buttonDesc[i].hwnd != NULL)
\r
8289 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8295 SetUserThinkingEnables()
\r
8297 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8301 SetMachineThinkingEnables()
\r
8303 HMENU hMenu = GetMenu(hwndMain);
\r
8304 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8306 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8308 if (gameMode == MachinePlaysBlack) {
\r
8309 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8310 } else if (gameMode == MachinePlaysWhite) {
\r
8311 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8312 } else if (gameMode == TwoMachinesPlay) {
\r
8313 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8319 DisplayTitle(char *str)
\r
8321 char title[MSG_SIZ], *host;
\r
8322 if (str[0] != NULLCHAR) {
\r
8323 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8324 } else if (appData.icsActive) {
\r
8325 if (appData.icsCommPort[0] != NULLCHAR)
\r
8328 host = appData.icsHost;
\r
8329 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8330 } else if (appData.noChessProgram) {
\r
8331 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8333 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8334 strcat(title, ": ");
\r
8335 strcat(title, first.tidy);
\r
8337 SetWindowText(hwndMain, title);
\r
8342 DisplayMessage(char *str1, char *str2)
\r
8346 int remain = MESSAGE_TEXT_MAX - 1;
\r
8349 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8350 messageText[0] = NULLCHAR;
\r
8352 len = strlen(str1);
\r
8353 if (len > remain) len = remain;
\r
8354 strncpy(messageText, str1, len);
\r
8355 messageText[len] = NULLCHAR;
\r
8358 if (*str2 && remain >= 2) {
\r
8360 strcat(messageText, " ");
\r
8363 len = strlen(str2);
\r
8364 if (len > remain) len = remain;
\r
8365 strncat(messageText, str2, len);
\r
8367 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8368 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8370 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8374 hdc = GetDC(hwndMain);
\r
8375 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8376 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8377 &messageRect, messageText, strlen(messageText), NULL);
\r
8378 (void) SelectObject(hdc, oldFont);
\r
8379 (void) ReleaseDC(hwndMain, hdc);
\r
8383 DisplayError(char *str, int error)
\r
8385 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8389 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8391 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8392 NULL, error, LANG_NEUTRAL,
\r
8393 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8395 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8397 ErrorMap *em = errmap;
\r
8398 while (em->err != 0 && em->err != error) em++;
\r
8399 if (em->err != 0) {
\r
8400 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8402 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8407 ErrorPopUp(_("Error"), buf);
\r
8412 DisplayMoveError(char *str)
\r
8414 fromX = fromY = -1;
\r
8415 ClearHighlights();
\r
8416 DrawPosition(FALSE, NULL);
\r
8417 if (appData.popupMoveErrors) {
\r
8418 ErrorPopUp(_("Error"), str);
\r
8420 DisplayMessage(str, "");
\r
8421 moveErrorMessageUp = TRUE;
\r
8426 DisplayFatalError(char *str, int error, int exitStatus)
\r
8428 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8430 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8433 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8434 NULL, error, LANG_NEUTRAL,
\r
8435 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8437 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8439 ErrorMap *em = errmap;
\r
8440 while (em->err != 0 && em->err != error) em++;
\r
8441 if (em->err != 0) {
\r
8442 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8444 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8449 if (appData.debugMode) {
\r
8450 fprintf(debugFP, "%s: %s\n", label, str);
\r
8452 if (appData.popupExitMessage) {
\r
8453 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8454 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8456 ExitEvent(exitStatus);
\r
8461 DisplayInformation(char *str)
\r
8463 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8468 DisplayNote(char *str)
\r
8470 ErrorPopUp(_("Note"), str);
\r
8475 char *title, *question, *replyPrefix;
\r
8480 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8482 static QuestionParams *qp;
\r
8483 char reply[MSG_SIZ];
\r
8486 switch (message) {
\r
8487 case WM_INITDIALOG:
\r
8488 qp = (QuestionParams *) lParam;
\r
8489 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8490 Translate(hDlg, DLG_Question);
\r
8491 SetWindowText(hDlg, qp->title);
\r
8492 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8493 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8497 switch (LOWORD(wParam)) {
\r
8499 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8500 if (*reply) strcat(reply, " ");
\r
8501 len = strlen(reply);
\r
8502 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8503 strcat(reply, "\n");
\r
8504 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8505 EndDialog(hDlg, TRUE);
\r
8506 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8509 EndDialog(hDlg, FALSE);
\r
8520 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8522 QuestionParams qp;
\r
8526 qp.question = question;
\r
8527 qp.replyPrefix = replyPrefix;
\r
8529 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8530 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8531 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8532 FreeProcInstance(lpProc);
\r
8535 /* [AS] Pick FRC position */
\r
8536 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8538 static int * lpIndexFRC;
\r
8544 case WM_INITDIALOG:
\r
8545 lpIndexFRC = (int *) lParam;
\r
8547 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8548 Translate(hDlg, DLG_NewGameFRC);
\r
8550 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8551 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8552 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8553 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8558 switch( LOWORD(wParam) ) {
\r
8560 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8561 EndDialog( hDlg, 0 );
\r
8562 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8565 EndDialog( hDlg, 1 );
\r
8567 case IDC_NFG_Edit:
\r
8568 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8569 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8571 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8574 case IDC_NFG_Random:
\r
8575 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8576 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8589 int index = appData.defaultFrcPosition;
\r
8590 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8592 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8594 if( result == 0 ) {
\r
8595 appData.defaultFrcPosition = index;
\r
8601 /* [AS] Game list options. Refactored by HGM */
\r
8603 HWND gameListOptionsDialog;
\r
8605 // low-level front-end: clear text edit / list widget
\r
8610 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8613 // low-level front-end: clear text edit / list widget
\r
8615 GLT_DeSelectList()
\r
8617 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8620 // low-level front-end: append line to text edit / list widget
\r
8622 GLT_AddToList( char *name )
\r
8625 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8629 // low-level front-end: get line from text edit / list widget
\r
8631 GLT_GetFromList( int index, char *name )
\r
8634 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8640 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8642 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8643 int idx2 = idx1 + delta;
\r
8644 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8646 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8649 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8650 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8651 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8652 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8656 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8660 case WM_INITDIALOG:
\r
8661 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8663 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8664 Translate(hDlg, DLG_GameListOptions);
\r
8666 /* Initialize list */
\r
8667 GLT_TagsToList( lpUserGLT );
\r
8669 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8674 switch( LOWORD(wParam) ) {
\r
8677 EndDialog( hDlg, 0 );
\r
8680 EndDialog( hDlg, 1 );
\r
8683 case IDC_GLT_Default:
\r
8684 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8687 case IDC_GLT_Restore:
\r
8688 GLT_TagsToList( appData.gameListTags );
\r
8692 GLT_MoveSelection( hDlg, -1 );
\r
8695 case IDC_GLT_Down:
\r
8696 GLT_MoveSelection( hDlg, +1 );
\r
8706 int GameListOptions()
\r
8709 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8711 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8713 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8715 if( result == 0 ) {
\r
8716 char *oldTags = appData.gameListTags;
\r
8717 /* [AS] Memory leak here! */
\r
8718 appData.gameListTags = strdup( lpUserGLT );
\r
8719 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8720 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8727 DisplayIcsInteractionTitle(char *str)
\r
8729 char consoleTitle[MSG_SIZ];
\r
8731 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8732 SetWindowText(hwndConsole, consoleTitle);
\r
8734 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8735 char buf[MSG_SIZ], *p = buf, *q;
\r
8736 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8738 q = strchr(p, ';');
\r
8740 if(*p) ChatPopUp(p);
\r
8744 SetActiveWindow(hwndMain);
\r
8748 DrawPosition(int fullRedraw, Board board)
\r
8750 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8753 void NotifyFrontendLogin()
\r
8756 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8762 fromX = fromY = -1;
\r
8763 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8764 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8765 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8766 dragInfo.lastpos = dragInfo.pos;
\r
8767 dragInfo.start.x = dragInfo.start.y = -1;
\r
8768 dragInfo.from = dragInfo.start;
\r
8770 DrawPosition(TRUE, NULL);
\r
8777 CommentPopUp(char *title, char *str)
\r
8779 HWND hwnd = GetActiveWindow();
\r
8780 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8782 SetActiveWindow(hwnd);
\r
8786 CommentPopDown(void)
\r
8788 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8789 if (commentDialog) {
\r
8790 ShowWindow(commentDialog, SW_HIDE);
\r
8792 commentUp = FALSE;
\r
8796 EditCommentPopUp(int index, char *title, char *str)
\r
8798 EitherCommentPopUp(index, title, str, TRUE);
\r
8805 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8812 MyPlaySound(&sounds[(int)SoundMove]);
\r
8815 VOID PlayIcsWinSound()
\r
8817 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8820 VOID PlayIcsLossSound()
\r
8822 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8825 VOID PlayIcsDrawSound()
\r
8827 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8830 VOID PlayIcsUnfinishedSound()
\r
8832 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8838 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8844 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8852 consoleEcho = TRUE;
\r
8853 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8854 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8855 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8864 consoleEcho = FALSE;
\r
8865 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8866 /* This works OK: set text and background both to the same color */
\r
8868 cf.crTextColor = COLOR_ECHOOFF;
\r
8869 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8870 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8873 /* No Raw()...? */
\r
8875 void Colorize(ColorClass cc, int continuation)
\r
8877 currentColorClass = cc;
\r
8878 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8879 consoleCF.crTextColor = textAttribs[cc].color;
\r
8880 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8881 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8887 static char buf[MSG_SIZ];
\r
8888 DWORD bufsiz = MSG_SIZ;
\r
8890 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8891 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8893 if (!GetUserName(buf, &bufsiz)) {
\r
8894 /*DisplayError("Error getting user name", GetLastError());*/
\r
8895 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8903 static char buf[MSG_SIZ];
\r
8904 DWORD bufsiz = MSG_SIZ;
\r
8906 if (!GetComputerName(buf, &bufsiz)) {
\r
8907 /*DisplayError("Error getting host name", GetLastError());*/
\r
8908 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8915 ClockTimerRunning()
\r
8917 return clockTimerEvent != 0;
\r
8923 if (clockTimerEvent == 0) return FALSE;
\r
8924 KillTimer(hwndMain, clockTimerEvent);
\r
8925 clockTimerEvent = 0;
\r
8930 StartClockTimer(long millisec)
\r
8932 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8933 (UINT) millisec, NULL);
\r
8937 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8940 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8942 if(appData.noGUI) return;
\r
8943 hdc = GetDC(hwndMain);
\r
8944 if (!IsIconic(hwndMain)) {
\r
8945 DisplayAClock(hdc, timeRemaining, highlight,
\r
8946 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8948 if (highlight && iconCurrent == iconBlack) {
\r
8949 iconCurrent = iconWhite;
\r
8950 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8951 if (IsIconic(hwndMain)) {
\r
8952 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8955 (void) ReleaseDC(hwndMain, hdc);
\r
8957 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8961 DisplayBlackClock(long timeRemaining, int highlight)
\r
8964 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8967 if(appData.noGUI) return;
\r
8968 hdc = GetDC(hwndMain);
\r
8969 if (!IsIconic(hwndMain)) {
\r
8970 DisplayAClock(hdc, timeRemaining, highlight,
\r
8971 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8973 if (highlight && iconCurrent == iconWhite) {
\r
8974 iconCurrent = iconBlack;
\r
8975 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8976 if (IsIconic(hwndMain)) {
\r
8977 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8980 (void) ReleaseDC(hwndMain, hdc);
\r
8982 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8987 LoadGameTimerRunning()
\r
8989 return loadGameTimerEvent != 0;
\r
8993 StopLoadGameTimer()
\r
8995 if (loadGameTimerEvent == 0) return FALSE;
\r
8996 KillTimer(hwndMain, loadGameTimerEvent);
\r
8997 loadGameTimerEvent = 0;
\r
9002 StartLoadGameTimer(long millisec)
\r
9004 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9005 (UINT) millisec, NULL);
\r
9013 char fileTitle[MSG_SIZ];
\r
9015 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9016 f = OpenFileDialog(hwndMain, "a", defName,
\r
9017 appData.oldSaveStyle ? "gam" : "pgn",
\r
9019 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9021 SaveGame(f, 0, "");
\r
9028 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9030 if (delayedTimerEvent != 0) {
\r
9031 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9032 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9034 KillTimer(hwndMain, delayedTimerEvent);
\r
9035 delayedTimerEvent = 0;
\r
9036 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9037 delayedTimerCallback();
\r
9039 delayedTimerCallback = cb;
\r
9040 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9041 (UINT) millisec, NULL);
\r
9044 DelayedEventCallback
\r
9047 if (delayedTimerEvent) {
\r
9048 return delayedTimerCallback;
\r
9055 CancelDelayedEvent()
\r
9057 if (delayedTimerEvent) {
\r
9058 KillTimer(hwndMain, delayedTimerEvent);
\r
9059 delayedTimerEvent = 0;
\r
9063 DWORD GetWin32Priority(int nice)
\r
9064 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9066 REALTIME_PRIORITY_CLASS 0x00000100
\r
9067 HIGH_PRIORITY_CLASS 0x00000080
\r
9068 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9069 NORMAL_PRIORITY_CLASS 0x00000020
\r
9070 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9071 IDLE_PRIORITY_CLASS 0x00000040
\r
9073 if (nice < -15) return 0x00000080;
\r
9074 if (nice < 0) return 0x00008000;
\r
9075 if (nice == 0) return 0x00000020;
\r
9076 if (nice < 15) return 0x00004000;
\r
9077 return 0x00000040;
\r
9080 void RunCommand(char *cmdLine)
\r
9082 /* Now create the child process. */
\r
9083 STARTUPINFO siStartInfo;
\r
9084 PROCESS_INFORMATION piProcInfo;
\r
9086 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9087 siStartInfo.lpReserved = NULL;
\r
9088 siStartInfo.lpDesktop = NULL;
\r
9089 siStartInfo.lpTitle = NULL;
\r
9090 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9091 siStartInfo.cbReserved2 = 0;
\r
9092 siStartInfo.lpReserved2 = NULL;
\r
9093 siStartInfo.hStdInput = NULL;
\r
9094 siStartInfo.hStdOutput = NULL;
\r
9095 siStartInfo.hStdError = NULL;
\r
9097 CreateProcess(NULL,
\r
9098 cmdLine, /* command line */
\r
9099 NULL, /* process security attributes */
\r
9100 NULL, /* primary thread security attrs */
\r
9101 TRUE, /* handles are inherited */
\r
9102 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9103 NULL, /* use parent's environment */
\r
9105 &siStartInfo, /* STARTUPINFO pointer */
\r
9106 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9108 CloseHandle(piProcInfo.hThread);
\r
9111 /* Start a child process running the given program.
\r
9112 The process's standard output can be read from "from", and its
\r
9113 standard input can be written to "to".
\r
9114 Exit with fatal error if anything goes wrong.
\r
9115 Returns an opaque pointer that can be used to destroy the process
\r
9119 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9121 #define BUFSIZE 4096
\r
9123 HANDLE hChildStdinRd, hChildStdinWr,
\r
9124 hChildStdoutRd, hChildStdoutWr;
\r
9125 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9126 SECURITY_ATTRIBUTES saAttr;
\r
9128 PROCESS_INFORMATION piProcInfo;
\r
9129 STARTUPINFO siStartInfo;
\r
9131 char buf[MSG_SIZ];
\r
9134 if (appData.debugMode) {
\r
9135 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9140 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9141 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9142 saAttr.bInheritHandle = TRUE;
\r
9143 saAttr.lpSecurityDescriptor = NULL;
\r
9146 * The steps for redirecting child's STDOUT:
\r
9147 * 1. Create anonymous pipe to be STDOUT for child.
\r
9148 * 2. Create a noninheritable duplicate of read handle,
\r
9149 * and close the inheritable read handle.
\r
9152 /* Create a pipe for the child's STDOUT. */
\r
9153 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9154 return GetLastError();
\r
9157 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9158 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9159 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9160 FALSE, /* not inherited */
\r
9161 DUPLICATE_SAME_ACCESS);
\r
9163 return GetLastError();
\r
9165 CloseHandle(hChildStdoutRd);
\r
9168 * The steps for redirecting child's STDIN:
\r
9169 * 1. Create anonymous pipe to be STDIN for child.
\r
9170 * 2. Create a noninheritable duplicate of write handle,
\r
9171 * and close the inheritable write handle.
\r
9174 /* Create a pipe for the child's STDIN. */
\r
9175 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9176 return GetLastError();
\r
9179 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9180 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9181 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9182 FALSE, /* not inherited */
\r
9183 DUPLICATE_SAME_ACCESS);
\r
9185 return GetLastError();
\r
9187 CloseHandle(hChildStdinWr);
\r
9189 /* Arrange to (1) look in dir for the child .exe file, and
\r
9190 * (2) have dir be the child's working directory. Interpret
\r
9191 * dir relative to the directory WinBoard loaded from. */
\r
9192 GetCurrentDirectory(MSG_SIZ, buf);
\r
9193 SetCurrentDirectory(installDir);
\r
9194 SetCurrentDirectory(dir);
\r
9196 /* Now create the child process. */
\r
9198 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9199 siStartInfo.lpReserved = NULL;
\r
9200 siStartInfo.lpDesktop = NULL;
\r
9201 siStartInfo.lpTitle = NULL;
\r
9202 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9203 siStartInfo.cbReserved2 = 0;
\r
9204 siStartInfo.lpReserved2 = NULL;
\r
9205 siStartInfo.hStdInput = hChildStdinRd;
\r
9206 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9207 siStartInfo.hStdError = hChildStdoutWr;
\r
9209 fSuccess = CreateProcess(NULL,
\r
9210 cmdLine, /* command line */
\r
9211 NULL, /* process security attributes */
\r
9212 NULL, /* primary thread security attrs */
\r
9213 TRUE, /* handles are inherited */
\r
9214 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9215 NULL, /* use parent's environment */
\r
9217 &siStartInfo, /* STARTUPINFO pointer */
\r
9218 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9220 err = GetLastError();
\r
9221 SetCurrentDirectory(buf); /* return to prev directory */
\r
9226 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9227 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9228 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9231 /* Close the handles we don't need in the parent */
\r
9232 CloseHandle(piProcInfo.hThread);
\r
9233 CloseHandle(hChildStdinRd);
\r
9234 CloseHandle(hChildStdoutWr);
\r
9236 /* Prepare return value */
\r
9237 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9238 cp->kind = CPReal;
\r
9239 cp->hProcess = piProcInfo.hProcess;
\r
9240 cp->pid = piProcInfo.dwProcessId;
\r
9241 cp->hFrom = hChildStdoutRdDup;
\r
9242 cp->hTo = hChildStdinWrDup;
\r
9244 *pr = (void *) cp;
\r
9246 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9247 2000 where engines sometimes don't see the initial command(s)
\r
9248 from WinBoard and hang. I don't understand how that can happen,
\r
9249 but the Sleep is harmless, so I've put it in. Others have also
\r
9250 reported what may be the same problem, so hopefully this will fix
\r
9251 it for them too. */
\r
9259 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9261 ChildProc *cp; int result;
\r
9263 cp = (ChildProc *) pr;
\r
9264 if (cp == NULL) return;
\r
9266 switch (cp->kind) {
\r
9268 /* TerminateProcess is considered harmful, so... */
\r
9269 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9270 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9271 /* The following doesn't work because the chess program
\r
9272 doesn't "have the same console" as WinBoard. Maybe
\r
9273 we could arrange for this even though neither WinBoard
\r
9274 nor the chess program uses a console for stdio? */
\r
9275 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9277 /* [AS] Special termination modes for misbehaving programs... */
\r
9278 if( signal & 8 ) {
\r
9279 result = TerminateProcess( cp->hProcess, 0 );
\r
9281 if ( appData.debugMode) {
\r
9282 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9285 else if( signal & 4 ) {
\r
9286 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9288 if( dw != WAIT_OBJECT_0 ) {
\r
9289 result = TerminateProcess( cp->hProcess, 0 );
\r
9291 if ( appData.debugMode) {
\r
9292 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9298 CloseHandle(cp->hProcess);
\r
9302 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9306 closesocket(cp->sock);
\r
9311 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9312 closesocket(cp->sock);
\r
9313 closesocket(cp->sock2);
\r
9321 InterruptChildProcess(ProcRef pr)
\r
9325 cp = (ChildProc *) pr;
\r
9326 if (cp == NULL) return;
\r
9327 switch (cp->kind) {
\r
9329 /* The following doesn't work because the chess program
\r
9330 doesn't "have the same console" as WinBoard. Maybe
\r
9331 we could arrange for this even though neither WinBoard
\r
9332 nor the chess program uses a console for stdio */
\r
9333 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9338 /* Can't interrupt */
\r
9342 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9349 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9351 char cmdLine[MSG_SIZ];
\r
9353 if (port[0] == NULLCHAR) {
\r
9354 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9356 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9358 return StartChildProcess(cmdLine, "", pr);
\r
9362 /* Code to open TCP sockets */
\r
9365 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9371 struct sockaddr_in sa, mysa;
\r
9372 struct hostent FAR *hp;
\r
9373 unsigned short uport;
\r
9374 WORD wVersionRequested;
\r
9377 /* Initialize socket DLL */
\r
9378 wVersionRequested = MAKEWORD(1, 1);
\r
9379 err = WSAStartup(wVersionRequested, &wsaData);
\r
9380 if (err != 0) return err;
\r
9383 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9384 err = WSAGetLastError();
\r
9389 /* Bind local address using (mostly) don't-care values.
\r
9391 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9392 mysa.sin_family = AF_INET;
\r
9393 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9394 uport = (unsigned short) 0;
\r
9395 mysa.sin_port = htons(uport);
\r
9396 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9397 == SOCKET_ERROR) {
\r
9398 err = WSAGetLastError();
\r
9403 /* Resolve remote host name */
\r
9404 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9405 if (!(hp = gethostbyname(host))) {
\r
9406 unsigned int b0, b1, b2, b3;
\r
9408 err = WSAGetLastError();
\r
9410 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9411 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9412 hp->h_addrtype = AF_INET;
\r
9414 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9415 hp->h_addr_list[0] = (char *) malloc(4);
\r
9416 hp->h_addr_list[0][0] = (char) b0;
\r
9417 hp->h_addr_list[0][1] = (char) b1;
\r
9418 hp->h_addr_list[0][2] = (char) b2;
\r
9419 hp->h_addr_list[0][3] = (char) b3;
\r
9425 sa.sin_family = hp->h_addrtype;
\r
9426 uport = (unsigned short) atoi(port);
\r
9427 sa.sin_port = htons(uport);
\r
9428 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9430 /* Make connection */
\r
9431 if (connect(s, (struct sockaddr *) &sa,
\r
9432 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9433 err = WSAGetLastError();
\r
9438 /* Prepare return value */
\r
9439 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9440 cp->kind = CPSock;
\r
9442 *pr = (ProcRef *) cp;
\r
9448 OpenCommPort(char *name, ProcRef *pr)
\r
9453 char fullname[MSG_SIZ];
\r
9455 if (*name != '\\')
\r
9456 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9458 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9460 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9461 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9462 if (h == (HANDLE) -1) {
\r
9463 return GetLastError();
\r
9467 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9469 /* Accumulate characters until a 100ms pause, then parse */
\r
9470 ct.ReadIntervalTimeout = 100;
\r
9471 ct.ReadTotalTimeoutMultiplier = 0;
\r
9472 ct.ReadTotalTimeoutConstant = 0;
\r
9473 ct.WriteTotalTimeoutMultiplier = 0;
\r
9474 ct.WriteTotalTimeoutConstant = 0;
\r
9475 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9477 /* Prepare return value */
\r
9478 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9479 cp->kind = CPComm;
\r
9482 *pr = (ProcRef *) cp;
\r
9488 OpenLoopback(ProcRef *pr)
\r
9490 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9496 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9501 struct sockaddr_in sa, mysa;
\r
9502 struct hostent FAR *hp;
\r
9503 unsigned short uport;
\r
9504 WORD wVersionRequested;
\r
9507 char stderrPortStr[MSG_SIZ];
\r
9509 /* Initialize socket DLL */
\r
9510 wVersionRequested = MAKEWORD(1, 1);
\r
9511 err = WSAStartup(wVersionRequested, &wsaData);
\r
9512 if (err != 0) return err;
\r
9514 /* Resolve remote host name */
\r
9515 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9516 if (!(hp = gethostbyname(host))) {
\r
9517 unsigned int b0, b1, b2, b3;
\r
9519 err = WSAGetLastError();
\r
9521 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9522 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9523 hp->h_addrtype = AF_INET;
\r
9525 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9526 hp->h_addr_list[0] = (char *) malloc(4);
\r
9527 hp->h_addr_list[0][0] = (char) b0;
\r
9528 hp->h_addr_list[0][1] = (char) b1;
\r
9529 hp->h_addr_list[0][2] = (char) b2;
\r
9530 hp->h_addr_list[0][3] = (char) b3;
\r
9536 sa.sin_family = hp->h_addrtype;
\r
9537 uport = (unsigned short) 514;
\r
9538 sa.sin_port = htons(uport);
\r
9539 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9541 /* Bind local socket to unused "privileged" port address
\r
9543 s = INVALID_SOCKET;
\r
9544 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9545 mysa.sin_family = AF_INET;
\r
9546 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9547 for (fromPort = 1023;; fromPort--) {
\r
9548 if (fromPort < 0) {
\r
9550 return WSAEADDRINUSE;
\r
9552 if (s == INVALID_SOCKET) {
\r
9553 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9554 err = WSAGetLastError();
\r
9559 uport = (unsigned short) fromPort;
\r
9560 mysa.sin_port = htons(uport);
\r
9561 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9562 == SOCKET_ERROR) {
\r
9563 err = WSAGetLastError();
\r
9564 if (err == WSAEADDRINUSE) continue;
\r
9568 if (connect(s, (struct sockaddr *) &sa,
\r
9569 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9570 err = WSAGetLastError();
\r
9571 if (err == WSAEADDRINUSE) {
\r
9582 /* Bind stderr local socket to unused "privileged" port address
\r
9584 s2 = INVALID_SOCKET;
\r
9585 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9586 mysa.sin_family = AF_INET;
\r
9587 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9588 for (fromPort = 1023;; fromPort--) {
\r
9589 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9590 if (fromPort < 0) {
\r
9591 (void) closesocket(s);
\r
9593 return WSAEADDRINUSE;
\r
9595 if (s2 == INVALID_SOCKET) {
\r
9596 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9597 err = WSAGetLastError();
\r
9603 uport = (unsigned short) fromPort;
\r
9604 mysa.sin_port = htons(uport);
\r
9605 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9606 == SOCKET_ERROR) {
\r
9607 err = WSAGetLastError();
\r
9608 if (err == WSAEADDRINUSE) continue;
\r
9609 (void) closesocket(s);
\r
9613 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9614 err = WSAGetLastError();
\r
9615 if (err == WSAEADDRINUSE) {
\r
9617 s2 = INVALID_SOCKET;
\r
9620 (void) closesocket(s);
\r
9621 (void) closesocket(s2);
\r
9627 prevStderrPort = fromPort; // remember port used
\r
9628 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9630 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9631 err = WSAGetLastError();
\r
9632 (void) closesocket(s);
\r
9633 (void) closesocket(s2);
\r
9638 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9639 err = WSAGetLastError();
\r
9640 (void) closesocket(s);
\r
9641 (void) closesocket(s2);
\r
9645 if (*user == NULLCHAR) user = UserName();
\r
9646 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9647 err = WSAGetLastError();
\r
9648 (void) closesocket(s);
\r
9649 (void) closesocket(s2);
\r
9653 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9654 err = WSAGetLastError();
\r
9655 (void) closesocket(s);
\r
9656 (void) closesocket(s2);
\r
9661 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9662 err = WSAGetLastError();
\r
9663 (void) closesocket(s);
\r
9664 (void) closesocket(s2);
\r
9668 (void) closesocket(s2); /* Stop listening */
\r
9670 /* Prepare return value */
\r
9671 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9672 cp->kind = CPRcmd;
\r
9675 *pr = (ProcRef *) cp;
\r
9682 AddInputSource(ProcRef pr, int lineByLine,
\r
9683 InputCallback func, VOIDSTAR closure)
\r
9685 InputSource *is, *is2 = NULL;
\r
9686 ChildProc *cp = (ChildProc *) pr;
\r
9688 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9689 is->lineByLine = lineByLine;
\r
9691 is->closure = closure;
\r
9692 is->second = NULL;
\r
9693 is->next = is->buf;
\r
9694 if (pr == NoProc) {
\r
9695 is->kind = CPReal;
\r
9696 consoleInputSource = is;
\r
9698 is->kind = cp->kind;
\r
9700 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9701 we create all threads suspended so that the is->hThread variable can be
\r
9702 safely assigned, then let the threads start with ResumeThread.
\r
9704 switch (cp->kind) {
\r
9706 is->hFile = cp->hFrom;
\r
9707 cp->hFrom = NULL; /* now owned by InputThread */
\r
9709 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9710 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9714 is->hFile = cp->hFrom;
\r
9715 cp->hFrom = NULL; /* now owned by InputThread */
\r
9717 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9718 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9722 is->sock = cp->sock;
\r
9724 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9725 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9729 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9731 is->sock = cp->sock;
\r
9733 is2->sock = cp->sock2;
\r
9734 is2->second = is2;
\r
9736 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9737 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9739 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9740 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9744 if( is->hThread != NULL ) {
\r
9745 ResumeThread( is->hThread );
\r
9748 if( is2 != NULL && is2->hThread != NULL ) {
\r
9749 ResumeThread( is2->hThread );
\r
9753 return (InputSourceRef) is;
\r
9757 RemoveInputSource(InputSourceRef isr)
\r
9761 is = (InputSource *) isr;
\r
9762 is->hThread = NULL; /* tell thread to stop */
\r
9763 CloseHandle(is->hThread);
\r
9764 if (is->second != NULL) {
\r
9765 is->second->hThread = NULL;
\r
9766 CloseHandle(is->second->hThread);
\r
9770 int no_wrap(char *message, int count)
\r
9772 ConsoleOutput(message, count, FALSE);
\r
9777 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9780 int outCount = SOCKET_ERROR;
\r
9781 ChildProc *cp = (ChildProc *) pr;
\r
9782 static OVERLAPPED ovl;
\r
9784 static int line = 0;
\r
9788 if (appData.noJoin || !appData.useInternalWrap)
\r
9789 return no_wrap(message, count);
\r
9792 int width = get_term_width();
\r
9793 int len = wrap(NULL, message, count, width, &line);
\r
9794 char *msg = malloc(len);
\r
9798 return no_wrap(message, count);
\r
9801 dbgchk = wrap(msg, message, count, width, &line);
\r
9802 if (dbgchk != len && appData.debugMode)
\r
9803 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9804 ConsoleOutput(msg, len, FALSE);
\r
9811 if (ovl.hEvent == NULL) {
\r
9812 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9814 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9816 switch (cp->kind) {
\r
9819 outCount = send(cp->sock, message, count, 0);
\r
9820 if (outCount == SOCKET_ERROR) {
\r
9821 *outError = WSAGetLastError();
\r
9823 *outError = NO_ERROR;
\r
9828 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9829 &dOutCount, NULL)) {
\r
9830 *outError = NO_ERROR;
\r
9831 outCount = (int) dOutCount;
\r
9833 *outError = GetLastError();
\r
9838 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9839 &dOutCount, &ovl);
\r
9840 if (*outError == NO_ERROR) {
\r
9841 outCount = (int) dOutCount;
\r
9851 if(n != 0) Sleep(n);
\r
9855 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9858 /* Ignore delay, not implemented for WinBoard */
\r
9859 return OutputToProcess(pr, message, count, outError);
\r
9864 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9865 char *buf, int count, int error)
\r
9867 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9870 /* see wgamelist.c for Game List functions */
\r
9871 /* see wedittags.c for Edit Tags functions */
\r
9878 char buf[MSG_SIZ];
\r
9881 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9882 f = fopen(buf, "r");
\r
9884 ProcessICSInitScript(f);
\r
9894 StartAnalysisClock()
\r
9896 if (analysisTimerEvent) return;
\r
9897 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9898 (UINT) 2000, NULL);
\r
9902 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9904 highlightInfo.sq[0].x = fromX;
\r
9905 highlightInfo.sq[0].y = fromY;
\r
9906 highlightInfo.sq[1].x = toX;
\r
9907 highlightInfo.sq[1].y = toY;
\r
9913 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9914 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9918 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9920 premoveHighlightInfo.sq[0].x = fromX;
\r
9921 premoveHighlightInfo.sq[0].y = fromY;
\r
9922 premoveHighlightInfo.sq[1].x = toX;
\r
9923 premoveHighlightInfo.sq[1].y = toY;
\r
9927 ClearPremoveHighlights()
\r
9929 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9930 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9934 ShutDownFrontEnd()
\r
9936 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9937 DeleteClipboardTempFiles();
\r
9943 if (IsIconic(hwndMain))
\r
9944 ShowWindow(hwndMain, SW_RESTORE);
\r
9946 SetActiveWindow(hwndMain);
\r
9950 * Prototypes for animation support routines
\r
9952 static void ScreenSquare(int column, int row, POINT * pt);
\r
9953 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9954 POINT frames[], int * nFrames);
\r
9960 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9961 { // [HGM] atomic: animate blast wave
\r
9964 explodeInfo.fromX = fromX;
\r
9965 explodeInfo.fromY = fromY;
\r
9966 explodeInfo.toX = toX;
\r
9967 explodeInfo.toY = toY;
\r
9968 for(i=1; i<4*kFactor; i++) {
\r
9969 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9970 DrawPosition(FALSE, board);
\r
9971 Sleep(appData.animSpeed);
\r
9973 explodeInfo.radius = 0;
\r
9974 DrawPosition(TRUE, board);
\r
9978 AnimateMove(board, fromX, fromY, toX, toY)
\r
9985 ChessSquare piece;
\r
9986 int x = toX, y = toY;
\r
9987 POINT start, finish, mid;
\r
9988 POINT frames[kFactor * 2 + 1];
\r
9991 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
9993 if (!appData.animate) return;
\r
9994 if (doingSizing) return;
\r
9995 if (fromY < 0 || fromX < 0) return;
\r
9996 piece = board[fromY][fromX];
\r
9997 if (piece >= EmptySquare) return;
\r
9999 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10003 ScreenSquare(fromX, fromY, &start);
\r
10004 ScreenSquare(toX, toY, &finish);
\r
10006 /* All moves except knight jumps move in straight line */
\r
10007 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10008 mid.x = start.x + (finish.x - start.x) / 2;
\r
10009 mid.y = start.y + (finish.y - start.y) / 2;
\r
10011 /* Knight: make straight movement then diagonal */
\r
10012 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10013 mid.x = start.x + (finish.x - start.x) / 2;
\r
10017 mid.y = start.y + (finish.y - start.y) / 2;
\r
10021 /* Don't use as many frames for very short moves */
\r
10022 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10023 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10025 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10027 animInfo.from.x = fromX;
\r
10028 animInfo.from.y = fromY;
\r
10029 animInfo.to.x = toX;
\r
10030 animInfo.to.y = toY;
\r
10031 animInfo.lastpos = start;
\r
10032 animInfo.piece = piece;
\r
10033 for (n = 0; n < nFrames; n++) {
\r
10034 animInfo.pos = frames[n];
\r
10035 DrawPosition(FALSE, NULL);
\r
10036 animInfo.lastpos = animInfo.pos;
\r
10037 Sleep(appData.animSpeed);
\r
10039 animInfo.pos = finish;
\r
10040 DrawPosition(FALSE, NULL);
\r
10042 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10044 animInfo.piece = EmptySquare;
\r
10045 Explode(board, fromX, fromY, toX, toY);
\r
10048 /* Convert board position to corner of screen rect and color */
\r
10051 ScreenSquare(column, row, pt)
\r
10052 int column; int row; POINT * pt;
\r
10055 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10056 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10058 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10059 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10063 /* Generate a series of frame coords from start->mid->finish.
\r
10064 The movement rate doubles until the half way point is
\r
10065 reached, then halves back down to the final destination,
\r
10066 which gives a nice slow in/out effect. The algorithmn
\r
10067 may seem to generate too many intermediates for short
\r
10068 moves, but remember that the purpose is to attract the
\r
10069 viewers attention to the piece about to be moved and
\r
10070 then to where it ends up. Too few frames would be less
\r
10074 Tween(start, mid, finish, factor, frames, nFrames)
\r
10075 POINT * start; POINT * mid;
\r
10076 POINT * finish; int factor;
\r
10077 POINT frames[]; int * nFrames;
\r
10079 int n, fraction = 1, count = 0;
\r
10081 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10082 for (n = 0; n < factor; n++)
\r
10084 for (n = 0; n < factor; n++) {
\r
10085 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10086 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10088 fraction = fraction / 2;
\r
10092 frames[count] = *mid;
\r
10095 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10097 for (n = 0; n < factor; n++) {
\r
10098 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10099 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10101 fraction = fraction * 2;
\r
10103 *nFrames = count;
\r
10107 SettingsPopUp(ChessProgramState *cps)
\r
10108 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10109 EngineOptionsPopup(savedHwnd, cps);
\r
10112 int flock(int fid, int code)
\r
10114 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10116 ov.hEvent = NULL;
\r
10118 ov.OffsetHigh = 0;
\r
10120 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10122 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10123 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10124 default: return -1;
\r
10133 static char col[8][20];
\r
10134 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10136 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10141 ActivateTheme (int new)
\r
10142 { // Redo initialization of features depending on options that can occur in themes
\r
10144 if(new) InitDrawingColors();
\r
10145 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10146 InitDrawingSizes(boardSize, 0);
\r
10147 InvalidateRect(hwndMain, NULL, TRUE);
\r