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, 2, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 2, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 2, 0, 0 },
\r
540 { "petite", 33, 1, 1, 2, 0, 0 },
\r
541 { "slim", 37, 2, 1, 1, 0, 0 },
\r
542 { "small", 40, 2, 1, 1, 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 == 2 ? 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[3][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_("&Fil"), N_("&Ed"), N_("&Vw"), N_("&Mod"), N_("&Act"), N_("E&ng"), N_("&Opt"), N_("&Hlp"), NULL },
\r
607 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
611 MySound sounds[(int)NSoundClasses];
\r
612 MyTextAttribs textAttribs[(int)NColorClasses];
\r
614 MyColorizeAttribs colorizeAttribs[] = {
\r
615 { (COLORREF)0, 0, N_("Shout Text") },
\r
616 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
617 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
618 { (COLORREF)0, 0, N_("Channel Text") },
\r
619 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
620 { (COLORREF)0, 0, N_("Tell Text") },
\r
621 { (COLORREF)0, 0, N_("Challenge Text") },
\r
622 { (COLORREF)0, 0, N_("Request Text") },
\r
623 { (COLORREF)0, 0, N_("Seek Text") },
\r
624 { (COLORREF)0, 0, N_("Normal Text") },
\r
625 { (COLORREF)0, 0, N_("None") }
\r
630 static char *commentTitle;
\r
631 static char *commentText;
\r
632 static int commentIndex;
\r
633 static Boolean editComment = FALSE;
\r
636 char errorTitle[MSG_SIZ];
\r
637 char errorMessage[2*MSG_SIZ];
\r
638 HWND errorDialog = NULL;
\r
639 BOOLEAN moveErrorMessageUp = FALSE;
\r
640 BOOLEAN consoleEcho = TRUE;
\r
641 CHARFORMAT consoleCF;
\r
642 COLORREF consoleBackgroundColor;
\r
644 char *programVersion;
\r
650 typedef int CPKind;
\r
659 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
662 #define INPUT_SOURCE_BUF_SIZE 4096
\r
664 typedef struct _InputSource {
\r
671 char buf[INPUT_SOURCE_BUF_SIZE];
\r
675 InputCallback func;
\r
676 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
680 InputSource *consoleInputSource;
\r
685 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
686 VOID ConsoleCreate();
\r
688 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
689 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
690 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
691 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
693 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
694 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
695 void ParseIcsTextMenu(char *icsTextMenuString);
\r
696 VOID PopUpNameDialog(char firstchar);
\r
697 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
701 int GameListOptions();
\r
703 int dummy; // [HGM] for obsolete args
\r
705 HWND hwndMain = NULL; /* root window*/
\r
706 HWND hwndConsole = NULL;
\r
707 HWND commentDialog = NULL;
\r
708 HWND moveHistoryDialog = NULL;
\r
709 HWND evalGraphDialog = NULL;
\r
710 HWND engineOutputDialog = NULL;
\r
711 HWND gameListDialog = NULL;
\r
712 HWND editTagsDialog = NULL;
\r
714 int commentUp = FALSE;
\r
716 WindowPlacement wpMain;
\r
717 WindowPlacement wpConsole;
\r
718 WindowPlacement wpComment;
\r
719 WindowPlacement wpMoveHistory;
\r
720 WindowPlacement wpEvalGraph;
\r
721 WindowPlacement wpEngineOutput;
\r
722 WindowPlacement wpGameList;
\r
723 WindowPlacement wpTags;
\r
725 VOID EngineOptionsPopup(); // [HGM] settings
\r
727 VOID GothicPopUp(char *title, VariantClass variant);
\r
729 * Setting "frozen" should disable all user input other than deleting
\r
730 * the window. We do this while engines are initializing themselves.
\r
732 static int frozen = 0;
\r
733 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
739 if (frozen) return;
\r
741 hmenu = GetMenu(hwndMain);
\r
742 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
743 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
745 DrawMenuBar(hwndMain);
\r
748 /* Undo a FreezeUI */
\r
754 if (!frozen) return;
\r
756 hmenu = GetMenu(hwndMain);
\r
757 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
758 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
760 DrawMenuBar(hwndMain);
\r
763 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
765 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
771 #define JAWS_ALT_INTERCEPT
\r
772 #define JAWS_KBUP_NAVIGATION
\r
773 #define JAWS_KBDOWN_NAVIGATION
\r
774 #define JAWS_MENU_ITEMS
\r
775 #define JAWS_SILENCE
\r
776 #define JAWS_REPLAY
\r
778 #define JAWS_COPYRIGHT
\r
779 #define JAWS_DELETE(X) X
\r
780 #define SAYMACHINEMOVE()
\r
784 /*---------------------------------------------------------------------------*\
\r
788 \*---------------------------------------------------------------------------*/
\r
790 static void HandleMessage P((MSG *message));
\r
791 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
794 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
795 LPSTR lpCmdLine, int nCmdShow)
\r
798 // INITCOMMONCONTROLSEX ex;
\r
802 LoadLibrary("RICHED32.DLL");
\r
803 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
805 if (!InitApplication(hInstance)) {
\r
808 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
815 // InitCommonControlsEx(&ex);
\r
816 InitCommonControls();
\r
818 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
819 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
820 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
822 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
824 while (GetMessage(&msg, /* message structure */
\r
825 NULL, /* handle of window receiving the message */
\r
826 0, /* lowest message to examine */
\r
827 0)) /* highest message to examine */
\r
829 HandleMessage(&msg);
\r
833 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
837 HandleMessage (MSG *message)
\r
839 MSG msg = *message;
\r
841 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
842 // [HGM] navigate: switch between all windows with tab
\r
843 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
844 int i, currentElement = 0;
\r
846 // first determine what element of the chain we come from (if any)
\r
847 if(appData.icsActive) {
\r
848 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
849 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
851 if(engineOutputDialog && EngineOutputIsUp()) {
\r
852 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
853 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
855 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
856 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
858 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
859 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
860 if(msg.hwnd == e1) currentElement = 2; else
\r
861 if(msg.hwnd == e2) currentElement = 3; else
\r
862 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
863 if(msg.hwnd == mh) currentElement = 4; else
\r
864 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
865 if(msg.hwnd == hText) currentElement = 5; else
\r
866 if(msg.hwnd == hInput) currentElement = 6; else
\r
867 for (i = 0; i < N_BUTTONS; i++) {
\r
868 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
871 // determine where to go to
\r
872 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
874 currentElement = (currentElement + direction) % 7;
\r
875 switch(currentElement) {
\r
877 h = hwndMain; break; // passing this case always makes the loop exit
\r
879 h = buttonDesc[0].hwnd; break; // could be NULL
\r
881 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
884 if(!EngineOutputIsUp()) continue;
\r
887 if(!MoveHistoryIsUp()) continue;
\r
889 // case 6: // input to eval graph does not seem to get here!
\r
890 // if(!EvalGraphIsUp()) continue;
\r
891 // h = evalGraphDialog; break;
\r
893 if(!appData.icsActive) continue;
\r
897 if(!appData.icsActive) continue;
\r
903 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
904 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
907 return; // this message now has been processed
\r
911 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
912 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
913 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
914 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
915 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
916 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
917 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
918 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
920 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
921 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
922 for(i=0; i<MAX_CHAT; i++)
\r
923 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
926 if(done) return; // [HGM] chat: end patch
\r
927 TranslateMessage(&msg); /* Translates virtual key codes */
\r
928 DispatchMessage(&msg); /* Dispatches message to window */
\r
934 { /* Dispatch pending messages */
\r
936 while (PeekMessage(&msg, /* message structure */
\r
937 NULL, /* handle of window receiving the message */
\r
938 0, /* lowest message to examine */
\r
939 0, /* highest message to examine */
\r
942 HandleMessage(&msg);
\r
946 /*---------------------------------------------------------------------------*\
\r
948 * Initialization functions
\r
950 \*---------------------------------------------------------------------------*/
\r
954 { // update user logo if necessary
\r
955 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
957 if(appData.autoLogo) {
\r
958 curName = UserName();
\r
959 if(strcmp(curName, oldUserName)) {
\r
960 GetCurrentDirectory(MSG_SIZ, dir);
\r
961 SetCurrentDirectory(installDir);
\r
962 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
963 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
964 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
965 if(userLogo == NULL)
\r
966 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
967 SetCurrentDirectory(dir); /* return to prev directory */
\r
973 InitApplication(HINSTANCE hInstance)
\r
977 /* Fill in window class structure with parameters that describe the */
\r
980 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
981 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
982 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
983 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
984 wc.hInstance = hInstance; /* Owner of this class */
\r
985 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
986 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
987 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
988 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
989 wc.lpszClassName = szAppName; /* Name to register as */
\r
991 /* Register the window class and return success/failure code. */
\r
992 if (!RegisterClass(&wc)) return FALSE;
\r
994 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
995 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
997 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
998 wc.hInstance = hInstance;
\r
999 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
1000 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1001 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1002 wc.lpszMenuName = NULL;
\r
1003 wc.lpszClassName = szConsoleName;
\r
1005 if (!RegisterClass(&wc)) return FALSE;
\r
1010 /* Set by InitInstance, used by EnsureOnScreen */
\r
1011 int screenHeight, screenWidth;
\r
1012 RECT screenGeometry;
\r
1015 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1017 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1018 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1019 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1020 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1021 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1022 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1026 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1028 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1029 GetCurrentDirectory(MSG_SIZ, dir);
\r
1030 SetCurrentDirectory(installDir);
\r
1031 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1032 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1034 if (cps->programLogo == NULL && appData.debugMode) {
\r
1035 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1037 } else if(appData.autoLogo) {
\r
1038 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1039 char *opponent = "";
\r
1040 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1041 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1042 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1043 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1044 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1045 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1048 if(appData.directory[n] && appData.directory[n][0]) {
\r
1049 SetCurrentDirectory(appData.directory[n]);
\r
1050 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1053 SetCurrentDirectory(dir); /* return to prev directory */
\r
1059 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1060 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1062 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1063 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1064 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1065 liteBackTextureMode = appData.liteBackTextureMode;
\r
1067 if (liteBackTexture == NULL && appData.debugMode) {
\r
1068 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1072 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1073 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1074 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1075 darkBackTextureMode = appData.darkBackTextureMode;
\r
1077 if (darkBackTexture == NULL && appData.debugMode) {
\r
1078 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1083 #ifndef SM_CXVIRTUALSCREEN
\r
1084 #define SM_CXVIRTUALSCREEN 78
\r
1086 #ifndef SM_CYVIRTUALSCREEN
\r
1087 #define SM_CYVIRTUALSCREEN 79
\r
1089 #ifndef SM_XVIRTUALSCREEN
\r
1090 #define SM_XVIRTUALSCREEN 76
\r
1092 #ifndef SM_YVIRTUALSCREEN
\r
1093 #define SM_YVIRTUALSCREEN 77
\r
1099 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1100 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1101 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1102 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1103 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1104 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1105 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1106 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1110 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1112 HWND hwnd; /* Main window handle. */
\r
1114 WINDOWPLACEMENT wp;
\r
1117 hInst = hInstance; /* Store instance handle in our global variable */
\r
1118 programName = szAppName;
\r
1120 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1121 *filepart = NULLCHAR;
\r
1122 SetCurrentDirectory(installDir);
\r
1124 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1126 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1128 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1129 /* xboard, and older WinBoards, controlled the move sound with the
\r
1130 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1131 always turn the option on (so that the backend will call us),
\r
1132 then let the user turn the sound off by setting it to silence if
\r
1133 desired. To accommodate old winboard.ini files saved by old
\r
1134 versions of WinBoard, we also turn off the sound if the option
\r
1135 was initially set to false. [HGM] taken out of InitAppData */
\r
1136 if (!appData.ringBellAfterMoves) {
\r
1137 sounds[(int)SoundMove].name = strdup("");
\r
1138 appData.ringBellAfterMoves = TRUE;
\r
1140 if (appData.debugMode) {
\r
1141 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1142 setbuf(debugFP, NULL);
\r
1145 LoadLanguageFile(appData.language);
\r
1149 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1150 // InitEngineUCI( installDir, &second );
\r
1152 /* Create a main window for this application instance. */
\r
1153 hwnd = CreateWindow(szAppName, szTitle,
\r
1154 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1155 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1156 NULL, NULL, hInstance, NULL);
\r
1159 /* If window could not be created, return "failure" */
\r
1164 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1165 LoadLogo(&first, 0, FALSE);
\r
1166 LoadLogo(&second, 1, appData.icsActive);
\r
1170 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1171 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1172 iconCurrent = iconWhite;
\r
1173 InitDrawingColors();
\r
1175 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1176 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1177 /* Compute window size for each board size, and use the largest
\r
1178 size that fits on this screen as the default. */
\r
1179 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1180 if (boardSize == (BoardSize)-1 &&
\r
1181 winH <= screenHeight
\r
1182 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1183 && winW <= screenWidth) {
\r
1184 boardSize = (BoardSize)ibs;
\r
1188 InitDrawingSizes(boardSize, 0);
\r
1189 RecentEngineMenu(appData.recentEngineList);
\r
1191 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1193 /* [AS] Load textures if specified */
\r
1196 mysrandom( (unsigned) time(NULL) );
\r
1198 /* [AS] Restore layout */
\r
1199 if( wpMoveHistory.visible ) {
\r
1200 MoveHistoryPopUp();
\r
1203 if( wpEvalGraph.visible ) {
\r
1207 if( wpEngineOutput.visible ) {
\r
1208 EngineOutputPopUp();
\r
1211 /* Make the window visible; update its client area; and return "success" */
\r
1212 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1213 wp.length = sizeof(WINDOWPLACEMENT);
\r
1215 wp.showCmd = nCmdShow;
\r
1216 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1217 wp.rcNormalPosition.left = wpMain.x;
\r
1218 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1219 wp.rcNormalPosition.top = wpMain.y;
\r
1220 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1221 SetWindowPlacement(hwndMain, &wp);
\r
1223 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1225 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1226 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1228 if (hwndConsole) {
\r
1230 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1231 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1233 ShowWindow(hwndConsole, nCmdShow);
\r
1234 SetActiveWindow(hwndConsole);
\r
1236 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1237 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1246 HMENU hmenu = GetMenu(hwndMain);
\r
1248 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1249 MF_BYCOMMAND|((appData.icsActive &&
\r
1250 *appData.icsCommPort != NULLCHAR) ?
\r
1251 MF_ENABLED : MF_GRAYED));
\r
1252 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1253 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1254 MF_CHECKED : MF_UNCHECKED));
\r
1255 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1258 //---------------------------------------------------------------------------------------------------------
\r
1260 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1261 #define XBOARD FALSE
\r
1263 #define OPTCHAR "/"
\r
1264 #define SEPCHAR "="
\r
1265 #define TOPLEVEL 0
\r
1269 // front-end part of option handling
\r
1272 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1274 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1275 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1278 lf->lfEscapement = 0;
\r
1279 lf->lfOrientation = 0;
\r
1280 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1281 lf->lfItalic = mfp->italic;
\r
1282 lf->lfUnderline = mfp->underline;
\r
1283 lf->lfStrikeOut = mfp->strikeout;
\r
1284 lf->lfCharSet = mfp->charset;
\r
1285 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1289 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1290 lf->lfQuality = DEFAULT_QUALITY;
\r
1291 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1292 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1296 CreateFontInMF(MyFont *mf)
\r
1298 LFfromMFP(&mf->lf, &mf->mfp);
\r
1299 if (mf->hf) DeleteObject(mf->hf);
\r
1300 mf->hf = CreateFontIndirect(&mf->lf);
\r
1303 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1305 colorVariable[] = {
\r
1306 &whitePieceColor,
\r
1307 &blackPieceColor,
\r
1308 &lightSquareColor,
\r
1309 &darkSquareColor,
\r
1310 &highlightSquareColor,
\r
1311 &premoveHighlightColor,
\r
1313 &consoleBackgroundColor,
\r
1314 &appData.fontForeColorWhite,
\r
1315 &appData.fontBackColorWhite,
\r
1316 &appData.fontForeColorBlack,
\r
1317 &appData.fontBackColorBlack,
\r
1318 &appData.evalHistColorWhite,
\r
1319 &appData.evalHistColorBlack,
\r
1320 &appData.highlightArrowColor,
\r
1323 /* Command line font name parser. NULL name means do nothing.
\r
1324 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1325 For backward compatibility, syntax without the colon is also
\r
1326 accepted, but font names with digits in them won't work in that case.
\r
1329 ParseFontName(char *name, MyFontParams *mfp)
\r
1332 if (name == NULL) return;
\r
1334 q = strchr(p, ':');
\r
1336 if (q - p >= sizeof(mfp->faceName))
\r
1337 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1338 memcpy(mfp->faceName, p, q - p);
\r
1339 mfp->faceName[q - p] = NULLCHAR;
\r
1342 q = mfp->faceName;
\r
1344 while (*p && !isdigit(*p)) {
\r
1346 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1347 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1349 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1352 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1353 mfp->pointSize = (float) atof(p);
\r
1354 mfp->bold = (strchr(p, 'b') != NULL);
\r
1355 mfp->italic = (strchr(p, 'i') != NULL);
\r
1356 mfp->underline = (strchr(p, 'u') != NULL);
\r
1357 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1358 mfp->charset = DEFAULT_CHARSET;
\r
1359 q = strchr(p, 'c');
\r
1361 mfp->charset = (BYTE) atoi(q+1);
\r
1365 ParseFont(char *name, int number)
\r
1366 { // wrapper to shield back-end from 'font'
\r
1367 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1372 { // in WB we have a 2D array of fonts; this initializes their description
\r
1374 /* Point font array elements to structures and
\r
1375 parse default font names */
\r
1376 for (i=0; i<NUM_FONTS; i++) {
\r
1377 for (j=0; j<NUM_SIZES; j++) {
\r
1378 font[j][i] = &fontRec[j][i];
\r
1379 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1386 { // here we create the actual fonts from the selected descriptions
\r
1388 for (i=0; i<NUM_FONTS; i++) {
\r
1389 for (j=0; j<NUM_SIZES; j++) {
\r
1390 CreateFontInMF(font[j][i]);
\r
1394 /* Color name parser.
\r
1395 X version accepts X color names, but this one
\r
1396 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1398 ParseColorName(char *name)
\r
1400 int red, green, blue, count;
\r
1401 char buf[MSG_SIZ];
\r
1403 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1405 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1406 &red, &green, &blue);
\r
1409 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1410 DisplayError(buf, 0);
\r
1411 return RGB(0, 0, 0);
\r
1413 return PALETTERGB(red, green, blue);
\r
1417 ParseColor(int n, char *name)
\r
1418 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1419 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1423 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1425 char *e = argValue;
\r
1429 if (*e == 'b') eff |= CFE_BOLD;
\r
1430 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1431 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1432 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1433 else if (*e == '#' || isdigit(*e)) break;
\r
1437 *color = ParseColorName(e);
\r
1441 ParseTextAttribs(ColorClass cc, char *s)
\r
1442 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1443 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1444 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1448 ParseBoardSize(void *addr, char *name)
\r
1449 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1450 BoardSize bs = SizeTiny;
\r
1451 while (sizeInfo[bs].name != NULL) {
\r
1452 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1453 *(BoardSize *)addr = bs;
\r
1458 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1463 { // [HGM] import name from appData first
\r
1466 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1467 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1468 textAttribs[cc].sound.data = NULL;
\r
1469 MyLoadSound(&textAttribs[cc].sound);
\r
1471 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1472 textAttribs[cc].sound.name = strdup("");
\r
1473 textAttribs[cc].sound.data = NULL;
\r
1475 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1476 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1477 sounds[sc].data = NULL;
\r
1478 MyLoadSound(&sounds[sc]);
\r
1483 SetCommPortDefaults()
\r
1485 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1486 dcb.DCBlength = sizeof(DCB);
\r
1487 dcb.BaudRate = 9600;
\r
1488 dcb.fBinary = TRUE;
\r
1489 dcb.fParity = FALSE;
\r
1490 dcb.fOutxCtsFlow = FALSE;
\r
1491 dcb.fOutxDsrFlow = FALSE;
\r
1492 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1493 dcb.fDsrSensitivity = FALSE;
\r
1494 dcb.fTXContinueOnXoff = TRUE;
\r
1495 dcb.fOutX = FALSE;
\r
1497 dcb.fNull = FALSE;
\r
1498 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1499 dcb.fAbortOnError = FALSE;
\r
1501 dcb.Parity = SPACEPARITY;
\r
1502 dcb.StopBits = ONESTOPBIT;
\r
1505 // [HGM] args: these three cases taken out to stay in front-end
\r
1507 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1508 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1509 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1510 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1512 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1513 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1514 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1515 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1516 ad->argName, mfp->faceName, mfp->pointSize,
\r
1517 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1518 mfp->bold ? "b" : "",
\r
1519 mfp->italic ? "i" : "",
\r
1520 mfp->underline ? "u" : "",
\r
1521 mfp->strikeout ? "s" : "",
\r
1522 (int)mfp->charset);
\r
1528 { // [HGM] copy the names from the internal WB variables to appData
\r
1531 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1532 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1533 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1534 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1538 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1539 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1540 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1541 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1542 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1543 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1544 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1545 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1546 (ta->effects) ? " " : "",
\r
1547 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1551 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1552 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1553 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1554 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1555 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1559 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1560 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1561 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1565 ParseCommPortSettings(char *s)
\r
1566 { // wrapper to keep dcb from back-end
\r
1567 ParseCommSettings(s, &dcb);
\r
1572 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1573 GetActualPlacement(hwndMain, &wpMain);
\r
1574 GetActualPlacement(hwndConsole, &wpConsole);
\r
1575 GetActualPlacement(commentDialog, &wpComment);
\r
1576 GetActualPlacement(editTagsDialog, &wpTags);
\r
1577 GetActualPlacement(gameListDialog, &wpGameList);
\r
1578 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1579 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1580 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1584 PrintCommPortSettings(FILE *f, char *name)
\r
1585 { // wrapper to shield back-end from DCB
\r
1586 PrintCommSettings(f, name, &dcb);
\r
1590 MySearchPath(char *installDir, char *name, char *fullname)
\r
1592 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1593 if(name[0]== '%') {
\r
1594 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1595 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1596 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1597 *strchr(buf, '%') = 0;
\r
1598 strcat(fullname, getenv(buf));
\r
1599 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1601 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1602 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1603 return (int) strlen(fullname);
\r
1605 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1609 MyGetFullPathName(char *name, char *fullname)
\r
1612 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1617 { // [HGM] args: allows testing if main window is realized from back-end
\r
1618 return hwndMain != NULL;
\r
1622 PopUpStartupDialog()
\r
1626 LoadLanguageFile(appData.language);
\r
1627 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1628 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1629 FreeProcInstance(lpProc);
\r
1632 /*---------------------------------------------------------------------------*\
\r
1634 * GDI board drawing routines
\r
1636 \*---------------------------------------------------------------------------*/
\r
1638 /* [AS] Draw square using background texture */
\r
1639 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1644 return; /* Should never happen! */
\r
1647 SetGraphicsMode( dst, GM_ADVANCED );
\r
1654 /* X reflection */
\r
1659 x.eDx = (FLOAT) dw + dx - 1;
\r
1662 SetWorldTransform( dst, &x );
\r
1665 /* Y reflection */
\r
1671 x.eDy = (FLOAT) dh + dy - 1;
\r
1673 SetWorldTransform( dst, &x );
\r
1681 x.eDx = (FLOAT) dx;
\r
1682 x.eDy = (FLOAT) dy;
\r
1685 SetWorldTransform( dst, &x );
\r
1689 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1697 SetWorldTransform( dst, &x );
\r
1699 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1702 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1704 PM_WP = (int) WhitePawn,
\r
1705 PM_WN = (int) WhiteKnight,
\r
1706 PM_WB = (int) WhiteBishop,
\r
1707 PM_WR = (int) WhiteRook,
\r
1708 PM_WQ = (int) WhiteQueen,
\r
1709 PM_WF = (int) WhiteFerz,
\r
1710 PM_WW = (int) WhiteWazir,
\r
1711 PM_WE = (int) WhiteAlfil,
\r
1712 PM_WM = (int) WhiteMan,
\r
1713 PM_WO = (int) WhiteCannon,
\r
1714 PM_WU = (int) WhiteUnicorn,
\r
1715 PM_WH = (int) WhiteNightrider,
\r
1716 PM_WA = (int) WhiteAngel,
\r
1717 PM_WC = (int) WhiteMarshall,
\r
1718 PM_WAB = (int) WhiteCardinal,
\r
1719 PM_WD = (int) WhiteDragon,
\r
1720 PM_WL = (int) WhiteLance,
\r
1721 PM_WS = (int) WhiteCobra,
\r
1722 PM_WV = (int) WhiteFalcon,
\r
1723 PM_WSG = (int) WhiteSilver,
\r
1724 PM_WG = (int) WhiteGrasshopper,
\r
1725 PM_WK = (int) WhiteKing,
\r
1726 PM_BP = (int) BlackPawn,
\r
1727 PM_BN = (int) BlackKnight,
\r
1728 PM_BB = (int) BlackBishop,
\r
1729 PM_BR = (int) BlackRook,
\r
1730 PM_BQ = (int) BlackQueen,
\r
1731 PM_BF = (int) BlackFerz,
\r
1732 PM_BW = (int) BlackWazir,
\r
1733 PM_BE = (int) BlackAlfil,
\r
1734 PM_BM = (int) BlackMan,
\r
1735 PM_BO = (int) BlackCannon,
\r
1736 PM_BU = (int) BlackUnicorn,
\r
1737 PM_BH = (int) BlackNightrider,
\r
1738 PM_BA = (int) BlackAngel,
\r
1739 PM_BC = (int) BlackMarshall,
\r
1740 PM_BG = (int) BlackGrasshopper,
\r
1741 PM_BAB = (int) BlackCardinal,
\r
1742 PM_BD = (int) BlackDragon,
\r
1743 PM_BL = (int) BlackLance,
\r
1744 PM_BS = (int) BlackCobra,
\r
1745 PM_BV = (int) BlackFalcon,
\r
1746 PM_BSG = (int) BlackSilver,
\r
1747 PM_BK = (int) BlackKing
\r
1750 static HFONT hPieceFont = NULL;
\r
1751 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1752 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1753 static int fontBitmapSquareSize = 0;
\r
1754 static char pieceToFontChar[(int) EmptySquare] =
\r
1755 { 'p', 'n', 'b', 'r', 'q',
\r
1756 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1757 'k', 'o', 'm', 'v', 't', 'w',
\r
1758 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1761 extern BOOL SetCharTable( char *table, const char * map );
\r
1762 /* [HGM] moved to backend.c */
\r
1764 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1767 BYTE r1 = GetRValue( color );
\r
1768 BYTE g1 = GetGValue( color );
\r
1769 BYTE b1 = GetBValue( color );
\r
1775 /* Create a uniform background first */
\r
1776 hbrush = CreateSolidBrush( color );
\r
1777 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1778 FillRect( hdc, &rc, hbrush );
\r
1779 DeleteObject( hbrush );
\r
1782 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1783 int steps = squareSize / 2;
\r
1786 for( i=0; i<steps; i++ ) {
\r
1787 BYTE r = r1 - (r1-r2) * i / steps;
\r
1788 BYTE g = g1 - (g1-g2) * i / steps;
\r
1789 BYTE b = b1 - (b1-b2) * i / steps;
\r
1791 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1792 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1793 FillRect( hdc, &rc, hbrush );
\r
1794 DeleteObject(hbrush);
\r
1797 else if( mode == 2 ) {
\r
1798 /* Diagonal gradient, good more or less for every piece */
\r
1799 POINT triangle[3];
\r
1800 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1801 HBRUSH hbrush_old;
\r
1802 int steps = squareSize;
\r
1805 triangle[0].x = squareSize - steps;
\r
1806 triangle[0].y = squareSize;
\r
1807 triangle[1].x = squareSize;
\r
1808 triangle[1].y = squareSize;
\r
1809 triangle[2].x = squareSize;
\r
1810 triangle[2].y = squareSize - steps;
\r
1812 for( i=0; i<steps; i++ ) {
\r
1813 BYTE r = r1 - (r1-r2) * i / steps;
\r
1814 BYTE g = g1 - (g1-g2) * i / steps;
\r
1815 BYTE b = b1 - (b1-b2) * i / steps;
\r
1817 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1818 hbrush_old = SelectObject( hdc, hbrush );
\r
1819 Polygon( hdc, triangle, 3 );
\r
1820 SelectObject( hdc, hbrush_old );
\r
1821 DeleteObject(hbrush);
\r
1826 SelectObject( hdc, hpen );
\r
1831 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1832 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1833 piece: follow the steps as explained below.
\r
1835 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1839 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1845 int backColor = whitePieceColor;
\r
1846 int foreColor = blackPieceColor;
\r
1848 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1849 backColor = appData.fontBackColorWhite;
\r
1850 foreColor = appData.fontForeColorWhite;
\r
1852 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1853 backColor = appData.fontBackColorBlack;
\r
1854 foreColor = appData.fontForeColorBlack;
\r
1858 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1860 hbm_old = SelectObject( hdc, hbm );
\r
1864 rc.right = squareSize;
\r
1865 rc.bottom = squareSize;
\r
1867 /* Step 1: background is now black */
\r
1868 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1870 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1872 pt.x = (squareSize - sz.cx) / 2;
\r
1873 pt.y = (squareSize - sz.cy) / 2;
\r
1875 SetBkMode( hdc, TRANSPARENT );
\r
1876 SetTextColor( hdc, chroma );
\r
1877 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1878 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1880 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1881 /* Step 3: the area outside the piece is filled with white */
\r
1882 // FloodFill( hdc, 0, 0, chroma );
\r
1883 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1884 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1885 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1886 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1887 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1889 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1890 but if the start point is not inside the piece we're lost!
\r
1891 There should be a better way to do this... if we could create a region or path
\r
1892 from the fill operation we would be fine for example.
\r
1894 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1895 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1897 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1898 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1899 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1901 SelectObject( dc2, bm2 );
\r
1902 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1903 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1904 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1905 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1906 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1909 DeleteObject( bm2 );
\r
1912 SetTextColor( hdc, 0 );
\r
1914 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1915 draw the piece again in black for safety.
\r
1917 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1919 SelectObject( hdc, hbm_old );
\r
1921 if( hPieceMask[index] != NULL ) {
\r
1922 DeleteObject( hPieceMask[index] );
\r
1925 hPieceMask[index] = hbm;
\r
1928 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1930 SelectObject( hdc, hbm );
\r
1933 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1934 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1935 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1937 SelectObject( dc1, hPieceMask[index] );
\r
1938 SelectObject( dc2, bm2 );
\r
1939 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1940 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1943 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1944 the piece background and deletes (makes transparent) the rest.
\r
1945 Thanks to that mask, we are free to paint the background with the greates
\r
1946 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1947 We use this, to make gradients and give the pieces a "roundish" look.
\r
1949 SetPieceBackground( hdc, backColor, 2 );
\r
1950 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1954 DeleteObject( bm2 );
\r
1957 SetTextColor( hdc, foreColor );
\r
1958 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1960 SelectObject( hdc, hbm_old );
\r
1962 if( hPieceFace[index] != NULL ) {
\r
1963 DeleteObject( hPieceFace[index] );
\r
1966 hPieceFace[index] = hbm;
\r
1969 static int TranslatePieceToFontPiece( int piece )
\r
1999 case BlackMarshall:
\r
2003 case BlackNightrider:
\r
2009 case BlackUnicorn:
\r
2013 case BlackGrasshopper:
\r
2025 case BlackCardinal:
\r
2032 case WhiteMarshall:
\r
2036 case WhiteNightrider:
\r
2042 case WhiteUnicorn:
\r
2046 case WhiteGrasshopper:
\r
2058 case WhiteCardinal:
\r
2067 void CreatePiecesFromFont()
\r
2070 HDC hdc_window = NULL;
\r
2076 if( fontBitmapSquareSize < 0 ) {
\r
2077 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2081 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2082 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2083 fontBitmapSquareSize = -1;
\r
2087 if( fontBitmapSquareSize != squareSize ) {
\r
2088 hdc_window = GetDC( hwndMain );
\r
2089 hdc = CreateCompatibleDC( hdc_window );
\r
2091 if( hPieceFont != NULL ) {
\r
2092 DeleteObject( hPieceFont );
\r
2095 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2096 hPieceMask[i] = NULL;
\r
2097 hPieceFace[i] = NULL;
\r
2103 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2104 fontHeight = appData.fontPieceSize;
\r
2107 fontHeight = (fontHeight * squareSize) / 100;
\r
2109 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2111 lf.lfEscapement = 0;
\r
2112 lf.lfOrientation = 0;
\r
2113 lf.lfWeight = FW_NORMAL;
\r
2115 lf.lfUnderline = 0;
\r
2116 lf.lfStrikeOut = 0;
\r
2117 lf.lfCharSet = DEFAULT_CHARSET;
\r
2118 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2119 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2120 lf.lfQuality = PROOF_QUALITY;
\r
2121 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2122 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2123 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2125 hPieceFont = CreateFontIndirect( &lf );
\r
2127 if( hPieceFont == NULL ) {
\r
2128 fontBitmapSquareSize = -2;
\r
2131 /* Setup font-to-piece character table */
\r
2132 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2133 /* No (or wrong) global settings, try to detect the font */
\r
2134 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2136 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2138 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2139 /* DiagramTT* family */
\r
2140 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2142 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2143 /* Fairy symbols */
\r
2144 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2146 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2147 /* Good Companion (Some characters get warped as literal :-( */
\r
2148 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2149 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2150 SetCharTable(pieceToFontChar, s);
\r
2153 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2154 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2158 /* Create bitmaps */
\r
2159 hfont_old = SelectObject( hdc, hPieceFont );
\r
2160 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2161 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2162 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2164 SelectObject( hdc, hfont_old );
\r
2166 fontBitmapSquareSize = squareSize;
\r
2170 if( hdc != NULL ) {
\r
2174 if( hdc_window != NULL ) {
\r
2175 ReleaseDC( hwndMain, hdc_window );
\r
2180 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2182 char name[128], buf[MSG_SIZ];
\r
2184 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2185 if(appData.pieceDirectory[0]) {
\r
2187 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2188 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2189 if(res) return res;
\r
2191 if (gameInfo.event &&
\r
2192 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2193 strcmp(name, "k80s") == 0) {
\r
2194 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2196 return LoadBitmap(hinst, name);
\r
2200 /* Insert a color into the program's logical palette
\r
2201 structure. This code assumes the given color is
\r
2202 the result of the RGB or PALETTERGB macro, and it
\r
2203 knows how those macros work (which is documented).
\r
2206 InsertInPalette(COLORREF color)
\r
2208 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2210 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2211 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2212 pLogPal->palNumEntries--;
\r
2216 pe->peFlags = (char) 0;
\r
2217 pe->peRed = (char) (0xFF & color);
\r
2218 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2219 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2225 InitDrawingColors()
\r
2228 if (pLogPal == NULL) {
\r
2229 /* Allocate enough memory for a logical palette with
\r
2230 * PALETTESIZE entries and set the size and version fields
\r
2231 * of the logical palette structure.
\r
2233 pLogPal = (NPLOGPALETTE)
\r
2234 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2235 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2236 pLogPal->palVersion = 0x300;
\r
2238 pLogPal->palNumEntries = 0;
\r
2240 InsertInPalette(lightSquareColor);
\r
2241 InsertInPalette(darkSquareColor);
\r
2242 InsertInPalette(whitePieceColor);
\r
2243 InsertInPalette(blackPieceColor);
\r
2244 InsertInPalette(highlightSquareColor);
\r
2245 InsertInPalette(premoveHighlightColor);
\r
2247 /* create a logical color palette according the information
\r
2248 * in the LOGPALETTE structure.
\r
2250 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2252 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2253 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2254 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2255 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2256 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2257 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2258 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2259 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2261 /* [AS] Force rendering of the font-based pieces */
\r
2262 if( fontBitmapSquareSize > 0 ) {
\r
2263 fontBitmapSquareSize = 0;
\r
2269 BoardWidth(int boardSize, int n)
\r
2270 { /* [HGM] argument n added to allow different width and height */
\r
2271 int lineGap = sizeInfo[boardSize].lineGap;
\r
2273 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2274 lineGap = appData.overrideLineGap;
\r
2277 return (n + 1) * lineGap +
\r
2278 n * sizeInfo[boardSize].squareSize;
\r
2281 /* Respond to board resize by dragging edge */
\r
2283 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2285 BoardSize newSize = NUM_SIZES - 1;
\r
2286 static int recurse = 0;
\r
2287 if (IsIconic(hwndMain)) return;
\r
2288 if (recurse > 0) return;
\r
2290 while (newSize > 0) {
\r
2291 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2292 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2293 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2296 boardSize = newSize;
\r
2297 InitDrawingSizes(boardSize, flags);
\r
2302 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2305 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2307 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2308 ChessSquare piece;
\r
2309 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2311 SIZE clockSize, messageSize;
\r
2313 char buf[MSG_SIZ];
\r
2315 HMENU hmenu = GetMenu(hwndMain);
\r
2316 RECT crect, wrect, oldRect;
\r
2318 LOGBRUSH logbrush;
\r
2319 VariantClass v = gameInfo.variant;
\r
2321 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2322 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2324 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2325 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2326 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2327 oldBoardSize = boardSize;
\r
2329 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2330 { // correct board size to one where built-in pieces exist
\r
2331 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2332 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2334 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2335 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2336 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2337 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2338 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2339 boardSize = SizeMiddling;
\r
2342 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2344 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2345 oldRect.top = wpMain.y;
\r
2346 oldRect.right = wpMain.x + wpMain.width;
\r
2347 oldRect.bottom = wpMain.y + wpMain.height;
\r
2349 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2350 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2351 squareSize = sizeInfo[boardSize].squareSize;
\r
2352 lineGap = sizeInfo[boardSize].lineGap;
\r
2353 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2354 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2356 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2357 lineGap = appData.overrideLineGap;
\r
2360 if (tinyLayout != oldTinyLayout) {
\r
2361 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2362 if (tinyLayout == 2) {
\r
2363 style &= ~WS_SYSMENU;
\r
2364 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2365 "&Minimize\tCtrl+F4");
\r
2367 style |= WS_SYSMENU;
\r
2368 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2370 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2372 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2373 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2374 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2376 DrawMenuBar(hwndMain);
\r
2379 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2380 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2382 /* Get text area sizes */
\r
2383 hdc = GetDC(hwndMain);
\r
2384 if (appData.clockMode) {
\r
2385 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2387 snprintf(buf, MSG_SIZ, _("White"));
\r
2389 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2390 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2391 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2392 str = _("We only care about the height here");
\r
2393 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2394 SelectObject(hdc, oldFont);
\r
2395 ReleaseDC(hwndMain, hdc);
\r
2397 /* Compute where everything goes */
\r
2398 if((first.programLogo || second.programLogo) && tinyLayout != 2) {
\r
2399 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2400 logoHeight = 2*clockSize.cy;
\r
2401 leftLogoRect.left = OUTER_MARGIN;
\r
2402 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2403 leftLogoRect.top = OUTER_MARGIN;
\r
2404 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2406 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2407 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2408 rightLogoRect.top = OUTER_MARGIN;
\r
2409 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2412 whiteRect.left = leftLogoRect.right;
\r
2413 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2414 whiteRect.top = OUTER_MARGIN;
\r
2415 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2417 blackRect.right = rightLogoRect.left;
\r
2418 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2419 blackRect.top = whiteRect.top;
\r
2420 blackRect.bottom = whiteRect.bottom;
\r
2422 whiteRect.left = OUTER_MARGIN;
\r
2423 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2424 whiteRect.top = OUTER_MARGIN;
\r
2425 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2427 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2428 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2429 blackRect.top = whiteRect.top;
\r
2430 blackRect.bottom = whiteRect.bottom;
\r
2432 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2435 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2436 if (appData.showButtonBar) {
\r
2437 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2438 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2440 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2442 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2443 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2445 boardRect.left = OUTER_MARGIN;
\r
2446 boardRect.right = boardRect.left + boardWidth;
\r
2447 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2448 boardRect.bottom = boardRect.top + boardHeight;
\r
2450 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2451 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2452 oldTinyLayout = tinyLayout;
\r
2453 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2454 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2455 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2456 winW *= 1 + twoBoards;
\r
2457 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2458 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2459 wpMain.height = winH; // without disturbing window attachments
\r
2460 GetWindowRect(hwndMain, &wrect);
\r
2461 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2462 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2464 // [HGM] placement: let attached windows follow size change.
\r
2465 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2466 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2467 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2468 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2469 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2471 /* compensate if menu bar wrapped */
\r
2472 GetClientRect(hwndMain, &crect);
\r
2473 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2474 wpMain.height += offby;
\r
2476 case WMSZ_TOPLEFT:
\r
2477 SetWindowPos(hwndMain, NULL,
\r
2478 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2479 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2482 case WMSZ_TOPRIGHT:
\r
2484 SetWindowPos(hwndMain, NULL,
\r
2485 wrect.left, wrect.bottom - wpMain.height,
\r
2486 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2489 case WMSZ_BOTTOMLEFT:
\r
2491 SetWindowPos(hwndMain, NULL,
\r
2492 wrect.right - wpMain.width, wrect.top,
\r
2493 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2496 case WMSZ_BOTTOMRIGHT:
\r
2500 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2501 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2506 for (i = 0; i < N_BUTTONS; i++) {
\r
2507 if (buttonDesc[i].hwnd != NULL) {
\r
2508 DestroyWindow(buttonDesc[i].hwnd);
\r
2509 buttonDesc[i].hwnd = NULL;
\r
2511 if (appData.showButtonBar) {
\r
2512 buttonDesc[i].hwnd =
\r
2513 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2514 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2515 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2516 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2517 (HMENU) buttonDesc[i].id,
\r
2518 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2519 if (tinyLayout == 2) {
\r
2520 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2521 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2522 MAKELPARAM(FALSE, 0));
\r
2524 if (buttonDesc[i].id == IDM_Pause)
\r
2525 hwndPause = buttonDesc[i].hwnd;
\r
2526 buttonDesc[i].wndproc = (WNDPROC)
\r
2527 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2530 if (gridPen != NULL) DeleteObject(gridPen);
\r
2531 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2532 if (premovePen != NULL) DeleteObject(premovePen);
\r
2533 if (lineGap != 0) {
\r
2534 logbrush.lbStyle = BS_SOLID;
\r
2535 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2537 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2538 lineGap, &logbrush, 0, NULL);
\r
2539 logbrush.lbColor = highlightSquareColor;
\r
2541 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2542 lineGap, &logbrush, 0, NULL);
\r
2544 logbrush.lbColor = premoveHighlightColor;
\r
2546 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2547 lineGap, &logbrush, 0, NULL);
\r
2549 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2550 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2551 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2552 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2553 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2554 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2555 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2556 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2558 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2559 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2560 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2561 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2562 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2563 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2564 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2565 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2569 /* [HGM] Licensing requirement */
\r
2571 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2574 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2576 GothicPopUp( "", VariantNormal);
\r
2579 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2581 /* Load piece bitmaps for this board size */
\r
2582 for (i=0; i<=2; i++) {
\r
2583 for (piece = WhitePawn;
\r
2584 (int) piece < (int) BlackPawn;
\r
2585 piece = (ChessSquare) ((int) piece + 1)) {
\r
2586 if (pieceBitmap[i][piece] != NULL)
\r
2587 DeleteObject(pieceBitmap[i][piece]);
\r
2591 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2592 // Orthodox Chess pieces
\r
2593 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2594 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2595 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2596 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2597 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2598 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2599 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2600 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2601 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2602 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2603 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2604 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2605 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2606 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2607 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2608 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2609 // in Shogi, Hijack the unused Queen for Lance
\r
2610 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2611 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2612 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2614 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2619 if(squareSize <= 72 && squareSize >= 33) {
\r
2620 /* A & C are available in most sizes now */
\r
2621 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2622 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2623 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2624 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2625 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2626 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2627 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2628 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2629 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2630 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2631 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2632 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2633 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2634 } else { // Smirf-like
\r
2635 if(gameInfo.variant == VariantSChess) {
\r
2636 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2637 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2638 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2640 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2641 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2642 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2645 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2646 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2647 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2648 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2649 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2650 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2653 } else { // WinBoard standard
\r
2654 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2655 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2656 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2661 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2662 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2663 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2664 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2665 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2666 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2667 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2668 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2669 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2670 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2671 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2672 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2673 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2674 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2677 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2678 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2679 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2680 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2681 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2682 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2683 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2684 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2685 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2686 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2687 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2688 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2689 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2690 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2691 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2692 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2693 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2694 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2696 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2697 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2698 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2699 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2700 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2701 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2702 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2703 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2704 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2705 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2706 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2707 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2708 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2710 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2711 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2712 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2713 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2714 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2715 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2716 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2717 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2718 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2719 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2720 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2721 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2724 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2725 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2726 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2727 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2728 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2729 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2730 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2731 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2732 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2733 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2734 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2735 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2736 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2737 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2738 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2742 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2743 /* special Shogi support in this size */
\r
2744 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2745 for (piece = WhitePawn;
\r
2746 (int) piece < (int) BlackPawn;
\r
2747 piece = (ChessSquare) ((int) piece + 1)) {
\r
2748 if (pieceBitmap[i][piece] != NULL)
\r
2749 DeleteObject(pieceBitmap[i][piece]);
\r
2752 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2753 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2754 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2755 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2756 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2757 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2758 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2762 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2763 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2764 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2765 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2766 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2767 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2768 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2769 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2770 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2771 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2772 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2776 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2777 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2778 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2779 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2780 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2781 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2782 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2783 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2784 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2785 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2786 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2790 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2791 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2792 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2793 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2799 PieceBitmap(ChessSquare p, int kind)
\r
2801 if ((int) p >= (int) BlackPawn)
\r
2802 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2804 return pieceBitmap[kind][(int) p];
\r
2807 /***************************************************************/
\r
2809 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2810 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2812 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2813 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2817 SquareToPos(int row, int column, int * x, int * y)
\r
2820 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2821 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2823 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2824 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2829 DrawCoordsOnDC(HDC hdc)
\r
2831 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2832 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2833 char str[2] = { NULLCHAR, NULLCHAR };
\r
2834 int oldMode, oldAlign, x, y, start, i;
\r
2838 if (!appData.showCoords)
\r
2841 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2843 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2844 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2845 oldAlign = GetTextAlign(hdc);
\r
2846 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2848 y = boardRect.top + lineGap;
\r
2849 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2852 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2853 x += border - lineGap - 4; y += squareSize - 6;
\r
2855 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2856 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2857 str[0] = files[start + i];
\r
2858 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2859 y += squareSize + lineGap;
\r
2862 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2865 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2866 x += -border + 4; y += border - squareSize + 6;
\r
2868 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2869 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2870 str[0] = ranks[start + i];
\r
2871 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2872 x += squareSize + lineGap;
\r
2875 SelectObject(hdc, oldBrush);
\r
2876 SetBkMode(hdc, oldMode);
\r
2877 SetTextAlign(hdc, oldAlign);
\r
2878 SelectObject(hdc, oldFont);
\r
2882 DrawGridOnDC(HDC hdc)
\r
2886 if (lineGap != 0) {
\r
2887 oldPen = SelectObject(hdc, gridPen);
\r
2888 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2889 SelectObject(hdc, oldPen);
\r
2893 #define HIGHLIGHT_PEN 0
\r
2894 #define PREMOVE_PEN 1
\r
2897 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2900 HPEN oldPen, hPen;
\r
2901 if (lineGap == 0) return;
\r
2903 x1 = boardRect.left +
\r
2904 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2905 y1 = boardRect.top +
\r
2906 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2908 x1 = boardRect.left +
\r
2909 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2910 y1 = boardRect.top +
\r
2911 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2913 hPen = pen ? premovePen : highlightPen;
\r
2914 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2915 MoveToEx(hdc, x1, y1, NULL);
\r
2916 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2917 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2918 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2919 LineTo(hdc, x1, y1);
\r
2920 SelectObject(hdc, oldPen);
\r
2924 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2927 for (i=0; i<2; i++) {
\r
2928 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2929 DrawHighlightOnDC(hdc, TRUE,
\r
2930 h->sq[i].x, h->sq[i].y,
\r
2935 /* Note: sqcolor is used only in monoMode */
\r
2936 /* Note that this code is largely duplicated in woptions.c,
\r
2937 function DrawSampleSquare, so that needs to be updated too */
\r
2939 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2941 HBITMAP oldBitmap;
\r
2945 if (appData.blindfold) return;
\r
2947 /* [AS] Use font-based pieces if needed */
\r
2948 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2949 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2950 CreatePiecesFromFont();
\r
2952 if( fontBitmapSquareSize == squareSize ) {
\r
2953 int index = TranslatePieceToFontPiece(piece);
\r
2955 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2957 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2958 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2962 squareSize, squareSize,
\r
2967 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2969 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2970 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2974 squareSize, squareSize,
\r
2983 if (appData.monoMode) {
\r
2984 SelectObject(tmphdc, PieceBitmap(piece,
\r
2985 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2986 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2987 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2989 HBRUSH xBrush = whitePieceBrush;
\r
2990 tmpSize = squareSize;
\r
2991 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2993 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2994 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2995 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2996 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2997 x += (squareSize - minorSize)>>1;
\r
2998 y += squareSize - minorSize - 2;
\r
2999 tmpSize = minorSize;
\r
3001 if (color || appData.allWhite ) {
\r
3002 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3004 oldBrush = SelectObject(hdc, xBrush);
\r
3005 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3006 if(appData.upsideDown && color==flipView)
\r
3007 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3009 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3010 /* Use black for outline of white pieces */
\r
3011 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3012 if(appData.upsideDown && color==flipView)
\r
3013 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3015 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3016 } else if(appData.pieceDirectory[0]) {
\r
3017 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3018 oldBrush = SelectObject(hdc, xBrush);
\r
3019 if(appData.upsideDown && color==flipView)
\r
3020 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3022 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3023 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3024 if(appData.upsideDown && color==flipView)
\r
3025 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3027 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3029 /* Use square color for details of black pieces */
\r
3030 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3031 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3032 if(appData.upsideDown && !flipView)
\r
3033 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3035 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3037 SelectObject(hdc, oldBrush);
\r
3038 SelectObject(tmphdc, oldBitmap);
\r
3042 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3043 int GetBackTextureMode( int algo )
\r
3045 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3049 case BACK_TEXTURE_MODE_PLAIN:
\r
3050 result = 1; /* Always use identity map */
\r
3052 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3053 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3061 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3062 to handle redraws cleanly (as random numbers would always be different).
\r
3064 VOID RebuildTextureSquareInfo()
\r
3074 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3076 if( liteBackTexture != NULL ) {
\r
3077 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3078 lite_w = bi.bmWidth;
\r
3079 lite_h = bi.bmHeight;
\r
3083 if( darkBackTexture != NULL ) {
\r
3084 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3085 dark_w = bi.bmWidth;
\r
3086 dark_h = bi.bmHeight;
\r
3090 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3091 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3092 if( (col + row) & 1 ) {
\r
3094 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3095 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3096 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3098 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3099 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3100 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3102 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3103 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3108 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3109 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3110 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3112 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3113 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3114 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3116 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3117 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3124 /* [AS] Arrow highlighting support */
\r
3126 static double A_WIDTH = 5; /* Width of arrow body */
\r
3128 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3129 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3131 static double Sqr( double x )
\r
3136 static int Round( double x )
\r
3138 return (int) (x + 0.5);
\r
3141 /* Draw an arrow between two points using current settings */
\r
3142 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3145 double dx, dy, j, k, x, y;
\r
3147 if( d_x == s_x ) {
\r
3148 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3150 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3153 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3154 arrow[1].y = d_y - h;
\r
3156 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3157 arrow[2].y = d_y - h;
\r
3162 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3163 arrow[5].y = d_y - h;
\r
3165 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3166 arrow[4].y = d_y - h;
\r
3168 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3171 else if( d_y == s_y ) {
\r
3172 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3175 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3177 arrow[1].x = d_x - w;
\r
3178 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3180 arrow[2].x = d_x - w;
\r
3181 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3186 arrow[5].x = d_x - w;
\r
3187 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3189 arrow[4].x = d_x - w;
\r
3190 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3193 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3196 /* [AS] Needed a lot of paper for this! :-) */
\r
3197 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3198 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3200 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3202 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3207 arrow[0].x = Round(x - j);
\r
3208 arrow[0].y = Round(y + j*dx);
\r
3210 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3211 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3214 x = (double) d_x - k;
\r
3215 y = (double) d_y - k*dy;
\r
3218 x = (double) d_x + k;
\r
3219 y = (double) d_y + k*dy;
\r
3222 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3224 arrow[6].x = Round(x - j);
\r
3225 arrow[6].y = Round(y + j*dx);
\r
3227 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3228 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3230 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3231 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3236 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3237 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3240 Polygon( hdc, arrow, 7 );
\r
3243 /* [AS] Draw an arrow between two squares */
\r
3244 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3246 int s_x, s_y, d_x, d_y;
\r
3253 if( s_col == d_col && s_row == d_row ) {
\r
3257 /* Get source and destination points */
\r
3258 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3259 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3262 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3264 else if( d_y < s_y ) {
\r
3265 d_y += squareSize / 2 + squareSize / 4;
\r
3268 d_y += squareSize / 2;
\r
3272 d_x += squareSize / 2 - squareSize / 4;
\r
3274 else if( d_x < s_x ) {
\r
3275 d_x += squareSize / 2 + squareSize / 4;
\r
3278 d_x += squareSize / 2;
\r
3281 s_x += squareSize / 2;
\r
3282 s_y += squareSize / 2;
\r
3284 /* Adjust width */
\r
3285 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3288 stLB.lbStyle = BS_SOLID;
\r
3289 stLB.lbColor = appData.highlightArrowColor;
\r
3292 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3293 holdpen = SelectObject( hdc, hpen );
\r
3294 hbrush = CreateBrushIndirect( &stLB );
\r
3295 holdbrush = SelectObject( hdc, hbrush );
\r
3297 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3299 SelectObject( hdc, holdpen );
\r
3300 SelectObject( hdc, holdbrush );
\r
3301 DeleteObject( hpen );
\r
3302 DeleteObject( hbrush );
\r
3305 BOOL HasHighlightInfo()
\r
3307 BOOL result = FALSE;
\r
3309 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3310 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3321 BOOL IsDrawArrowEnabled()
\r
3323 BOOL result = FALSE;
\r
3325 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3332 VOID DrawArrowHighlight( HDC hdc )
\r
3334 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3335 DrawArrowBetweenSquares( hdc,
\r
3336 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3337 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3341 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3343 HRGN result = NULL;
\r
3345 if( HasHighlightInfo() ) {
\r
3346 int x1, y1, x2, y2;
\r
3347 int sx, sy, dx, dy;
\r
3349 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3350 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3352 sx = MIN( x1, x2 );
\r
3353 sy = MIN( y1, y2 );
\r
3354 dx = MAX( x1, x2 ) + squareSize;
\r
3355 dy = MAX( y1, y2 ) + squareSize;
\r
3357 result = CreateRectRgn( sx, sy, dx, dy );
\r
3364 Warning: this function modifies the behavior of several other functions.
\r
3366 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3367 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3368 repaint is scattered all over the place, which is not good for features such as
\r
3369 "arrow highlighting" that require a full repaint of the board.
\r
3371 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3372 user interaction, when speed is not so important) but especially to avoid errors
\r
3373 in the displayed graphics.
\r
3375 In such patched places, I always try refer to this function so there is a single
\r
3376 place to maintain knowledge.
\r
3378 To restore the original behavior, just return FALSE unconditionally.
\r
3380 BOOL IsFullRepaintPreferrable()
\r
3382 BOOL result = FALSE;
\r
3384 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3385 /* Arrow may appear on the board */
\r
3393 This function is called by DrawPosition to know whether a full repaint must
\r
3396 Only DrawPosition may directly call this function, which makes use of
\r
3397 some state information. Other function should call DrawPosition specifying
\r
3398 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3400 BOOL DrawPositionNeedsFullRepaint()
\r
3402 BOOL result = FALSE;
\r
3405 Probably a slightly better policy would be to trigger a full repaint
\r
3406 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3407 but animation is fast enough that it's difficult to notice.
\r
3409 if( animInfo.piece == EmptySquare ) {
\r
3410 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3418 static HBITMAP borderBitmap;
\r
3421 DrawBackgroundOnDC(HDC hdc)
\r
3427 static char oldBorder[MSG_SIZ];
\r
3428 int w = 600, h = 600, mode;
\r
3430 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3431 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3432 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3434 if(borderBitmap == NULL) { // loading failed, use white
\r
3435 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3438 tmphdc = CreateCompatibleDC(hdc);
\r
3439 hbm = SelectObject(tmphdc, borderBitmap);
\r
3440 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3444 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3445 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3446 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3447 SetStretchBltMode(hdc, mode);
\r
3448 SelectObject(tmphdc, hbm);
\r
3453 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3455 int row, column, x, y, square_color, piece_color;
\r
3456 ChessSquare piece;
\r
3458 HDC texture_hdc = NULL;
\r
3460 /* [AS] Initialize background textures if needed */
\r
3461 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3462 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3463 if( backTextureSquareSize != squareSize
\r
3464 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3465 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3466 backTextureSquareSize = squareSize;
\r
3467 RebuildTextureSquareInfo();
\r
3470 texture_hdc = CreateCompatibleDC( hdc );
\r
3473 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3474 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3476 SquareToPos(row, column, &x, &y);
\r
3478 piece = board[row][column];
\r
3480 square_color = ((column + row) % 2) == 1;
\r
3481 if( gameInfo.variant == VariantXiangqi ) {
\r
3482 square_color = !InPalace(row, column);
\r
3483 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3484 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3486 piece_color = (int) piece < (int) BlackPawn;
\r
3489 /* [HGM] holdings file: light square or black */
\r
3490 if(column == BOARD_LEFT-2) {
\r
3491 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3494 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3498 if(column == BOARD_RGHT + 1 ) {
\r
3499 if( row < gameInfo.holdingsSize )
\r
3502 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3506 if(column == BOARD_LEFT-1 ) /* left align */
\r
3507 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3508 else if( column == BOARD_RGHT) /* right align */
\r
3509 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3510 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3512 if (appData.monoMode) {
\r
3513 if (piece == EmptySquare) {
\r
3514 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3515 square_color ? WHITENESS : BLACKNESS);
\r
3517 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3520 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3521 /* [AS] Draw the square using a texture bitmap */
\r
3522 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3523 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3524 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3527 squareSize, squareSize,
\r
3530 backTextureSquareInfo[r][c].mode,
\r
3531 backTextureSquareInfo[r][c].x,
\r
3532 backTextureSquareInfo[r][c].y );
\r
3534 SelectObject( texture_hdc, hbm );
\r
3536 if (piece != EmptySquare) {
\r
3537 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3541 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3543 oldBrush = SelectObject(hdc, brush );
\r
3544 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3545 SelectObject(hdc, oldBrush);
\r
3546 if (piece != EmptySquare)
\r
3547 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3552 if( texture_hdc != NULL ) {
\r
3553 DeleteDC( texture_hdc );
\r
3557 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3558 void fputDW(FILE *f, int x)
\r
3560 fputc(x & 255, f);
\r
3561 fputc(x>>8 & 255, f);
\r
3562 fputc(x>>16 & 255, f);
\r
3563 fputc(x>>24 & 255, f);
\r
3566 #define MAX_CLIPS 200 /* more than enough */
\r
3569 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3571 // HBITMAP bufferBitmap;
\r
3576 int w = 100, h = 50;
\r
3578 if(logo == NULL) {
\r
3579 if(!logoHeight) return;
\r
3580 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3582 // GetClientRect(hwndMain, &Rect);
\r
3583 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3584 // Rect.bottom-Rect.top+1);
\r
3585 tmphdc = CreateCompatibleDC(hdc);
\r
3586 hbm = SelectObject(tmphdc, logo);
\r
3587 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3591 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3592 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3593 SelectObject(tmphdc, hbm);
\r
3601 HDC hdc = GetDC(hwndMain);
\r
3602 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3603 if(appData.autoLogo) {
\r
3605 switch(gameMode) { // pick logos based on game mode
\r
3606 case IcsObserving:
\r
3607 whiteLogo = second.programLogo; // ICS logo
\r
3608 blackLogo = second.programLogo;
\r
3611 case IcsPlayingWhite:
\r
3612 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3613 blackLogo = second.programLogo; // ICS logo
\r
3615 case IcsPlayingBlack:
\r
3616 whiteLogo = second.programLogo; // ICS logo
\r
3617 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3619 case TwoMachinesPlay:
\r
3620 if(first.twoMachinesColor[0] == 'b') {
\r
3621 whiteLogo = second.programLogo;
\r
3622 blackLogo = first.programLogo;
\r
3625 case MachinePlaysWhite:
\r
3626 blackLogo = userLogo;
\r
3628 case MachinePlaysBlack:
\r
3629 whiteLogo = userLogo;
\r
3630 blackLogo = first.programLogo;
\r
3633 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3634 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3635 ReleaseDC(hwndMain, hdc);
\r
3640 UpdateLogos(int display)
\r
3641 { // called after loading new engine(s), in tourney or from menu
\r
3642 LoadLogo(&first, 0, FALSE);
\r
3643 LoadLogo(&second, 1, appData.icsActive);
\r
3644 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3645 if(display) DisplayLogos();
\r
3648 static HDC hdcSeek;
\r
3650 // [HGM] seekgraph
\r
3651 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3654 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3655 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3656 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3657 SelectObject( hdcSeek, hp );
\r
3660 // front-end wrapper for drawing functions to do rectangles
\r
3661 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3666 if (hdcSeek == NULL) {
\r
3667 hdcSeek = GetDC(hwndMain);
\r
3668 if (!appData.monoMode) {
\r
3669 SelectPalette(hdcSeek, hPal, FALSE);
\r
3670 RealizePalette(hdcSeek);
\r
3673 hp = SelectObject( hdcSeek, gridPen );
\r
3674 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3675 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3676 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3677 SelectObject( hdcSeek, hp );
\r
3680 // front-end wrapper for putting text in graph
\r
3681 void DrawSeekText(char *buf, int x, int y)
\r
3684 SetBkMode( hdcSeek, TRANSPARENT );
\r
3685 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3686 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3689 void DrawSeekDot(int x, int y, int color)
\r
3691 int square = color & 0x80;
\r
3692 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3693 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3696 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3697 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3699 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3700 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3701 SelectObject(hdcSeek, oldBrush);
\r
3704 void DrawSeekOpen()
\r
3708 void DrawSeekClose()
\r
3713 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3715 static Board lastReq[2], lastDrawn[2];
\r
3716 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3717 static int lastDrawnFlipView = 0;
\r
3718 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3719 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3722 HBITMAP bufferBitmap;
\r
3723 HBITMAP oldBitmap;
\r
3725 HRGN clips[MAX_CLIPS];
\r
3726 ChessSquare dragged_piece = EmptySquare;
\r
3727 int nr = twoBoards*partnerUp;
\r
3729 /* I'm undecided on this - this function figures out whether a full
\r
3730 * repaint is necessary on its own, so there's no real reason to have the
\r
3731 * caller tell it that. I think this can safely be set to FALSE - but
\r
3732 * if we trust the callers not to request full repaints unnessesarily, then
\r
3733 * we could skip some clipping work. In other words, only request a full
\r
3734 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3735 * gamestart and similar) --Hawk
\r
3737 Boolean fullrepaint = repaint;
\r
3739 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3741 if( DrawPositionNeedsFullRepaint() ) {
\r
3742 fullrepaint = TRUE;
\r
3745 if (board == NULL) {
\r
3746 if (!lastReqValid[nr]) {
\r
3749 board = lastReq[nr];
\r
3751 CopyBoard(lastReq[nr], board);
\r
3752 lastReqValid[nr] = 1;
\r
3755 if (doingSizing) {
\r
3759 if (IsIconic(hwndMain)) {
\r
3763 if (hdc == NULL) {
\r
3764 hdc = GetDC(hwndMain);
\r
3765 if (!appData.monoMode) {
\r
3766 SelectPalette(hdc, hPal, FALSE);
\r
3767 RealizePalette(hdc);
\r
3771 releaseDC = FALSE;
\r
3774 /* Create some work-DCs */
\r
3775 hdcmem = CreateCompatibleDC(hdc);
\r
3776 tmphdc = CreateCompatibleDC(hdc);
\r
3778 /* If dragging is in progress, we temporarely remove the piece */
\r
3779 /* [HGM] or temporarily decrease count if stacked */
\r
3780 /* !! Moved to before board compare !! */
\r
3781 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3782 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3783 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3784 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3785 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3787 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3788 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3789 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3791 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3794 /* Figure out which squares need updating by comparing the
\r
3795 * newest board with the last drawn board and checking if
\r
3796 * flipping has changed.
\r
3798 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3799 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3800 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3801 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3802 SquareToPos(row, column, &x, &y);
\r
3803 clips[num_clips++] =
\r
3804 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3808 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3809 for (i=0; i<2; i++) {
\r
3810 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3811 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3812 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3813 lastDrawnHighlight.sq[i].y >= 0) {
\r
3814 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3815 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3816 clips[num_clips++] =
\r
3817 CreateRectRgn(x - lineGap, y - lineGap,
\r
3818 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3820 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3821 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3822 clips[num_clips++] =
\r
3823 CreateRectRgn(x - lineGap, y - lineGap,
\r
3824 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3828 for (i=0; i<2; i++) {
\r
3829 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3830 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3831 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3832 lastDrawnPremove.sq[i].y >= 0) {
\r
3833 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3834 lastDrawnPremove.sq[i].x, &x, &y);
\r
3835 clips[num_clips++] =
\r
3836 CreateRectRgn(x - lineGap, y - lineGap,
\r
3837 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3839 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3840 premoveHighlightInfo.sq[i].y >= 0) {
\r
3841 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3842 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3843 clips[num_clips++] =
\r
3844 CreateRectRgn(x - lineGap, y - lineGap,
\r
3845 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3849 } else { // nr == 1
\r
3850 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3851 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3852 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3853 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3854 for (i=0; i<2; i++) {
\r
3855 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3856 partnerHighlightInfo.sq[i].y >= 0) {
\r
3857 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3858 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3859 clips[num_clips++] =
\r
3860 CreateRectRgn(x - lineGap, y - lineGap,
\r
3861 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3863 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3864 oldPartnerHighlight.sq[i].y >= 0) {
\r
3865 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3866 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3867 clips[num_clips++] =
\r
3868 CreateRectRgn(x - lineGap, y - lineGap,
\r
3869 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3874 fullrepaint = TRUE;
\r
3877 /* Create a buffer bitmap - this is the actual bitmap
\r
3878 * being written to. When all the work is done, we can
\r
3879 * copy it to the real DC (the screen). This avoids
\r
3880 * the problems with flickering.
\r
3882 GetClientRect(hwndMain, &Rect);
\r
3883 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3884 Rect.bottom-Rect.top+1);
\r
3885 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3886 if (!appData.monoMode) {
\r
3887 SelectPalette(hdcmem, hPal, FALSE);
\r
3890 /* Create clips for dragging */
\r
3891 if (!fullrepaint) {
\r
3892 if (dragInfo.from.x >= 0) {
\r
3893 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3894 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3896 if (dragInfo.start.x >= 0) {
\r
3897 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3898 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3900 if (dragInfo.pos.x >= 0) {
\r
3901 x = dragInfo.pos.x - squareSize / 2;
\r
3902 y = dragInfo.pos.y - squareSize / 2;
\r
3903 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3905 if (dragInfo.lastpos.x >= 0) {
\r
3906 x = dragInfo.lastpos.x - squareSize / 2;
\r
3907 y = dragInfo.lastpos.y - squareSize / 2;
\r
3908 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3912 /* Are we animating a move?
\r
3914 * - remove the piece from the board (temporarely)
\r
3915 * - calculate the clipping region
\r
3917 if (!fullrepaint) {
\r
3918 if (animInfo.piece != EmptySquare) {
\r
3919 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3920 x = boardRect.left + animInfo.lastpos.x;
\r
3921 y = boardRect.top + animInfo.lastpos.y;
\r
3922 x2 = boardRect.left + animInfo.pos.x;
\r
3923 y2 = boardRect.top + animInfo.pos.y;
\r
3924 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3925 /* Slight kludge. The real problem is that after AnimateMove is
\r
3926 done, the position on the screen does not match lastDrawn.
\r
3927 This currently causes trouble only on e.p. captures in
\r
3928 atomic, where the piece moves to an empty square and then
\r
3929 explodes. The old and new positions both had an empty square
\r
3930 at the destination, but animation has drawn a piece there and
\r
3931 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3932 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3936 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3937 if (num_clips == 0)
\r
3938 fullrepaint = TRUE;
\r
3940 /* Set clipping on the memory DC */
\r
3941 if (!fullrepaint) {
\r
3942 SelectClipRgn(hdcmem, clips[0]);
\r
3943 for (x = 1; x < num_clips; x++) {
\r
3944 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3945 abort(); // this should never ever happen!
\r
3949 /* Do all the drawing to the memory DC */
\r
3950 if(explodeInfo.radius) { // [HGM] atomic
\r
3952 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3953 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3954 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3955 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3956 x += squareSize/2;
\r
3957 y += squareSize/2;
\r
3958 if(!fullrepaint) {
\r
3959 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3960 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3962 DrawGridOnDC(hdcmem);
\r
3963 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3964 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3965 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3966 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3967 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3968 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3969 SelectObject(hdcmem, oldBrush);
\r
3971 if(border) DrawBackgroundOnDC(hdcmem);
\r
3972 DrawGridOnDC(hdcmem);
\r
3973 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3974 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3975 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3977 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3978 oldPartnerHighlight = partnerHighlightInfo;
\r
3980 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3982 if(nr == 0) // [HGM] dual: markers only on left board
\r
3983 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3984 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3985 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3986 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
3987 SquareToPos(row, column, &x, &y);
\r
3988 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3989 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3990 SelectObject(hdcmem, oldBrush);
\r
3995 if( appData.highlightMoveWithArrow ) {
\r
3997 DrawArrowHighlight(hdcmem);
\r
4000 DrawCoordsOnDC(hdcmem);
\r
4002 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
4003 /* to make sure lastDrawn contains what is actually drawn */
\r
4005 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4006 if (dragged_piece != EmptySquare) {
\r
4007 /* [HGM] or restack */
\r
4008 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4009 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4011 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4012 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4014 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4015 x = dragInfo.pos.x - squareSize / 2;
\r
4016 y = dragInfo.pos.y - squareSize / 2;
\r
4017 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
4018 ((int) dragInfo.piece < (int) BlackPawn),
\r
4019 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4022 /* Put the animated piece back into place and draw it */
\r
4023 if (animInfo.piece != EmptySquare) {
\r
4024 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4025 x = boardRect.left + animInfo.pos.x;
\r
4026 y = boardRect.top + animInfo.pos.y;
\r
4027 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4028 ((int) animInfo.piece < (int) BlackPawn),
\r
4029 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4032 /* Release the bufferBitmap by selecting in the old bitmap
\r
4033 * and delete the memory DC
\r
4035 SelectObject(hdcmem, oldBitmap);
\r
4038 /* Set clipping on the target DC */
\r
4039 if (!fullrepaint) {
\r
4040 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4042 GetRgnBox(clips[x], &rect);
\r
4043 DeleteObject(clips[x]);
\r
4044 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4045 rect.right + wpMain.width/2, rect.bottom);
\r
4047 SelectClipRgn(hdc, clips[0]);
\r
4048 for (x = 1; x < num_clips; x++) {
\r
4049 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4050 abort(); // this should never ever happen!
\r
4054 /* Copy the new bitmap onto the screen in one go.
\r
4055 * This way we avoid any flickering
\r
4057 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4058 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4059 boardRect.right - boardRect.left,
\r
4060 boardRect.bottom - boardRect.top,
\r
4061 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4062 if(saveDiagFlag) {
\r
4063 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4064 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4066 GetObject(bufferBitmap, sizeof(b), &b);
\r
4067 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4068 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4069 bih.biWidth = b.bmWidth;
\r
4070 bih.biHeight = b.bmHeight;
\r
4072 bih.biBitCount = b.bmBitsPixel;
\r
4073 bih.biCompression = 0;
\r
4074 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4075 bih.biXPelsPerMeter = 0;
\r
4076 bih.biYPelsPerMeter = 0;
\r
4077 bih.biClrUsed = 0;
\r
4078 bih.biClrImportant = 0;
\r
4079 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4080 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4081 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4082 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4084 wb = b.bmWidthBytes;
\r
4086 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4087 int k = ((int*) pData)[i];
\r
4088 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4089 if(j >= 16) break;
\r
4091 if(j >= nrColors) nrColors = j+1;
\r
4093 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4095 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4096 for(w=0; w<(wb>>2); w+=2) {
\r
4097 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4098 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4099 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4100 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4101 pData[p++] = m | j<<4;
\r
4103 while(p&3) pData[p++] = 0;
\r
4106 wb = ((wb+31)>>5)<<2;
\r
4108 // write BITMAPFILEHEADER
\r
4109 fprintf(diagFile, "BM");
\r
4110 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4111 fputDW(diagFile, 0);
\r
4112 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4113 // write BITMAPINFOHEADER
\r
4114 fputDW(diagFile, 40);
\r
4115 fputDW(diagFile, b.bmWidth);
\r
4116 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4117 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4118 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4119 fputDW(diagFile, 0);
\r
4120 fputDW(diagFile, 0);
\r
4121 fputDW(diagFile, 0);
\r
4122 fputDW(diagFile, 0);
\r
4123 fputDW(diagFile, 0);
\r
4124 fputDW(diagFile, 0);
\r
4125 // write color table
\r
4127 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4128 // write bitmap data
\r
4129 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4130 fputc(pData[i], diagFile);
\r
4135 SelectObject(tmphdc, oldBitmap);
\r
4137 /* Massive cleanup */
\r
4138 for (x = 0; x < num_clips; x++)
\r
4139 DeleteObject(clips[x]);
\r
4142 DeleteObject(bufferBitmap);
\r
4145 ReleaseDC(hwndMain, hdc);
\r
4147 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4149 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4151 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4154 /* CopyBoard(lastDrawn, board);*/
\r
4155 lastDrawnHighlight = highlightInfo;
\r
4156 lastDrawnPremove = premoveHighlightInfo;
\r
4157 lastDrawnFlipView = flipView;
\r
4158 lastDrawnValid[nr] = 1;
\r
4161 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4166 saveDiagFlag = 1; diagFile = f;
\r
4167 HDCDrawPosition(NULL, TRUE, NULL);
\r
4175 /*---------------------------------------------------------------------------*\
\r
4176 | CLIENT PAINT PROCEDURE
\r
4177 | This is the main event-handler for the WM_PAINT message.
\r
4179 \*---------------------------------------------------------------------------*/
\r
4181 PaintProc(HWND hwnd)
\r
4187 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4188 if (IsIconic(hwnd)) {
\r
4189 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4191 if (!appData.monoMode) {
\r
4192 SelectPalette(hdc, hPal, FALSE);
\r
4193 RealizePalette(hdc);
\r
4195 HDCDrawPosition(hdc, 1, NULL);
\r
4196 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4197 flipView = !flipView; partnerUp = !partnerUp;
\r
4198 HDCDrawPosition(hdc, 1, NULL);
\r
4199 flipView = !flipView; partnerUp = !partnerUp;
\r
4202 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4203 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4204 ETO_CLIPPED|ETO_OPAQUE,
\r
4205 &messageRect, messageText, strlen(messageText), NULL);
\r
4206 SelectObject(hdc, oldFont);
\r
4207 DisplayBothClocks();
\r
4210 EndPaint(hwnd,&ps);
\r
4218 * If the user selects on a border boundary, return -1; if off the board,
\r
4219 * return -2. Otherwise map the event coordinate to the square.
\r
4220 * The offset boardRect.left or boardRect.top must already have been
\r
4221 * subtracted from x.
\r
4223 int EventToSquare(x, limit)
\r
4228 if (x < lineGap + border)
\r
4230 x -= lineGap + border;
\r
4231 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4233 x /= (squareSize + lineGap);
\r
4245 DropEnable dropEnables[] = {
\r
4246 { 'P', DP_Pawn, N_("Pawn") },
\r
4247 { 'N', DP_Knight, N_("Knight") },
\r
4248 { 'B', DP_Bishop, N_("Bishop") },
\r
4249 { 'R', DP_Rook, N_("Rook") },
\r
4250 { 'Q', DP_Queen, N_("Queen") },
\r
4254 SetupDropMenu(HMENU hmenu)
\r
4256 int i, count, enable;
\r
4258 extern char white_holding[], black_holding[];
\r
4259 char item[MSG_SIZ];
\r
4261 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4262 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4263 dropEnables[i].piece);
\r
4265 while (p && *p++ == dropEnables[i].piece) count++;
\r
4266 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4267 enable = count > 0 || !appData.testLegality
\r
4268 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4269 && !appData.icsActive);
\r
4270 ModifyMenu(hmenu, dropEnables[i].command,
\r
4271 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4272 dropEnables[i].command, item);
\r
4276 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4278 dragInfo.lastpos.x = boardRect.left + x;
\r
4279 dragInfo.lastpos.y = boardRect.top + y;
\r
4280 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4281 dragInfo.from.x = fromX;
\r
4282 dragInfo.from.y = fromY;
\r
4283 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4284 dragInfo.start = dragInfo.from;
\r
4285 SetCapture(hwndMain);
\r
4288 void DragPieceEnd(int x, int y)
\r
4291 dragInfo.start.x = dragInfo.start.y = -1;
\r
4292 dragInfo.from = dragInfo.start;
\r
4293 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4296 void ChangeDragPiece(ChessSquare piece)
\r
4298 dragInfo.piece = piece;
\r
4301 /* Event handler for mouse messages */
\r
4303 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4307 static int recursive = 0;
\r
4309 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4312 if (message == WM_MBUTTONUP) {
\r
4313 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4314 to the middle button: we simulate pressing the left button too!
\r
4316 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4317 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4323 pt.x = LOWORD(lParam);
\r
4324 pt.y = HIWORD(lParam);
\r
4325 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4326 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4327 if (!flipView && y >= 0) {
\r
4328 y = BOARD_HEIGHT - 1 - y;
\r
4330 if (flipView && x >= 0) {
\r
4331 x = BOARD_WIDTH - 1 - x;
\r
4334 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4335 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4337 switch (message) {
\r
4338 case WM_LBUTTONDOWN:
\r
4339 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4340 ClockClick(flipClock); break;
\r
4341 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4342 ClockClick(!flipClock); break;
\r
4344 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4345 dragInfo.start.x = dragInfo.start.y = -1;
\r
4346 dragInfo.from = dragInfo.start;
\r
4348 if(fromX == -1 && frozen) { // not sure where this is for
\r
4349 fromX = fromY = -1;
\r
4350 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4353 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4354 DrawPosition(TRUE, NULL);
\r
4357 case WM_LBUTTONUP:
\r
4358 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4359 DrawPosition(TRUE, NULL);
\r
4362 case WM_MOUSEMOVE:
\r
4363 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4364 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4365 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4366 if ((appData.animateDragging || appData.highlightDragging)
\r
4367 && (wParam & MK_LBUTTON || dragging == 2)
\r
4368 && dragInfo.from.x >= 0)
\r
4370 BOOL full_repaint = FALSE;
\r
4372 if (appData.animateDragging) {
\r
4373 dragInfo.pos = pt;
\r
4375 if (appData.highlightDragging) {
\r
4376 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4377 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4378 full_repaint = TRUE;
\r
4382 DrawPosition( full_repaint, NULL);
\r
4384 dragInfo.lastpos = dragInfo.pos;
\r
4388 case WM_MOUSEWHEEL: // [DM]
\r
4389 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4390 /* Mouse Wheel is being rolled forward
\r
4391 * Play moves forward
\r
4393 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4394 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4395 /* Mouse Wheel is being rolled backward
\r
4396 * Play moves backward
\r
4398 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4399 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4403 case WM_MBUTTONUP:
\r
4404 case WM_RBUTTONUP:
\r
4406 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4409 case WM_MBUTTONDOWN:
\r
4410 case WM_RBUTTONDOWN:
\r
4413 fromX = fromY = -1;
\r
4414 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4415 dragInfo.start.x = dragInfo.start.y = -1;
\r
4416 dragInfo.from = dragInfo.start;
\r
4417 dragInfo.lastpos = dragInfo.pos;
\r
4418 if (appData.highlightDragging) {
\r
4419 ClearHighlights();
\r
4422 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4423 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4424 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4425 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4426 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4430 DrawPosition(TRUE, NULL);
\r
4432 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4435 if (message == WM_MBUTTONDOWN) {
\r
4436 buttonCount = 3; /* even if system didn't think so */
\r
4437 if (wParam & MK_SHIFT)
\r
4438 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4440 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4441 } else { /* message == WM_RBUTTONDOWN */
\r
4442 /* Just have one menu, on the right button. Windows users don't
\r
4443 think to try the middle one, and sometimes other software steals
\r
4444 it, or it doesn't really exist. */
\r
4445 if(gameInfo.variant != VariantShogi)
\r
4446 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4448 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4452 SetCapture(hwndMain);
\r
4455 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4456 SetupDropMenu(hmenu);
\r
4457 MenuPopup(hwnd, pt, hmenu, -1);
\r
4467 /* Preprocess messages for buttons in main window */
\r
4469 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4471 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4474 for (i=0; i<N_BUTTONS; i++) {
\r
4475 if (buttonDesc[i].id == id) break;
\r
4477 if (i == N_BUTTONS) return 0;
\r
4478 switch (message) {
\r
4483 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4484 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4491 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4494 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4495 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4496 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4497 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4499 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4501 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4502 TypeInEvent((char)wParam);
\r
4508 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4511 static int promoStyle;
\r
4513 /* Process messages for Promotion dialog box */
\r
4515 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4520 switch (message) {
\r
4522 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4523 /* Center the dialog over the application window */
\r
4524 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4525 Translate(hDlg, DLG_PromotionKing);
\r
4526 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4527 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4528 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4529 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4530 SW_SHOW : SW_HIDE);
\r
4531 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4532 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4533 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4534 PieceToChar(WhiteAngel) != '~') ||
\r
4535 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4536 PieceToChar(BlackAngel) != '~') ) ?
\r
4537 SW_SHOW : SW_HIDE);
\r
4538 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4539 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4540 PieceToChar(WhiteMarshall) != '~') ||
\r
4541 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4542 PieceToChar(BlackMarshall) != '~') ) ?
\r
4543 SW_SHOW : SW_HIDE);
\r
4544 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4545 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4546 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4548 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4549 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4550 SetWindowText(hDlg, "Promote?");
\r
4552 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4553 gameInfo.variant == VariantSuper ?
\r
4554 SW_SHOW : SW_HIDE);
\r
4557 case WM_COMMAND: /* message: received a command */
\r
4558 switch (LOWORD(wParam)) {
\r
4560 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4561 ClearHighlights();
\r
4562 DrawPosition(FALSE, NULL);
\r
4565 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4568 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4571 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4572 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4575 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4576 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4578 case PB_Chancellor:
\r
4579 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4581 case PB_Archbishop:
\r
4582 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4585 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4586 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4591 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4592 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4593 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4594 fromX = fromY = -1;
\r
4595 if (!appData.highlightLastMove) {
\r
4596 ClearHighlights();
\r
4597 DrawPosition(FALSE, NULL);
\r
4604 /* Pop up promotion dialog */
\r
4606 PromotionPopup(HWND hwnd)
\r
4610 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4611 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4612 hwnd, (DLGPROC)lpProc);
\r
4613 FreeProcInstance(lpProc);
\r
4617 PromotionPopUp(char choice)
\r
4619 promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant));
\r
4620 DrawPosition(TRUE, NULL);
\r
4621 PromotionPopup(hwndMain);
\r
4625 LoadGameDialog(HWND hwnd, char* title)
\r
4629 char fileTitle[MSG_SIZ];
\r
4630 f = OpenFileDialog(hwnd, "rb", "",
\r
4631 appData.oldSaveStyle ? "gam" : "pgn",
\r
4633 title, &number, fileTitle, NULL);
\r
4635 cmailMsgLoaded = FALSE;
\r
4636 if (number == 0) {
\r
4637 int error = GameListBuild(f);
\r
4639 DisplayError(_("Cannot build game list"), error);
\r
4640 } else if (!ListEmpty(&gameList) &&
\r
4641 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4642 GameListPopUp(f, fileTitle);
\r
4645 GameListDestroy();
\r
4648 LoadGame(f, number, fileTitle, FALSE);
\r
4652 int get_term_width()
\r
4657 HFONT hfont, hold_font;
\r
4662 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4666 // get the text metrics
\r
4667 hdc = GetDC(hText);
\r
4668 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4669 if (consoleCF.dwEffects & CFE_BOLD)
\r
4670 lf.lfWeight = FW_BOLD;
\r
4671 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4672 lf.lfItalic = TRUE;
\r
4673 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4674 lf.lfStrikeOut = TRUE;
\r
4675 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4676 lf.lfUnderline = TRUE;
\r
4677 hfont = CreateFontIndirect(&lf);
\r
4678 hold_font = SelectObject(hdc, hfont);
\r
4679 GetTextMetrics(hdc, &tm);
\r
4680 SelectObject(hdc, hold_font);
\r
4681 DeleteObject(hfont);
\r
4682 ReleaseDC(hText, hdc);
\r
4684 // get the rectangle
\r
4685 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4687 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4690 void UpdateICSWidth(HWND hText)
\r
4692 LONG old_width, new_width;
\r
4694 new_width = get_term_width(hText, FALSE);
\r
4695 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4696 if (new_width != old_width)
\r
4698 ics_update_width(new_width);
\r
4699 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4704 ChangedConsoleFont()
\r
4707 CHARRANGE tmpsel, sel;
\r
4708 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4709 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4710 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4713 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4714 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4715 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4716 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4717 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4718 * size. This was undocumented in the version of MSVC++ that I had
\r
4719 * when I wrote the code, but is apparently documented now.
\r
4721 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4722 cfmt.bCharSet = f->lf.lfCharSet;
\r
4723 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4724 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4725 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4726 /* Why are the following seemingly needed too? */
\r
4727 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4728 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4729 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4731 tmpsel.cpMax = -1; /*999999?*/
\r
4732 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4733 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4734 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4735 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4737 paraf.cbSize = sizeof(paraf);
\r
4738 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4739 paraf.dxStartIndent = 0;
\r
4740 paraf.dxOffset = WRAP_INDENT;
\r
4741 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4742 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4743 UpdateICSWidth(hText);
\r
4746 /*---------------------------------------------------------------------------*\
\r
4748 * Window Proc for main window
\r
4750 \*---------------------------------------------------------------------------*/
\r
4752 /* Process messages for main window, etc. */
\r
4754 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4761 char fileTitle[MSG_SIZ];
\r
4762 static SnapData sd;
\r
4763 static int peek=0;
\r
4765 switch (message) {
\r
4767 case WM_PAINT: /* message: repaint portion of window */
\r
4771 case WM_ERASEBKGND:
\r
4772 if (IsIconic(hwnd)) {
\r
4773 /* Cheat; change the message */
\r
4774 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4776 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4780 case WM_LBUTTONDOWN:
\r
4781 case WM_MBUTTONDOWN:
\r
4782 case WM_RBUTTONDOWN:
\r
4783 case WM_LBUTTONUP:
\r
4784 case WM_MBUTTONUP:
\r
4785 case WM_RBUTTONUP:
\r
4786 case WM_MOUSEMOVE:
\r
4787 case WM_MOUSEWHEEL:
\r
4788 MouseEvent(hwnd, message, wParam, lParam);
\r
4792 if((char)wParam == '\b') {
\r
4793 ForwardEvent(); peek = 0;
\r
4796 JAWS_KBUP_NAVIGATION
\r
4801 if((char)wParam == '\b') {
\r
4802 if(!peek) BackwardEvent(), peek = 1;
\r
4805 JAWS_KBDOWN_NAVIGATION
\r
4811 JAWS_ALT_INTERCEPT
\r
4813 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4814 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4815 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4816 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4818 SendMessage(h, message, wParam, lParam);
\r
4819 } else if(lParam != KF_REPEAT) {
\r
4820 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4821 TypeInEvent((char)wParam);
\r
4822 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4823 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4828 case WM_PALETTECHANGED:
\r
4829 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4831 HDC hdc = GetDC(hwndMain);
\r
4832 SelectPalette(hdc, hPal, TRUE);
\r
4833 nnew = RealizePalette(hdc);
\r
4835 paletteChanged = TRUE;
\r
4837 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4839 ReleaseDC(hwnd, hdc);
\r
4843 case WM_QUERYNEWPALETTE:
\r
4844 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4846 HDC hdc = GetDC(hwndMain);
\r
4847 paletteChanged = FALSE;
\r
4848 SelectPalette(hdc, hPal, FALSE);
\r
4849 nnew = RealizePalette(hdc);
\r
4851 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4853 ReleaseDC(hwnd, hdc);
\r
4858 case WM_COMMAND: /* message: command from application menu */
\r
4859 wmId = LOWORD(wParam);
\r
4864 SAY("new game enter a move to play against the computer with white");
\r
4867 case IDM_NewGameFRC:
\r
4868 if( NewGameFRC() == 0 ) {
\r
4873 case IDM_NewVariant:
\r
4874 NewVariantPopup(hwnd);
\r
4877 case IDM_LoadGame:
\r
4878 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4881 case IDM_LoadNextGame:
\r
4885 case IDM_LoadPrevGame:
\r
4889 case IDM_ReloadGame:
\r
4893 case IDM_LoadPosition:
\r
4894 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4895 Reset(FALSE, TRUE);
\r
4898 f = OpenFileDialog(hwnd, "rb", "",
\r
4899 appData.oldSaveStyle ? "pos" : "fen",
\r
4901 _("Load Position from File"), &number, fileTitle, NULL);
\r
4903 LoadPosition(f, number, fileTitle);
\r
4907 case IDM_LoadNextPosition:
\r
4908 ReloadPosition(1);
\r
4911 case IDM_LoadPrevPosition:
\r
4912 ReloadPosition(-1);
\r
4915 case IDM_ReloadPosition:
\r
4916 ReloadPosition(0);
\r
4919 case IDM_SaveGame:
\r
4920 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4921 f = OpenFileDialog(hwnd, "a", defName,
\r
4922 appData.oldSaveStyle ? "gam" : "pgn",
\r
4924 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4926 SaveGame(f, 0, "");
\r
4930 case IDM_SavePosition:
\r
4931 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4932 f = OpenFileDialog(hwnd, "a", defName,
\r
4933 appData.oldSaveStyle ? "pos" : "fen",
\r
4935 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4937 SavePosition(f, 0, "");
\r
4941 case IDM_SaveDiagram:
\r
4942 defName = "diagram";
\r
4943 f = OpenFileDialog(hwnd, "wb", defName,
\r
4946 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4952 case IDM_SaveSelected:
\r
4953 f = OpenFileDialog(hwnd, "a", "",
\r
4956 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4958 SaveSelected(f, 0, "");
\r
4962 case IDM_CreateBook:
\r
4963 CreateBookEvent();
\r
4966 case IDM_CopyGame:
\r
4967 CopyGameToClipboard();
\r
4970 case IDM_PasteGame:
\r
4971 PasteGameFromClipboard();
\r
4974 case IDM_CopyGameListToClipboard:
\r
4975 CopyGameListToClipboard();
\r
4978 /* [AS] Autodetect FEN or PGN data */
\r
4979 case IDM_PasteAny:
\r
4980 PasteGameOrFENFromClipboard();
\r
4983 /* [AS] Move history */
\r
4984 case IDM_ShowMoveHistory:
\r
4985 if( MoveHistoryIsUp() ) {
\r
4986 MoveHistoryPopDown();
\r
4989 MoveHistoryPopUp();
\r
4993 /* [AS] Eval graph */
\r
4994 case IDM_ShowEvalGraph:
\r
4995 if( EvalGraphIsUp() ) {
\r
4996 EvalGraphPopDown();
\r
5000 SetFocus(hwndMain);
\r
5004 /* [AS] Engine output */
\r
5005 case IDM_ShowEngineOutput:
\r
5006 if( EngineOutputIsUp() ) {
\r
5007 EngineOutputPopDown();
\r
5010 EngineOutputPopUp();
\r
5014 /* [AS] User adjudication */
\r
5015 case IDM_UserAdjudication_White:
\r
5016 UserAdjudicationEvent( +1 );
\r
5019 case IDM_UserAdjudication_Black:
\r
5020 UserAdjudicationEvent( -1 );
\r
5023 case IDM_UserAdjudication_Draw:
\r
5024 UserAdjudicationEvent( 0 );
\r
5027 /* [AS] Game list options dialog */
\r
5028 case IDM_GameListOptions:
\r
5029 GameListOptions();
\r
5036 case IDM_CopyPosition:
\r
5037 CopyFENToClipboard();
\r
5040 case IDM_PastePosition:
\r
5041 PasteFENFromClipboard();
\r
5044 case IDM_MailMove:
\r
5048 case IDM_ReloadCMailMsg:
\r
5049 Reset(TRUE, TRUE);
\r
5050 ReloadCmailMsgEvent(FALSE);
\r
5053 case IDM_Minimize:
\r
5054 ShowWindow(hwnd, SW_MINIMIZE);
\r
5061 case IDM_MachineWhite:
\r
5062 MachineWhiteEvent();
\r
5064 * refresh the tags dialog only if it's visible
\r
5066 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5068 tags = PGNTags(&gameInfo);
\r
5069 TagsPopUp(tags, CmailMsg());
\r
5072 SAY("computer starts playing white");
\r
5075 case IDM_MachineBlack:
\r
5076 MachineBlackEvent();
\r
5078 * refresh the tags dialog only if it's visible
\r
5080 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5082 tags = PGNTags(&gameInfo);
\r
5083 TagsPopUp(tags, CmailMsg());
\r
5086 SAY("computer starts playing black");
\r
5089 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5090 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5093 case IDM_TwoMachines:
\r
5094 TwoMachinesEvent();
\r
5097 * refresh the tags dialog only if it's visible
\r
5099 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5101 tags = PGNTags(&gameInfo);
\r
5102 TagsPopUp(tags, CmailMsg());
\r
5105 SAY("computer starts playing both sides");
\r
5108 case IDM_AnalysisMode:
\r
5109 if(AnalyzeModeEvent()) {
\r
5110 SAY("analyzing current position");
\r
5114 case IDM_AnalyzeFile:
\r
5115 AnalyzeFileEvent();
\r
5118 case IDM_IcsClient:
\r
5122 case IDM_EditGame:
\r
5123 case IDM_EditGame2:
\r
5128 case IDM_EditPosition:
\r
5129 case IDM_EditPosition2:
\r
5130 EditPositionEvent();
\r
5131 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5134 case IDM_Training:
\r
5138 case IDM_ShowGameList:
\r
5139 ShowGameListProc();
\r
5142 case IDM_EditProgs1:
\r
5143 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5146 case IDM_LoadProg1:
\r
5147 LoadEnginePopUp(hwndMain, 0);
\r
5150 case IDM_LoadProg2:
\r
5151 LoadEnginePopUp(hwndMain, 1);
\r
5154 case IDM_EditServers:
\r
5155 EditTagsPopUp(icsNames, &icsNames);
\r
5158 case IDM_EditTags:
\r
5163 case IDM_EditBook:
\r
5167 case IDM_EditComment:
\r
5169 if (commentUp && editComment) {
\r
5172 EditCommentEvent();
\r
5193 case IDM_CallFlag:
\r
5213 case IDM_StopObserving:
\r
5214 StopObservingEvent();
\r
5217 case IDM_StopExamining:
\r
5218 StopExaminingEvent();
\r
5222 UploadGameEvent();
\r
5225 case IDM_TypeInMove:
\r
5226 TypeInEvent('\000');
\r
5229 case IDM_TypeInName:
\r
5230 PopUpNameDialog('\000');
\r
5233 case IDM_Backward:
\r
5235 SetFocus(hwndMain);
\r
5242 SetFocus(hwndMain);
\r
5247 SetFocus(hwndMain);
\r
5252 SetFocus(hwndMain);
\r
5255 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5256 case OPT_GameListPrev:
\r
5257 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5261 RevertEvent(FALSE);
\r
5264 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5265 RevertEvent(TRUE);
\r
5268 case IDM_TruncateGame:
\r
5269 TruncateGameEvent();
\r
5276 case IDM_RetractMove:
\r
5277 RetractMoveEvent();
\r
5280 case IDM_FlipView:
\r
5281 flipView = !flipView;
\r
5282 DrawPosition(FALSE, NULL);
\r
5285 case IDM_FlipClock:
\r
5286 flipClock = !flipClock;
\r
5287 DisplayBothClocks();
\r
5291 case IDM_MuteSounds:
\r
5292 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5293 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5294 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5297 case IDM_GeneralOptions:
\r
5298 GeneralOptionsPopup(hwnd);
\r
5299 DrawPosition(TRUE, NULL);
\r
5302 case IDM_BoardOptions:
\r
5303 BoardOptionsPopup(hwnd);
\r
5306 case IDM_ThemeOptions:
\r
5307 ThemeOptionsPopup(hwnd);
\r
5310 case IDM_EnginePlayOptions:
\r
5311 EnginePlayOptionsPopup(hwnd);
\r
5314 case IDM_Engine1Options:
\r
5315 EngineOptionsPopup(hwnd, &first);
\r
5318 case IDM_Engine2Options:
\r
5320 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5321 EngineOptionsPopup(hwnd, &second);
\r
5324 case IDM_OptionsUCI:
\r
5325 UciOptionsPopup(hwnd);
\r
5329 TourneyPopup(hwnd);
\r
5332 case IDM_IcsOptions:
\r
5333 IcsOptionsPopup(hwnd);
\r
5337 FontsOptionsPopup(hwnd);
\r
5341 SoundOptionsPopup(hwnd);
\r
5344 case IDM_CommPort:
\r
5345 CommPortOptionsPopup(hwnd);
\r
5348 case IDM_LoadOptions:
\r
5349 LoadOptionsPopup(hwnd);
\r
5352 case IDM_SaveOptions:
\r
5353 SaveOptionsPopup(hwnd);
\r
5356 case IDM_TimeControl:
\r
5357 TimeControlOptionsPopup(hwnd);
\r
5360 case IDM_SaveSettings:
\r
5361 SaveSettings(settingsFileName);
\r
5364 case IDM_SaveSettingsOnExit:
\r
5365 saveSettingsOnExit = !saveSettingsOnExit;
\r
5366 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5367 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5368 MF_CHECKED : MF_UNCHECKED));
\r
5379 case IDM_AboutGame:
\r
5384 appData.debugMode = !appData.debugMode;
\r
5385 if (appData.debugMode) {
\r
5386 char dir[MSG_SIZ];
\r
5387 GetCurrentDirectory(MSG_SIZ, dir);
\r
5388 SetCurrentDirectory(installDir);
\r
5389 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5390 SetCurrentDirectory(dir);
\r
5391 setbuf(debugFP, NULL);
\r
5398 case IDM_HELPCONTENTS:
\r
5399 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5400 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5401 MessageBox (GetFocus(),
\r
5402 _("Unable to activate help"),
\r
5403 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5407 case IDM_HELPSEARCH:
\r
5408 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5409 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5410 MessageBox (GetFocus(),
\r
5411 _("Unable to activate help"),
\r
5412 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5416 case IDM_HELPHELP:
\r
5417 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5418 MessageBox (GetFocus(),
\r
5419 _("Unable to activate help"),
\r
5420 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5425 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5427 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5428 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5429 FreeProcInstance(lpProc);
\r
5432 case IDM_DirectCommand1:
\r
5433 AskQuestionEvent(_("Direct Command"),
\r
5434 _("Send to chess program:"), "", "1");
\r
5436 case IDM_DirectCommand2:
\r
5437 AskQuestionEvent(_("Direct Command"),
\r
5438 _("Send to second chess program:"), "", "2");
\r
5441 case EP_WhitePawn:
\r
5442 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5443 fromX = fromY = -1;
\r
5446 case EP_WhiteKnight:
\r
5447 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5448 fromX = fromY = -1;
\r
5451 case EP_WhiteBishop:
\r
5452 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5453 fromX = fromY = -1;
\r
5456 case EP_WhiteRook:
\r
5457 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5458 fromX = fromY = -1;
\r
5461 case EP_WhiteQueen:
\r
5462 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5463 fromX = fromY = -1;
\r
5466 case EP_WhiteFerz:
\r
5467 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5468 fromX = fromY = -1;
\r
5471 case EP_WhiteWazir:
\r
5472 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5473 fromX = fromY = -1;
\r
5476 case EP_WhiteAlfil:
\r
5477 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5478 fromX = fromY = -1;
\r
5481 case EP_WhiteCannon:
\r
5482 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5483 fromX = fromY = -1;
\r
5486 case EP_WhiteCardinal:
\r
5487 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5488 fromX = fromY = -1;
\r
5491 case EP_WhiteMarshall:
\r
5492 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5493 fromX = fromY = -1;
\r
5496 case EP_WhiteKing:
\r
5497 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5498 fromX = fromY = -1;
\r
5501 case EP_BlackPawn:
\r
5502 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5503 fromX = fromY = -1;
\r
5506 case EP_BlackKnight:
\r
5507 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5508 fromX = fromY = -1;
\r
5511 case EP_BlackBishop:
\r
5512 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5513 fromX = fromY = -1;
\r
5516 case EP_BlackRook:
\r
5517 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5518 fromX = fromY = -1;
\r
5521 case EP_BlackQueen:
\r
5522 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5523 fromX = fromY = -1;
\r
5526 case EP_BlackFerz:
\r
5527 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5528 fromX = fromY = -1;
\r
5531 case EP_BlackWazir:
\r
5532 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5533 fromX = fromY = -1;
\r
5536 case EP_BlackAlfil:
\r
5537 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5538 fromX = fromY = -1;
\r
5541 case EP_BlackCannon:
\r
5542 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5543 fromX = fromY = -1;
\r
5546 case EP_BlackCardinal:
\r
5547 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5548 fromX = fromY = -1;
\r
5551 case EP_BlackMarshall:
\r
5552 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5553 fromX = fromY = -1;
\r
5556 case EP_BlackKing:
\r
5557 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5558 fromX = fromY = -1;
\r
5561 case EP_EmptySquare:
\r
5562 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5563 fromX = fromY = -1;
\r
5566 case EP_ClearBoard:
\r
5567 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5568 fromX = fromY = -1;
\r
5572 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5573 fromX = fromY = -1;
\r
5577 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5578 fromX = fromY = -1;
\r
5582 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5583 fromX = fromY = -1;
\r
5587 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5588 fromX = fromY = -1;
\r
5592 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5593 fromX = fromY = -1;
\r
5597 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5598 fromX = fromY = -1;
\r
5602 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5603 fromX = fromY = -1;
\r
5607 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5608 fromX = fromY = -1;
\r
5612 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5613 fromX = fromY = -1;
\r
5617 barbaric = 0; appData.language = "";
\r
5618 TranslateMenus(0);
\r
5619 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5620 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5621 lastChecked = wmId;
\r
5625 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5626 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5628 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5629 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5630 TranslateMenus(0);
\r
5631 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5632 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5633 lastChecked = wmId;
\r
5636 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5642 case CLOCK_TIMER_ID:
\r
5643 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5644 clockTimerEvent = 0;
\r
5645 DecrementClocks(); /* call into back end */
\r
5647 case LOAD_GAME_TIMER_ID:
\r
5648 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5649 loadGameTimerEvent = 0;
\r
5650 AutoPlayGameLoop(); /* call into back end */
\r
5652 case ANALYSIS_TIMER_ID:
\r
5653 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5654 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5655 AnalysisPeriodicEvent(0);
\r
5657 KillTimer(hwnd, analysisTimerEvent);
\r
5658 analysisTimerEvent = 0;
\r
5661 case DELAYED_TIMER_ID:
\r
5662 KillTimer(hwnd, delayedTimerEvent);
\r
5663 delayedTimerEvent = 0;
\r
5664 delayedTimerCallback();
\r
5669 case WM_USER_Input:
\r
5670 InputEvent(hwnd, message, wParam, lParam);
\r
5673 /* [AS] Also move "attached" child windows */
\r
5674 case WM_WINDOWPOSCHANGING:
\r
5676 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5677 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5679 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5680 /* Window is moving */
\r
5683 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5684 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5685 rcMain.right = wpMain.x + wpMain.width;
\r
5686 rcMain.top = wpMain.y;
\r
5687 rcMain.bottom = wpMain.y + wpMain.height;
\r
5689 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5690 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5691 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5692 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5693 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5694 wpMain.x = lpwp->x;
\r
5695 wpMain.y = lpwp->y;
\r
5700 /* [AS] Snapping */
\r
5701 case WM_ENTERSIZEMOVE:
\r
5702 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5703 if (hwnd == hwndMain) {
\r
5704 doingSizing = TRUE;
\r
5707 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5711 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5712 if (hwnd == hwndMain) {
\r
5713 lastSizing = wParam;
\r
5718 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5719 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5721 case WM_EXITSIZEMOVE:
\r
5722 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5723 if (hwnd == hwndMain) {
\r
5725 doingSizing = FALSE;
\r
5726 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5727 GetClientRect(hwnd, &client);
\r
5728 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5730 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5732 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5735 case WM_DESTROY: /* message: window being destroyed */
\r
5736 PostQuitMessage(0);
\r
5740 if (hwnd == hwndMain) {
\r
5745 default: /* Passes it on if unprocessed */
\r
5746 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5753 /*---------------------------------------------------------------------------*\
\r
5755 * Misc utility routines
\r
5757 \*---------------------------------------------------------------------------*/
\r
5760 * Decent random number generator, at least not as bad as Windows
\r
5761 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5763 unsigned int randstate;
\r
5768 randstate = randstate * 1664525 + 1013904223;
\r
5769 return (int) randstate & 0x7fffffff;
\r
5773 mysrandom(unsigned int seed)
\r
5780 * returns TRUE if user selects a different color, FALSE otherwise
\r
5784 ChangeColor(HWND hwnd, COLORREF *which)
\r
5786 static BOOL firstTime = TRUE;
\r
5787 static DWORD customColors[16];
\r
5789 COLORREF newcolor;
\r
5794 /* Make initial colors in use available as custom colors */
\r
5795 /* Should we put the compiled-in defaults here instead? */
\r
5797 customColors[i++] = lightSquareColor & 0xffffff;
\r
5798 customColors[i++] = darkSquareColor & 0xffffff;
\r
5799 customColors[i++] = whitePieceColor & 0xffffff;
\r
5800 customColors[i++] = blackPieceColor & 0xffffff;
\r
5801 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5802 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5804 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5805 customColors[i++] = textAttribs[ccl].color;
\r
5807 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5808 firstTime = FALSE;
\r
5811 cc.lStructSize = sizeof(cc);
\r
5812 cc.hwndOwner = hwnd;
\r
5813 cc.hInstance = NULL;
\r
5814 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5815 cc.lpCustColors = (LPDWORD) customColors;
\r
5816 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5818 if (!ChooseColor(&cc)) return FALSE;
\r
5820 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5821 if (newcolor == *which) return FALSE;
\r
5822 *which = newcolor;
\r
5826 InitDrawingColors();
\r
5827 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5832 MyLoadSound(MySound *ms)
\r
5838 if (ms->data && ms->flag) free(ms->data);
\r
5841 switch (ms->name[0]) {
\r
5847 /* System sound from Control Panel. Don't preload here. */
\r
5851 if (ms->name[1] == NULLCHAR) {
\r
5852 /* "!" alone = silence */
\r
5855 /* Builtin wave resource. Error if not found. */
\r
5856 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5857 if (h == NULL) break;
\r
5858 ms->data = (void *)LoadResource(hInst, h);
\r
5859 ms->flag = 0; // not maloced, so cannot be freed!
\r
5860 if (h == NULL) break;
\r
5865 /* .wav file. Error if not found. */
\r
5866 f = fopen(ms->name, "rb");
\r
5867 if (f == NULL) break;
\r
5868 if (fstat(fileno(f), &st) < 0) break;
\r
5869 ms->data = malloc(st.st_size);
\r
5871 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5877 char buf[MSG_SIZ];
\r
5878 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5879 DisplayError(buf, GetLastError());
\r
5885 MyPlaySound(MySound *ms)
\r
5887 BOOLEAN ok = FALSE;
\r
5889 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5890 switch (ms->name[0]) {
\r
5892 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5897 /* System sound from Control Panel (deprecated feature).
\r
5898 "$" alone or an unset sound name gets default beep (still in use). */
\r
5899 if (ms->name[1]) {
\r
5900 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5902 if (!ok) ok = MessageBeep(MB_OK);
\r
5905 /* Builtin wave resource, or "!" alone for silence */
\r
5906 if (ms->name[1]) {
\r
5907 if (ms->data == NULL) return FALSE;
\r
5908 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5914 /* .wav file. Error if not found. */
\r
5915 if (ms->data == NULL) return FALSE;
\r
5916 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5919 /* Don't print an error: this can happen innocently if the sound driver
\r
5920 is busy; for instance, if another instance of WinBoard is playing
\r
5921 a sound at about the same time. */
\r
5927 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5930 OPENFILENAME *ofn;
\r
5931 static UINT *number; /* gross that this is static */
\r
5933 switch (message) {
\r
5934 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5935 /* Center the dialog over the application window */
\r
5936 ofn = (OPENFILENAME *) lParam;
\r
5937 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5938 number = (UINT *) ofn->lCustData;
\r
5939 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5943 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5944 Translate(hDlg, 1536);
\r
5945 return FALSE; /* Allow for further processing */
\r
5948 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5949 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5951 return FALSE; /* Allow for further processing */
\r
5957 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5959 static UINT *number;
\r
5960 OPENFILENAME *ofname;
\r
5963 case WM_INITDIALOG:
\r
5964 Translate(hdlg, DLG_IndexNumber);
\r
5965 ofname = (OPENFILENAME *)lParam;
\r
5966 number = (UINT *)(ofname->lCustData);
\r
5969 ofnot = (OFNOTIFY *)lParam;
\r
5970 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5971 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5980 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5981 char *nameFilt, char *dlgTitle, UINT *number,
\r
5982 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5984 OPENFILENAME openFileName;
\r
5985 char buf1[MSG_SIZ];
\r
5988 if (fileName == NULL) fileName = buf1;
\r
5989 if (defName == NULL) {
\r
5990 safeStrCpy(fileName, "*.", 3 );
\r
5991 strcat(fileName, defExt);
\r
5993 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5995 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5996 if (number) *number = 0;
\r
5998 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5999 openFileName.hwndOwner = hwnd;
\r
6000 openFileName.hInstance = (HANDLE) hInst;
\r
6001 openFileName.lpstrFilter = nameFilt;
\r
6002 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6003 openFileName.nMaxCustFilter = 0L;
\r
6004 openFileName.nFilterIndex = 1L;
\r
6005 openFileName.lpstrFile = fileName;
\r
6006 openFileName.nMaxFile = MSG_SIZ;
\r
6007 openFileName.lpstrFileTitle = fileTitle;
\r
6008 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6009 openFileName.lpstrInitialDir = NULL;
\r
6010 openFileName.lpstrTitle = dlgTitle;
\r
6011 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6012 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6013 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6014 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6015 openFileName.nFileOffset = 0;
\r
6016 openFileName.nFileExtension = 0;
\r
6017 openFileName.lpstrDefExt = defExt;
\r
6018 openFileName.lCustData = (LONG) number;
\r
6019 openFileName.lpfnHook = oldDialog ?
\r
6020 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6021 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6023 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6024 GetOpenFileName(&openFileName)) {
\r
6025 /* open the file */
\r
6026 f = fopen(openFileName.lpstrFile, write);
\r
6028 MessageBox(hwnd, _("File open failed"), NULL,
\r
6029 MB_OK|MB_ICONEXCLAMATION);
\r
6033 int err = CommDlgExtendedError();
\r
6034 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6043 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6045 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6048 * Get the first pop-up menu in the menu template. This is the
\r
6049 * menu that TrackPopupMenu displays.
\r
6051 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6052 TranslateOneMenu(10, hmenuTrackPopup);
\r
6054 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6057 * TrackPopup uses screen coordinates, so convert the
\r
6058 * coordinates of the mouse click to screen coordinates.
\r
6060 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6062 /* Draw and track the floating pop-up menu. */
\r
6063 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6064 pt.x, pt.y, 0, hwnd, NULL);
\r
6066 /* Destroy the menu.*/
\r
6067 DestroyMenu(hmenu);
\r
6072 int sizeX, sizeY, newSizeX, newSizeY;
\r
6074 } ResizeEditPlusButtonsClosure;
\r
6077 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6079 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6083 if (hChild == cl->hText) return TRUE;
\r
6084 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6085 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6086 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6087 ScreenToClient(cl->hDlg, &pt);
\r
6088 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6089 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6093 /* Resize a dialog that has a (rich) edit field filling most of
\r
6094 the top, with a row of buttons below */
\r
6096 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6099 int newTextHeight, newTextWidth;
\r
6100 ResizeEditPlusButtonsClosure cl;
\r
6102 /*if (IsIconic(hDlg)) return;*/
\r
6103 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6105 cl.hdwp = BeginDeferWindowPos(8);
\r
6107 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6108 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6109 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6110 if (newTextHeight < 0) {
\r
6111 newSizeY += -newTextHeight;
\r
6112 newTextHeight = 0;
\r
6114 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6115 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6121 cl.newSizeX = newSizeX;
\r
6122 cl.newSizeY = newSizeY;
\r
6123 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6125 EndDeferWindowPos(cl.hdwp);
\r
6128 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6130 RECT rChild, rParent;
\r
6131 int wChild, hChild, wParent, hParent;
\r
6132 int wScreen, hScreen, xNew, yNew;
\r
6135 /* Get the Height and Width of the child window */
\r
6136 GetWindowRect (hwndChild, &rChild);
\r
6137 wChild = rChild.right - rChild.left;
\r
6138 hChild = rChild.bottom - rChild.top;
\r
6140 /* Get the Height and Width of the parent window */
\r
6141 GetWindowRect (hwndParent, &rParent);
\r
6142 wParent = rParent.right - rParent.left;
\r
6143 hParent = rParent.bottom - rParent.top;
\r
6145 /* Get the display limits */
\r
6146 hdc = GetDC (hwndChild);
\r
6147 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6148 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6149 ReleaseDC(hwndChild, hdc);
\r
6151 /* Calculate new X position, then adjust for screen */
\r
6152 xNew = rParent.left + ((wParent - wChild) /2);
\r
6155 } else if ((xNew+wChild) > wScreen) {
\r
6156 xNew = wScreen - wChild;
\r
6159 /* Calculate new Y position, then adjust for screen */
\r
6161 yNew = rParent.top + ((hParent - hChild) /2);
\r
6164 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6169 } else if ((yNew+hChild) > hScreen) {
\r
6170 yNew = hScreen - hChild;
\r
6173 /* Set it, and return */
\r
6174 return SetWindowPos (hwndChild, NULL,
\r
6175 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6178 /* Center one window over another */
\r
6179 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6181 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6184 /*---------------------------------------------------------------------------*\
\r
6186 * Startup Dialog functions
\r
6188 \*---------------------------------------------------------------------------*/
\r
6190 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6192 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6194 while (*cd != NULL) {
\r
6195 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6201 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6203 char buf1[MAX_ARG_LEN];
\r
6206 if (str[0] == '@') {
\r
6207 FILE* f = fopen(str + 1, "r");
\r
6209 DisplayFatalError(str + 1, errno, 2);
\r
6212 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6214 buf1[len] = NULLCHAR;
\r
6218 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6221 char buf[MSG_SIZ];
\r
6222 char *end = strchr(str, '\n');
\r
6223 if (end == NULL) return;
\r
6224 memcpy(buf, str, end - str);
\r
6225 buf[end - str] = NULLCHAR;
\r
6226 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6232 SetStartupDialogEnables(HWND hDlg)
\r
6234 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6235 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6236 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6237 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6238 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6239 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6240 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6241 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6242 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6243 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6244 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6245 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6246 IsDlgButtonChecked(hDlg, OPT_View));
\r
6250 QuoteForFilename(char *filename)
\r
6252 int dquote, space;
\r
6253 dquote = strchr(filename, '"') != NULL;
\r
6254 space = strchr(filename, ' ') != NULL;
\r
6255 if (dquote || space) {
\r
6267 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6269 char buf[MSG_SIZ];
\r
6272 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6273 q = QuoteForFilename(nthcp);
\r
6274 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6275 if (*nthdir != NULLCHAR) {
\r
6276 q = QuoteForFilename(nthdir);
\r
6277 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6279 if (*nthcp == NULLCHAR) {
\r
6280 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6281 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6282 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6283 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6288 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6290 char buf[MSG_SIZ];
\r
6294 switch (message) {
\r
6295 case WM_INITDIALOG:
\r
6296 /* Center the dialog */
\r
6297 CenterWindow (hDlg, GetDesktopWindow());
\r
6298 Translate(hDlg, DLG_Startup);
\r
6299 /* Initialize the dialog items */
\r
6300 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6301 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6302 firstChessProgramNames);
\r
6303 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6304 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6305 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6306 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6307 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6308 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6309 if (*appData.icsHelper != NULLCHAR) {
\r
6310 char *q = QuoteForFilename(appData.icsHelper);
\r
6311 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6313 if (*appData.icsHost == NULLCHAR) {
\r
6314 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6315 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6316 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6317 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6318 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6321 if (appData.icsActive) {
\r
6322 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6324 else if (appData.noChessProgram) {
\r
6325 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6328 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6331 SetStartupDialogEnables(hDlg);
\r
6335 switch (LOWORD(wParam)) {
\r
6337 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6338 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6339 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6341 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6342 ParseArgs(StringGet, &p);
\r
6343 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6344 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6346 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6347 ParseArgs(StringGet, &p);
\r
6348 SwapEngines(singleList); // ... and then make it 'second'
\r
6350 appData.noChessProgram = FALSE;
\r
6351 appData.icsActive = FALSE;
\r
6352 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6353 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6354 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6356 ParseArgs(StringGet, &p);
\r
6357 if (appData.zippyPlay) {
\r
6358 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6359 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6361 ParseArgs(StringGet, &p);
\r
6363 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6364 appData.noChessProgram = TRUE;
\r
6365 appData.icsActive = FALSE;
\r
6367 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6368 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6371 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6372 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6374 ParseArgs(StringGet, &p);
\r
6376 EndDialog(hDlg, TRUE);
\r
6383 case IDM_HELPCONTENTS:
\r
6384 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6385 MessageBox (GetFocus(),
\r
6386 _("Unable to activate help"),
\r
6387 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6392 SetStartupDialogEnables(hDlg);
\r
6400 /*---------------------------------------------------------------------------*\
\r
6402 * About box dialog functions
\r
6404 \*---------------------------------------------------------------------------*/
\r
6406 /* Process messages for "About" dialog box */
\r
6408 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6410 switch (message) {
\r
6411 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6412 /* Center the dialog over the application window */
\r
6413 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6414 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6415 Translate(hDlg, ABOUTBOX);
\r
6419 case WM_COMMAND: /* message: received a command */
\r
6420 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6421 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6422 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6430 /*---------------------------------------------------------------------------*\
\r
6432 * Comment Dialog functions
\r
6434 \*---------------------------------------------------------------------------*/
\r
6437 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6439 static HANDLE hwndText = NULL;
\r
6440 int len, newSizeX, newSizeY;
\r
6441 static int sizeX, sizeY;
\r
6446 switch (message) {
\r
6447 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6448 /* Initialize the dialog items */
\r
6449 Translate(hDlg, DLG_EditComment);
\r
6450 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6451 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6452 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6453 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6454 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6455 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6456 SetWindowText(hDlg, commentTitle);
\r
6457 if (editComment) {
\r
6458 SetFocus(hwndText);
\r
6460 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6462 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6463 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6464 MAKELPARAM(FALSE, 0));
\r
6465 /* Size and position the dialog */
\r
6466 if (!commentDialog) {
\r
6467 commentDialog = hDlg;
\r
6468 GetClientRect(hDlg, &rect);
\r
6469 sizeX = rect.right;
\r
6470 sizeY = rect.bottom;
\r
6471 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6472 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6473 WINDOWPLACEMENT wp;
\r
6474 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6475 wp.length = sizeof(WINDOWPLACEMENT);
\r
6477 wp.showCmd = SW_SHOW;
\r
6478 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6479 wp.rcNormalPosition.left = wpComment.x;
\r
6480 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6481 wp.rcNormalPosition.top = wpComment.y;
\r
6482 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6483 SetWindowPlacement(hDlg, &wp);
\r
6485 GetClientRect(hDlg, &rect);
\r
6486 newSizeX = rect.right;
\r
6487 newSizeY = rect.bottom;
\r
6488 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6489 newSizeX, newSizeY);
\r
6494 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6497 case WM_COMMAND: /* message: received a command */
\r
6498 switch (LOWORD(wParam)) {
\r
6500 if (editComment) {
\r
6502 /* Read changed options from the dialog box */
\r
6503 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6504 len = GetWindowTextLength(hwndText);
\r
6505 str = (char *) malloc(len + 1);
\r
6506 GetWindowText(hwndText, str, len + 1);
\r
6515 ReplaceComment(commentIndex, str);
\r
6522 case OPT_CancelComment:
\r
6526 case OPT_ClearComment:
\r
6527 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6530 case OPT_EditComment:
\r
6531 EditCommentEvent();
\r
6539 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6540 if( wParam == OPT_CommentText ) {
\r
6541 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6543 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6544 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6548 pt.x = LOWORD( lpMF->lParam );
\r
6549 pt.y = HIWORD( lpMF->lParam );
\r
6551 if(lpMF->msg == WM_CHAR) {
\r
6553 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6554 index = sel.cpMin;
\r
6556 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6558 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6559 len = GetWindowTextLength(hwndText);
\r
6560 str = (char *) malloc(len + 1);
\r
6561 GetWindowText(hwndText, str, len + 1);
\r
6562 ReplaceComment(commentIndex, str);
\r
6563 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6564 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6567 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6568 lpMF->msg = WM_USER;
\r
6576 newSizeX = LOWORD(lParam);
\r
6577 newSizeY = HIWORD(lParam);
\r
6578 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6583 case WM_GETMINMAXINFO:
\r
6584 /* Prevent resizing window too small */
\r
6585 mmi = (MINMAXINFO *) lParam;
\r
6586 mmi->ptMinTrackSize.x = 100;
\r
6587 mmi->ptMinTrackSize.y = 100;
\r
6594 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6599 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6601 if (str == NULL) str = "";
\r
6602 p = (char *) malloc(2 * strlen(str) + 2);
\r
6605 if (*str == '\n') *q++ = '\r';
\r
6609 if (commentText != NULL) free(commentText);
\r
6611 commentIndex = index;
\r
6612 commentTitle = title;
\r
6614 editComment = edit;
\r
6616 if (commentDialog) {
\r
6617 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6618 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6620 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6621 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6622 hwndMain, (DLGPROC)lpProc);
\r
6623 FreeProcInstance(lpProc);
\r
6629 /*---------------------------------------------------------------------------*\
\r
6631 * Type-in move dialog functions
\r
6633 \*---------------------------------------------------------------------------*/
\r
6636 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6638 char move[MSG_SIZ];
\r
6641 switch (message) {
\r
6642 case WM_INITDIALOG:
\r
6643 move[0] = (char) lParam;
\r
6644 move[1] = NULLCHAR;
\r
6645 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6646 Translate(hDlg, DLG_TypeInMove);
\r
6647 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6648 SetWindowText(hInput, move);
\r
6650 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6654 switch (LOWORD(wParam)) {
\r
6657 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6658 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6659 TypeInDoneEvent(move);
\r
6660 EndDialog(hDlg, TRUE);
\r
6663 EndDialog(hDlg, FALSE);
\r
6674 PopUpMoveDialog(char firstchar)
\r
6678 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6679 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6680 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6681 FreeProcInstance(lpProc);
\r
6684 /*---------------------------------------------------------------------------*\
\r
6686 * Type-in name dialog functions
\r
6688 \*---------------------------------------------------------------------------*/
\r
6691 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6693 char move[MSG_SIZ];
\r
6696 switch (message) {
\r
6697 case WM_INITDIALOG:
\r
6698 move[0] = (char) lParam;
\r
6699 move[1] = NULLCHAR;
\r
6700 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6701 Translate(hDlg, DLG_TypeInName);
\r
6702 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6703 SetWindowText(hInput, move);
\r
6705 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6709 switch (LOWORD(wParam)) {
\r
6711 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6712 appData.userName = strdup(move);
\r
6715 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6716 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6717 DisplayTitle(move);
\r
6721 EndDialog(hDlg, TRUE);
\r
6724 EndDialog(hDlg, FALSE);
\r
6735 PopUpNameDialog(char firstchar)
\r
6739 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6740 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6741 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6742 FreeProcInstance(lpProc);
\r
6745 /*---------------------------------------------------------------------------*\
\r
6749 \*---------------------------------------------------------------------------*/
\r
6751 /* Nonmodal error box */
\r
6752 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6753 WPARAM wParam, LPARAM lParam);
\r
6756 ErrorPopUp(char *title, char *content)
\r
6760 BOOLEAN modal = hwndMain == NULL;
\r
6778 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6779 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6782 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6784 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6785 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6786 hwndMain, (DLGPROC)lpProc);
\r
6787 FreeProcInstance(lpProc);
\r
6794 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6795 if (errorDialog == NULL) return;
\r
6796 DestroyWindow(errorDialog);
\r
6797 errorDialog = NULL;
\r
6798 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6802 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6806 switch (message) {
\r
6807 case WM_INITDIALOG:
\r
6808 GetWindowRect(hDlg, &rChild);
\r
6811 SetWindowPos(hDlg, NULL, rChild.left,
\r
6812 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6813 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6817 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6818 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6819 and it doesn't work when you resize the dialog.
\r
6820 For now, just give it a default position.
\r
6822 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6823 Translate(hDlg, DLG_Error);
\r
6825 errorDialog = hDlg;
\r
6826 SetWindowText(hDlg, errorTitle);
\r
6827 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6831 switch (LOWORD(wParam)) {
\r
6834 if (errorDialog == hDlg) errorDialog = NULL;
\r
6835 DestroyWindow(hDlg);
\r
6847 HWND gothicDialog = NULL;
\r
6850 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6853 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6855 switch (message) {
\r
6856 case WM_INITDIALOG:
\r
6857 GetWindowRect(hDlg, &rChild);
\r
6859 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6863 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6864 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6865 and it doesn't work when you resize the dialog.
\r
6866 For now, just give it a default position.
\r
6868 gothicDialog = hDlg;
\r
6869 SetWindowText(hDlg, errorTitle);
\r
6870 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6874 switch (LOWORD(wParam)) {
\r
6877 if (errorDialog == hDlg) errorDialog = NULL;
\r
6878 DestroyWindow(hDlg);
\r
6890 GothicPopUp(char *title, VariantClass variant)
\r
6893 static char *lastTitle;
\r
6895 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6896 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6898 if(lastTitle != title && gothicDialog != NULL) {
\r
6899 DestroyWindow(gothicDialog);
\r
6900 gothicDialog = NULL;
\r
6902 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6903 title = lastTitle;
\r
6904 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6905 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6906 hwndMain, (DLGPROC)lpProc);
\r
6907 FreeProcInstance(lpProc);
\r
6912 /*---------------------------------------------------------------------------*\
\r
6914 * Ics Interaction console functions
\r
6916 \*---------------------------------------------------------------------------*/
\r
6918 #define HISTORY_SIZE 64
\r
6919 static char *history[HISTORY_SIZE];
\r
6920 int histIn = 0, histP = 0;
\r
6924 SaveInHistory(char *cmd)
\r
6926 if (history[histIn] != NULL) {
\r
6927 free(history[histIn]);
\r
6928 history[histIn] = NULL;
\r
6930 if (*cmd == NULLCHAR) return;
\r
6931 history[histIn] = StrSave(cmd);
\r
6932 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6933 if (history[histIn] != NULL) {
\r
6934 free(history[histIn]);
\r
6936 history[histIn] = NULL;
\r
6942 PrevInHistory(char *cmd)
\r
6945 if (histP == histIn) {
\r
6946 if (history[histIn] != NULL) free(history[histIn]);
\r
6947 history[histIn] = StrSave(cmd);
\r
6949 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6950 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6952 return history[histP];
\r
6958 if (histP == histIn) return NULL;
\r
6959 histP = (histP + 1) % HISTORY_SIZE;
\r
6960 return history[histP];
\r
6964 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6968 hmenu = LoadMenu(hInst, "TextMenu");
\r
6969 h = GetSubMenu(hmenu, 0);
\r
6971 if (strcmp(e->item, "-") == 0) {
\r
6972 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6973 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6974 int flags = MF_STRING, j = 0;
\r
6975 if (e->item[0] == '|') {
\r
6976 flags |= MF_MENUBARBREAK;
\r
6979 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6980 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6988 WNDPROC consoleTextWindowProc;
\r
6991 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6993 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6994 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6998 SetWindowText(hInput, command);
\r
7000 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7002 sel.cpMin = 999999;
\r
7003 sel.cpMax = 999999;
\r
7004 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7009 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7010 if (sel.cpMin == sel.cpMax) {
\r
7011 /* Expand to surrounding word */
\r
7014 tr.chrg.cpMax = sel.cpMin;
\r
7015 tr.chrg.cpMin = --sel.cpMin;
\r
7016 if (sel.cpMin < 0) break;
\r
7017 tr.lpstrText = name;
\r
7018 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7019 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7023 tr.chrg.cpMin = sel.cpMax;
\r
7024 tr.chrg.cpMax = ++sel.cpMax;
\r
7025 tr.lpstrText = name;
\r
7026 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7027 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7030 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7031 MessageBeep(MB_ICONEXCLAMATION);
\r
7035 tr.lpstrText = name;
\r
7036 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7038 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7039 MessageBeep(MB_ICONEXCLAMATION);
\r
7042 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7045 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7046 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7047 SetWindowText(hInput, buf);
\r
7048 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7050 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7051 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7052 SetWindowText(hInput, buf);
\r
7053 sel.cpMin = 999999;
\r
7054 sel.cpMax = 999999;
\r
7055 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7061 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7066 switch (message) {
\r
7068 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7069 if(wParam=='R') return 0;
\r
7072 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7075 sel.cpMin = 999999;
\r
7076 sel.cpMax = 999999;
\r
7077 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7078 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7083 if(wParam != '\022') {
\r
7084 if (wParam == '\t') {
\r
7085 if (GetKeyState(VK_SHIFT) < 0) {
\r
7087 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7088 if (buttonDesc[0].hwnd) {
\r
7089 SetFocus(buttonDesc[0].hwnd);
\r
7091 SetFocus(hwndMain);
\r
7095 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7098 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7099 JAWS_DELETE( SetFocus(hInput); )
\r
7100 SendMessage(hInput, message, wParam, lParam);
\r
7103 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7105 case WM_RBUTTONDOWN:
\r
7106 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7107 /* Move selection here if it was empty */
\r
7109 pt.x = LOWORD(lParam);
\r
7110 pt.y = HIWORD(lParam);
\r
7111 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7112 if (sel.cpMin == sel.cpMax) {
\r
7113 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7114 sel.cpMax = sel.cpMin;
\r
7115 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7117 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7118 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7120 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7121 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7122 if (sel.cpMin == sel.cpMax) {
\r
7123 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7124 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7126 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7127 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7129 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7130 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7131 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7132 MenuPopup(hwnd, pt, hmenu, -1);
\r
7136 case WM_RBUTTONUP:
\r
7137 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7138 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7139 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7143 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7145 return SendMessage(hInput, message, wParam, lParam);
\r
7146 case WM_MBUTTONDOWN:
\r
7147 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7149 switch (LOWORD(wParam)) {
\r
7150 case IDM_QuickPaste:
\r
7152 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7153 if (sel.cpMin == sel.cpMax) {
\r
7154 MessageBeep(MB_ICONEXCLAMATION);
\r
7157 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7158 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7159 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7164 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7167 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7170 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7174 int i = LOWORD(wParam) - IDM_CommandX;
\r
7175 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7176 icsTextMenuEntry[i].command != NULL) {
\r
7177 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7178 icsTextMenuEntry[i].getname,
\r
7179 icsTextMenuEntry[i].immediate);
\r
7187 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7190 WNDPROC consoleInputWindowProc;
\r
7193 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7195 char buf[MSG_SIZ];
\r
7197 static BOOL sendNextChar = FALSE;
\r
7198 static BOOL quoteNextChar = FALSE;
\r
7199 InputSource *is = consoleInputSource;
\r
7203 switch (message) {
\r
7205 if (!appData.localLineEditing || sendNextChar) {
\r
7206 is->buf[0] = (CHAR) wParam;
\r
7208 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7209 sendNextChar = FALSE;
\r
7212 if (quoteNextChar) {
\r
7213 buf[0] = (char) wParam;
\r
7214 buf[1] = NULLCHAR;
\r
7215 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7216 quoteNextChar = FALSE;
\r
7220 case '\r': /* Enter key */
\r
7221 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7222 if (consoleEcho) SaveInHistory(is->buf);
\r
7223 is->buf[is->count++] = '\n';
\r
7224 is->buf[is->count] = NULLCHAR;
\r
7225 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7226 if (consoleEcho) {
\r
7227 ConsoleOutput(is->buf, is->count, TRUE);
\r
7228 } else if (appData.localLineEditing) {
\r
7229 ConsoleOutput("\n", 1, TRUE);
\r
7232 case '\033': /* Escape key */
\r
7233 SetWindowText(hwnd, "");
\r
7234 cf.cbSize = sizeof(CHARFORMAT);
\r
7235 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7236 if (consoleEcho) {
\r
7237 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7239 cf.crTextColor = COLOR_ECHOOFF;
\r
7241 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7242 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7244 case '\t': /* Tab key */
\r
7245 if (GetKeyState(VK_SHIFT) < 0) {
\r
7247 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7250 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7251 if (buttonDesc[0].hwnd) {
\r
7252 SetFocus(buttonDesc[0].hwnd);
\r
7254 SetFocus(hwndMain);
\r
7258 case '\023': /* Ctrl+S */
\r
7259 sendNextChar = TRUE;
\r
7261 case '\021': /* Ctrl+Q */
\r
7262 quoteNextChar = TRUE;
\r
7272 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7273 p = PrevInHistory(buf);
\r
7275 SetWindowText(hwnd, p);
\r
7276 sel.cpMin = 999999;
\r
7277 sel.cpMax = 999999;
\r
7278 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7283 p = NextInHistory();
\r
7285 SetWindowText(hwnd, p);
\r
7286 sel.cpMin = 999999;
\r
7287 sel.cpMax = 999999;
\r
7288 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7294 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7298 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7302 case WM_MBUTTONDOWN:
\r
7303 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7304 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7306 case WM_RBUTTONUP:
\r
7307 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7308 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7309 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7313 hmenu = LoadMenu(hInst, "InputMenu");
\r
7314 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7315 if (sel.cpMin == sel.cpMax) {
\r
7316 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7317 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7319 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7320 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7322 pt.x = LOWORD(lParam);
\r
7323 pt.y = HIWORD(lParam);
\r
7324 MenuPopup(hwnd, pt, hmenu, -1);
\r
7328 switch (LOWORD(wParam)) {
\r
7330 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7332 case IDM_SelectAll:
\r
7334 sel.cpMax = -1; /*999999?*/
\r
7335 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7338 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7341 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7344 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7349 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7352 #define CO_MAX 100000
\r
7353 #define CO_TRIM 1000
\r
7356 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7358 static SnapData sd;
\r
7359 HWND hText, hInput;
\r
7361 static int sizeX, sizeY;
\r
7362 int newSizeX, newSizeY;
\r
7366 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7367 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7369 switch (message) {
\r
7371 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7373 ENLINK *pLink = (ENLINK*)lParam;
\r
7374 if (pLink->msg == WM_LBUTTONUP)
\r
7378 tr.chrg = pLink->chrg;
\r
7379 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7380 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7381 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7382 free(tr.lpstrText);
\r
7386 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7387 hwndConsole = hDlg;
\r
7389 consoleTextWindowProc = (WNDPROC)
\r
7390 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7391 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7392 consoleInputWindowProc = (WNDPROC)
\r
7393 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7394 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7395 Colorize(ColorNormal, TRUE);
\r
7396 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7397 ChangedConsoleFont();
\r
7398 GetClientRect(hDlg, &rect);
\r
7399 sizeX = rect.right;
\r
7400 sizeY = rect.bottom;
\r
7401 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7402 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7403 WINDOWPLACEMENT wp;
\r
7404 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7405 wp.length = sizeof(WINDOWPLACEMENT);
\r
7407 wp.showCmd = SW_SHOW;
\r
7408 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7409 wp.rcNormalPosition.left = wpConsole.x;
\r
7410 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7411 wp.rcNormalPosition.top = wpConsole.y;
\r
7412 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7413 SetWindowPlacement(hDlg, &wp);
\r
7416 // [HGM] Chessknight's change 2004-07-13
\r
7417 else { /* Determine Defaults */
\r
7418 WINDOWPLACEMENT wp;
\r
7419 wpConsole.x = wpMain.width + 1;
\r
7420 wpConsole.y = wpMain.y;
\r
7421 wpConsole.width = screenWidth - wpMain.width;
\r
7422 wpConsole.height = wpMain.height;
\r
7423 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7424 wp.length = sizeof(WINDOWPLACEMENT);
\r
7426 wp.showCmd = SW_SHOW;
\r
7427 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7428 wp.rcNormalPosition.left = wpConsole.x;
\r
7429 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7430 wp.rcNormalPosition.top = wpConsole.y;
\r
7431 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7432 SetWindowPlacement(hDlg, &wp);
\r
7435 // Allow hText to highlight URLs and send notifications on them
\r
7436 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7437 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7438 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7439 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7453 if (IsIconic(hDlg)) break;
\r
7454 newSizeX = LOWORD(lParam);
\r
7455 newSizeY = HIWORD(lParam);
\r
7456 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7457 RECT rectText, rectInput;
\r
7459 int newTextHeight, newTextWidth;
\r
7460 GetWindowRect(hText, &rectText);
\r
7461 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7462 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7463 if (newTextHeight < 0) {
\r
7464 newSizeY += -newTextHeight;
\r
7465 newTextHeight = 0;
\r
7467 SetWindowPos(hText, NULL, 0, 0,
\r
7468 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7469 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7470 pt.x = rectInput.left;
\r
7471 pt.y = rectInput.top + newSizeY - sizeY;
\r
7472 ScreenToClient(hDlg, &pt);
\r
7473 SetWindowPos(hInput, NULL,
\r
7474 pt.x, pt.y, /* needs client coords */
\r
7475 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7476 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7482 case WM_GETMINMAXINFO:
\r
7483 /* Prevent resizing window too small */
\r
7484 mmi = (MINMAXINFO *) lParam;
\r
7485 mmi->ptMinTrackSize.x = 100;
\r
7486 mmi->ptMinTrackSize.y = 100;
\r
7489 /* [AS] Snapping */
\r
7490 case WM_ENTERSIZEMOVE:
\r
7491 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7494 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7497 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7499 case WM_EXITSIZEMOVE:
\r
7500 UpdateICSWidth(hText);
\r
7501 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7504 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7512 if (hwndConsole) return;
\r
7513 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7514 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7519 ConsoleOutput(char* data, int length, int forceVisible)
\r
7524 char buf[CO_MAX+1];
\r
7527 static int delayLF = 0;
\r
7528 CHARRANGE savesel, sel;
\r
7530 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7538 while (length--) {
\r
7546 } else if (*p == '\007') {
\r
7547 MyPlaySound(&sounds[(int)SoundBell]);
\r
7554 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7555 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7556 /* Save current selection */
\r
7557 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7558 exlen = GetWindowTextLength(hText);
\r
7559 /* Find out whether current end of text is visible */
\r
7560 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7561 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7562 /* Trim existing text if it's too long */
\r
7563 if (exlen + (q - buf) > CO_MAX) {
\r
7564 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7567 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7568 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7570 savesel.cpMin -= trim;
\r
7571 savesel.cpMax -= trim;
\r
7572 if (exlen < 0) exlen = 0;
\r
7573 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7574 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7576 /* Append the new text */
\r
7577 sel.cpMin = exlen;
\r
7578 sel.cpMax = exlen;
\r
7579 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7580 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7581 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7582 if (forceVisible || exlen == 0 ||
\r
7583 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7584 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7585 /* Scroll to make new end of text visible if old end of text
\r
7586 was visible or new text is an echo of user typein */
\r
7587 sel.cpMin = 9999999;
\r
7588 sel.cpMax = 9999999;
\r
7589 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7590 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7591 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7592 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7594 if (savesel.cpMax == exlen || forceVisible) {
\r
7595 /* Move insert point to new end of text if it was at the old
\r
7596 end of text or if the new text is an echo of user typein */
\r
7597 sel.cpMin = 9999999;
\r
7598 sel.cpMax = 9999999;
\r
7599 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7601 /* Restore previous selection */
\r
7602 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7604 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7611 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7615 COLORREF oldFg, oldBg;
\r
7619 if(copyNumber > 1)
\r
7620 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7622 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7623 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7624 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7627 rect.right = x + squareSize;
\r
7629 rect.bottom = y + squareSize;
\r
7632 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7633 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7634 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7635 &rect, str, strlen(str), NULL);
\r
7637 (void) SetTextColor(hdc, oldFg);
\r
7638 (void) SetBkColor(hdc, oldBg);
\r
7639 (void) SelectObject(hdc, oldFont);
\r
7643 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7644 RECT *rect, char *color, char *flagFell)
\r
7648 COLORREF oldFg, oldBg;
\r
7651 if (twoBoards && partnerUp) return;
\r
7652 if (appData.clockMode) {
\r
7653 if (tinyLayout == 2)
\r
7654 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7656 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7663 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7664 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7666 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7667 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7669 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7673 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7674 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7675 rect, str, strlen(str), NULL);
\r
7676 if(logoHeight > 0 && appData.clockMode) {
\r
7678 str += strlen(color)+2;
\r
7679 r.top = rect->top + logoHeight/2;
\r
7680 r.left = rect->left;
\r
7681 r.right = rect->right;
\r
7682 r.bottom = rect->bottom;
\r
7683 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7684 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7685 &r, str, strlen(str), NULL);
\r
7687 (void) SetTextColor(hdc, oldFg);
\r
7688 (void) SetBkColor(hdc, oldBg);
\r
7689 (void) SelectObject(hdc, oldFont);
\r
7694 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7700 if( count <= 0 ) {
\r
7701 if (appData.debugMode) {
\r
7702 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7705 return ERROR_INVALID_USER_BUFFER;
\r
7708 ResetEvent(ovl->hEvent);
\r
7709 ovl->Offset = ovl->OffsetHigh = 0;
\r
7710 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7714 err = GetLastError();
\r
7715 if (err == ERROR_IO_PENDING) {
\r
7716 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7720 err = GetLastError();
\r
7727 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7732 ResetEvent(ovl->hEvent);
\r
7733 ovl->Offset = ovl->OffsetHigh = 0;
\r
7734 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7738 err = GetLastError();
\r
7739 if (err == ERROR_IO_PENDING) {
\r
7740 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7744 err = GetLastError();
\r
7751 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7752 void CheckForInputBufferFull( InputSource * is )
\r
7754 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7755 /* Look for end of line */
\r
7756 char * p = is->buf;
\r
7758 while( p < is->next && *p != '\n' ) {
\r
7762 if( p >= is->next ) {
\r
7763 if (appData.debugMode) {
\r
7764 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7767 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7768 is->count = (DWORD) -1;
\r
7769 is->next = is->buf;
\r
7775 InputThread(LPVOID arg)
\r
7780 is = (InputSource *) arg;
\r
7781 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7782 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7783 while (is->hThread != NULL) {
\r
7784 is->error = DoReadFile(is->hFile, is->next,
\r
7785 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7786 &is->count, &ovl);
\r
7787 if (is->error == NO_ERROR) {
\r
7788 is->next += is->count;
\r
7790 if (is->error == ERROR_BROKEN_PIPE) {
\r
7791 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7794 is->count = (DWORD) -1;
\r
7795 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7800 CheckForInputBufferFull( is );
\r
7802 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7804 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7806 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7809 CloseHandle(ovl.hEvent);
\r
7810 CloseHandle(is->hFile);
\r
7812 if (appData.debugMode) {
\r
7813 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7820 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7822 NonOvlInputThread(LPVOID arg)
\r
7829 is = (InputSource *) arg;
\r
7830 while (is->hThread != NULL) {
\r
7831 is->error = ReadFile(is->hFile, is->next,
\r
7832 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7833 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7834 if (is->error == NO_ERROR) {
\r
7835 /* Change CRLF to LF */
\r
7836 if (is->next > is->buf) {
\r
7838 i = is->count + 1;
\r
7846 if (prev == '\r' && *p == '\n') {
\r
7858 if (is->error == ERROR_BROKEN_PIPE) {
\r
7859 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7862 is->count = (DWORD) -1;
\r
7866 CheckForInputBufferFull( is );
\r
7868 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7870 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7872 if (is->count < 0) break; /* Quit on error */
\r
7874 CloseHandle(is->hFile);
\r
7879 SocketInputThread(LPVOID arg)
\r
7883 is = (InputSource *) arg;
\r
7884 while (is->hThread != NULL) {
\r
7885 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7886 if ((int)is->count == SOCKET_ERROR) {
\r
7887 is->count = (DWORD) -1;
\r
7888 is->error = WSAGetLastError();
\r
7890 is->error = NO_ERROR;
\r
7891 is->next += is->count;
\r
7892 if (is->count == 0 && is->second == is) {
\r
7893 /* End of file on stderr; quit with no message */
\r
7897 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7899 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7901 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7907 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7911 is = (InputSource *) lParam;
\r
7912 if (is->lineByLine) {
\r
7913 /* Feed in lines one by one */
\r
7914 char *p = is->buf;
\r
7916 while (q < is->next) {
\r
7917 if (*q++ == '\n') {
\r
7918 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7923 /* Move any partial line to the start of the buffer */
\r
7925 while (p < is->next) {
\r
7930 if (is->error != NO_ERROR || is->count == 0) {
\r
7931 /* Notify backend of the error. Note: If there was a partial
\r
7932 line at the end, it is not flushed through. */
\r
7933 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7936 /* Feed in the whole chunk of input at once */
\r
7937 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7938 is->next = is->buf;
\r
7942 /*---------------------------------------------------------------------------*\
\r
7944 * Menu enables. Used when setting various modes.
\r
7946 \*---------------------------------------------------------------------------*/
\r
7954 GreyRevert(Boolean grey)
\r
7955 { // [HGM] vari: for retracting variations in local mode
\r
7956 HMENU hmenu = GetMenu(hwndMain);
\r
7957 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7958 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7962 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7964 while (enab->item > 0) {
\r
7965 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7970 Enables gnuEnables[] = {
\r
7971 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7972 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7980 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7981 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7982 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7983 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7985 // Needed to switch from ncp to GNU mode on Engine Load
\r
7986 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7987 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7990 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7991 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7992 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7993 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7994 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7995 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7996 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7997 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7998 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7999 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8003 Enables icsEnables[] = {
\r
8004 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8005 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8006 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8007 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8008 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8012 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8019 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8020 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8021 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8022 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8023 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8028 Enables zippyEnables[] = {
\r
8029 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8030 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8031 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8032 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8037 Enables ncpEnables[] = {
\r
8038 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8039 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8040 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8041 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8042 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8043 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8044 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8045 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8046 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8047 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8048 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8053 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8055 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8056 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8057 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8058 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8059 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8063 Enables trainingOnEnables[] = {
\r
8064 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8065 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8066 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8067 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8068 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8069 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8070 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8071 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8072 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8076 Enables trainingOffEnables[] = {
\r
8077 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8078 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8079 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8080 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8081 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8082 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8083 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8084 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8085 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8089 /* These modify either ncpEnables or gnuEnables */
\r
8090 Enables cmailEnables[] = {
\r
8091 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8092 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8093 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8094 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8095 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8096 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8097 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8101 Enables machineThinkingEnables[] = {
\r
8102 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8103 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8104 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8105 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8106 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8107 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8109 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8110 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8111 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8112 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8113 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8114 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8115 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8116 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8117 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8121 Enables userThinkingEnables[] = {
\r
8122 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8123 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8124 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8125 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8126 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8127 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8129 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8130 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8131 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8132 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8133 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8134 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8135 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8136 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8137 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8141 /*---------------------------------------------------------------------------*\
\r
8143 * Front-end interface functions exported by XBoard.
\r
8144 * Functions appear in same order as prototypes in frontend.h.
\r
8146 \*---------------------------------------------------------------------------*/
\r
8148 CheckMark(UINT item, int state)
\r
8150 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8156 static UINT prevChecked = 0;
\r
8157 static int prevPausing = 0;
\r
8160 if (pausing != prevPausing) {
\r
8161 prevPausing = pausing;
\r
8162 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8163 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8164 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8167 switch (gameMode) {
\r
8168 case BeginningOfGame:
\r
8169 if (appData.icsActive)
\r
8170 nowChecked = IDM_IcsClient;
\r
8171 else if (appData.noChessProgram)
\r
8172 nowChecked = IDM_EditGame;
\r
8174 nowChecked = IDM_MachineBlack;
\r
8176 case MachinePlaysBlack:
\r
8177 nowChecked = IDM_MachineBlack;
\r
8179 case MachinePlaysWhite:
\r
8180 nowChecked = IDM_MachineWhite;
\r
8182 case TwoMachinesPlay:
\r
8183 nowChecked = IDM_TwoMachines;
\r
8186 nowChecked = IDM_AnalysisMode;
\r
8189 nowChecked = IDM_AnalyzeFile;
\r
8192 nowChecked = IDM_EditGame;
\r
8194 case PlayFromGameFile:
\r
8195 nowChecked = IDM_LoadGame;
\r
8197 case EditPosition:
\r
8198 nowChecked = IDM_EditPosition;
\r
8201 nowChecked = IDM_Training;
\r
8203 case IcsPlayingWhite:
\r
8204 case IcsPlayingBlack:
\r
8205 case IcsObserving:
\r
8207 nowChecked = IDM_IcsClient;
\r
8214 CheckMark(prevChecked, MF_UNCHECKED);
\r
8215 CheckMark(nowChecked, MF_CHECKED);
\r
8216 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8218 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8219 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8220 MF_BYCOMMAND|MF_ENABLED);
\r
8222 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8223 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8226 prevChecked = nowChecked;
\r
8228 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8229 if (appData.icsActive) {
\r
8230 if (appData.icsEngineAnalyze) {
\r
8231 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8233 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8236 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8242 HMENU hmenu = GetMenu(hwndMain);
\r
8243 SetMenuEnables(hmenu, icsEnables);
\r
8244 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8245 MF_BYCOMMAND|MF_ENABLED);
\r
8247 if (appData.zippyPlay) {
\r
8248 SetMenuEnables(hmenu, zippyEnables);
\r
8249 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8250 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8251 MF_BYCOMMAND|MF_ENABLED);
\r
8259 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8265 HMENU hmenu = GetMenu(hwndMain);
\r
8266 SetMenuEnables(hmenu, ncpEnables);
\r
8267 DrawMenuBar(hwndMain);
\r
8273 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8277 SetTrainingModeOn()
\r
8280 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8281 for (i = 0; i < N_BUTTONS; i++) {
\r
8282 if (buttonDesc[i].hwnd != NULL)
\r
8283 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8288 VOID SetTrainingModeOff()
\r
8291 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8292 for (i = 0; i < N_BUTTONS; i++) {
\r
8293 if (buttonDesc[i].hwnd != NULL)
\r
8294 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8300 SetUserThinkingEnables()
\r
8302 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8306 SetMachineThinkingEnables()
\r
8308 HMENU hMenu = GetMenu(hwndMain);
\r
8309 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8311 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8313 if (gameMode == MachinePlaysBlack) {
\r
8314 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8315 } else if (gameMode == MachinePlaysWhite) {
\r
8316 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8317 } else if (gameMode == TwoMachinesPlay) {
\r
8318 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8324 DisplayTitle(char *str)
\r
8326 char title[MSG_SIZ], *host;
\r
8327 if (str[0] != NULLCHAR) {
\r
8328 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8329 } else if (appData.icsActive) {
\r
8330 if (appData.icsCommPort[0] != NULLCHAR)
\r
8333 host = appData.icsHost;
\r
8334 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8335 } else if (appData.noChessProgram) {
\r
8336 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8338 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8339 strcat(title, ": ");
\r
8340 strcat(title, first.tidy);
\r
8342 SetWindowText(hwndMain, title);
\r
8347 DisplayMessage(char *str1, char *str2)
\r
8351 int remain = MESSAGE_TEXT_MAX - 1;
\r
8354 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8355 messageText[0] = NULLCHAR;
\r
8357 len = strlen(str1);
\r
8358 if (len > remain) len = remain;
\r
8359 strncpy(messageText, str1, len);
\r
8360 messageText[len] = NULLCHAR;
\r
8363 if (*str2 && remain >= 2) {
\r
8365 strcat(messageText, " ");
\r
8368 len = strlen(str2);
\r
8369 if (len > remain) len = remain;
\r
8370 strncat(messageText, str2, len);
\r
8372 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8373 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8375 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8379 hdc = GetDC(hwndMain);
\r
8380 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8381 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8382 &messageRect, messageText, strlen(messageText), NULL);
\r
8383 (void) SelectObject(hdc, oldFont);
\r
8384 (void) ReleaseDC(hwndMain, hdc);
\r
8388 DisplayError(char *str, int error)
\r
8390 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8394 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8396 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8397 NULL, error, LANG_NEUTRAL,
\r
8398 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8400 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8402 ErrorMap *em = errmap;
\r
8403 while (em->err != 0 && em->err != error) em++;
\r
8404 if (em->err != 0) {
\r
8405 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8407 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8412 ErrorPopUp(_("Error"), buf);
\r
8417 DisplayMoveError(char *str)
\r
8419 fromX = fromY = -1;
\r
8420 ClearHighlights();
\r
8421 DrawPosition(FALSE, NULL);
\r
8422 if (appData.popupMoveErrors) {
\r
8423 ErrorPopUp(_("Error"), str);
\r
8425 DisplayMessage(str, "");
\r
8426 moveErrorMessageUp = TRUE;
\r
8431 DisplayFatalError(char *str, int error, int exitStatus)
\r
8433 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8435 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8438 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8439 NULL, error, LANG_NEUTRAL,
\r
8440 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8442 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8444 ErrorMap *em = errmap;
\r
8445 while (em->err != 0 && em->err != error) em++;
\r
8446 if (em->err != 0) {
\r
8447 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8449 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8454 if (appData.debugMode) {
\r
8455 fprintf(debugFP, "%s: %s\n", label, str);
\r
8457 if (appData.popupExitMessage) {
\r
8458 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8459 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8461 ExitEvent(exitStatus);
\r
8466 DisplayInformation(char *str)
\r
8468 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8473 DisplayNote(char *str)
\r
8475 ErrorPopUp(_("Note"), str);
\r
8480 char *title, *question, *replyPrefix;
\r
8485 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8487 static QuestionParams *qp;
\r
8488 char reply[MSG_SIZ];
\r
8491 switch (message) {
\r
8492 case WM_INITDIALOG:
\r
8493 qp = (QuestionParams *) lParam;
\r
8494 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8495 Translate(hDlg, DLG_Question);
\r
8496 SetWindowText(hDlg, qp->title);
\r
8497 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8498 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8502 switch (LOWORD(wParam)) {
\r
8504 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8505 if (*reply) strcat(reply, " ");
\r
8506 len = strlen(reply);
\r
8507 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8508 strcat(reply, "\n");
\r
8509 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8510 EndDialog(hDlg, TRUE);
\r
8511 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8514 EndDialog(hDlg, FALSE);
\r
8525 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8527 QuestionParams qp;
\r
8531 qp.question = question;
\r
8532 qp.replyPrefix = replyPrefix;
\r
8534 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8535 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8536 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8537 FreeProcInstance(lpProc);
\r
8540 /* [AS] Pick FRC position */
\r
8541 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8543 static int * lpIndexFRC;
\r
8549 case WM_INITDIALOG:
\r
8550 lpIndexFRC = (int *) lParam;
\r
8552 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8553 Translate(hDlg, DLG_NewGameFRC);
\r
8555 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8556 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8557 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8558 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8563 switch( LOWORD(wParam) ) {
\r
8565 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8566 EndDialog( hDlg, 0 );
\r
8567 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8570 EndDialog( hDlg, 1 );
\r
8572 case IDC_NFG_Edit:
\r
8573 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8574 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8576 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8579 case IDC_NFG_Random:
\r
8580 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8581 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8594 int index = appData.defaultFrcPosition;
\r
8595 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8597 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8599 if( result == 0 ) {
\r
8600 appData.defaultFrcPosition = index;
\r
8606 /* [AS] Game list options. Refactored by HGM */
\r
8608 HWND gameListOptionsDialog;
\r
8610 // low-level front-end: clear text edit / list widget
\r
8615 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8618 // low-level front-end: clear text edit / list widget
\r
8620 GLT_DeSelectList()
\r
8622 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8625 // low-level front-end: append line to text edit / list widget
\r
8627 GLT_AddToList( char *name )
\r
8630 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8634 // low-level front-end: get line from text edit / list widget
\r
8636 GLT_GetFromList( int index, char *name )
\r
8639 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8645 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8647 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8648 int idx2 = idx1 + delta;
\r
8649 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8651 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8654 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8655 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8656 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8657 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8661 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8665 case WM_INITDIALOG:
\r
8666 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8668 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8669 Translate(hDlg, DLG_GameListOptions);
\r
8671 /* Initialize list */
\r
8672 GLT_TagsToList( lpUserGLT );
\r
8674 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8679 switch( LOWORD(wParam) ) {
\r
8682 EndDialog( hDlg, 0 );
\r
8685 EndDialog( hDlg, 1 );
\r
8688 case IDC_GLT_Default:
\r
8689 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8692 case IDC_GLT_Restore:
\r
8693 GLT_TagsToList( appData.gameListTags );
\r
8697 GLT_MoveSelection( hDlg, -1 );
\r
8700 case IDC_GLT_Down:
\r
8701 GLT_MoveSelection( hDlg, +1 );
\r
8711 int GameListOptions()
\r
8714 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8716 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8718 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8720 if( result == 0 ) {
\r
8721 char *oldTags = appData.gameListTags;
\r
8722 /* [AS] Memory leak here! */
\r
8723 appData.gameListTags = strdup( lpUserGLT );
\r
8724 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8725 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8732 DisplayIcsInteractionTitle(char *str)
\r
8734 char consoleTitle[MSG_SIZ];
\r
8736 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8737 SetWindowText(hwndConsole, consoleTitle);
\r
8739 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8740 char buf[MSG_SIZ], *p = buf, *q;
\r
8741 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8743 q = strchr(p, ';');
\r
8745 if(*p) ChatPopUp(p);
\r
8749 SetActiveWindow(hwndMain);
\r
8753 DrawPosition(int fullRedraw, Board board)
\r
8755 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8758 void NotifyFrontendLogin()
\r
8761 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8767 fromX = fromY = -1;
\r
8768 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8769 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8770 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8771 dragInfo.lastpos = dragInfo.pos;
\r
8772 dragInfo.start.x = dragInfo.start.y = -1;
\r
8773 dragInfo.from = dragInfo.start;
\r
8775 DrawPosition(TRUE, NULL);
\r
8782 CommentPopUp(char *title, char *str)
\r
8784 HWND hwnd = GetActiveWindow();
\r
8785 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8787 SetActiveWindow(hwnd);
\r
8791 CommentPopDown(void)
\r
8793 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8794 if (commentDialog) {
\r
8795 ShowWindow(commentDialog, SW_HIDE);
\r
8797 commentUp = FALSE;
\r
8801 EditCommentPopUp(int index, char *title, char *str)
\r
8803 EitherCommentPopUp(index, title, str, TRUE);
\r
8810 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8817 MyPlaySound(&sounds[(int)SoundMove]);
\r
8820 VOID PlayIcsWinSound()
\r
8822 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8825 VOID PlayIcsLossSound()
\r
8827 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8830 VOID PlayIcsDrawSound()
\r
8832 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8835 VOID PlayIcsUnfinishedSound()
\r
8837 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8843 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8849 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8857 consoleEcho = TRUE;
\r
8858 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8859 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8860 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8869 consoleEcho = FALSE;
\r
8870 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8871 /* This works OK: set text and background both to the same color */
\r
8873 cf.crTextColor = COLOR_ECHOOFF;
\r
8874 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8875 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8878 /* No Raw()...? */
\r
8880 void Colorize(ColorClass cc, int continuation)
\r
8882 currentColorClass = cc;
\r
8883 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8884 consoleCF.crTextColor = textAttribs[cc].color;
\r
8885 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8886 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8892 static char buf[MSG_SIZ];
\r
8893 DWORD bufsiz = MSG_SIZ;
\r
8895 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8896 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8898 if (!GetUserName(buf, &bufsiz)) {
\r
8899 /*DisplayError("Error getting user name", GetLastError());*/
\r
8900 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8908 static char buf[MSG_SIZ];
\r
8909 DWORD bufsiz = MSG_SIZ;
\r
8911 if (!GetComputerName(buf, &bufsiz)) {
\r
8912 /*DisplayError("Error getting host name", GetLastError());*/
\r
8913 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8920 ClockTimerRunning()
\r
8922 return clockTimerEvent != 0;
\r
8928 if (clockTimerEvent == 0) return FALSE;
\r
8929 KillTimer(hwndMain, clockTimerEvent);
\r
8930 clockTimerEvent = 0;
\r
8935 StartClockTimer(long millisec)
\r
8937 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8938 (UINT) millisec, NULL);
\r
8942 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8945 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8947 if(appData.noGUI) return;
\r
8948 hdc = GetDC(hwndMain);
\r
8949 if (!IsIconic(hwndMain)) {
\r
8950 DisplayAClock(hdc, timeRemaining, highlight,
\r
8951 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8953 if (highlight && iconCurrent == iconBlack) {
\r
8954 iconCurrent = iconWhite;
\r
8955 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8956 if (IsIconic(hwndMain)) {
\r
8957 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8960 (void) ReleaseDC(hwndMain, hdc);
\r
8962 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8966 DisplayBlackClock(long timeRemaining, int highlight)
\r
8969 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8972 if(appData.noGUI) return;
\r
8973 hdc = GetDC(hwndMain);
\r
8974 if (!IsIconic(hwndMain)) {
\r
8975 DisplayAClock(hdc, timeRemaining, highlight,
\r
8976 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8978 if (highlight && iconCurrent == iconWhite) {
\r
8979 iconCurrent = iconBlack;
\r
8980 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8981 if (IsIconic(hwndMain)) {
\r
8982 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8985 (void) ReleaseDC(hwndMain, hdc);
\r
8987 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8992 LoadGameTimerRunning()
\r
8994 return loadGameTimerEvent != 0;
\r
8998 StopLoadGameTimer()
\r
9000 if (loadGameTimerEvent == 0) return FALSE;
\r
9001 KillTimer(hwndMain, loadGameTimerEvent);
\r
9002 loadGameTimerEvent = 0;
\r
9007 StartLoadGameTimer(long millisec)
\r
9009 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9010 (UINT) millisec, NULL);
\r
9018 char fileTitle[MSG_SIZ];
\r
9020 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9021 f = OpenFileDialog(hwndMain, "a", defName,
\r
9022 appData.oldSaveStyle ? "gam" : "pgn",
\r
9024 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9026 SaveGame(f, 0, "");
\r
9033 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9035 if (delayedTimerEvent != 0) {
\r
9036 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9037 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9039 KillTimer(hwndMain, delayedTimerEvent);
\r
9040 delayedTimerEvent = 0;
\r
9041 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9042 delayedTimerCallback();
\r
9044 delayedTimerCallback = cb;
\r
9045 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9046 (UINT) millisec, NULL);
\r
9049 DelayedEventCallback
\r
9052 if (delayedTimerEvent) {
\r
9053 return delayedTimerCallback;
\r
9060 CancelDelayedEvent()
\r
9062 if (delayedTimerEvent) {
\r
9063 KillTimer(hwndMain, delayedTimerEvent);
\r
9064 delayedTimerEvent = 0;
\r
9068 DWORD GetWin32Priority(int nice)
\r
9069 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9071 REALTIME_PRIORITY_CLASS 0x00000100
\r
9072 HIGH_PRIORITY_CLASS 0x00000080
\r
9073 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9074 NORMAL_PRIORITY_CLASS 0x00000020
\r
9075 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9076 IDLE_PRIORITY_CLASS 0x00000040
\r
9078 if (nice < -15) return 0x00000080;
\r
9079 if (nice < 0) return 0x00008000;
\r
9080 if (nice == 0) return 0x00000020;
\r
9081 if (nice < 15) return 0x00004000;
\r
9082 return 0x00000040;
\r
9085 void RunCommand(char *cmdLine)
\r
9087 /* Now create the child process. */
\r
9088 STARTUPINFO siStartInfo;
\r
9089 PROCESS_INFORMATION piProcInfo;
\r
9091 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9092 siStartInfo.lpReserved = NULL;
\r
9093 siStartInfo.lpDesktop = NULL;
\r
9094 siStartInfo.lpTitle = NULL;
\r
9095 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9096 siStartInfo.cbReserved2 = 0;
\r
9097 siStartInfo.lpReserved2 = NULL;
\r
9098 siStartInfo.hStdInput = NULL;
\r
9099 siStartInfo.hStdOutput = NULL;
\r
9100 siStartInfo.hStdError = NULL;
\r
9102 CreateProcess(NULL,
\r
9103 cmdLine, /* command line */
\r
9104 NULL, /* process security attributes */
\r
9105 NULL, /* primary thread security attrs */
\r
9106 TRUE, /* handles are inherited */
\r
9107 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9108 NULL, /* use parent's environment */
\r
9110 &siStartInfo, /* STARTUPINFO pointer */
\r
9111 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9113 CloseHandle(piProcInfo.hThread);
\r
9116 /* Start a child process running the given program.
\r
9117 The process's standard output can be read from "from", and its
\r
9118 standard input can be written to "to".
\r
9119 Exit with fatal error if anything goes wrong.
\r
9120 Returns an opaque pointer that can be used to destroy the process
\r
9124 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9126 #define BUFSIZE 4096
\r
9128 HANDLE hChildStdinRd, hChildStdinWr,
\r
9129 hChildStdoutRd, hChildStdoutWr;
\r
9130 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9131 SECURITY_ATTRIBUTES saAttr;
\r
9133 PROCESS_INFORMATION piProcInfo;
\r
9134 STARTUPINFO siStartInfo;
\r
9136 char buf[MSG_SIZ];
\r
9139 if (appData.debugMode) {
\r
9140 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9145 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9146 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9147 saAttr.bInheritHandle = TRUE;
\r
9148 saAttr.lpSecurityDescriptor = NULL;
\r
9151 * The steps for redirecting child's STDOUT:
\r
9152 * 1. Create anonymous pipe to be STDOUT for child.
\r
9153 * 2. Create a noninheritable duplicate of read handle,
\r
9154 * and close the inheritable read handle.
\r
9157 /* Create a pipe for the child's STDOUT. */
\r
9158 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9159 return GetLastError();
\r
9162 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9163 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9164 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9165 FALSE, /* not inherited */
\r
9166 DUPLICATE_SAME_ACCESS);
\r
9168 return GetLastError();
\r
9170 CloseHandle(hChildStdoutRd);
\r
9173 * The steps for redirecting child's STDIN:
\r
9174 * 1. Create anonymous pipe to be STDIN for child.
\r
9175 * 2. Create a noninheritable duplicate of write handle,
\r
9176 * and close the inheritable write handle.
\r
9179 /* Create a pipe for the child's STDIN. */
\r
9180 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9181 return GetLastError();
\r
9184 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9185 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9186 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9187 FALSE, /* not inherited */
\r
9188 DUPLICATE_SAME_ACCESS);
\r
9190 return GetLastError();
\r
9192 CloseHandle(hChildStdinWr);
\r
9194 /* Arrange to (1) look in dir for the child .exe file, and
\r
9195 * (2) have dir be the child's working directory. Interpret
\r
9196 * dir relative to the directory WinBoard loaded from. */
\r
9197 GetCurrentDirectory(MSG_SIZ, buf);
\r
9198 SetCurrentDirectory(installDir);
\r
9199 SetCurrentDirectory(dir);
\r
9201 /* Now create the child process. */
\r
9203 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9204 siStartInfo.lpReserved = NULL;
\r
9205 siStartInfo.lpDesktop = NULL;
\r
9206 siStartInfo.lpTitle = NULL;
\r
9207 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9208 siStartInfo.cbReserved2 = 0;
\r
9209 siStartInfo.lpReserved2 = NULL;
\r
9210 siStartInfo.hStdInput = hChildStdinRd;
\r
9211 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9212 siStartInfo.hStdError = hChildStdoutWr;
\r
9214 fSuccess = CreateProcess(NULL,
\r
9215 cmdLine, /* command line */
\r
9216 NULL, /* process security attributes */
\r
9217 NULL, /* primary thread security attrs */
\r
9218 TRUE, /* handles are inherited */
\r
9219 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9220 NULL, /* use parent's environment */
\r
9222 &siStartInfo, /* STARTUPINFO pointer */
\r
9223 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9225 err = GetLastError();
\r
9226 SetCurrentDirectory(buf); /* return to prev directory */
\r
9231 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9232 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9233 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9236 /* Close the handles we don't need in the parent */
\r
9237 CloseHandle(piProcInfo.hThread);
\r
9238 CloseHandle(hChildStdinRd);
\r
9239 CloseHandle(hChildStdoutWr);
\r
9241 /* Prepare return value */
\r
9242 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9243 cp->kind = CPReal;
\r
9244 cp->hProcess = piProcInfo.hProcess;
\r
9245 cp->pid = piProcInfo.dwProcessId;
\r
9246 cp->hFrom = hChildStdoutRdDup;
\r
9247 cp->hTo = hChildStdinWrDup;
\r
9249 *pr = (void *) cp;
\r
9251 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9252 2000 where engines sometimes don't see the initial command(s)
\r
9253 from WinBoard and hang. I don't understand how that can happen,
\r
9254 but the Sleep is harmless, so I've put it in. Others have also
\r
9255 reported what may be the same problem, so hopefully this will fix
\r
9256 it for them too. */
\r
9264 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9266 ChildProc *cp; int result;
\r
9268 cp = (ChildProc *) pr;
\r
9269 if (cp == NULL) return;
\r
9271 switch (cp->kind) {
\r
9273 /* TerminateProcess is considered harmful, so... */
\r
9274 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9275 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9276 /* The following doesn't work because the chess program
\r
9277 doesn't "have the same console" as WinBoard. Maybe
\r
9278 we could arrange for this even though neither WinBoard
\r
9279 nor the chess program uses a console for stdio? */
\r
9280 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9282 /* [AS] Special termination modes for misbehaving programs... */
\r
9283 if( signal & 8 ) {
\r
9284 result = TerminateProcess( cp->hProcess, 0 );
\r
9286 if ( appData.debugMode) {
\r
9287 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9290 else if( signal & 4 ) {
\r
9291 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9293 if( dw != WAIT_OBJECT_0 ) {
\r
9294 result = TerminateProcess( cp->hProcess, 0 );
\r
9296 if ( appData.debugMode) {
\r
9297 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9303 CloseHandle(cp->hProcess);
\r
9307 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9311 closesocket(cp->sock);
\r
9316 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9317 closesocket(cp->sock);
\r
9318 closesocket(cp->sock2);
\r
9326 InterruptChildProcess(ProcRef pr)
\r
9330 cp = (ChildProc *) pr;
\r
9331 if (cp == NULL) return;
\r
9332 switch (cp->kind) {
\r
9334 /* The following doesn't work because the chess program
\r
9335 doesn't "have the same console" as WinBoard. Maybe
\r
9336 we could arrange for this even though neither WinBoard
\r
9337 nor the chess program uses a console for stdio */
\r
9338 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9343 /* Can't interrupt */
\r
9347 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9354 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9356 char cmdLine[MSG_SIZ];
\r
9358 if (port[0] == NULLCHAR) {
\r
9359 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9361 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9363 return StartChildProcess(cmdLine, "", pr);
\r
9367 /* Code to open TCP sockets */
\r
9370 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9376 struct sockaddr_in sa, mysa;
\r
9377 struct hostent FAR *hp;
\r
9378 unsigned short uport;
\r
9379 WORD wVersionRequested;
\r
9382 /* Initialize socket DLL */
\r
9383 wVersionRequested = MAKEWORD(1, 1);
\r
9384 err = WSAStartup(wVersionRequested, &wsaData);
\r
9385 if (err != 0) return err;
\r
9388 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9389 err = WSAGetLastError();
\r
9394 /* Bind local address using (mostly) don't-care values.
\r
9396 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9397 mysa.sin_family = AF_INET;
\r
9398 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9399 uport = (unsigned short) 0;
\r
9400 mysa.sin_port = htons(uport);
\r
9401 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9402 == SOCKET_ERROR) {
\r
9403 err = WSAGetLastError();
\r
9408 /* Resolve remote host name */
\r
9409 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9410 if (!(hp = gethostbyname(host))) {
\r
9411 unsigned int b0, b1, b2, b3;
\r
9413 err = WSAGetLastError();
\r
9415 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9416 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9417 hp->h_addrtype = AF_INET;
\r
9419 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9420 hp->h_addr_list[0] = (char *) malloc(4);
\r
9421 hp->h_addr_list[0][0] = (char) b0;
\r
9422 hp->h_addr_list[0][1] = (char) b1;
\r
9423 hp->h_addr_list[0][2] = (char) b2;
\r
9424 hp->h_addr_list[0][3] = (char) b3;
\r
9430 sa.sin_family = hp->h_addrtype;
\r
9431 uport = (unsigned short) atoi(port);
\r
9432 sa.sin_port = htons(uport);
\r
9433 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9435 /* Make connection */
\r
9436 if (connect(s, (struct sockaddr *) &sa,
\r
9437 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9438 err = WSAGetLastError();
\r
9443 /* Prepare return value */
\r
9444 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9445 cp->kind = CPSock;
\r
9447 *pr = (ProcRef *) cp;
\r
9453 OpenCommPort(char *name, ProcRef *pr)
\r
9458 char fullname[MSG_SIZ];
\r
9460 if (*name != '\\')
\r
9461 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9463 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9465 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9466 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9467 if (h == (HANDLE) -1) {
\r
9468 return GetLastError();
\r
9472 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9474 /* Accumulate characters until a 100ms pause, then parse */
\r
9475 ct.ReadIntervalTimeout = 100;
\r
9476 ct.ReadTotalTimeoutMultiplier = 0;
\r
9477 ct.ReadTotalTimeoutConstant = 0;
\r
9478 ct.WriteTotalTimeoutMultiplier = 0;
\r
9479 ct.WriteTotalTimeoutConstant = 0;
\r
9480 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9482 /* Prepare return value */
\r
9483 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9484 cp->kind = CPComm;
\r
9487 *pr = (ProcRef *) cp;
\r
9493 OpenLoopback(ProcRef *pr)
\r
9495 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9501 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9506 struct sockaddr_in sa, mysa;
\r
9507 struct hostent FAR *hp;
\r
9508 unsigned short uport;
\r
9509 WORD wVersionRequested;
\r
9512 char stderrPortStr[MSG_SIZ];
\r
9514 /* Initialize socket DLL */
\r
9515 wVersionRequested = MAKEWORD(1, 1);
\r
9516 err = WSAStartup(wVersionRequested, &wsaData);
\r
9517 if (err != 0) return err;
\r
9519 /* Resolve remote host name */
\r
9520 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9521 if (!(hp = gethostbyname(host))) {
\r
9522 unsigned int b0, b1, b2, b3;
\r
9524 err = WSAGetLastError();
\r
9526 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9527 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9528 hp->h_addrtype = AF_INET;
\r
9530 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9531 hp->h_addr_list[0] = (char *) malloc(4);
\r
9532 hp->h_addr_list[0][0] = (char) b0;
\r
9533 hp->h_addr_list[0][1] = (char) b1;
\r
9534 hp->h_addr_list[0][2] = (char) b2;
\r
9535 hp->h_addr_list[0][3] = (char) b3;
\r
9541 sa.sin_family = hp->h_addrtype;
\r
9542 uport = (unsigned short) 514;
\r
9543 sa.sin_port = htons(uport);
\r
9544 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9546 /* Bind local socket to unused "privileged" port address
\r
9548 s = INVALID_SOCKET;
\r
9549 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9550 mysa.sin_family = AF_INET;
\r
9551 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9552 for (fromPort = 1023;; fromPort--) {
\r
9553 if (fromPort < 0) {
\r
9555 return WSAEADDRINUSE;
\r
9557 if (s == INVALID_SOCKET) {
\r
9558 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9559 err = WSAGetLastError();
\r
9564 uport = (unsigned short) fromPort;
\r
9565 mysa.sin_port = htons(uport);
\r
9566 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9567 == SOCKET_ERROR) {
\r
9568 err = WSAGetLastError();
\r
9569 if (err == WSAEADDRINUSE) continue;
\r
9573 if (connect(s, (struct sockaddr *) &sa,
\r
9574 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9575 err = WSAGetLastError();
\r
9576 if (err == WSAEADDRINUSE) {
\r
9587 /* Bind stderr local socket to unused "privileged" port address
\r
9589 s2 = INVALID_SOCKET;
\r
9590 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9591 mysa.sin_family = AF_INET;
\r
9592 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9593 for (fromPort = 1023;; fromPort--) {
\r
9594 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9595 if (fromPort < 0) {
\r
9596 (void) closesocket(s);
\r
9598 return WSAEADDRINUSE;
\r
9600 if (s2 == INVALID_SOCKET) {
\r
9601 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9602 err = WSAGetLastError();
\r
9608 uport = (unsigned short) fromPort;
\r
9609 mysa.sin_port = htons(uport);
\r
9610 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9611 == SOCKET_ERROR) {
\r
9612 err = WSAGetLastError();
\r
9613 if (err == WSAEADDRINUSE) continue;
\r
9614 (void) closesocket(s);
\r
9618 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9619 err = WSAGetLastError();
\r
9620 if (err == WSAEADDRINUSE) {
\r
9622 s2 = INVALID_SOCKET;
\r
9625 (void) closesocket(s);
\r
9626 (void) closesocket(s2);
\r
9632 prevStderrPort = fromPort; // remember port used
\r
9633 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9635 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9636 err = WSAGetLastError();
\r
9637 (void) closesocket(s);
\r
9638 (void) closesocket(s2);
\r
9643 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9644 err = WSAGetLastError();
\r
9645 (void) closesocket(s);
\r
9646 (void) closesocket(s2);
\r
9650 if (*user == NULLCHAR) user = UserName();
\r
9651 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9652 err = WSAGetLastError();
\r
9653 (void) closesocket(s);
\r
9654 (void) closesocket(s2);
\r
9658 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9659 err = WSAGetLastError();
\r
9660 (void) closesocket(s);
\r
9661 (void) closesocket(s2);
\r
9666 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9667 err = WSAGetLastError();
\r
9668 (void) closesocket(s);
\r
9669 (void) closesocket(s2);
\r
9673 (void) closesocket(s2); /* Stop listening */
\r
9675 /* Prepare return value */
\r
9676 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9677 cp->kind = CPRcmd;
\r
9680 *pr = (ProcRef *) cp;
\r
9687 AddInputSource(ProcRef pr, int lineByLine,
\r
9688 InputCallback func, VOIDSTAR closure)
\r
9690 InputSource *is, *is2 = NULL;
\r
9691 ChildProc *cp = (ChildProc *) pr;
\r
9693 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9694 is->lineByLine = lineByLine;
\r
9696 is->closure = closure;
\r
9697 is->second = NULL;
\r
9698 is->next = is->buf;
\r
9699 if (pr == NoProc) {
\r
9700 is->kind = CPReal;
\r
9701 consoleInputSource = is;
\r
9703 is->kind = cp->kind;
\r
9705 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9706 we create all threads suspended so that the is->hThread variable can be
\r
9707 safely assigned, then let the threads start with ResumeThread.
\r
9709 switch (cp->kind) {
\r
9711 is->hFile = cp->hFrom;
\r
9712 cp->hFrom = NULL; /* now owned by InputThread */
\r
9714 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9715 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9719 is->hFile = cp->hFrom;
\r
9720 cp->hFrom = NULL; /* now owned by InputThread */
\r
9722 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9723 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9727 is->sock = cp->sock;
\r
9729 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9730 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9734 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9736 is->sock = cp->sock;
\r
9738 is2->sock = cp->sock2;
\r
9739 is2->second = is2;
\r
9741 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9742 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9744 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9745 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9749 if( is->hThread != NULL ) {
\r
9750 ResumeThread( is->hThread );
\r
9753 if( is2 != NULL && is2->hThread != NULL ) {
\r
9754 ResumeThread( is2->hThread );
\r
9758 return (InputSourceRef) is;
\r
9762 RemoveInputSource(InputSourceRef isr)
\r
9766 is = (InputSource *) isr;
\r
9767 is->hThread = NULL; /* tell thread to stop */
\r
9768 CloseHandle(is->hThread);
\r
9769 if (is->second != NULL) {
\r
9770 is->second->hThread = NULL;
\r
9771 CloseHandle(is->second->hThread);
\r
9775 int no_wrap(char *message, int count)
\r
9777 ConsoleOutput(message, count, FALSE);
\r
9782 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9785 int outCount = SOCKET_ERROR;
\r
9786 ChildProc *cp = (ChildProc *) pr;
\r
9787 static OVERLAPPED ovl;
\r
9789 static int line = 0;
\r
9793 if (appData.noJoin || !appData.useInternalWrap)
\r
9794 return no_wrap(message, count);
\r
9797 int width = get_term_width();
\r
9798 int len = wrap(NULL, message, count, width, &line);
\r
9799 char *msg = malloc(len);
\r
9803 return no_wrap(message, count);
\r
9806 dbgchk = wrap(msg, message, count, width, &line);
\r
9807 if (dbgchk != len && appData.debugMode)
\r
9808 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9809 ConsoleOutput(msg, len, FALSE);
\r
9816 if (ovl.hEvent == NULL) {
\r
9817 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9819 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9821 switch (cp->kind) {
\r
9824 outCount = send(cp->sock, message, count, 0);
\r
9825 if (outCount == SOCKET_ERROR) {
\r
9826 *outError = WSAGetLastError();
\r
9828 *outError = NO_ERROR;
\r
9833 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9834 &dOutCount, NULL)) {
\r
9835 *outError = NO_ERROR;
\r
9836 outCount = (int) dOutCount;
\r
9838 *outError = GetLastError();
\r
9843 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9844 &dOutCount, &ovl);
\r
9845 if (*outError == NO_ERROR) {
\r
9846 outCount = (int) dOutCount;
\r
9856 if(n != 0) Sleep(n);
\r
9860 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9863 /* Ignore delay, not implemented for WinBoard */
\r
9864 return OutputToProcess(pr, message, count, outError);
\r
9869 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9870 char *buf, int count, int error)
\r
9872 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9875 /* see wgamelist.c for Game List functions */
\r
9876 /* see wedittags.c for Edit Tags functions */
\r
9883 char buf[MSG_SIZ];
\r
9886 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9887 f = fopen(buf, "r");
\r
9889 ProcessICSInitScript(f);
\r
9899 StartAnalysisClock()
\r
9901 if (analysisTimerEvent) return;
\r
9902 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9903 (UINT) 2000, NULL);
\r
9907 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9909 highlightInfo.sq[0].x = fromX;
\r
9910 highlightInfo.sq[0].y = fromY;
\r
9911 highlightInfo.sq[1].x = toX;
\r
9912 highlightInfo.sq[1].y = toY;
\r
9918 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9919 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9923 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9925 premoveHighlightInfo.sq[0].x = fromX;
\r
9926 premoveHighlightInfo.sq[0].y = fromY;
\r
9927 premoveHighlightInfo.sq[1].x = toX;
\r
9928 premoveHighlightInfo.sq[1].y = toY;
\r
9932 ClearPremoveHighlights()
\r
9934 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9935 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9939 ShutDownFrontEnd()
\r
9941 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9942 DeleteClipboardTempFiles();
\r
9948 if (IsIconic(hwndMain))
\r
9949 ShowWindow(hwndMain, SW_RESTORE);
\r
9951 SetActiveWindow(hwndMain);
\r
9955 * Prototypes for animation support routines
\r
9957 static void ScreenSquare(int column, int row, POINT * pt);
\r
9958 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9959 POINT frames[], int * nFrames);
\r
9965 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9966 { // [HGM] atomic: animate blast wave
\r
9969 explodeInfo.fromX = fromX;
\r
9970 explodeInfo.fromY = fromY;
\r
9971 explodeInfo.toX = toX;
\r
9972 explodeInfo.toY = toY;
\r
9973 for(i=1; i<4*kFactor; i++) {
\r
9974 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9975 DrawPosition(FALSE, board);
\r
9976 Sleep(appData.animSpeed);
\r
9978 explodeInfo.radius = 0;
\r
9979 DrawPosition(TRUE, board);
\r
9983 AnimateMove(board, fromX, fromY, toX, toY)
\r
9990 ChessSquare piece;
\r
9991 int x = toX, y = toY;
\r
9992 POINT start, finish, mid;
\r
9993 POINT frames[kFactor * 2 + 1];
\r
9996 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
9998 if (!appData.animate) return;
\r
9999 if (doingSizing) return;
\r
10000 if (fromY < 0 || fromX < 0) return;
\r
10001 piece = board[fromY][fromX];
\r
10002 if (piece >= EmptySquare) return;
\r
10004 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10008 ScreenSquare(fromX, fromY, &start);
\r
10009 ScreenSquare(toX, toY, &finish);
\r
10011 /* All moves except knight jumps move in straight line */
\r
10012 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10013 mid.x = start.x + (finish.x - start.x) / 2;
\r
10014 mid.y = start.y + (finish.y - start.y) / 2;
\r
10016 /* Knight: make straight movement then diagonal */
\r
10017 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10018 mid.x = start.x + (finish.x - start.x) / 2;
\r
10022 mid.y = start.y + (finish.y - start.y) / 2;
\r
10026 /* Don't use as many frames for very short moves */
\r
10027 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10028 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10030 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10032 animInfo.from.x = fromX;
\r
10033 animInfo.from.y = fromY;
\r
10034 animInfo.to.x = toX;
\r
10035 animInfo.to.y = toY;
\r
10036 animInfo.lastpos = start;
\r
10037 animInfo.piece = piece;
\r
10038 for (n = 0; n < nFrames; n++) {
\r
10039 animInfo.pos = frames[n];
\r
10040 DrawPosition(FALSE, NULL);
\r
10041 animInfo.lastpos = animInfo.pos;
\r
10042 Sleep(appData.animSpeed);
\r
10044 animInfo.pos = finish;
\r
10045 DrawPosition(FALSE, NULL);
\r
10047 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10049 animInfo.piece = EmptySquare;
\r
10050 Explode(board, fromX, fromY, toX, toY);
\r
10053 /* Convert board position to corner of screen rect and color */
\r
10056 ScreenSquare(column, row, pt)
\r
10057 int column; int row; POINT * pt;
\r
10060 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10061 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10063 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10064 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10068 /* Generate a series of frame coords from start->mid->finish.
\r
10069 The movement rate doubles until the half way point is
\r
10070 reached, then halves back down to the final destination,
\r
10071 which gives a nice slow in/out effect. The algorithmn
\r
10072 may seem to generate too many intermediates for short
\r
10073 moves, but remember that the purpose is to attract the
\r
10074 viewers attention to the piece about to be moved and
\r
10075 then to where it ends up. Too few frames would be less
\r
10079 Tween(start, mid, finish, factor, frames, nFrames)
\r
10080 POINT * start; POINT * mid;
\r
10081 POINT * finish; int factor;
\r
10082 POINT frames[]; int * nFrames;
\r
10084 int n, fraction = 1, count = 0;
\r
10086 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10087 for (n = 0; n < factor; n++)
\r
10089 for (n = 0; n < factor; n++) {
\r
10090 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10091 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10093 fraction = fraction / 2;
\r
10097 frames[count] = *mid;
\r
10100 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10102 for (n = 0; n < factor; n++) {
\r
10103 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10104 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10106 fraction = fraction * 2;
\r
10108 *nFrames = count;
\r
10112 SettingsPopUp(ChessProgramState *cps)
\r
10113 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10114 EngineOptionsPopup(savedHwnd, cps);
\r
10117 int flock(int fid, int code)
\r
10119 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10121 ov.hEvent = NULL;
\r
10123 ov.OffsetHigh = 0;
\r
10125 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10127 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10128 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10129 default: return -1;
\r
10138 static char col[8][20];
\r
10139 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10141 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10146 ActivateTheme (int new)
\r
10147 { // Redo initialization of features depending on options that can occur in themes
\r
10149 if(new) InitDrawingColors();
\r
10150 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10151 InitDrawingSizes(boardSize, 0);
\r
10152 InvalidateRect(hwndMain, NULL, TRUE);
\r