2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
96 #define DATADIR "~~"
\r
98 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
100 int myrandom(void);
\r
101 void mysrandom(unsigned int seed);
\r
103 extern int whiteFlag, blackFlag;
\r
104 Boolean flipClock = FALSE;
\r
105 extern HANDLE chatHandle[];
\r
106 extern enum ICS_TYPE ics_type;
\r
108 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
109 int MyGetFullPathName P((char *name, char *fullname));
\r
110 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
111 VOID NewVariantPopup(HWND hwnd);
\r
112 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
113 /*char*/int promoChar));
\r
114 void DisplayMove P((int moveNumber));
\r
115 void ChatPopUp P((char *s));
\r
117 ChessSquare piece;
\r
118 POINT pos; /* window coordinates of current pos */
\r
119 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
120 POINT from; /* board coordinates of the piece's orig pos */
\r
121 POINT to; /* board coordinates of the piece's new pos */
\r
124 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
127 POINT start; /* window coordinates of start pos */
\r
128 POINT pos; /* window coordinates of current pos */
\r
129 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
130 POINT from; /* board coordinates of the piece's orig pos */
\r
134 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
137 POINT sq[2]; /* board coordinates of from, to squares */
\r
140 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
145 typedef struct { // [HGM] atomic
\r
146 int fromX, fromY, toX, toY, radius;
\r
149 static ExplodeInfo explodeInfo;
\r
151 /* Window class names */
\r
152 char szAppName[] = "WinBoard";
\r
153 char szConsoleName[] = "WBConsole";
\r
155 /* Title bar text */
\r
156 char szTitle[] = "WinBoard";
\r
157 char szConsoleTitle[] = "I C S Interaction";
\r
160 char *settingsFileName;
\r
161 Boolean saveSettingsOnExit;
\r
162 char installDir[MSG_SIZ];
\r
163 int errorExitStatus;
\r
165 BoardSize boardSize;
\r
166 Boolean chessProgram;
\r
167 //static int boardX, boardY;
\r
168 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
169 int squareSize, lineGap, minorSize;
\r
170 static int winW, winH;
\r
171 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
172 static int logoHeight = 0;
\r
173 static char messageText[MESSAGE_TEXT_MAX];
\r
174 static int clockTimerEvent = 0;
\r
175 static int loadGameTimerEvent = 0;
\r
176 static int analysisTimerEvent = 0;
\r
177 static DelayedEventCallback delayedTimerCallback;
\r
178 static int delayedTimerEvent = 0;
\r
179 static int buttonCount = 2;
\r
180 char *icsTextMenuString;
\r
182 char *firstChessProgramNames;
\r
183 char *secondChessProgramNames;
\r
185 #define PALETTESIZE 256
\r
187 HINSTANCE hInst; /* current instance */
\r
188 Boolean alwaysOnTop = FALSE;
\r
190 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
191 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
192 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
194 ColorClass currentColorClass;
\r
196 static HWND savedHwnd;
\r
197 HWND hCommPort = NULL; /* currently open comm port */
\r
198 static HWND hwndPause; /* pause button */
\r
199 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
200 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
201 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
202 explodeBrush, /* [HGM] atomic */
\r
203 markerBrush[8], /* [HGM] markers */
\r
204 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
205 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
206 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
207 static HPEN gridPen = NULL;
\r
208 static HPEN highlightPen = NULL;
\r
209 static HPEN premovePen = NULL;
\r
210 static NPLOGPALETTE pLogPal;
\r
211 static BOOL paletteChanged = FALSE;
\r
212 static HICON iconWhite, iconBlack, iconCurrent;
\r
213 static int doingSizing = FALSE;
\r
214 static int lastSizing = 0;
\r
215 static int prevStderrPort;
\r
216 static HBITMAP userLogo;
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
229 #if defined(_winmajor)
\r
230 #define oldDialog (_winmajor < 4)
\r
232 #define oldDialog 0
\r
236 #define INTERNATIONAL
\r
238 #ifdef INTERNATIONAL
\r
239 # define _(s) T_(s)
\r
245 # define Translate(x, y)
\r
246 # define LoadLanguageFile(s)
\r
249 #ifdef INTERNATIONAL
\r
251 Boolean barbaric; // flag indicating if translation is needed
\r
253 // list of item numbers used in each dialog (used to alter language at run time)
\r
255 #define ABOUTBOX -1 /* not sure why these are needed */
\r
256 #define ABOUTBOX2 -1
\r
258 int dialogItems[][42] = {
\r
259 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
260 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
261 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
262 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
263 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds,
\r
264 OPT_Ranget, IDOK, IDCANCEL },
\r
265 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
266 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
267 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
268 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
269 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
270 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
271 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
272 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
273 { ABOUTBOX2, IDC_ChessBoard },
\r
274 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
275 OPT_GameListClose, IDC_GameListDoFilter },
\r
276 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
277 { DLG_Error, IDOK },
\r
278 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
279 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
280 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
281 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
282 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
283 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
284 { DLG_IndexNumber, IDC_Index },
\r
285 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
286 { DLG_TypeInName, IDOK, IDCANCEL },
\r
287 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
288 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
289 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
290 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
291 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
292 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
293 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
294 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
295 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
296 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
297 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
298 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
299 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
300 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
301 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
302 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
303 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
304 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
305 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
306 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
307 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
308 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
309 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
310 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
311 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
312 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
313 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
314 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
315 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
316 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
317 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
318 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
319 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
320 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
321 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
322 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
323 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
324 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
325 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
326 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
327 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
328 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
329 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
330 { DLG_MoveHistory },
\r
331 { DLG_EvalGraph },
\r
332 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
333 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
334 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
335 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
336 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
337 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
338 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
339 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
340 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
344 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
345 static int lastChecked;
\r
346 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
347 extern int tinyLayout;
\r
348 extern char * menuBarText[][10];
\r
351 LoadLanguageFile(char *name)
\r
352 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
354 int i=0, j=0, n=0, k;
\r
357 if(!name || name[0] == NULLCHAR) return;
\r
358 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
359 appData.language = oldLanguage;
\r
360 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
361 if((f = fopen(buf, "r")) == NULL) return;
\r
362 while((k = fgetc(f)) != EOF) {
\r
363 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
364 languageBuf[i] = k;
\r
366 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
368 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
369 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
370 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
371 english[j] = languageBuf + n + 1; *p = 0;
\r
372 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
373 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
378 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
380 case 'n': k = '\n'; break;
\r
381 case 'r': k = '\r'; break;
\r
382 case 't': k = '\t'; break;
\r
384 languageBuf[--i] = k;
\r
389 barbaric = (j != 0);
\r
390 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
395 { // return the translation of the given string
\r
396 // efficiency can be improved a lot...
\r
398 static char buf[MSG_SIZ];
\r
399 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
400 if(!barbaric) return s;
\r
401 if(!s) return ""; // sanity
\r
402 while(english[i]) {
\r
403 if(!strcmp(s, english[i])) return foreign[i];
\r
404 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
405 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
414 Translate(HWND hDlg, int dialogID)
\r
415 { // translate all text items in the given dialog
\r
417 char buf[MSG_SIZ], *s;
\r
418 if(!barbaric) return;
\r
419 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
420 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
421 GetWindowText( hDlg, buf, MSG_SIZ );
\r
423 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
424 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
425 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
426 if(strlen(buf) == 0) continue;
\r
428 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
433 TranslateOneMenu(int i, HMENU subMenu)
\r
436 static MENUITEMINFO info;
\r
438 info.cbSize = sizeof(MENUITEMINFO);
\r
439 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
440 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
442 info.dwTypeData = buf;
\r
443 info.cch = sizeof(buf);
\r
444 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
446 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
447 else menuText[i][j] = strdup(buf); // remember original on first change
\r
449 if(buf[0] == NULLCHAR) continue;
\r
450 info.dwTypeData = T_(buf);
\r
451 info.cch = strlen(buf)+1;
\r
452 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
458 TranslateMenus(int addLanguage)
\r
461 WIN32_FIND_DATA fileData;
\r
463 #define IDM_English 1970
\r
465 HMENU mainMenu = GetMenu(hwndMain);
\r
466 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
467 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
468 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
469 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
470 TranslateOneMenu(i, subMenu);
\r
472 DrawMenuBar(hwndMain);
\r
475 if(!addLanguage) return;
\r
476 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
477 HMENU mainMenu = GetMenu(hwndMain);
\r
478 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
479 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
480 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
481 i = 0; lastChecked = IDM_English;
\r
483 char *p, *q = fileData.cFileName;
\r
484 int checkFlag = MF_UNCHECKED;
\r
485 languageFile[i] = strdup(q);
\r
486 if(barbaric && !strcmp(oldLanguage, q)) {
\r
487 checkFlag = MF_CHECKED;
\r
488 lastChecked = IDM_English + i + 1;
\r
489 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
491 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
492 p = strstr(fileData.cFileName, ".lng");
\r
494 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
495 } while(FindNextFile(hFind, &fileData));
\r
502 #define IDM_RecentEngines 3000
\r
505 RecentEngineMenu (char *s)
\r
507 if(appData.icsActive) return;
\r
508 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
509 HMENU mainMenu = GetMenu(hwndMain);
\r
510 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
511 int i=IDM_RecentEngines;
\r
512 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
513 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
515 char *p = strchr(s, '\n');
\r
516 if(p == NULL) return; // malformed!
\r
518 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
532 int cliWidth, cliHeight;
\r
535 SizeInfo sizeInfo[] =
\r
537 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
540 { "petite", 33, 1, 1, 1, 0, 0 },
\r
541 { "slim", 37, 2, 1, 0, 0, 0 },
\r
542 { "small", 40, 2, 1, 0, 0, 0 },
\r
543 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
544 { "middling", 49, 2, 0, 0, 0, 0 },
\r
545 { "average", 54, 2, 0, 0, 0, 0 },
\r
546 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
547 { "medium", 64, 3, 0, 0, 0, 0 },
\r
548 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
549 { "large", 80, 3, 0, 0, 0, 0 },
\r
550 { "big", 87, 3, 0, 0, 0, 0 },
\r
551 { "huge", 95, 3, 0, 0, 0, 0 },
\r
552 { "giant", 108, 3, 0, 0, 0, 0 },
\r
553 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
554 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
555 { NULL, 0, 0, 0, 0, 0, 0 }
\r
558 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
559 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
561 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
562 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
578 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
581 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
590 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
591 #define N_BUTTONS 5
\r
593 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
595 {"<<", IDM_ToStart, NULL, NULL},
\r
596 {"<", IDM_Backward, NULL, NULL},
\r
597 {"P", IDM_Pause, NULL, NULL},
\r
598 {">", IDM_Forward, NULL, NULL},
\r
599 {">>", IDM_ToEnd, NULL, NULL},
\r
602 int tinyLayout = 0, smallLayout = 0;
\r
603 #define MENU_BAR_ITEMS 9
\r
604 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
605 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
606 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
610 MySound sounds[(int)NSoundClasses];
\r
611 MyTextAttribs textAttribs[(int)NColorClasses];
\r
613 MyColorizeAttribs colorizeAttribs[] = {
\r
614 { (COLORREF)0, 0, N_("Shout Text") },
\r
615 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
616 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
617 { (COLORREF)0, 0, N_("Channel Text") },
\r
618 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
619 { (COLORREF)0, 0, N_("Tell Text") },
\r
620 { (COLORREF)0, 0, N_("Challenge Text") },
\r
621 { (COLORREF)0, 0, N_("Request Text") },
\r
622 { (COLORREF)0, 0, N_("Seek Text") },
\r
623 { (COLORREF)0, 0, N_("Normal Text") },
\r
624 { (COLORREF)0, 0, N_("None") }
\r
629 static char *commentTitle;
\r
630 static char *commentText;
\r
631 static int commentIndex;
\r
632 static Boolean editComment = FALSE;
\r
635 char errorTitle[MSG_SIZ];
\r
636 char errorMessage[2*MSG_SIZ];
\r
637 HWND errorDialog = NULL;
\r
638 BOOLEAN moveErrorMessageUp = FALSE;
\r
639 BOOLEAN consoleEcho = TRUE;
\r
640 CHARFORMAT consoleCF;
\r
641 COLORREF consoleBackgroundColor;
\r
643 char *programVersion;
\r
649 typedef int CPKind;
\r
658 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
661 #define INPUT_SOURCE_BUF_SIZE 4096
\r
663 typedef struct _InputSource {
\r
670 char buf[INPUT_SOURCE_BUF_SIZE];
\r
674 InputCallback func;
\r
675 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
679 InputSource *consoleInputSource;
\r
684 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
685 VOID ConsoleCreate();
\r
687 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
689 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
690 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
692 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
693 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
694 void ParseIcsTextMenu(char *icsTextMenuString);
\r
695 VOID PopUpNameDialog(char firstchar);
\r
696 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
700 int GameListOptions();
\r
702 int dummy; // [HGM] for obsolete args
\r
704 HWND hwndMain = NULL; /* root window*/
\r
705 HWND hwndConsole = NULL;
\r
706 HWND commentDialog = NULL;
\r
707 HWND moveHistoryDialog = NULL;
\r
708 HWND evalGraphDialog = NULL;
\r
709 HWND engineOutputDialog = NULL;
\r
710 HWND gameListDialog = NULL;
\r
711 HWND editTagsDialog = NULL;
\r
713 int commentUp = FALSE;
\r
715 WindowPlacement wpMain;
\r
716 WindowPlacement wpConsole;
\r
717 WindowPlacement wpComment;
\r
718 WindowPlacement wpMoveHistory;
\r
719 WindowPlacement wpEvalGraph;
\r
720 WindowPlacement wpEngineOutput;
\r
721 WindowPlacement wpGameList;
\r
722 WindowPlacement wpTags;
\r
724 VOID EngineOptionsPopup(); // [HGM] settings
\r
726 VOID GothicPopUp(char *title, VariantClass variant);
\r
728 * Setting "frozen" should disable all user input other than deleting
\r
729 * the window. We do this while engines are initializing themselves.
\r
731 static int frozen = 0;
\r
732 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
738 if (frozen) return;
\r
740 hmenu = GetMenu(hwndMain);
\r
741 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
742 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
744 DrawMenuBar(hwndMain);
\r
747 /* Undo a FreezeUI */
\r
753 if (!frozen) return;
\r
755 hmenu = GetMenu(hwndMain);
\r
756 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
757 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
759 DrawMenuBar(hwndMain);
\r
762 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
764 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
770 #define JAWS_ALT_INTERCEPT
\r
771 #define JAWS_KBUP_NAVIGATION
\r
772 #define JAWS_KBDOWN_NAVIGATION
\r
773 #define JAWS_MENU_ITEMS
\r
774 #define JAWS_SILENCE
\r
775 #define JAWS_REPLAY
\r
777 #define JAWS_COPYRIGHT
\r
778 #define JAWS_DELETE(X) X
\r
779 #define SAYMACHINEMOVE()
\r
783 /*---------------------------------------------------------------------------*\
\r
787 \*---------------------------------------------------------------------------*/
\r
789 static void HandleMessage P((MSG *message));
\r
790 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
793 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
794 LPSTR lpCmdLine, int nCmdShow)
\r
797 // INITCOMMONCONTROLSEX ex;
\r
801 LoadLibrary("RICHED32.DLL");
\r
802 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
804 if (!InitApplication(hInstance)) {
\r
807 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
814 // InitCommonControlsEx(&ex);
\r
815 InitCommonControls();
\r
817 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
818 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
819 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
821 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
823 while (GetMessage(&msg, /* message structure */
\r
824 NULL, /* handle of window receiving the message */
\r
825 0, /* lowest message to examine */
\r
826 0)) /* highest message to examine */
\r
828 HandleMessage(&msg);
\r
832 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
836 HandleMessage (MSG *message)
\r
838 MSG msg = *message;
\r
840 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
841 // [HGM] navigate: switch between all windows with tab
\r
842 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
843 int i, currentElement = 0;
\r
845 // first determine what element of the chain we come from (if any)
\r
846 if(appData.icsActive) {
\r
847 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
848 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
850 if(engineOutputDialog && EngineOutputIsUp()) {
\r
851 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
852 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
854 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
855 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
857 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
858 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
859 if(msg.hwnd == e1) currentElement = 2; else
\r
860 if(msg.hwnd == e2) currentElement = 3; else
\r
861 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
862 if(msg.hwnd == mh) currentElement = 4; else
\r
863 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
864 if(msg.hwnd == hText) currentElement = 5; else
\r
865 if(msg.hwnd == hInput) currentElement = 6; else
\r
866 for (i = 0; i < N_BUTTONS; i++) {
\r
867 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
870 // determine where to go to
\r
871 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
873 currentElement = (currentElement + direction) % 7;
\r
874 switch(currentElement) {
\r
876 h = hwndMain; break; // passing this case always makes the loop exit
\r
878 h = buttonDesc[0].hwnd; break; // could be NULL
\r
880 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
883 if(!EngineOutputIsUp()) continue;
\r
886 if(!MoveHistoryIsUp()) continue;
\r
888 // case 6: // input to eval graph does not seem to get here!
\r
889 // if(!EvalGraphIsUp()) continue;
\r
890 // h = evalGraphDialog; break;
\r
892 if(!appData.icsActive) continue;
\r
896 if(!appData.icsActive) continue;
\r
902 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
903 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
906 return; // this message now has been processed
\r
910 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
911 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
912 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
913 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
914 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
915 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
916 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
917 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
918 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
920 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
921 for(i=0; i<MAX_CHAT; i++)
\r
922 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
925 if(done) return; // [HGM] chat: end patch
\r
926 TranslateMessage(&msg); /* Translates virtual key codes */
\r
927 DispatchMessage(&msg); /* Dispatches message to window */
\r
933 { /* Dispatch pending messages */
\r
935 while (PeekMessage(&msg, /* message structure */
\r
936 NULL, /* handle of window receiving the message */
\r
937 0, /* lowest message to examine */
\r
938 0, /* highest message to examine */
\r
941 HandleMessage(&msg);
\r
945 /*---------------------------------------------------------------------------*\
\r
947 * Initialization functions
\r
949 \*---------------------------------------------------------------------------*/
\r
953 { // update user logo if necessary
\r
954 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
956 if(appData.autoLogo) {
\r
957 curName = UserName();
\r
958 if(strcmp(curName, oldUserName)) {
\r
959 GetCurrentDirectory(MSG_SIZ, dir);
\r
960 SetCurrentDirectory(installDir);
\r
961 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
962 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
963 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
964 if(userLogo == NULL)
\r
965 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
966 SetCurrentDirectory(dir); /* return to prev directory */
\r
972 InitApplication(HINSTANCE hInstance)
\r
976 /* Fill in window class structure with parameters that describe the */
\r
979 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
980 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
981 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
982 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
983 wc.hInstance = hInstance; /* Owner of this class */
\r
984 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
985 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
986 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
987 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
988 wc.lpszClassName = szAppName; /* Name to register as */
\r
990 /* Register the window class and return success/failure code. */
\r
991 if (!RegisterClass(&wc)) return FALSE;
\r
993 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
994 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
996 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
997 wc.hInstance = hInstance;
\r
998 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
999 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1000 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1001 wc.lpszMenuName = NULL;
\r
1002 wc.lpszClassName = szConsoleName;
\r
1004 if (!RegisterClass(&wc)) return FALSE;
\r
1009 /* Set by InitInstance, used by EnsureOnScreen */
\r
1010 int screenHeight, screenWidth;
\r
1011 RECT screenGeometry;
\r
1014 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1016 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1017 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1018 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1019 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1020 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1021 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1025 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1027 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1028 GetCurrentDirectory(MSG_SIZ, dir);
\r
1029 SetCurrentDirectory(installDir);
\r
1030 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1031 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1033 if (cps->programLogo == NULL && appData.debugMode) {
\r
1034 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1036 } else if(appData.autoLogo) {
\r
1037 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1038 char *opponent = "";
\r
1039 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1040 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1041 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1042 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1043 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1044 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1047 if(appData.directory[n] && appData.directory[n][0]) {
\r
1048 SetCurrentDirectory(appData.directory[n]);
\r
1049 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1052 SetCurrentDirectory(dir); /* return to prev directory */
\r
1058 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1059 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1061 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1062 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1063 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1064 liteBackTextureMode = appData.liteBackTextureMode;
\r
1066 if (liteBackTexture == NULL && appData.debugMode) {
\r
1067 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1071 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1072 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1073 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1074 darkBackTextureMode = appData.darkBackTextureMode;
\r
1076 if (darkBackTexture == NULL && appData.debugMode) {
\r
1077 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1082 #ifndef SM_CXVIRTUALSCREEN
\r
1083 #define SM_CXVIRTUALSCREEN 78
\r
1085 #ifndef SM_CYVIRTUALSCREEN
\r
1086 #define SM_CYVIRTUALSCREEN 79
\r
1088 #ifndef SM_XVIRTUALSCREEN
\r
1089 #define SM_XVIRTUALSCREEN 76
\r
1091 #ifndef SM_YVIRTUALSCREEN
\r
1092 #define SM_YVIRTUALSCREEN 77
\r
1098 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1099 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1100 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1101 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1102 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1103 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1104 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1105 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1109 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1111 HWND hwnd; /* Main window handle. */
\r
1113 WINDOWPLACEMENT wp;
\r
1116 hInst = hInstance; /* Store instance handle in our global variable */
\r
1117 programName = szAppName;
\r
1119 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1120 *filepart = NULLCHAR;
\r
1121 SetCurrentDirectory(installDir);
\r
1123 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1125 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1127 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1128 /* xboard, and older WinBoards, controlled the move sound with the
\r
1129 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1130 always turn the option on (so that the backend will call us),
\r
1131 then let the user turn the sound off by setting it to silence if
\r
1132 desired. To accommodate old winboard.ini files saved by old
\r
1133 versions of WinBoard, we also turn off the sound if the option
\r
1134 was initially set to false. [HGM] taken out of InitAppData */
\r
1135 if (!appData.ringBellAfterMoves) {
\r
1136 sounds[(int)SoundMove].name = strdup("");
\r
1137 appData.ringBellAfterMoves = TRUE;
\r
1139 if (appData.debugMode) {
\r
1140 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1141 setbuf(debugFP, NULL);
\r
1144 LoadLanguageFile(appData.language);
\r
1148 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1149 // InitEngineUCI( installDir, &second );
\r
1151 /* Create a main window for this application instance. */
\r
1152 hwnd = CreateWindow(szAppName, szTitle,
\r
1153 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1154 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1155 NULL, NULL, hInstance, NULL);
\r
1158 /* If window could not be created, return "failure" */
\r
1163 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1164 LoadLogo(&first, 0, FALSE);
\r
1165 LoadLogo(&second, 1, appData.icsActive);
\r
1169 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1170 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1171 iconCurrent = iconWhite;
\r
1172 InitDrawingColors();
\r
1174 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1175 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1176 /* Compute window size for each board size, and use the largest
\r
1177 size that fits on this screen as the default. */
\r
1178 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1179 if (boardSize == (BoardSize)-1 &&
\r
1180 winH <= screenHeight
\r
1181 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1182 && winW <= screenWidth) {
\r
1183 boardSize = (BoardSize)ibs;
\r
1187 InitDrawingSizes(boardSize, 0);
\r
1188 RecentEngineMenu(appData.recentEngineList);
\r
1190 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1192 /* [AS] Load textures if specified */
\r
1195 mysrandom( (unsigned) time(NULL) );
\r
1197 /* [AS] Restore layout */
\r
1198 if( wpMoveHistory.visible ) {
\r
1199 MoveHistoryPopUp();
\r
1202 if( wpEvalGraph.visible ) {
\r
1206 if( wpEngineOutput.visible ) {
\r
1207 EngineOutputPopUp();
\r
1210 /* Make the window visible; update its client area; and return "success" */
\r
1211 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1212 wp.length = sizeof(WINDOWPLACEMENT);
\r
1214 wp.showCmd = nCmdShow;
\r
1215 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1216 wp.rcNormalPosition.left = wpMain.x;
\r
1217 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1218 wp.rcNormalPosition.top = wpMain.y;
\r
1219 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1220 SetWindowPlacement(hwndMain, &wp);
\r
1222 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1224 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1225 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1227 if (hwndConsole) {
\r
1229 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1230 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1232 ShowWindow(hwndConsole, nCmdShow);
\r
1233 SetActiveWindow(hwndConsole);
\r
1235 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1236 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1245 HMENU hmenu = GetMenu(hwndMain);
\r
1247 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1248 MF_BYCOMMAND|((appData.icsActive &&
\r
1249 *appData.icsCommPort != NULLCHAR) ?
\r
1250 MF_ENABLED : MF_GRAYED));
\r
1251 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1252 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1253 MF_CHECKED : MF_UNCHECKED));
\r
1254 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1257 //---------------------------------------------------------------------------------------------------------
\r
1259 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1260 #define XBOARD FALSE
\r
1262 #define OPTCHAR "/"
\r
1263 #define SEPCHAR "="
\r
1264 #define TOPLEVEL 0
\r
1268 // front-end part of option handling
\r
1271 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1273 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1274 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1277 lf->lfEscapement = 0;
\r
1278 lf->lfOrientation = 0;
\r
1279 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1280 lf->lfItalic = mfp->italic;
\r
1281 lf->lfUnderline = mfp->underline;
\r
1282 lf->lfStrikeOut = mfp->strikeout;
\r
1283 lf->lfCharSet = mfp->charset;
\r
1284 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
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 == '+' || IS_SHOGI(gameInfo.variant));
\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
5093 * refresh the tags dialog only if it's visible
\r
5095 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5097 tags = PGNTags(&gameInfo);
\r
5098 TagsPopUp(tags, CmailMsg());
\r
5101 SAY("computer starts playing both sides");
\r
5104 case IDM_AnalysisMode:
\r
5105 if(AnalyzeModeEvent()) {
\r
5106 SAY("analyzing current position");
\r
5110 case IDM_AnalyzeFile:
\r
5111 AnalyzeFileEvent();
\r
5114 case IDM_IcsClient:
\r
5118 case IDM_EditGame:
\r
5119 case IDM_EditGame2:
\r
5124 case IDM_EditPosition:
\r
5125 case IDM_EditPosition2:
\r
5126 EditPositionEvent();
\r
5127 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5130 case IDM_Training:
\r
5134 case IDM_ShowGameList:
\r
5135 ShowGameListProc();
\r
5138 case IDM_EditProgs1:
\r
5139 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5142 case IDM_LoadProg1:
\r
5143 LoadEnginePopUp(hwndMain, 0);
\r
5146 case IDM_LoadProg2:
\r
5147 LoadEnginePopUp(hwndMain, 1);
\r
5150 case IDM_EditServers:
\r
5151 EditTagsPopUp(icsNames, &icsNames);
\r
5154 case IDM_EditTags:
\r
5159 case IDM_EditBook:
\r
5163 case IDM_EditComment:
\r
5165 if (commentUp && editComment) {
\r
5168 EditCommentEvent();
\r
5189 case IDM_CallFlag:
\r
5209 case IDM_StopObserving:
\r
5210 StopObservingEvent();
\r
5213 case IDM_StopExamining:
\r
5214 StopExaminingEvent();
\r
5218 UploadGameEvent();
\r
5221 case IDM_TypeInMove:
\r
5222 TypeInEvent('\000');
\r
5225 case IDM_TypeInName:
\r
5226 PopUpNameDialog('\000');
\r
5229 case IDM_Backward:
\r
5231 SetFocus(hwndMain);
\r
5238 SetFocus(hwndMain);
\r
5243 SetFocus(hwndMain);
\r
5248 SetFocus(hwndMain);
\r
5251 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5252 case OPT_GameListPrev:
\r
5253 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5257 RevertEvent(FALSE);
\r
5260 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5261 RevertEvent(TRUE);
\r
5264 case IDM_TruncateGame:
\r
5265 TruncateGameEvent();
\r
5272 case IDM_RetractMove:
\r
5273 RetractMoveEvent();
\r
5276 case IDM_FlipView:
\r
5277 flipView = !flipView;
\r
5278 DrawPosition(FALSE, NULL);
\r
5281 case IDM_FlipClock:
\r
5282 flipClock = !flipClock;
\r
5283 DisplayBothClocks();
\r
5287 case IDM_MuteSounds:
\r
5288 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5289 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5290 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5293 case IDM_GeneralOptions:
\r
5294 GeneralOptionsPopup(hwnd);
\r
5295 DrawPosition(TRUE, NULL);
\r
5298 case IDM_BoardOptions:
\r
5299 BoardOptionsPopup(hwnd);
\r
5302 case IDM_ThemeOptions:
\r
5303 ThemeOptionsPopup(hwnd);
\r
5306 case IDM_EnginePlayOptions:
\r
5307 EnginePlayOptionsPopup(hwnd);
\r
5310 case IDM_Engine1Options:
\r
5311 EngineOptionsPopup(hwnd, &first);
\r
5314 case IDM_Engine2Options:
\r
5316 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5317 EngineOptionsPopup(hwnd, &second);
\r
5320 case IDM_OptionsUCI:
\r
5321 UciOptionsPopup(hwnd);
\r
5325 TourneyPopup(hwnd);
\r
5328 case IDM_IcsOptions:
\r
5329 IcsOptionsPopup(hwnd);
\r
5333 FontsOptionsPopup(hwnd);
\r
5337 SoundOptionsPopup(hwnd);
\r
5340 case IDM_CommPort:
\r
5341 CommPortOptionsPopup(hwnd);
\r
5344 case IDM_LoadOptions:
\r
5345 LoadOptionsPopup(hwnd);
\r
5348 case IDM_SaveOptions:
\r
5349 SaveOptionsPopup(hwnd);
\r
5352 case IDM_TimeControl:
\r
5353 TimeControlOptionsPopup(hwnd);
\r
5356 case IDM_SaveSettings:
\r
5357 SaveSettings(settingsFileName);
\r
5360 case IDM_SaveSettingsOnExit:
\r
5361 saveSettingsOnExit = !saveSettingsOnExit;
\r
5362 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5363 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5364 MF_CHECKED : MF_UNCHECKED));
\r
5375 case IDM_AboutGame:
\r
5380 appData.debugMode = !appData.debugMode;
\r
5381 if (appData.debugMode) {
\r
5382 char dir[MSG_SIZ];
\r
5383 GetCurrentDirectory(MSG_SIZ, dir);
\r
5384 SetCurrentDirectory(installDir);
\r
5385 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5386 SetCurrentDirectory(dir);
\r
5387 setbuf(debugFP, NULL);
\r
5394 case IDM_HELPCONTENTS:
\r
5395 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5396 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5397 MessageBox (GetFocus(),
\r
5398 _("Unable to activate help"),
\r
5399 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5403 case IDM_HELPSEARCH:
\r
5404 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5405 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5406 MessageBox (GetFocus(),
\r
5407 _("Unable to activate help"),
\r
5408 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5412 case IDM_HELPHELP:
\r
5413 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5414 MessageBox (GetFocus(),
\r
5415 _("Unable to activate help"),
\r
5416 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5421 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5423 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5424 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5425 FreeProcInstance(lpProc);
\r
5428 case IDM_DirectCommand1:
\r
5429 AskQuestionEvent(_("Direct Command"),
\r
5430 _("Send to chess program:"), "", "1");
\r
5432 case IDM_DirectCommand2:
\r
5433 AskQuestionEvent(_("Direct Command"),
\r
5434 _("Send to second chess program:"), "", "2");
\r
5437 case EP_WhitePawn:
\r
5438 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5439 fromX = fromY = -1;
\r
5442 case EP_WhiteKnight:
\r
5443 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5444 fromX = fromY = -1;
\r
5447 case EP_WhiteBishop:
\r
5448 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5449 fromX = fromY = -1;
\r
5452 case EP_WhiteRook:
\r
5453 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5454 fromX = fromY = -1;
\r
5457 case EP_WhiteQueen:
\r
5458 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5459 fromX = fromY = -1;
\r
5462 case EP_WhiteFerz:
\r
5463 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5464 fromX = fromY = -1;
\r
5467 case EP_WhiteWazir:
\r
5468 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5469 fromX = fromY = -1;
\r
5472 case EP_WhiteAlfil:
\r
5473 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5474 fromX = fromY = -1;
\r
5477 case EP_WhiteCannon:
\r
5478 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5479 fromX = fromY = -1;
\r
5482 case EP_WhiteCardinal:
\r
5483 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5484 fromX = fromY = -1;
\r
5487 case EP_WhiteMarshall:
\r
5488 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5489 fromX = fromY = -1;
\r
5492 case EP_WhiteKing:
\r
5493 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5494 fromX = fromY = -1;
\r
5497 case EP_BlackPawn:
\r
5498 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5499 fromX = fromY = -1;
\r
5502 case EP_BlackKnight:
\r
5503 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5504 fromX = fromY = -1;
\r
5507 case EP_BlackBishop:
\r
5508 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5509 fromX = fromY = -1;
\r
5512 case EP_BlackRook:
\r
5513 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5514 fromX = fromY = -1;
\r
5517 case EP_BlackQueen:
\r
5518 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5519 fromX = fromY = -1;
\r
5522 case EP_BlackFerz:
\r
5523 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5524 fromX = fromY = -1;
\r
5527 case EP_BlackWazir:
\r
5528 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5529 fromX = fromY = -1;
\r
5532 case EP_BlackAlfil:
\r
5533 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5534 fromX = fromY = -1;
\r
5537 case EP_BlackCannon:
\r
5538 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5539 fromX = fromY = -1;
\r
5542 case EP_BlackCardinal:
\r
5543 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5544 fromX = fromY = -1;
\r
5547 case EP_BlackMarshall:
\r
5548 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5549 fromX = fromY = -1;
\r
5552 case EP_BlackKing:
\r
5553 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5554 fromX = fromY = -1;
\r
5557 case EP_EmptySquare:
\r
5558 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5559 fromX = fromY = -1;
\r
5562 case EP_ClearBoard:
\r
5563 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5564 fromX = fromY = -1;
\r
5568 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5569 fromX = fromY = -1;
\r
5573 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5574 fromX = fromY = -1;
\r
5578 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5579 fromX = fromY = -1;
\r
5583 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5584 fromX = fromY = -1;
\r
5588 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5589 fromX = fromY = -1;
\r
5593 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5594 fromX = fromY = -1;
\r
5598 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5599 fromX = fromY = -1;
\r
5603 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5604 fromX = fromY = -1;
\r
5608 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5609 fromX = fromY = -1;
\r
5613 barbaric = 0; appData.language = "";
\r
5614 TranslateMenus(0);
\r
5615 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5616 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5617 lastChecked = wmId;
\r
5621 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5622 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5624 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5625 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5626 TranslateMenus(0);
\r
5627 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5628 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5629 lastChecked = wmId;
\r
5632 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5638 case CLOCK_TIMER_ID:
\r
5639 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5640 clockTimerEvent = 0;
\r
5641 DecrementClocks(); /* call into back end */
\r
5643 case LOAD_GAME_TIMER_ID:
\r
5644 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5645 loadGameTimerEvent = 0;
\r
5646 AutoPlayGameLoop(); /* call into back end */
\r
5648 case ANALYSIS_TIMER_ID:
\r
5649 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5650 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5651 AnalysisPeriodicEvent(0);
\r
5653 KillTimer(hwnd, analysisTimerEvent);
\r
5654 analysisTimerEvent = 0;
\r
5657 case DELAYED_TIMER_ID:
\r
5658 KillTimer(hwnd, delayedTimerEvent);
\r
5659 delayedTimerEvent = 0;
\r
5660 delayedTimerCallback();
\r
5665 case WM_USER_Input:
\r
5666 InputEvent(hwnd, message, wParam, lParam);
\r
5669 /* [AS] Also move "attached" child windows */
\r
5670 case WM_WINDOWPOSCHANGING:
\r
5672 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5673 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5675 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5676 /* Window is moving */
\r
5679 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5680 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5681 rcMain.right = wpMain.x + wpMain.width;
\r
5682 rcMain.top = wpMain.y;
\r
5683 rcMain.bottom = wpMain.y + wpMain.height;
\r
5685 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5686 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5687 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5688 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5689 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5690 wpMain.x = lpwp->x;
\r
5691 wpMain.y = lpwp->y;
\r
5696 /* [AS] Snapping */
\r
5697 case WM_ENTERSIZEMOVE:
\r
5698 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5699 if (hwnd == hwndMain) {
\r
5700 doingSizing = TRUE;
\r
5703 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5707 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5708 if (hwnd == hwndMain) {
\r
5709 lastSizing = wParam;
\r
5714 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5715 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5717 case WM_EXITSIZEMOVE:
\r
5718 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5719 if (hwnd == hwndMain) {
\r
5721 doingSizing = FALSE;
\r
5722 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5723 GetClientRect(hwnd, &client);
\r
5724 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5726 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5728 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5731 case WM_DESTROY: /* message: window being destroyed */
\r
5732 PostQuitMessage(0);
\r
5736 if (hwnd == hwndMain) {
\r
5741 default: /* Passes it on if unprocessed */
\r
5742 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5749 /*---------------------------------------------------------------------------*\
\r
5751 * Misc utility routines
\r
5753 \*---------------------------------------------------------------------------*/
\r
5756 * Decent random number generator, at least not as bad as Windows
\r
5757 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5759 unsigned int randstate;
\r
5764 randstate = randstate * 1664525 + 1013904223;
\r
5765 return (int) randstate & 0x7fffffff;
\r
5769 mysrandom(unsigned int seed)
\r
5776 * returns TRUE if user selects a different color, FALSE otherwise
\r
5780 ChangeColor(HWND hwnd, COLORREF *which)
\r
5782 static BOOL firstTime = TRUE;
\r
5783 static DWORD customColors[16];
\r
5785 COLORREF newcolor;
\r
5790 /* Make initial colors in use available as custom colors */
\r
5791 /* Should we put the compiled-in defaults here instead? */
\r
5793 customColors[i++] = lightSquareColor & 0xffffff;
\r
5794 customColors[i++] = darkSquareColor & 0xffffff;
\r
5795 customColors[i++] = whitePieceColor & 0xffffff;
\r
5796 customColors[i++] = blackPieceColor & 0xffffff;
\r
5797 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5798 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5800 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5801 customColors[i++] = textAttribs[ccl].color;
\r
5803 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5804 firstTime = FALSE;
\r
5807 cc.lStructSize = sizeof(cc);
\r
5808 cc.hwndOwner = hwnd;
\r
5809 cc.hInstance = NULL;
\r
5810 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5811 cc.lpCustColors = (LPDWORD) customColors;
\r
5812 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5814 if (!ChooseColor(&cc)) return FALSE;
\r
5816 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5817 if (newcolor == *which) return FALSE;
\r
5818 *which = newcolor;
\r
5822 InitDrawingColors();
\r
5823 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5828 MyLoadSound(MySound *ms)
\r
5834 if (ms->data && ms->flag) free(ms->data);
\r
5837 switch (ms->name[0]) {
\r
5843 /* System sound from Control Panel. Don't preload here. */
\r
5847 if (ms->name[1] == NULLCHAR) {
\r
5848 /* "!" alone = silence */
\r
5851 /* Builtin wave resource. Error if not found. */
\r
5852 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5853 if (h == NULL) break;
\r
5854 ms->data = (void *)LoadResource(hInst, h);
\r
5855 ms->flag = 0; // not maloced, so cannot be freed!
\r
5856 if (h == NULL) break;
\r
5861 /* .wav file. Error if not found. */
\r
5862 f = fopen(ms->name, "rb");
\r
5863 if (f == NULL) break;
\r
5864 if (fstat(fileno(f), &st) < 0) break;
\r
5865 ms->data = malloc(st.st_size);
\r
5867 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5873 char buf[MSG_SIZ];
\r
5874 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5875 DisplayError(buf, GetLastError());
\r
5881 MyPlaySound(MySound *ms)
\r
5883 BOOLEAN ok = FALSE;
\r
5885 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5886 switch (ms->name[0]) {
\r
5888 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5893 /* System sound from Control Panel (deprecated feature).
\r
5894 "$" alone or an unset sound name gets default beep (still in use). */
\r
5895 if (ms->name[1]) {
\r
5896 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5898 if (!ok) ok = MessageBeep(MB_OK);
\r
5901 /* Builtin wave resource, or "!" alone for silence */
\r
5902 if (ms->name[1]) {
\r
5903 if (ms->data == NULL) return FALSE;
\r
5904 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5910 /* .wav file. Error if not found. */
\r
5911 if (ms->data == NULL) return FALSE;
\r
5912 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5915 /* Don't print an error: this can happen innocently if the sound driver
\r
5916 is busy; for instance, if another instance of WinBoard is playing
\r
5917 a sound at about the same time. */
\r
5923 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5926 OPENFILENAME *ofn;
\r
5927 static UINT *number; /* gross that this is static */
\r
5929 switch (message) {
\r
5930 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5931 /* Center the dialog over the application window */
\r
5932 ofn = (OPENFILENAME *) lParam;
\r
5933 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5934 number = (UINT *) ofn->lCustData;
\r
5935 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5939 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5940 Translate(hDlg, 1536);
\r
5941 return FALSE; /* Allow for further processing */
\r
5944 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5945 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5947 return FALSE; /* Allow for further processing */
\r
5953 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5955 static UINT *number;
\r
5956 OPENFILENAME *ofname;
\r
5959 case WM_INITDIALOG:
\r
5960 Translate(hdlg, DLG_IndexNumber);
\r
5961 ofname = (OPENFILENAME *)lParam;
\r
5962 number = (UINT *)(ofname->lCustData);
\r
5965 ofnot = (OFNOTIFY *)lParam;
\r
5966 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5967 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5976 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5977 char *nameFilt, char *dlgTitle, UINT *number,
\r
5978 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5980 OPENFILENAME openFileName;
\r
5981 char buf1[MSG_SIZ];
\r
5984 if (fileName == NULL) fileName = buf1;
\r
5985 if (defName == NULL) {
\r
5986 safeStrCpy(fileName, "*.", 3 );
\r
5987 strcat(fileName, defExt);
\r
5989 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5991 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5992 if (number) *number = 0;
\r
5994 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5995 openFileName.hwndOwner = hwnd;
\r
5996 openFileName.hInstance = (HANDLE) hInst;
\r
5997 openFileName.lpstrFilter = nameFilt;
\r
5998 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5999 openFileName.nMaxCustFilter = 0L;
\r
6000 openFileName.nFilterIndex = 1L;
\r
6001 openFileName.lpstrFile = fileName;
\r
6002 openFileName.nMaxFile = MSG_SIZ;
\r
6003 openFileName.lpstrFileTitle = fileTitle;
\r
6004 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6005 openFileName.lpstrInitialDir = NULL;
\r
6006 openFileName.lpstrTitle = dlgTitle;
\r
6007 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6008 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6009 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6010 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6011 openFileName.nFileOffset = 0;
\r
6012 openFileName.nFileExtension = 0;
\r
6013 openFileName.lpstrDefExt = defExt;
\r
6014 openFileName.lCustData = (LONG) number;
\r
6015 openFileName.lpfnHook = oldDialog ?
\r
6016 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6017 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6019 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6020 GetOpenFileName(&openFileName)) {
\r
6021 /* open the file */
\r
6022 f = fopen(openFileName.lpstrFile, write);
\r
6024 MessageBox(hwnd, _("File open failed"), NULL,
\r
6025 MB_OK|MB_ICONEXCLAMATION);
\r
6029 int err = CommDlgExtendedError();
\r
6030 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6039 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6041 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6044 * Get the first pop-up menu in the menu template. This is the
\r
6045 * menu that TrackPopupMenu displays.
\r
6047 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6048 TranslateOneMenu(10, hmenuTrackPopup);
\r
6050 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6053 * TrackPopup uses screen coordinates, so convert the
\r
6054 * coordinates of the mouse click to screen coordinates.
\r
6056 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6058 /* Draw and track the floating pop-up menu. */
\r
6059 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6060 pt.x, pt.y, 0, hwnd, NULL);
\r
6062 /* Destroy the menu.*/
\r
6063 DestroyMenu(hmenu);
\r
6068 int sizeX, sizeY, newSizeX, newSizeY;
\r
6070 } ResizeEditPlusButtonsClosure;
\r
6073 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6075 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6079 if (hChild == cl->hText) return TRUE;
\r
6080 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6081 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6082 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6083 ScreenToClient(cl->hDlg, &pt);
\r
6084 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6085 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6089 /* Resize a dialog that has a (rich) edit field filling most of
\r
6090 the top, with a row of buttons below */
\r
6092 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6095 int newTextHeight, newTextWidth;
\r
6096 ResizeEditPlusButtonsClosure cl;
\r
6098 /*if (IsIconic(hDlg)) return;*/
\r
6099 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6101 cl.hdwp = BeginDeferWindowPos(8);
\r
6103 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6104 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6105 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6106 if (newTextHeight < 0) {
\r
6107 newSizeY += -newTextHeight;
\r
6108 newTextHeight = 0;
\r
6110 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6111 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6117 cl.newSizeX = newSizeX;
\r
6118 cl.newSizeY = newSizeY;
\r
6119 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6121 EndDeferWindowPos(cl.hdwp);
\r
6124 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6126 RECT rChild, rParent;
\r
6127 int wChild, hChild, wParent, hParent;
\r
6128 int wScreen, hScreen, xNew, yNew;
\r
6131 /* Get the Height and Width of the child window */
\r
6132 GetWindowRect (hwndChild, &rChild);
\r
6133 wChild = rChild.right - rChild.left;
\r
6134 hChild = rChild.bottom - rChild.top;
\r
6136 /* Get the Height and Width of the parent window */
\r
6137 GetWindowRect (hwndParent, &rParent);
\r
6138 wParent = rParent.right - rParent.left;
\r
6139 hParent = rParent.bottom - rParent.top;
\r
6141 /* Get the display limits */
\r
6142 hdc = GetDC (hwndChild);
\r
6143 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6144 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6145 ReleaseDC(hwndChild, hdc);
\r
6147 /* Calculate new X position, then adjust for screen */
\r
6148 xNew = rParent.left + ((wParent - wChild) /2);
\r
6151 } else if ((xNew+wChild) > wScreen) {
\r
6152 xNew = wScreen - wChild;
\r
6155 /* Calculate new Y position, then adjust for screen */
\r
6157 yNew = rParent.top + ((hParent - hChild) /2);
\r
6160 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6165 } else if ((yNew+hChild) > hScreen) {
\r
6166 yNew = hScreen - hChild;
\r
6169 /* Set it, and return */
\r
6170 return SetWindowPos (hwndChild, NULL,
\r
6171 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6174 /* Center one window over another */
\r
6175 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6177 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6180 /*---------------------------------------------------------------------------*\
\r
6182 * Startup Dialog functions
\r
6184 \*---------------------------------------------------------------------------*/
\r
6186 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6188 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6190 while (*cd != NULL) {
\r
6191 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6197 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6199 char buf1[MAX_ARG_LEN];
\r
6202 if (str[0] == '@') {
\r
6203 FILE* f = fopen(str + 1, "r");
\r
6205 DisplayFatalError(str + 1, errno, 2);
\r
6208 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6210 buf1[len] = NULLCHAR;
\r
6214 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6217 char buf[MSG_SIZ];
\r
6218 char *end = strchr(str, '\n');
\r
6219 if (end == NULL) return;
\r
6220 memcpy(buf, str, end - str);
\r
6221 buf[end - str] = NULLCHAR;
\r
6222 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6228 SetStartupDialogEnables(HWND hDlg)
\r
6230 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6231 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6232 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6233 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6234 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6235 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6236 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6237 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6238 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6239 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6240 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6241 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6242 IsDlgButtonChecked(hDlg, OPT_View));
\r
6246 QuoteForFilename(char *filename)
\r
6248 int dquote, space;
\r
6249 dquote = strchr(filename, '"') != NULL;
\r
6250 space = strchr(filename, ' ') != NULL;
\r
6251 if (dquote || space) {
\r
6263 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6265 char buf[MSG_SIZ];
\r
6268 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6269 q = QuoteForFilename(nthcp);
\r
6270 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6271 if (*nthdir != NULLCHAR) {
\r
6272 q = QuoteForFilename(nthdir);
\r
6273 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6275 if (*nthcp == NULLCHAR) {
\r
6276 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6277 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6278 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6279 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6284 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6286 char buf[MSG_SIZ];
\r
6290 switch (message) {
\r
6291 case WM_INITDIALOG:
\r
6292 /* Center the dialog */
\r
6293 CenterWindow (hDlg, GetDesktopWindow());
\r
6294 Translate(hDlg, DLG_Startup);
\r
6295 /* Initialize the dialog items */
\r
6296 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6297 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6298 firstChessProgramNames);
\r
6299 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6300 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6301 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6302 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6303 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6304 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6305 if (*appData.icsHelper != NULLCHAR) {
\r
6306 char *q = QuoteForFilename(appData.icsHelper);
\r
6307 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6309 if (*appData.icsHost == NULLCHAR) {
\r
6310 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6311 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6312 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6313 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6314 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6317 if (appData.icsActive) {
\r
6318 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6320 else if (appData.noChessProgram) {
\r
6321 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6324 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6327 SetStartupDialogEnables(hDlg);
\r
6331 switch (LOWORD(wParam)) {
\r
6333 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6334 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6335 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6337 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6338 ParseArgs(StringGet, &p);
\r
6339 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6340 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6342 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6343 ParseArgs(StringGet, &p);
\r
6344 SwapEngines(singleList); // ... and then make it 'second'
\r
6346 appData.noChessProgram = FALSE;
\r
6347 appData.icsActive = FALSE;
\r
6348 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6349 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6350 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6352 ParseArgs(StringGet, &p);
\r
6353 if (appData.zippyPlay) {
\r
6354 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6355 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6357 ParseArgs(StringGet, &p);
\r
6359 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6360 appData.noChessProgram = TRUE;
\r
6361 appData.icsActive = FALSE;
\r
6363 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6364 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6367 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6368 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6370 ParseArgs(StringGet, &p);
\r
6372 EndDialog(hDlg, TRUE);
\r
6379 case IDM_HELPCONTENTS:
\r
6380 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6381 MessageBox (GetFocus(),
\r
6382 _("Unable to activate help"),
\r
6383 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6388 SetStartupDialogEnables(hDlg);
\r
6396 /*---------------------------------------------------------------------------*\
\r
6398 * About box dialog functions
\r
6400 \*---------------------------------------------------------------------------*/
\r
6402 /* Process messages for "About" dialog box */
\r
6404 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6406 switch (message) {
\r
6407 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6408 /* Center the dialog over the application window */
\r
6409 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6410 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6411 Translate(hDlg, ABOUTBOX);
\r
6415 case WM_COMMAND: /* message: received a command */
\r
6416 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6417 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6418 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6426 /*---------------------------------------------------------------------------*\
\r
6428 * Comment Dialog functions
\r
6430 \*---------------------------------------------------------------------------*/
\r
6433 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6435 static HANDLE hwndText = NULL;
\r
6436 int len, newSizeX, newSizeY;
\r
6437 static int sizeX, sizeY;
\r
6442 switch (message) {
\r
6443 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6444 /* Initialize the dialog items */
\r
6445 Translate(hDlg, DLG_EditComment);
\r
6446 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6447 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6448 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6449 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6450 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6451 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6452 SetWindowText(hDlg, commentTitle);
\r
6453 if (editComment) {
\r
6454 SetFocus(hwndText);
\r
6456 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6458 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6459 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6460 MAKELPARAM(FALSE, 0));
\r
6461 /* Size and position the dialog */
\r
6462 if (!commentDialog) {
\r
6463 commentDialog = hDlg;
\r
6464 GetClientRect(hDlg, &rect);
\r
6465 sizeX = rect.right;
\r
6466 sizeY = rect.bottom;
\r
6467 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6468 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6469 WINDOWPLACEMENT wp;
\r
6470 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6471 wp.length = sizeof(WINDOWPLACEMENT);
\r
6473 wp.showCmd = SW_SHOW;
\r
6474 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6475 wp.rcNormalPosition.left = wpComment.x;
\r
6476 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6477 wp.rcNormalPosition.top = wpComment.y;
\r
6478 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6479 SetWindowPlacement(hDlg, &wp);
\r
6481 GetClientRect(hDlg, &rect);
\r
6482 newSizeX = rect.right;
\r
6483 newSizeY = rect.bottom;
\r
6484 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6485 newSizeX, newSizeY);
\r
6490 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6493 case WM_COMMAND: /* message: received a command */
\r
6494 switch (LOWORD(wParam)) {
\r
6496 if (editComment) {
\r
6498 /* Read changed options from the dialog box */
\r
6499 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6500 len = GetWindowTextLength(hwndText);
\r
6501 str = (char *) malloc(len + 1);
\r
6502 GetWindowText(hwndText, str, len + 1);
\r
6511 ReplaceComment(commentIndex, str);
\r
6518 case OPT_CancelComment:
\r
6522 case OPT_ClearComment:
\r
6523 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6526 case OPT_EditComment:
\r
6527 EditCommentEvent();
\r
6535 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6536 if( wParam == OPT_CommentText ) {
\r
6537 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6539 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6540 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6544 pt.x = LOWORD( lpMF->lParam );
\r
6545 pt.y = HIWORD( lpMF->lParam );
\r
6547 if(lpMF->msg == WM_CHAR) {
\r
6549 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6550 index = sel.cpMin;
\r
6552 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6554 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6555 len = GetWindowTextLength(hwndText);
\r
6556 str = (char *) malloc(len + 1);
\r
6557 GetWindowText(hwndText, str, len + 1);
\r
6558 ReplaceComment(commentIndex, str);
\r
6559 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6560 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6563 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6564 lpMF->msg = WM_USER;
\r
6572 newSizeX = LOWORD(lParam);
\r
6573 newSizeY = HIWORD(lParam);
\r
6574 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6579 case WM_GETMINMAXINFO:
\r
6580 /* Prevent resizing window too small */
\r
6581 mmi = (MINMAXINFO *) lParam;
\r
6582 mmi->ptMinTrackSize.x = 100;
\r
6583 mmi->ptMinTrackSize.y = 100;
\r
6590 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6595 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6597 if (str == NULL) str = "";
\r
6598 p = (char *) malloc(2 * strlen(str) + 2);
\r
6601 if (*str == '\n') *q++ = '\r';
\r
6605 if (commentText != NULL) free(commentText);
\r
6607 commentIndex = index;
\r
6608 commentTitle = title;
\r
6610 editComment = edit;
\r
6612 if (commentDialog) {
\r
6613 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6614 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6616 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6617 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6618 hwndMain, (DLGPROC)lpProc);
\r
6619 FreeProcInstance(lpProc);
\r
6625 /*---------------------------------------------------------------------------*\
\r
6627 * Type-in move dialog functions
\r
6629 \*---------------------------------------------------------------------------*/
\r
6632 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6634 char move[MSG_SIZ];
\r
6637 switch (message) {
\r
6638 case WM_INITDIALOG:
\r
6639 move[0] = (char) lParam;
\r
6640 move[1] = NULLCHAR;
\r
6641 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6642 Translate(hDlg, DLG_TypeInMove);
\r
6643 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6644 SetWindowText(hInput, move);
\r
6646 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6650 switch (LOWORD(wParam)) {
\r
6653 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6654 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6655 TypeInDoneEvent(move);
\r
6656 EndDialog(hDlg, TRUE);
\r
6659 EndDialog(hDlg, FALSE);
\r
6670 PopUpMoveDialog(char firstchar)
\r
6674 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6675 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6676 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6677 FreeProcInstance(lpProc);
\r
6680 /*---------------------------------------------------------------------------*\
\r
6682 * Type-in name dialog functions
\r
6684 \*---------------------------------------------------------------------------*/
\r
6687 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6689 char move[MSG_SIZ];
\r
6692 switch (message) {
\r
6693 case WM_INITDIALOG:
\r
6694 move[0] = (char) lParam;
\r
6695 move[1] = NULLCHAR;
\r
6696 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6697 Translate(hDlg, DLG_TypeInName);
\r
6698 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6699 SetWindowText(hInput, move);
\r
6701 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6705 switch (LOWORD(wParam)) {
\r
6707 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6708 appData.userName = strdup(move);
\r
6711 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6712 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6713 DisplayTitle(move);
\r
6717 EndDialog(hDlg, TRUE);
\r
6720 EndDialog(hDlg, FALSE);
\r
6731 PopUpNameDialog(char firstchar)
\r
6735 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6736 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6737 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6738 FreeProcInstance(lpProc);
\r
6741 /*---------------------------------------------------------------------------*\
\r
6745 \*---------------------------------------------------------------------------*/
\r
6747 /* Nonmodal error box */
\r
6748 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6749 WPARAM wParam, LPARAM lParam);
\r
6752 ErrorPopUp(char *title, char *content)
\r
6756 BOOLEAN modal = hwndMain == NULL;
\r
6774 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6775 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6778 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6780 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6781 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6782 hwndMain, (DLGPROC)lpProc);
\r
6783 FreeProcInstance(lpProc);
\r
6790 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6791 if (errorDialog == NULL) return;
\r
6792 DestroyWindow(errorDialog);
\r
6793 errorDialog = NULL;
\r
6794 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6798 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6802 switch (message) {
\r
6803 case WM_INITDIALOG:
\r
6804 GetWindowRect(hDlg, &rChild);
\r
6807 SetWindowPos(hDlg, NULL, rChild.left,
\r
6808 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6809 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6813 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6814 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6815 and it doesn't work when you resize the dialog.
\r
6816 For now, just give it a default position.
\r
6818 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6819 Translate(hDlg, DLG_Error);
\r
6821 errorDialog = hDlg;
\r
6822 SetWindowText(hDlg, errorTitle);
\r
6823 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6827 switch (LOWORD(wParam)) {
\r
6830 if (errorDialog == hDlg) errorDialog = NULL;
\r
6831 DestroyWindow(hDlg);
\r
6843 HWND gothicDialog = NULL;
\r
6846 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6849 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6851 switch (message) {
\r
6852 case WM_INITDIALOG:
\r
6853 GetWindowRect(hDlg, &rChild);
\r
6855 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6859 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6860 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6861 and it doesn't work when you resize the dialog.
\r
6862 For now, just give it a default position.
\r
6864 gothicDialog = hDlg;
\r
6865 SetWindowText(hDlg, errorTitle);
\r
6866 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6870 switch (LOWORD(wParam)) {
\r
6873 if (errorDialog == hDlg) errorDialog = NULL;
\r
6874 DestroyWindow(hDlg);
\r
6886 GothicPopUp(char *title, VariantClass variant)
\r
6889 static char *lastTitle;
\r
6891 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6892 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6894 if(lastTitle != title && gothicDialog != NULL) {
\r
6895 DestroyWindow(gothicDialog);
\r
6896 gothicDialog = NULL;
\r
6898 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6899 title = lastTitle;
\r
6900 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6901 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6902 hwndMain, (DLGPROC)lpProc);
\r
6903 FreeProcInstance(lpProc);
\r
6908 /*---------------------------------------------------------------------------*\
\r
6910 * Ics Interaction console functions
\r
6912 \*---------------------------------------------------------------------------*/
\r
6914 #define HISTORY_SIZE 64
\r
6915 static char *history[HISTORY_SIZE];
\r
6916 int histIn = 0, histP = 0;
\r
6920 SaveInHistory(char *cmd)
\r
6922 if (history[histIn] != NULL) {
\r
6923 free(history[histIn]);
\r
6924 history[histIn] = NULL;
\r
6926 if (*cmd == NULLCHAR) return;
\r
6927 history[histIn] = StrSave(cmd);
\r
6928 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6929 if (history[histIn] != NULL) {
\r
6930 free(history[histIn]);
\r
6932 history[histIn] = NULL;
\r
6938 PrevInHistory(char *cmd)
\r
6941 if (histP == histIn) {
\r
6942 if (history[histIn] != NULL) free(history[histIn]);
\r
6943 history[histIn] = StrSave(cmd);
\r
6945 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6946 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6948 return history[histP];
\r
6954 if (histP == histIn) return NULL;
\r
6955 histP = (histP + 1) % HISTORY_SIZE;
\r
6956 return history[histP];
\r
6960 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6964 hmenu = LoadMenu(hInst, "TextMenu");
\r
6965 h = GetSubMenu(hmenu, 0);
\r
6967 if (strcmp(e->item, "-") == 0) {
\r
6968 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6969 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6970 int flags = MF_STRING, j = 0;
\r
6971 if (e->item[0] == '|') {
\r
6972 flags |= MF_MENUBARBREAK;
\r
6975 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6976 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6984 WNDPROC consoleTextWindowProc;
\r
6987 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6989 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6990 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6994 SetWindowText(hInput, command);
\r
6996 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6998 sel.cpMin = 999999;
\r
6999 sel.cpMax = 999999;
\r
7000 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7005 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7006 if (sel.cpMin == sel.cpMax) {
\r
7007 /* Expand to surrounding word */
\r
7010 tr.chrg.cpMax = sel.cpMin;
\r
7011 tr.chrg.cpMin = --sel.cpMin;
\r
7012 if (sel.cpMin < 0) break;
\r
7013 tr.lpstrText = name;
\r
7014 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7015 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7019 tr.chrg.cpMin = sel.cpMax;
\r
7020 tr.chrg.cpMax = ++sel.cpMax;
\r
7021 tr.lpstrText = name;
\r
7022 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7023 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7026 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7027 MessageBeep(MB_ICONEXCLAMATION);
\r
7031 tr.lpstrText = name;
\r
7032 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7034 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7035 MessageBeep(MB_ICONEXCLAMATION);
\r
7038 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7041 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7042 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7043 SetWindowText(hInput, buf);
\r
7044 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7046 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7047 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7048 SetWindowText(hInput, buf);
\r
7049 sel.cpMin = 999999;
\r
7050 sel.cpMax = 999999;
\r
7051 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7057 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7062 switch (message) {
\r
7064 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7065 if(wParam=='R') return 0;
\r
7068 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7071 sel.cpMin = 999999;
\r
7072 sel.cpMax = 999999;
\r
7073 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7074 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7079 if(wParam != '\022') {
\r
7080 if (wParam == '\t') {
\r
7081 if (GetKeyState(VK_SHIFT) < 0) {
\r
7083 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7084 if (buttonDesc[0].hwnd) {
\r
7085 SetFocus(buttonDesc[0].hwnd);
\r
7087 SetFocus(hwndMain);
\r
7091 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7094 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7095 JAWS_DELETE( SetFocus(hInput); )
\r
7096 SendMessage(hInput, message, wParam, lParam);
\r
7099 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7101 case WM_RBUTTONDOWN:
\r
7102 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7103 /* Move selection here if it was empty */
\r
7105 pt.x = LOWORD(lParam);
\r
7106 pt.y = HIWORD(lParam);
\r
7107 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7108 if (sel.cpMin == sel.cpMax) {
\r
7109 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7110 sel.cpMax = sel.cpMin;
\r
7111 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7113 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7114 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7116 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7117 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7118 if (sel.cpMin == sel.cpMax) {
\r
7119 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7120 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7122 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7123 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7125 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7126 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7127 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7128 MenuPopup(hwnd, pt, hmenu, -1);
\r
7132 case WM_RBUTTONUP:
\r
7133 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7134 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7135 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7139 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7141 return SendMessage(hInput, message, wParam, lParam);
\r
7142 case WM_MBUTTONDOWN:
\r
7143 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7145 switch (LOWORD(wParam)) {
\r
7146 case IDM_QuickPaste:
\r
7148 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7149 if (sel.cpMin == sel.cpMax) {
\r
7150 MessageBeep(MB_ICONEXCLAMATION);
\r
7153 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7154 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7155 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7160 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7163 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7166 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7170 int i = LOWORD(wParam) - IDM_CommandX;
\r
7171 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7172 icsTextMenuEntry[i].command != NULL) {
\r
7173 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7174 icsTextMenuEntry[i].getname,
\r
7175 icsTextMenuEntry[i].immediate);
\r
7183 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7186 WNDPROC consoleInputWindowProc;
\r
7189 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7191 char buf[MSG_SIZ];
\r
7193 static BOOL sendNextChar = FALSE;
\r
7194 static BOOL quoteNextChar = FALSE;
\r
7195 InputSource *is = consoleInputSource;
\r
7199 switch (message) {
\r
7201 if (!appData.localLineEditing || sendNextChar) {
\r
7202 is->buf[0] = (CHAR) wParam;
\r
7204 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7205 sendNextChar = FALSE;
\r
7208 if (quoteNextChar) {
\r
7209 buf[0] = (char) wParam;
\r
7210 buf[1] = NULLCHAR;
\r
7211 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7212 quoteNextChar = FALSE;
\r
7216 case '\r': /* Enter key */
\r
7217 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7218 if (consoleEcho) SaveInHistory(is->buf);
\r
7219 is->buf[is->count++] = '\n';
\r
7220 is->buf[is->count] = NULLCHAR;
\r
7221 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7222 if (consoleEcho) {
\r
7223 ConsoleOutput(is->buf, is->count, TRUE);
\r
7224 } else if (appData.localLineEditing) {
\r
7225 ConsoleOutput("\n", 1, TRUE);
\r
7228 case '\033': /* Escape key */
\r
7229 SetWindowText(hwnd, "");
\r
7230 cf.cbSize = sizeof(CHARFORMAT);
\r
7231 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7232 if (consoleEcho) {
\r
7233 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7235 cf.crTextColor = COLOR_ECHOOFF;
\r
7237 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7238 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7240 case '\t': /* Tab key */
\r
7241 if (GetKeyState(VK_SHIFT) < 0) {
\r
7243 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7246 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7247 if (buttonDesc[0].hwnd) {
\r
7248 SetFocus(buttonDesc[0].hwnd);
\r
7250 SetFocus(hwndMain);
\r
7254 case '\023': /* Ctrl+S */
\r
7255 sendNextChar = TRUE;
\r
7257 case '\021': /* Ctrl+Q */
\r
7258 quoteNextChar = TRUE;
\r
7268 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7269 p = PrevInHistory(buf);
\r
7271 SetWindowText(hwnd, p);
\r
7272 sel.cpMin = 999999;
\r
7273 sel.cpMax = 999999;
\r
7274 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7279 p = NextInHistory();
\r
7281 SetWindowText(hwnd, p);
\r
7282 sel.cpMin = 999999;
\r
7283 sel.cpMax = 999999;
\r
7284 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7290 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7294 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7298 case WM_MBUTTONDOWN:
\r
7299 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7300 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7302 case WM_RBUTTONUP:
\r
7303 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7304 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7305 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7309 hmenu = LoadMenu(hInst, "InputMenu");
\r
7310 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7311 if (sel.cpMin == sel.cpMax) {
\r
7312 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7313 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7315 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7316 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7318 pt.x = LOWORD(lParam);
\r
7319 pt.y = HIWORD(lParam);
\r
7320 MenuPopup(hwnd, pt, hmenu, -1);
\r
7324 switch (LOWORD(wParam)) {
\r
7326 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7328 case IDM_SelectAll:
\r
7330 sel.cpMax = -1; /*999999?*/
\r
7331 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7334 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7337 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7340 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7345 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7348 #define CO_MAX 100000
\r
7349 #define CO_TRIM 1000
\r
7352 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7354 static SnapData sd;
\r
7355 HWND hText, hInput;
\r
7357 static int sizeX, sizeY;
\r
7358 int newSizeX, newSizeY;
\r
7362 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7363 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7365 switch (message) {
\r
7367 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7369 ENLINK *pLink = (ENLINK*)lParam;
\r
7370 if (pLink->msg == WM_LBUTTONUP)
\r
7374 tr.chrg = pLink->chrg;
\r
7375 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7376 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7377 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7378 free(tr.lpstrText);
\r
7382 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7383 hwndConsole = hDlg;
\r
7385 consoleTextWindowProc = (WNDPROC)
\r
7386 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7387 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7388 consoleInputWindowProc = (WNDPROC)
\r
7389 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7390 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7391 Colorize(ColorNormal, TRUE);
\r
7392 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7393 ChangedConsoleFont();
\r
7394 GetClientRect(hDlg, &rect);
\r
7395 sizeX = rect.right;
\r
7396 sizeY = rect.bottom;
\r
7397 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7398 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7399 WINDOWPLACEMENT wp;
\r
7400 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7401 wp.length = sizeof(WINDOWPLACEMENT);
\r
7403 wp.showCmd = SW_SHOW;
\r
7404 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7405 wp.rcNormalPosition.left = wpConsole.x;
\r
7406 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7407 wp.rcNormalPosition.top = wpConsole.y;
\r
7408 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7409 SetWindowPlacement(hDlg, &wp);
\r
7412 // [HGM] Chessknight's change 2004-07-13
\r
7413 else { /* Determine Defaults */
\r
7414 WINDOWPLACEMENT wp;
\r
7415 wpConsole.x = wpMain.width + 1;
\r
7416 wpConsole.y = wpMain.y;
\r
7417 wpConsole.width = screenWidth - wpMain.width;
\r
7418 wpConsole.height = wpMain.height;
\r
7419 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7420 wp.length = sizeof(WINDOWPLACEMENT);
\r
7422 wp.showCmd = SW_SHOW;
\r
7423 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7424 wp.rcNormalPosition.left = wpConsole.x;
\r
7425 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7426 wp.rcNormalPosition.top = wpConsole.y;
\r
7427 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7428 SetWindowPlacement(hDlg, &wp);
\r
7431 // Allow hText to highlight URLs and send notifications on them
\r
7432 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7433 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7434 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7435 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7449 if (IsIconic(hDlg)) break;
\r
7450 newSizeX = LOWORD(lParam);
\r
7451 newSizeY = HIWORD(lParam);
\r
7452 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7453 RECT rectText, rectInput;
\r
7455 int newTextHeight, newTextWidth;
\r
7456 GetWindowRect(hText, &rectText);
\r
7457 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7458 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7459 if (newTextHeight < 0) {
\r
7460 newSizeY += -newTextHeight;
\r
7461 newTextHeight = 0;
\r
7463 SetWindowPos(hText, NULL, 0, 0,
\r
7464 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7465 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7466 pt.x = rectInput.left;
\r
7467 pt.y = rectInput.top + newSizeY - sizeY;
\r
7468 ScreenToClient(hDlg, &pt);
\r
7469 SetWindowPos(hInput, NULL,
\r
7470 pt.x, pt.y, /* needs client coords */
\r
7471 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7472 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7478 case WM_GETMINMAXINFO:
\r
7479 /* Prevent resizing window too small */
\r
7480 mmi = (MINMAXINFO *) lParam;
\r
7481 mmi->ptMinTrackSize.x = 100;
\r
7482 mmi->ptMinTrackSize.y = 100;
\r
7485 /* [AS] Snapping */
\r
7486 case WM_ENTERSIZEMOVE:
\r
7487 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7490 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7493 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7495 case WM_EXITSIZEMOVE:
\r
7496 UpdateICSWidth(hText);
\r
7497 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7500 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7508 if (hwndConsole) return;
\r
7509 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7510 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7515 ConsoleOutput(char* data, int length, int forceVisible)
\r
7520 char buf[CO_MAX+1];
\r
7523 static int delayLF = 0;
\r
7524 CHARRANGE savesel, sel;
\r
7526 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7534 while (length--) {
\r
7542 } else if (*p == '\007') {
\r
7543 MyPlaySound(&sounds[(int)SoundBell]);
\r
7550 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7551 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7552 /* Save current selection */
\r
7553 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7554 exlen = GetWindowTextLength(hText);
\r
7555 /* Find out whether current end of text is visible */
\r
7556 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7557 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7558 /* Trim existing text if it's too long */
\r
7559 if (exlen + (q - buf) > CO_MAX) {
\r
7560 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7563 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7564 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7566 savesel.cpMin -= trim;
\r
7567 savesel.cpMax -= trim;
\r
7568 if (exlen < 0) exlen = 0;
\r
7569 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7570 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7572 /* Append the new text */
\r
7573 sel.cpMin = exlen;
\r
7574 sel.cpMax = exlen;
\r
7575 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7576 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7577 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7578 if (forceVisible || exlen == 0 ||
\r
7579 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7580 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7581 /* Scroll to make new end of text visible if old end of text
\r
7582 was visible or new text is an echo of user typein */
\r
7583 sel.cpMin = 9999999;
\r
7584 sel.cpMax = 9999999;
\r
7585 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7586 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7587 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7588 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7590 if (savesel.cpMax == exlen || forceVisible) {
\r
7591 /* Move insert point to new end of text if it was at the old
\r
7592 end of text or if the new text is an echo of user typein */
\r
7593 sel.cpMin = 9999999;
\r
7594 sel.cpMax = 9999999;
\r
7595 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7597 /* Restore previous selection */
\r
7598 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7600 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7607 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7611 COLORREF oldFg, oldBg;
\r
7615 if(copyNumber > 1)
\r
7616 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7618 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7619 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7620 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7623 rect.right = x + squareSize;
\r
7625 rect.bottom = y + squareSize;
\r
7628 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7629 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7630 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7631 &rect, str, strlen(str), NULL);
\r
7633 (void) SetTextColor(hdc, oldFg);
\r
7634 (void) SetBkColor(hdc, oldBg);
\r
7635 (void) SelectObject(hdc, oldFont);
\r
7639 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7640 RECT *rect, char *color, char *flagFell)
\r
7644 COLORREF oldFg, oldBg;
\r
7647 if (twoBoards && partnerUp) return;
\r
7648 if (appData.clockMode) {
\r
7650 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7652 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7659 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7660 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7662 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7663 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7665 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7669 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7670 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7671 rect, str, strlen(str), NULL);
\r
7672 if(logoHeight > 0 && appData.clockMode) {
\r
7674 str += strlen(color)+2;
\r
7675 r.top = rect->top + logoHeight/2;
\r
7676 r.left = rect->left;
\r
7677 r.right = rect->right;
\r
7678 r.bottom = rect->bottom;
\r
7679 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7680 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7681 &r, str, strlen(str), NULL);
\r
7683 (void) SetTextColor(hdc, oldFg);
\r
7684 (void) SetBkColor(hdc, oldBg);
\r
7685 (void) SelectObject(hdc, oldFont);
\r
7690 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7696 if( count <= 0 ) {
\r
7697 if (appData.debugMode) {
\r
7698 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7701 return ERROR_INVALID_USER_BUFFER;
\r
7704 ResetEvent(ovl->hEvent);
\r
7705 ovl->Offset = ovl->OffsetHigh = 0;
\r
7706 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7710 err = GetLastError();
\r
7711 if (err == ERROR_IO_PENDING) {
\r
7712 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7716 err = GetLastError();
\r
7723 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7728 ResetEvent(ovl->hEvent);
\r
7729 ovl->Offset = ovl->OffsetHigh = 0;
\r
7730 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7734 err = GetLastError();
\r
7735 if (err == ERROR_IO_PENDING) {
\r
7736 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7740 err = GetLastError();
\r
7747 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7748 void CheckForInputBufferFull( InputSource * is )
\r
7750 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7751 /* Look for end of line */
\r
7752 char * p = is->buf;
\r
7754 while( p < is->next && *p != '\n' ) {
\r
7758 if( p >= is->next ) {
\r
7759 if (appData.debugMode) {
\r
7760 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7763 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7764 is->count = (DWORD) -1;
\r
7765 is->next = is->buf;
\r
7771 InputThread(LPVOID arg)
\r
7776 is = (InputSource *) arg;
\r
7777 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7778 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7779 while (is->hThread != NULL) {
\r
7780 is->error = DoReadFile(is->hFile, is->next,
\r
7781 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7782 &is->count, &ovl);
\r
7783 if (is->error == NO_ERROR) {
\r
7784 is->next += is->count;
\r
7786 if (is->error == ERROR_BROKEN_PIPE) {
\r
7787 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7790 is->count = (DWORD) -1;
\r
7791 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7796 CheckForInputBufferFull( is );
\r
7798 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7800 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7802 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7805 CloseHandle(ovl.hEvent);
\r
7806 CloseHandle(is->hFile);
\r
7808 if (appData.debugMode) {
\r
7809 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7816 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7818 NonOvlInputThread(LPVOID arg)
\r
7825 is = (InputSource *) arg;
\r
7826 while (is->hThread != NULL) {
\r
7827 is->error = ReadFile(is->hFile, is->next,
\r
7828 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7829 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7830 if (is->error == NO_ERROR) {
\r
7831 /* Change CRLF to LF */
\r
7832 if (is->next > is->buf) {
\r
7834 i = is->count + 1;
\r
7842 if (prev == '\r' && *p == '\n') {
\r
7854 if (is->error == ERROR_BROKEN_PIPE) {
\r
7855 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7858 is->count = (DWORD) -1;
\r
7862 CheckForInputBufferFull( is );
\r
7864 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7866 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7868 if (is->count < 0) break; /* Quit on error */
\r
7870 CloseHandle(is->hFile);
\r
7875 SocketInputThread(LPVOID arg)
\r
7879 is = (InputSource *) arg;
\r
7880 while (is->hThread != NULL) {
\r
7881 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7882 if ((int)is->count == SOCKET_ERROR) {
\r
7883 is->count = (DWORD) -1;
\r
7884 is->error = WSAGetLastError();
\r
7886 is->error = NO_ERROR;
\r
7887 is->next += is->count;
\r
7888 if (is->count == 0 && is->second == is) {
\r
7889 /* End of file on stderr; quit with no message */
\r
7893 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7895 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7897 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7903 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7907 is = (InputSource *) lParam;
\r
7908 if (is->lineByLine) {
\r
7909 /* Feed in lines one by one */
\r
7910 char *p = is->buf;
\r
7912 while (q < is->next) {
\r
7913 if (*q++ == '\n') {
\r
7914 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7919 /* Move any partial line to the start of the buffer */
\r
7921 while (p < is->next) {
\r
7926 if (is->error != NO_ERROR || is->count == 0) {
\r
7927 /* Notify backend of the error. Note: If there was a partial
\r
7928 line at the end, it is not flushed through. */
\r
7929 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7932 /* Feed in the whole chunk of input at once */
\r
7933 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7934 is->next = is->buf;
\r
7938 /*---------------------------------------------------------------------------*\
\r
7940 * Menu enables. Used when setting various modes.
\r
7942 \*---------------------------------------------------------------------------*/
\r
7950 GreyRevert(Boolean grey)
\r
7951 { // [HGM] vari: for retracting variations in local mode
\r
7952 HMENU hmenu = GetMenu(hwndMain);
\r
7953 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7954 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7958 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7960 while (enab->item > 0) {
\r
7961 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7966 Enables gnuEnables[] = {
\r
7967 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7968 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7969 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7970 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7971 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7972 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7981 // Needed to switch from ncp to GNU mode on Engine Load
\r
7982 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7983 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7984 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7985 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7986 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7987 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7990 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7991 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7992 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7993 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7994 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7995 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7999 Enables icsEnables[] = {
\r
8000 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8001 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8002 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8003 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8004 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8005 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8006 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8007 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8008 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8016 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8019 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8024 Enables zippyEnables[] = {
\r
8025 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8026 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8027 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8028 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8033 Enables ncpEnables[] = {
\r
8034 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8035 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8036 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8037 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8038 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8039 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8040 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8041 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8042 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8043 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8044 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8045 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8046 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8047 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8048 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8053 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8055 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8059 Enables trainingOnEnables[] = {
\r
8060 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8062 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8063 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8064 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8065 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8066 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8067 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8068 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8072 Enables trainingOffEnables[] = {
\r
8073 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8074 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8075 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8076 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8077 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8078 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8079 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8080 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8081 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8085 /* These modify either ncpEnables or gnuEnables */
\r
8086 Enables cmailEnables[] = {
\r
8087 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8088 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8089 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8090 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8091 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8092 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8093 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8097 Enables machineThinkingEnables[] = {
\r
8098 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8099 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8100 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8101 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8102 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8103 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8104 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8105 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8106 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8107 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8109 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8110 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8111 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8112 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8113 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8117 Enables userThinkingEnables[] = {
\r
8118 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8119 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8120 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8121 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8122 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8123 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8124 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8125 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8126 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8127 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8129 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8130 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8131 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8132 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8133 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8137 /*---------------------------------------------------------------------------*\
\r
8139 * Front-end interface functions exported by XBoard.
\r
8140 * Functions appear in same order as prototypes in frontend.h.
\r
8142 \*---------------------------------------------------------------------------*/
\r
8144 CheckMark(UINT item, int state)
\r
8146 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8152 static UINT prevChecked = 0;
\r
8153 static int prevPausing = 0;
\r
8156 if (pausing != prevPausing) {
\r
8157 prevPausing = pausing;
\r
8158 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8159 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8160 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8163 switch (gameMode) {
\r
8164 case BeginningOfGame:
\r
8165 if (appData.icsActive)
\r
8166 nowChecked = IDM_IcsClient;
\r
8167 else if (appData.noChessProgram)
\r
8168 nowChecked = IDM_EditGame;
\r
8170 nowChecked = IDM_MachineBlack;
\r
8172 case MachinePlaysBlack:
\r
8173 nowChecked = IDM_MachineBlack;
\r
8175 case MachinePlaysWhite:
\r
8176 nowChecked = IDM_MachineWhite;
\r
8178 case TwoMachinesPlay:
\r
8179 nowChecked = IDM_TwoMachines;
\r
8182 nowChecked = IDM_AnalysisMode;
\r
8185 nowChecked = IDM_AnalyzeFile;
\r
8188 nowChecked = IDM_EditGame;
\r
8190 case PlayFromGameFile:
\r
8191 nowChecked = IDM_LoadGame;
\r
8193 case EditPosition:
\r
8194 nowChecked = IDM_EditPosition;
\r
8197 nowChecked = IDM_Training;
\r
8199 case IcsPlayingWhite:
\r
8200 case IcsPlayingBlack:
\r
8201 case IcsObserving:
\r
8203 nowChecked = IDM_IcsClient;
\r
8210 CheckMark(prevChecked, MF_UNCHECKED);
\r
8211 CheckMark(nowChecked, MF_CHECKED);
\r
8212 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8214 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8215 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8216 MF_BYCOMMAND|MF_ENABLED);
\r
8218 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8219 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8222 prevChecked = nowChecked;
\r
8224 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8225 if (appData.icsActive) {
\r
8226 if (appData.icsEngineAnalyze) {
\r
8227 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8229 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8232 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8238 HMENU hmenu = GetMenu(hwndMain);
\r
8239 SetMenuEnables(hmenu, icsEnables);
\r
8240 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8241 MF_BYCOMMAND|MF_ENABLED);
\r
8243 if (appData.zippyPlay) {
\r
8244 SetMenuEnables(hmenu, zippyEnables);
\r
8245 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8246 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8247 MF_BYCOMMAND|MF_ENABLED);
\r
8255 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8261 HMENU hmenu = GetMenu(hwndMain);
\r
8262 SetMenuEnables(hmenu, ncpEnables);
\r
8263 DrawMenuBar(hwndMain);
\r
8269 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8273 SetTrainingModeOn()
\r
8276 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8277 for (i = 0; i < N_BUTTONS; i++) {
\r
8278 if (buttonDesc[i].hwnd != NULL)
\r
8279 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8284 VOID SetTrainingModeOff()
\r
8287 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8288 for (i = 0; i < N_BUTTONS; i++) {
\r
8289 if (buttonDesc[i].hwnd != NULL)
\r
8290 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8296 SetUserThinkingEnables()
\r
8298 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8302 SetMachineThinkingEnables()
\r
8304 HMENU hMenu = GetMenu(hwndMain);
\r
8305 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8307 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8309 if (gameMode == MachinePlaysBlack) {
\r
8310 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8311 } else if (gameMode == MachinePlaysWhite) {
\r
8312 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8313 } else if (gameMode == TwoMachinesPlay) {
\r
8314 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8320 DisplayTitle(char *str)
\r
8322 char title[MSG_SIZ], *host;
\r
8323 if (str[0] != NULLCHAR) {
\r
8324 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8325 } else if (appData.icsActive) {
\r
8326 if (appData.icsCommPort[0] != NULLCHAR)
\r
8329 host = appData.icsHost;
\r
8330 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8331 } else if (appData.noChessProgram) {
\r
8332 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8334 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8335 strcat(title, ": ");
\r
8336 strcat(title, first.tidy);
\r
8338 SetWindowText(hwndMain, title);
\r
8343 DisplayMessage(char *str1, char *str2)
\r
8347 int remain = MESSAGE_TEXT_MAX - 1;
\r
8350 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8351 messageText[0] = NULLCHAR;
\r
8353 len = strlen(str1);
\r
8354 if (len > remain) len = remain;
\r
8355 strncpy(messageText, str1, len);
\r
8356 messageText[len] = NULLCHAR;
\r
8359 if (*str2 && remain >= 2) {
\r
8361 strcat(messageText, " ");
\r
8364 len = strlen(str2);
\r
8365 if (len > remain) len = remain;
\r
8366 strncat(messageText, str2, len);
\r
8368 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8369 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8371 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8375 hdc = GetDC(hwndMain);
\r
8376 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8377 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8378 &messageRect, messageText, strlen(messageText), NULL);
\r
8379 (void) SelectObject(hdc, oldFont);
\r
8380 (void) ReleaseDC(hwndMain, hdc);
\r
8384 DisplayError(char *str, int error)
\r
8386 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8390 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8392 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8393 NULL, error, LANG_NEUTRAL,
\r
8394 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8396 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8398 ErrorMap *em = errmap;
\r
8399 while (em->err != 0 && em->err != error) em++;
\r
8400 if (em->err != 0) {
\r
8401 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8403 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8408 ErrorPopUp(_("Error"), buf);
\r
8413 DisplayMoveError(char *str)
\r
8415 fromX = fromY = -1;
\r
8416 ClearHighlights();
\r
8417 DrawPosition(FALSE, NULL);
\r
8418 if (appData.popupMoveErrors) {
\r
8419 ErrorPopUp(_("Error"), str);
\r
8421 DisplayMessage(str, "");
\r
8422 moveErrorMessageUp = TRUE;
\r
8427 DisplayFatalError(char *str, int error, int exitStatus)
\r
8429 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8431 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8434 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8435 NULL, error, LANG_NEUTRAL,
\r
8436 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8438 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8440 ErrorMap *em = errmap;
\r
8441 while (em->err != 0 && em->err != error) em++;
\r
8442 if (em->err != 0) {
\r
8443 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8445 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8450 if (appData.debugMode) {
\r
8451 fprintf(debugFP, "%s: %s\n", label, str);
\r
8453 if (appData.popupExitMessage) {
\r
8454 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8455 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8457 ExitEvent(exitStatus);
\r
8462 DisplayInformation(char *str)
\r
8464 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8469 DisplayNote(char *str)
\r
8471 ErrorPopUp(_("Note"), str);
\r
8476 char *title, *question, *replyPrefix;
\r
8481 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8483 static QuestionParams *qp;
\r
8484 char reply[MSG_SIZ];
\r
8487 switch (message) {
\r
8488 case WM_INITDIALOG:
\r
8489 qp = (QuestionParams *) lParam;
\r
8490 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8491 Translate(hDlg, DLG_Question);
\r
8492 SetWindowText(hDlg, qp->title);
\r
8493 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8494 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8498 switch (LOWORD(wParam)) {
\r
8500 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8501 if (*reply) strcat(reply, " ");
\r
8502 len = strlen(reply);
\r
8503 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8504 strcat(reply, "\n");
\r
8505 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8506 EndDialog(hDlg, TRUE);
\r
8507 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8510 EndDialog(hDlg, FALSE);
\r
8521 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8523 QuestionParams qp;
\r
8527 qp.question = question;
\r
8528 qp.replyPrefix = replyPrefix;
\r
8530 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8531 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8532 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8533 FreeProcInstance(lpProc);
\r
8536 /* [AS] Pick FRC position */
\r
8537 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8539 static int * lpIndexFRC;
\r
8545 case WM_INITDIALOG:
\r
8546 lpIndexFRC = (int *) lParam;
\r
8548 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8549 Translate(hDlg, DLG_NewGameFRC);
\r
8551 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8552 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8553 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8554 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8559 switch( LOWORD(wParam) ) {
\r
8561 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8562 EndDialog( hDlg, 0 );
\r
8563 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8566 EndDialog( hDlg, 1 );
\r
8568 case IDC_NFG_Edit:
\r
8569 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8570 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8572 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8575 case IDC_NFG_Random:
\r
8576 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8577 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8590 int index = appData.defaultFrcPosition;
\r
8591 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8593 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8595 if( result == 0 ) {
\r
8596 appData.defaultFrcPosition = index;
\r
8602 /* [AS] Game list options. Refactored by HGM */
\r
8604 HWND gameListOptionsDialog;
\r
8606 // low-level front-end: clear text edit / list widget
\r
8611 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8614 // low-level front-end: clear text edit / list widget
\r
8616 GLT_DeSelectList()
\r
8618 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8621 // low-level front-end: append line to text edit / list widget
\r
8623 GLT_AddToList( char *name )
\r
8626 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8630 // low-level front-end: get line from text edit / list widget
\r
8632 GLT_GetFromList( int index, char *name )
\r
8635 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8641 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8643 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8644 int idx2 = idx1 + delta;
\r
8645 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8647 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8650 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8651 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8652 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8653 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8657 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8661 case WM_INITDIALOG:
\r
8662 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8664 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8665 Translate(hDlg, DLG_GameListOptions);
\r
8667 /* Initialize list */
\r
8668 GLT_TagsToList( lpUserGLT );
\r
8670 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8675 switch( LOWORD(wParam) ) {
\r
8678 EndDialog( hDlg, 0 );
\r
8681 EndDialog( hDlg, 1 );
\r
8684 case IDC_GLT_Default:
\r
8685 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8688 case IDC_GLT_Restore:
\r
8689 GLT_TagsToList( appData.gameListTags );
\r
8693 GLT_MoveSelection( hDlg, -1 );
\r
8696 case IDC_GLT_Down:
\r
8697 GLT_MoveSelection( hDlg, +1 );
\r
8707 int GameListOptions()
\r
8710 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8712 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8714 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8716 if( result == 0 ) {
\r
8717 char *oldTags = appData.gameListTags;
\r
8718 /* [AS] Memory leak here! */
\r
8719 appData.gameListTags = strdup( lpUserGLT );
\r
8720 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8721 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8728 DisplayIcsInteractionTitle(char *str)
\r
8730 char consoleTitle[MSG_SIZ];
\r
8732 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8733 SetWindowText(hwndConsole, consoleTitle);
\r
8735 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8736 char buf[MSG_SIZ], *p = buf, *q;
\r
8737 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8739 q = strchr(p, ';');
\r
8741 if(*p) ChatPopUp(p);
\r
8745 SetActiveWindow(hwndMain);
\r
8749 DrawPosition(int fullRedraw, Board board)
\r
8751 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8754 void NotifyFrontendLogin()
\r
8757 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8763 fromX = fromY = -1;
\r
8764 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8765 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8766 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8767 dragInfo.lastpos = dragInfo.pos;
\r
8768 dragInfo.start.x = dragInfo.start.y = -1;
\r
8769 dragInfo.from = dragInfo.start;
\r
8771 DrawPosition(TRUE, NULL);
\r
8778 CommentPopUp(char *title, char *str)
\r
8780 HWND hwnd = GetActiveWindow();
\r
8781 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8783 SetActiveWindow(hwnd);
\r
8787 CommentPopDown(void)
\r
8789 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8790 if (commentDialog) {
\r
8791 ShowWindow(commentDialog, SW_HIDE);
\r
8793 commentUp = FALSE;
\r
8797 EditCommentPopUp(int index, char *title, char *str)
\r
8799 EitherCommentPopUp(index, title, str, TRUE);
\r
8806 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8813 MyPlaySound(&sounds[(int)SoundMove]);
\r
8816 VOID PlayIcsWinSound()
\r
8818 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8821 VOID PlayIcsLossSound()
\r
8823 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8826 VOID PlayIcsDrawSound()
\r
8828 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8831 VOID PlayIcsUnfinishedSound()
\r
8833 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8839 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8845 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8853 consoleEcho = TRUE;
\r
8854 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8855 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8856 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8865 consoleEcho = FALSE;
\r
8866 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8867 /* This works OK: set text and background both to the same color */
\r
8869 cf.crTextColor = COLOR_ECHOOFF;
\r
8870 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8871 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8874 /* No Raw()...? */
\r
8876 void Colorize(ColorClass cc, int continuation)
\r
8878 currentColorClass = cc;
\r
8879 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8880 consoleCF.crTextColor = textAttribs[cc].color;
\r
8881 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8882 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8888 static char buf[MSG_SIZ];
\r
8889 DWORD bufsiz = MSG_SIZ;
\r
8891 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8892 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8894 if (!GetUserName(buf, &bufsiz)) {
\r
8895 /*DisplayError("Error getting user name", GetLastError());*/
\r
8896 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8904 static char buf[MSG_SIZ];
\r
8905 DWORD bufsiz = MSG_SIZ;
\r
8907 if (!GetComputerName(buf, &bufsiz)) {
\r
8908 /*DisplayError("Error getting host name", GetLastError());*/
\r
8909 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8916 ClockTimerRunning()
\r
8918 return clockTimerEvent != 0;
\r
8924 if (clockTimerEvent == 0) return FALSE;
\r
8925 KillTimer(hwndMain, clockTimerEvent);
\r
8926 clockTimerEvent = 0;
\r
8931 StartClockTimer(long millisec)
\r
8933 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8934 (UINT) millisec, NULL);
\r
8938 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8941 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8943 if(appData.noGUI) return;
\r
8944 hdc = GetDC(hwndMain);
\r
8945 if (!IsIconic(hwndMain)) {
\r
8946 DisplayAClock(hdc, timeRemaining, highlight,
\r
8947 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8949 if (highlight && iconCurrent == iconBlack) {
\r
8950 iconCurrent = iconWhite;
\r
8951 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8952 if (IsIconic(hwndMain)) {
\r
8953 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8956 (void) ReleaseDC(hwndMain, hdc);
\r
8958 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8962 DisplayBlackClock(long timeRemaining, int highlight)
\r
8965 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8968 if(appData.noGUI) return;
\r
8969 hdc = GetDC(hwndMain);
\r
8970 if (!IsIconic(hwndMain)) {
\r
8971 DisplayAClock(hdc, timeRemaining, highlight,
\r
8972 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8974 if (highlight && iconCurrent == iconWhite) {
\r
8975 iconCurrent = iconBlack;
\r
8976 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8977 if (IsIconic(hwndMain)) {
\r
8978 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8981 (void) ReleaseDC(hwndMain, hdc);
\r
8983 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8988 LoadGameTimerRunning()
\r
8990 return loadGameTimerEvent != 0;
\r
8994 StopLoadGameTimer()
\r
8996 if (loadGameTimerEvent == 0) return FALSE;
\r
8997 KillTimer(hwndMain, loadGameTimerEvent);
\r
8998 loadGameTimerEvent = 0;
\r
9003 StartLoadGameTimer(long millisec)
\r
9005 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9006 (UINT) millisec, NULL);
\r
9014 char fileTitle[MSG_SIZ];
\r
9016 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9017 f = OpenFileDialog(hwndMain, "a", defName,
\r
9018 appData.oldSaveStyle ? "gam" : "pgn",
\r
9020 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9022 SaveGame(f, 0, "");
\r
9029 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9031 if (delayedTimerEvent != 0) {
\r
9032 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9033 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9035 KillTimer(hwndMain, delayedTimerEvent);
\r
9036 delayedTimerEvent = 0;
\r
9037 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9038 delayedTimerCallback();
\r
9040 delayedTimerCallback = cb;
\r
9041 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9042 (UINT) millisec, NULL);
\r
9045 DelayedEventCallback
\r
9048 if (delayedTimerEvent) {
\r
9049 return delayedTimerCallback;
\r
9056 CancelDelayedEvent()
\r
9058 if (delayedTimerEvent) {
\r
9059 KillTimer(hwndMain, delayedTimerEvent);
\r
9060 delayedTimerEvent = 0;
\r
9064 DWORD GetWin32Priority(int nice)
\r
9065 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9067 REALTIME_PRIORITY_CLASS 0x00000100
\r
9068 HIGH_PRIORITY_CLASS 0x00000080
\r
9069 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9070 NORMAL_PRIORITY_CLASS 0x00000020
\r
9071 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9072 IDLE_PRIORITY_CLASS 0x00000040
\r
9074 if (nice < -15) return 0x00000080;
\r
9075 if (nice < 0) return 0x00008000;
\r
9076 if (nice == 0) return 0x00000020;
\r
9077 if (nice < 15) return 0x00004000;
\r
9078 return 0x00000040;
\r
9081 void RunCommand(char *cmdLine)
\r
9083 /* Now create the child process. */
\r
9084 STARTUPINFO siStartInfo;
\r
9085 PROCESS_INFORMATION piProcInfo;
\r
9087 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9088 siStartInfo.lpReserved = NULL;
\r
9089 siStartInfo.lpDesktop = NULL;
\r
9090 siStartInfo.lpTitle = NULL;
\r
9091 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9092 siStartInfo.cbReserved2 = 0;
\r
9093 siStartInfo.lpReserved2 = NULL;
\r
9094 siStartInfo.hStdInput = NULL;
\r
9095 siStartInfo.hStdOutput = NULL;
\r
9096 siStartInfo.hStdError = NULL;
\r
9098 CreateProcess(NULL,
\r
9099 cmdLine, /* command line */
\r
9100 NULL, /* process security attributes */
\r
9101 NULL, /* primary thread security attrs */
\r
9102 TRUE, /* handles are inherited */
\r
9103 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9104 NULL, /* use parent's environment */
\r
9106 &siStartInfo, /* STARTUPINFO pointer */
\r
9107 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9109 CloseHandle(piProcInfo.hThread);
\r
9112 /* Start a child process running the given program.
\r
9113 The process's standard output can be read from "from", and its
\r
9114 standard input can be written to "to".
\r
9115 Exit with fatal error if anything goes wrong.
\r
9116 Returns an opaque pointer that can be used to destroy the process
\r
9120 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9122 #define BUFSIZE 4096
\r
9124 HANDLE hChildStdinRd, hChildStdinWr,
\r
9125 hChildStdoutRd, hChildStdoutWr;
\r
9126 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9127 SECURITY_ATTRIBUTES saAttr;
\r
9129 PROCESS_INFORMATION piProcInfo;
\r
9130 STARTUPINFO siStartInfo;
\r
9132 char buf[MSG_SIZ];
\r
9135 if (appData.debugMode) {
\r
9136 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9141 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9142 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9143 saAttr.bInheritHandle = TRUE;
\r
9144 saAttr.lpSecurityDescriptor = NULL;
\r
9147 * The steps for redirecting child's STDOUT:
\r
9148 * 1. Create anonymous pipe to be STDOUT for child.
\r
9149 * 2. Create a noninheritable duplicate of read handle,
\r
9150 * and close the inheritable read handle.
\r
9153 /* Create a pipe for the child's STDOUT. */
\r
9154 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9155 return GetLastError();
\r
9158 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9159 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9160 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9161 FALSE, /* not inherited */
\r
9162 DUPLICATE_SAME_ACCESS);
\r
9164 return GetLastError();
\r
9166 CloseHandle(hChildStdoutRd);
\r
9169 * The steps for redirecting child's STDIN:
\r
9170 * 1. Create anonymous pipe to be STDIN for child.
\r
9171 * 2. Create a noninheritable duplicate of write handle,
\r
9172 * and close the inheritable write handle.
\r
9175 /* Create a pipe for the child's STDIN. */
\r
9176 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9177 return GetLastError();
\r
9180 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9181 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9182 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9183 FALSE, /* not inherited */
\r
9184 DUPLICATE_SAME_ACCESS);
\r
9186 return GetLastError();
\r
9188 CloseHandle(hChildStdinWr);
\r
9190 /* Arrange to (1) look in dir for the child .exe file, and
\r
9191 * (2) have dir be the child's working directory. Interpret
\r
9192 * dir relative to the directory WinBoard loaded from. */
\r
9193 GetCurrentDirectory(MSG_SIZ, buf);
\r
9194 SetCurrentDirectory(installDir);
\r
9195 SetCurrentDirectory(dir);
\r
9197 /* Now create the child process. */
\r
9199 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9200 siStartInfo.lpReserved = NULL;
\r
9201 siStartInfo.lpDesktop = NULL;
\r
9202 siStartInfo.lpTitle = NULL;
\r
9203 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9204 siStartInfo.cbReserved2 = 0;
\r
9205 siStartInfo.lpReserved2 = NULL;
\r
9206 siStartInfo.hStdInput = hChildStdinRd;
\r
9207 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9208 siStartInfo.hStdError = hChildStdoutWr;
\r
9210 fSuccess = CreateProcess(NULL,
\r
9211 cmdLine, /* command line */
\r
9212 NULL, /* process security attributes */
\r
9213 NULL, /* primary thread security attrs */
\r
9214 TRUE, /* handles are inherited */
\r
9215 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9216 NULL, /* use parent's environment */
\r
9218 &siStartInfo, /* STARTUPINFO pointer */
\r
9219 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9221 err = GetLastError();
\r
9222 SetCurrentDirectory(buf); /* return to prev directory */
\r
9227 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9228 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9229 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9232 /* Close the handles we don't need in the parent */
\r
9233 CloseHandle(piProcInfo.hThread);
\r
9234 CloseHandle(hChildStdinRd);
\r
9235 CloseHandle(hChildStdoutWr);
\r
9237 /* Prepare return value */
\r
9238 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9239 cp->kind = CPReal;
\r
9240 cp->hProcess = piProcInfo.hProcess;
\r
9241 cp->pid = piProcInfo.dwProcessId;
\r
9242 cp->hFrom = hChildStdoutRdDup;
\r
9243 cp->hTo = hChildStdinWrDup;
\r
9245 *pr = (void *) cp;
\r
9247 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9248 2000 where engines sometimes don't see the initial command(s)
\r
9249 from WinBoard and hang. I don't understand how that can happen,
\r
9250 but the Sleep is harmless, so I've put it in. Others have also
\r
9251 reported what may be the same problem, so hopefully this will fix
\r
9252 it for them too. */
\r
9260 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9262 ChildProc *cp; int result;
\r
9264 cp = (ChildProc *) pr;
\r
9265 if (cp == NULL) return;
\r
9267 switch (cp->kind) {
\r
9269 /* TerminateProcess is considered harmful, so... */
\r
9270 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9271 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9272 /* The following doesn't work because the chess program
\r
9273 doesn't "have the same console" as WinBoard. Maybe
\r
9274 we could arrange for this even though neither WinBoard
\r
9275 nor the chess program uses a console for stdio? */
\r
9276 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9278 /* [AS] Special termination modes for misbehaving programs... */
\r
9279 if( signal & 8 ) {
\r
9280 result = TerminateProcess( cp->hProcess, 0 );
\r
9282 if ( appData.debugMode) {
\r
9283 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9286 else if( signal & 4 ) {
\r
9287 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9289 if( dw != WAIT_OBJECT_0 ) {
\r
9290 result = TerminateProcess( cp->hProcess, 0 );
\r
9292 if ( appData.debugMode) {
\r
9293 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9299 CloseHandle(cp->hProcess);
\r
9303 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9307 closesocket(cp->sock);
\r
9312 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9313 closesocket(cp->sock);
\r
9314 closesocket(cp->sock2);
\r
9322 InterruptChildProcess(ProcRef pr)
\r
9326 cp = (ChildProc *) pr;
\r
9327 if (cp == NULL) return;
\r
9328 switch (cp->kind) {
\r
9330 /* The following doesn't work because the chess program
\r
9331 doesn't "have the same console" as WinBoard. Maybe
\r
9332 we could arrange for this even though neither WinBoard
\r
9333 nor the chess program uses a console for stdio */
\r
9334 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9339 /* Can't interrupt */
\r
9343 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9350 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9352 char cmdLine[MSG_SIZ];
\r
9354 if (port[0] == NULLCHAR) {
\r
9355 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9357 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9359 return StartChildProcess(cmdLine, "", pr);
\r
9363 /* Code to open TCP sockets */
\r
9366 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9372 struct sockaddr_in sa, mysa;
\r
9373 struct hostent FAR *hp;
\r
9374 unsigned short uport;
\r
9375 WORD wVersionRequested;
\r
9378 /* Initialize socket DLL */
\r
9379 wVersionRequested = MAKEWORD(1, 1);
\r
9380 err = WSAStartup(wVersionRequested, &wsaData);
\r
9381 if (err != 0) return err;
\r
9384 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9385 err = WSAGetLastError();
\r
9390 /* Bind local address using (mostly) don't-care values.
\r
9392 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9393 mysa.sin_family = AF_INET;
\r
9394 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9395 uport = (unsigned short) 0;
\r
9396 mysa.sin_port = htons(uport);
\r
9397 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9398 == SOCKET_ERROR) {
\r
9399 err = WSAGetLastError();
\r
9404 /* Resolve remote host name */
\r
9405 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9406 if (!(hp = gethostbyname(host))) {
\r
9407 unsigned int b0, b1, b2, b3;
\r
9409 err = WSAGetLastError();
\r
9411 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9412 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9413 hp->h_addrtype = AF_INET;
\r
9415 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9416 hp->h_addr_list[0] = (char *) malloc(4);
\r
9417 hp->h_addr_list[0][0] = (char) b0;
\r
9418 hp->h_addr_list[0][1] = (char) b1;
\r
9419 hp->h_addr_list[0][2] = (char) b2;
\r
9420 hp->h_addr_list[0][3] = (char) b3;
\r
9426 sa.sin_family = hp->h_addrtype;
\r
9427 uport = (unsigned short) atoi(port);
\r
9428 sa.sin_port = htons(uport);
\r
9429 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9431 /* Make connection */
\r
9432 if (connect(s, (struct sockaddr *) &sa,
\r
9433 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9434 err = WSAGetLastError();
\r
9439 /* Prepare return value */
\r
9440 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9441 cp->kind = CPSock;
\r
9443 *pr = (ProcRef *) cp;
\r
9449 OpenCommPort(char *name, ProcRef *pr)
\r
9454 char fullname[MSG_SIZ];
\r
9456 if (*name != '\\')
\r
9457 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9459 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9461 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9462 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9463 if (h == (HANDLE) -1) {
\r
9464 return GetLastError();
\r
9468 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9470 /* Accumulate characters until a 100ms pause, then parse */
\r
9471 ct.ReadIntervalTimeout = 100;
\r
9472 ct.ReadTotalTimeoutMultiplier = 0;
\r
9473 ct.ReadTotalTimeoutConstant = 0;
\r
9474 ct.WriteTotalTimeoutMultiplier = 0;
\r
9475 ct.WriteTotalTimeoutConstant = 0;
\r
9476 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9478 /* Prepare return value */
\r
9479 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9480 cp->kind = CPComm;
\r
9483 *pr = (ProcRef *) cp;
\r
9489 OpenLoopback(ProcRef *pr)
\r
9491 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9497 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9502 struct sockaddr_in sa, mysa;
\r
9503 struct hostent FAR *hp;
\r
9504 unsigned short uport;
\r
9505 WORD wVersionRequested;
\r
9508 char stderrPortStr[MSG_SIZ];
\r
9510 /* Initialize socket DLL */
\r
9511 wVersionRequested = MAKEWORD(1, 1);
\r
9512 err = WSAStartup(wVersionRequested, &wsaData);
\r
9513 if (err != 0) return err;
\r
9515 /* Resolve remote host name */
\r
9516 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9517 if (!(hp = gethostbyname(host))) {
\r
9518 unsigned int b0, b1, b2, b3;
\r
9520 err = WSAGetLastError();
\r
9522 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9523 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9524 hp->h_addrtype = AF_INET;
\r
9526 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9527 hp->h_addr_list[0] = (char *) malloc(4);
\r
9528 hp->h_addr_list[0][0] = (char) b0;
\r
9529 hp->h_addr_list[0][1] = (char) b1;
\r
9530 hp->h_addr_list[0][2] = (char) b2;
\r
9531 hp->h_addr_list[0][3] = (char) b3;
\r
9537 sa.sin_family = hp->h_addrtype;
\r
9538 uport = (unsigned short) 514;
\r
9539 sa.sin_port = htons(uport);
\r
9540 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9542 /* Bind local socket to unused "privileged" port address
\r
9544 s = INVALID_SOCKET;
\r
9545 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9546 mysa.sin_family = AF_INET;
\r
9547 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9548 for (fromPort = 1023;; fromPort--) {
\r
9549 if (fromPort < 0) {
\r
9551 return WSAEADDRINUSE;
\r
9553 if (s == INVALID_SOCKET) {
\r
9554 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9555 err = WSAGetLastError();
\r
9560 uport = (unsigned short) fromPort;
\r
9561 mysa.sin_port = htons(uport);
\r
9562 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9563 == SOCKET_ERROR) {
\r
9564 err = WSAGetLastError();
\r
9565 if (err == WSAEADDRINUSE) continue;
\r
9569 if (connect(s, (struct sockaddr *) &sa,
\r
9570 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9571 err = WSAGetLastError();
\r
9572 if (err == WSAEADDRINUSE) {
\r
9583 /* Bind stderr local socket to unused "privileged" port address
\r
9585 s2 = INVALID_SOCKET;
\r
9586 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9587 mysa.sin_family = AF_INET;
\r
9588 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9589 for (fromPort = 1023;; fromPort--) {
\r
9590 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9591 if (fromPort < 0) {
\r
9592 (void) closesocket(s);
\r
9594 return WSAEADDRINUSE;
\r
9596 if (s2 == INVALID_SOCKET) {
\r
9597 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9598 err = WSAGetLastError();
\r
9604 uport = (unsigned short) fromPort;
\r
9605 mysa.sin_port = htons(uport);
\r
9606 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9607 == SOCKET_ERROR) {
\r
9608 err = WSAGetLastError();
\r
9609 if (err == WSAEADDRINUSE) continue;
\r
9610 (void) closesocket(s);
\r
9614 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9615 err = WSAGetLastError();
\r
9616 if (err == WSAEADDRINUSE) {
\r
9618 s2 = INVALID_SOCKET;
\r
9621 (void) closesocket(s);
\r
9622 (void) closesocket(s2);
\r
9628 prevStderrPort = fromPort; // remember port used
\r
9629 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9631 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9632 err = WSAGetLastError();
\r
9633 (void) closesocket(s);
\r
9634 (void) closesocket(s2);
\r
9639 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9640 err = WSAGetLastError();
\r
9641 (void) closesocket(s);
\r
9642 (void) closesocket(s2);
\r
9646 if (*user == NULLCHAR) user = UserName();
\r
9647 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9648 err = WSAGetLastError();
\r
9649 (void) closesocket(s);
\r
9650 (void) closesocket(s2);
\r
9654 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9655 err = WSAGetLastError();
\r
9656 (void) closesocket(s);
\r
9657 (void) closesocket(s2);
\r
9662 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9663 err = WSAGetLastError();
\r
9664 (void) closesocket(s);
\r
9665 (void) closesocket(s2);
\r
9669 (void) closesocket(s2); /* Stop listening */
\r
9671 /* Prepare return value */
\r
9672 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9673 cp->kind = CPRcmd;
\r
9676 *pr = (ProcRef *) cp;
\r
9683 AddInputSource(ProcRef pr, int lineByLine,
\r
9684 InputCallback func, VOIDSTAR closure)
\r
9686 InputSource *is, *is2 = NULL;
\r
9687 ChildProc *cp = (ChildProc *) pr;
\r
9689 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9690 is->lineByLine = lineByLine;
\r
9692 is->closure = closure;
\r
9693 is->second = NULL;
\r
9694 is->next = is->buf;
\r
9695 if (pr == NoProc) {
\r
9696 is->kind = CPReal;
\r
9697 consoleInputSource = is;
\r
9699 is->kind = cp->kind;
\r
9701 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9702 we create all threads suspended so that the is->hThread variable can be
\r
9703 safely assigned, then let the threads start with ResumeThread.
\r
9705 switch (cp->kind) {
\r
9707 is->hFile = cp->hFrom;
\r
9708 cp->hFrom = NULL; /* now owned by InputThread */
\r
9710 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9711 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9715 is->hFile = cp->hFrom;
\r
9716 cp->hFrom = NULL; /* now owned by InputThread */
\r
9718 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9719 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9723 is->sock = cp->sock;
\r
9725 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9726 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9730 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9732 is->sock = cp->sock;
\r
9734 is2->sock = cp->sock2;
\r
9735 is2->second = is2;
\r
9737 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9738 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9740 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9741 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9745 if( is->hThread != NULL ) {
\r
9746 ResumeThread( is->hThread );
\r
9749 if( is2 != NULL && is2->hThread != NULL ) {
\r
9750 ResumeThread( is2->hThread );
\r
9754 return (InputSourceRef) is;
\r
9758 RemoveInputSource(InputSourceRef isr)
\r
9762 is = (InputSource *) isr;
\r
9763 is->hThread = NULL; /* tell thread to stop */
\r
9764 CloseHandle(is->hThread);
\r
9765 if (is->second != NULL) {
\r
9766 is->second->hThread = NULL;
\r
9767 CloseHandle(is->second->hThread);
\r
9771 int no_wrap(char *message, int count)
\r
9773 ConsoleOutput(message, count, FALSE);
\r
9778 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9781 int outCount = SOCKET_ERROR;
\r
9782 ChildProc *cp = (ChildProc *) pr;
\r
9783 static OVERLAPPED ovl;
\r
9785 static int line = 0;
\r
9789 if (appData.noJoin || !appData.useInternalWrap)
\r
9790 return no_wrap(message, count);
\r
9793 int width = get_term_width();
\r
9794 int len = wrap(NULL, message, count, width, &line);
\r
9795 char *msg = malloc(len);
\r
9799 return no_wrap(message, count);
\r
9802 dbgchk = wrap(msg, message, count, width, &line);
\r
9803 if (dbgchk != len && appData.debugMode)
\r
9804 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9805 ConsoleOutput(msg, len, FALSE);
\r
9812 if (ovl.hEvent == NULL) {
\r
9813 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9815 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9817 switch (cp->kind) {
\r
9820 outCount = send(cp->sock, message, count, 0);
\r
9821 if (outCount == SOCKET_ERROR) {
\r
9822 *outError = WSAGetLastError();
\r
9824 *outError = NO_ERROR;
\r
9829 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9830 &dOutCount, NULL)) {
\r
9831 *outError = NO_ERROR;
\r
9832 outCount = (int) dOutCount;
\r
9834 *outError = GetLastError();
\r
9839 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9840 &dOutCount, &ovl);
\r
9841 if (*outError == NO_ERROR) {
\r
9842 outCount = (int) dOutCount;
\r
9852 if(n != 0) Sleep(n);
\r
9856 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9859 /* Ignore delay, not implemented for WinBoard */
\r
9860 return OutputToProcess(pr, message, count, outError);
\r
9865 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9866 char *buf, int count, int error)
\r
9868 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9871 /* see wgamelist.c for Game List functions */
\r
9872 /* see wedittags.c for Edit Tags functions */
\r
9879 char buf[MSG_SIZ];
\r
9882 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9883 f = fopen(buf, "r");
\r
9885 ProcessICSInitScript(f);
\r
9895 StartAnalysisClock()
\r
9897 if (analysisTimerEvent) return;
\r
9898 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9899 (UINT) 2000, NULL);
\r
9903 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9905 highlightInfo.sq[0].x = fromX;
\r
9906 highlightInfo.sq[0].y = fromY;
\r
9907 highlightInfo.sq[1].x = toX;
\r
9908 highlightInfo.sq[1].y = toY;
\r
9914 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9915 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9919 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9921 premoveHighlightInfo.sq[0].x = fromX;
\r
9922 premoveHighlightInfo.sq[0].y = fromY;
\r
9923 premoveHighlightInfo.sq[1].x = toX;
\r
9924 premoveHighlightInfo.sq[1].y = toY;
\r
9928 ClearPremoveHighlights()
\r
9930 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9931 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9935 ShutDownFrontEnd()
\r
9937 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9938 DeleteClipboardTempFiles();
\r
9944 if (IsIconic(hwndMain))
\r
9945 ShowWindow(hwndMain, SW_RESTORE);
\r
9947 SetActiveWindow(hwndMain);
\r
9951 * Prototypes for animation support routines
\r
9953 static void ScreenSquare(int column, int row, POINT * pt);
\r
9954 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9955 POINT frames[], int * nFrames);
\r
9961 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9962 { // [HGM] atomic: animate blast wave
\r
9965 explodeInfo.fromX = fromX;
\r
9966 explodeInfo.fromY = fromY;
\r
9967 explodeInfo.toX = toX;
\r
9968 explodeInfo.toY = toY;
\r
9969 for(i=1; i<4*kFactor; i++) {
\r
9970 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9971 DrawPosition(FALSE, board);
\r
9972 Sleep(appData.animSpeed);
\r
9974 explodeInfo.radius = 0;
\r
9975 DrawPosition(TRUE, board);
\r
9979 AnimateMove(board, fromX, fromY, toX, toY)
\r
9986 ChessSquare piece;
\r
9987 int x = toX, y = toY;
\r
9988 POINT start, finish, mid;
\r
9989 POINT frames[kFactor * 2 + 1];
\r
9992 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
9994 if (!appData.animate) return;
\r
9995 if (doingSizing) return;
\r
9996 if (fromY < 0 || fromX < 0) return;
\r
9997 piece = board[fromY][fromX];
\r
9998 if (piece >= EmptySquare) return;
\r
10000 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10004 ScreenSquare(fromX, fromY, &start);
\r
10005 ScreenSquare(toX, toY, &finish);
\r
10007 /* All moves except knight jumps move in straight line */
\r
10008 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10009 mid.x = start.x + (finish.x - start.x) / 2;
\r
10010 mid.y = start.y + (finish.y - start.y) / 2;
\r
10012 /* Knight: make straight movement then diagonal */
\r
10013 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10014 mid.x = start.x + (finish.x - start.x) / 2;
\r
10018 mid.y = start.y + (finish.y - start.y) / 2;
\r
10022 /* Don't use as many frames for very short moves */
\r
10023 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10024 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10026 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10028 animInfo.from.x = fromX;
\r
10029 animInfo.from.y = fromY;
\r
10030 animInfo.to.x = toX;
\r
10031 animInfo.to.y = toY;
\r
10032 animInfo.lastpos = start;
\r
10033 animInfo.piece = piece;
\r
10034 for (n = 0; n < nFrames; n++) {
\r
10035 animInfo.pos = frames[n];
\r
10036 DrawPosition(FALSE, NULL);
\r
10037 animInfo.lastpos = animInfo.pos;
\r
10038 Sleep(appData.animSpeed);
\r
10040 animInfo.pos = finish;
\r
10041 DrawPosition(FALSE, NULL);
\r
10043 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10045 animInfo.piece = EmptySquare;
\r
10046 Explode(board, fromX, fromY, toX, toY);
\r
10049 /* Convert board position to corner of screen rect and color */
\r
10052 ScreenSquare(column, row, pt)
\r
10053 int column; int row; POINT * pt;
\r
10056 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10057 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10059 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10060 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10064 /* Generate a series of frame coords from start->mid->finish.
\r
10065 The movement rate doubles until the half way point is
\r
10066 reached, then halves back down to the final destination,
\r
10067 which gives a nice slow in/out effect. The algorithmn
\r
10068 may seem to generate too many intermediates for short
\r
10069 moves, but remember that the purpose is to attract the
\r
10070 viewers attention to the piece about to be moved and
\r
10071 then to where it ends up. Too few frames would be less
\r
10075 Tween(start, mid, finish, factor, frames, nFrames)
\r
10076 POINT * start; POINT * mid;
\r
10077 POINT * finish; int factor;
\r
10078 POINT frames[]; int * nFrames;
\r
10080 int n, fraction = 1, count = 0;
\r
10082 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10083 for (n = 0; n < factor; n++)
\r
10085 for (n = 0; n < factor; n++) {
\r
10086 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10087 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10089 fraction = fraction / 2;
\r
10093 frames[count] = *mid;
\r
10096 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10098 for (n = 0; n < factor; n++) {
\r
10099 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10100 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10102 fraction = fraction * 2;
\r
10104 *nFrames = count;
\r
10108 SettingsPopUp(ChessProgramState *cps)
\r
10109 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10110 EngineOptionsPopup(savedHwnd, cps);
\r
10113 int flock(int fid, int code)
\r
10115 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10117 ov.hEvent = NULL;
\r
10119 ov.OffsetHigh = 0;
\r
10121 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10123 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10124 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10125 default: return -1;
\r
10134 static char col[8][20];
\r
10135 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10137 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10142 ActivateTheme (int new)
\r
10143 { // Redo initialization of features depending on options that can occur in themes
\r
10145 if(new) InitDrawingColors();
\r
10146 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10147 InitDrawingSizes(boardSize, 0);
\r
10148 InvalidateRect(hwndMain, NULL, TRUE);
\r