2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free
\r
9 * Software Foundation, Inc.
\r
11 * Enhancements Copyright 2005 Alessandro Scotti
\r
13 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
14 * which was written and is copyrighted by Wayne Christopher.
\r
16 * The following terms apply to Digital Equipment Corporation's copyright
\r
17 * interest in XBoard:
\r
18 * ------------------------------------------------------------------------
\r
19 * All Rights Reserved
\r
21 * Permission to use, copy, modify, and distribute this software and its
\r
22 * documentation for any purpose and without fee is hereby granted,
\r
23 * provided that the above copyright notice appear in all copies and that
\r
24 * both that copyright notice and this permission notice appear in
\r
25 * supporting documentation, and that the name of Digital not be
\r
26 * used in advertising or publicity pertaining to distribution of the
\r
27 * software without specific, written prior permission.
\r
29 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
30 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
31 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
32 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
33 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
34 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
36 * ------------------------------------------------------------------------
\r
38 * The following terms apply to the enhanced version of XBoard
\r
39 * distributed by the Free Software Foundation:
\r
40 * ------------------------------------------------------------------------
\r
42 * GNU XBoard is free software: you can redistribute it and/or modify
\r
43 * it under the terms of the GNU General Public License as published by
\r
44 * the Free Software Foundation, either version 3 of the License, or (at
\r
45 * your option) any later version.
\r
47 * GNU XBoard is distributed in the hope that it will be useful, but
\r
48 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
49 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
50 * General Public License for more details.
\r
52 * You should have received a copy of the GNU General Public License
\r
53 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
55 *------------------------------------------------------------------------
\r
56 ** See the file ChangeLog for a revision history. */
\r
60 #include <windows.h>
\r
61 #include <winuser.h>
\r
62 #include <winsock.h>
\r
63 #include <commctrl.h>
\r
69 #include <sys/stat.h>
\r
72 #include <commdlg.h>
\r
74 #include <richedit.h>
\r
75 #include <mmsystem.h>
\r
85 #include "frontend.h"
\r
86 #include "backend.h"
\r
87 #include "winboard.h"
\r
89 #include "wclipbrd.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
97 #define DATADIR "~~"
\r
99 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
101 int myrandom(void);
\r
102 void mysrandom(unsigned int seed);
\r
104 extern int whiteFlag, blackFlag;
\r
105 Boolean flipClock = FALSE;
\r
106 extern HANDLE chatHandle[];
\r
107 extern enum ICS_TYPE ics_type;
\r
109 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
110 int MyGetFullPathName P((char *name, char *fullname));
\r
111 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
112 VOID NewVariantPopup(HWND hwnd);
\r
113 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
114 /*char*/int promoChar));
\r
115 void DisplayMove P((int moveNumber));
\r
116 void ChatPopUp P((char *s));
\r
118 ChessSquare piece;
\r
119 POINT pos; /* window coordinates of current pos */
\r
120 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
121 POINT from; /* board coordinates of the piece's orig pos */
\r
122 POINT to; /* board coordinates of the piece's new pos */
\r
125 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
128 POINT start; /* window coordinates of start pos */
\r
129 POINT pos; /* window coordinates of current pos */
\r
130 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
131 POINT from; /* board coordinates of the piece's orig pos */
\r
135 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
138 POINT sq[2]; /* board coordinates of from, to squares */
\r
141 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
144 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
146 typedef struct { // [HGM] atomic
\r
147 int fromX, fromY, toX, toY, radius;
\r
150 static ExplodeInfo explodeInfo;
\r
152 /* Window class names */
\r
153 char szAppName[] = "WinBoard";
\r
154 char szConsoleName[] = "WBConsole";
\r
156 /* Title bar text */
\r
157 char szTitle[] = "WinBoard";
\r
158 char szConsoleTitle[] = "I C S Interaction";
\r
161 char *settingsFileName;
\r
162 Boolean saveSettingsOnExit;
\r
163 char installDir[MSG_SIZ];
\r
164 int errorExitStatus;
\r
166 BoardSize boardSize;
\r
167 Boolean chessProgram;
\r
168 //static int boardX, boardY;
\r
169 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
170 int squareSize, lineGap, minorSize;
\r
171 static int winW, winH;
\r
172 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
173 static int logoHeight = 0;
\r
174 static char messageText[MESSAGE_TEXT_MAX];
\r
175 static int clockTimerEvent = 0;
\r
176 static int loadGameTimerEvent = 0;
\r
177 static int analysisTimerEvent = 0;
\r
178 static DelayedEventCallback delayedTimerCallback;
\r
179 static int delayedTimerEvent = 0;
\r
180 static int buttonCount = 2;
\r
181 char *icsTextMenuString;
\r
183 char *firstChessProgramNames;
\r
184 char *secondChessProgramNames;
\r
186 #define PALETTESIZE 256
\r
188 HINSTANCE hInst; /* current instance */
\r
189 Boolean alwaysOnTop = FALSE;
\r
191 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
192 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
193 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
195 ColorClass currentColorClass;
\r
197 static HWND savedHwnd;
\r
198 HWND hCommPort = NULL; /* currently open comm port */
\r
199 static HWND hwndPause; /* pause button */
\r
200 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
201 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
202 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
203 explodeBrush, /* [HGM] atomic */
\r
204 markerBrush[8], /* [HGM] markers */
\r
205 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
206 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
207 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
208 static HPEN gridPen = NULL;
\r
209 static HPEN highlightPen = NULL;
\r
210 static HPEN premovePen = NULL;
\r
211 static NPLOGPALETTE pLogPal;
\r
212 static BOOL paletteChanged = FALSE;
\r
213 static HICON iconWhite, iconBlack, iconCurrent;
\r
214 static int doingSizing = FALSE;
\r
215 static int lastSizing = 0;
\r
216 static int prevStderrPort;
\r
217 static HBITMAP userLogo;
\r
219 static HBITMAP liteBackTexture = NULL;
\r
220 static HBITMAP darkBackTexture = NULL;
\r
221 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
223 static int backTextureSquareSize = 0;
\r
224 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
226 #if __GNUC__ && !defined(_winmajor)
\r
227 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
230 #if defined(_winmajor)
\r
231 #define oldDialog (_winmajor < 4)
\r
233 #define oldDialog 0
\r
237 #define INTERNATIONAL
\r
239 #ifdef INTERNATIONAL
\r
240 # define _(s) T_(s)
\r
246 # define Translate(x, y)
\r
247 # define LoadLanguageFile(s)
\r
250 #ifdef INTERNATIONAL
\r
252 Boolean barbaric; // flag indicating if translation is needed
\r
254 // list of item numbers used in each dialog (used to alter language at run time)
\r
256 #define ABOUTBOX -1 /* not sure why these are needed */
\r
257 #define ABOUTBOX2 -1
\r
259 int dialogItems[][42] = {
\r
260 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
261 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
262 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
263 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
264 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds,
\r
265 OPT_Ranget, IDOK, IDCANCEL },
\r
266 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
267 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
268 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
269 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
270 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
271 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
272 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
273 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
274 { ABOUTBOX2, IDC_ChessBoard },
\r
275 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
276 OPT_GameListClose, IDC_GameListDoFilter },
\r
277 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
278 { DLG_Error, IDOK },
\r
279 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
280 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
281 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
282 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
283 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
284 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
285 { DLG_IndexNumber, IDC_Index },
\r
286 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
287 { DLG_TypeInName, IDOK, IDCANCEL },
\r
288 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
289 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
290 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
291 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
292 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
293 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
294 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
295 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
296 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
297 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
298 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
299 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
300 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
301 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
302 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
303 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
304 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
305 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
306 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
307 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
308 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
309 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
310 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
311 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
312 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
313 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
314 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
315 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
316 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
317 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
318 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
319 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
320 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
321 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
322 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
323 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
324 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
325 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
326 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
327 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
328 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
329 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
330 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
331 { DLG_MoveHistory },
\r
332 { DLG_EvalGraph },
\r
333 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
334 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
335 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
336 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
337 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
338 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
339 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
340 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
341 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
345 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
346 static int lastChecked;
\r
347 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
348 extern int tinyLayout;
\r
349 extern char * menuBarText[][10];
\r
352 LoadLanguageFile(char *name)
\r
353 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
355 int i=0, j=0, n=0, k;
\r
358 if(!name || name[0] == NULLCHAR) return;
\r
359 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
360 appData.language = oldLanguage;
\r
361 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
362 if((f = fopen(buf, "r")) == NULL) return;
\r
363 while((k = fgetc(f)) != EOF) {
\r
364 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
365 languageBuf[i] = k;
\r
367 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
369 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
370 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
371 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
372 english[j] = languageBuf + n + 1; *p = 0;
\r
373 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
374 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
379 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
381 case 'n': k = '\n'; break;
\r
382 case 'r': k = '\r'; break;
\r
383 case 't': k = '\t'; break;
\r
385 languageBuf[--i] = k;
\r
390 barbaric = (j != 0);
\r
391 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
396 { // return the translation of the given string
\r
397 // efficiency can be improved a lot...
\r
399 static char buf[MSG_SIZ];
\r
400 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
401 if(!barbaric) return s;
\r
402 if(!s) return ""; // sanity
\r
403 while(english[i]) {
\r
404 if(!strcmp(s, english[i])) return foreign[i];
\r
405 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
406 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
415 Translate(HWND hDlg, int dialogID)
\r
416 { // translate all text items in the given dialog
\r
418 char buf[MSG_SIZ], *s;
\r
419 if(!barbaric) return;
\r
420 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
421 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
422 GetWindowText( hDlg, buf, MSG_SIZ );
\r
424 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
425 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
426 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
427 if(strlen(buf) == 0) continue;
\r
429 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
434 TranslateOneMenu(int i, HMENU subMenu)
\r
437 static MENUITEMINFO info;
\r
439 info.cbSize = sizeof(MENUITEMINFO);
\r
440 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
441 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
443 info.dwTypeData = buf;
\r
444 info.cch = sizeof(buf);
\r
445 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
447 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
448 else menuText[i][j] = strdup(buf); // remember original on first change
\r
450 if(buf[0] == NULLCHAR) continue;
\r
451 info.dwTypeData = T_(buf);
\r
452 info.cch = strlen(buf)+1;
\r
453 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
459 TranslateMenus(int addLanguage)
\r
462 WIN32_FIND_DATA fileData;
\r
464 #define IDM_English 1970
\r
466 HMENU mainMenu = GetMenu(hwndMain);
\r
467 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
468 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
469 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
470 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
471 TranslateOneMenu(i, subMenu);
\r
473 DrawMenuBar(hwndMain);
\r
476 if(!addLanguage) return;
\r
477 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
478 HMENU mainMenu = GetMenu(hwndMain);
\r
479 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
480 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
481 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
482 i = 0; lastChecked = IDM_English;
\r
484 char *p, *q = fileData.cFileName;
\r
485 int checkFlag = MF_UNCHECKED;
\r
486 languageFile[i] = strdup(q);
\r
487 if(barbaric && !strcmp(oldLanguage, q)) {
\r
488 checkFlag = MF_CHECKED;
\r
489 lastChecked = IDM_English + i + 1;
\r
490 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
492 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
493 p = strstr(fileData.cFileName, ".lng");
\r
495 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
496 } while(FindNextFile(hFind, &fileData));
\r
503 #define IDM_RecentEngines 3000
\r
506 RecentEngineMenu (char *s)
\r
508 if(appData.icsActive) return;
\r
509 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
510 HMENU mainMenu = GetMenu(hwndMain);
\r
511 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
512 int i=IDM_RecentEngines;
\r
513 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
514 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
516 char *p = strchr(s, '\n');
\r
517 if(p == NULL) return; // malformed!
\r
519 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
533 int cliWidth, cliHeight;
\r
536 SizeInfo sizeInfo[] =
\r
538 { "tiny", 21, 0, 1, 2, 0, 0 },
\r
539 { "teeny", 25, 1, 1, 2, 0, 0 },
\r
540 { "dinky", 29, 1, 1, 2, 0, 0 },
\r
541 { "petite", 33, 1, 1, 2, 0, 0 },
\r
542 { "slim", 37, 2, 1, 1, 0, 0 },
\r
543 { "small", 40, 2, 1, 1, 0, 0 },
\r
544 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
545 { "middling", 49, 2, 0, 0, 0, 0 },
\r
546 { "average", 54, 2, 0, 0, 0, 0 },
\r
547 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
548 { "medium", 64, 3, 0, 0, 0, 0 },
\r
549 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
550 { "large", 80, 3, 0, 0, 0, 0 },
\r
551 { "big", 87, 3, 0, 0, 0, 0 },
\r
552 { "huge", 95, 3, 0, 0, 0, 0 },
\r
553 { "giant", 108, 3, 0, 0, 0, 0 },
\r
554 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
555 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
556 { NULL, 0, 0, 0, 0, 0, 0 }
\r
559 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
560 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
562 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
578 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
579 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
582 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
591 #define BUTTON_WIDTH (tinyLayout == 2 ? 16 : 32)
\r
592 #define N_BUTTONS 5
\r
594 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
596 {"<<", IDM_ToStart, NULL, NULL},
\r
597 {"<", IDM_Backward, NULL, NULL},
\r
598 {"P", IDM_Pause, NULL, NULL},
\r
599 {">", IDM_Forward, NULL, NULL},
\r
600 {">>", IDM_ToEnd, NULL, NULL},
\r
603 int tinyLayout = 0, smallLayout = 0;
\r
604 #define MENU_BAR_ITEMS 9
\r
605 char *menuBarText[3][MENU_BAR_ITEMS+1] = {
\r
606 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
607 { N_("&Fil"), N_("&Ed"), N_("&Vw"), N_("&Mod"), N_("&Act"), N_("E&ng"), N_("&Opt"), N_("&Hlp"), NULL },
\r
608 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
612 MySound sounds[(int)NSoundClasses];
\r
613 MyTextAttribs textAttribs[(int)NColorClasses];
\r
615 MyColorizeAttribs colorizeAttribs[] = {
\r
616 { (COLORREF)0, 0, N_("Shout Text") },
\r
617 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
618 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
619 { (COLORREF)0, 0, N_("Channel Text") },
\r
620 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
621 { (COLORREF)0, 0, N_("Tell Text") },
\r
622 { (COLORREF)0, 0, N_("Challenge Text") },
\r
623 { (COLORREF)0, 0, N_("Request Text") },
\r
624 { (COLORREF)0, 0, N_("Seek Text") },
\r
625 { (COLORREF)0, 0, N_("Normal Text") },
\r
626 { (COLORREF)0, 0, N_("None") }
\r
631 static char *commentTitle;
\r
632 static char *commentText;
\r
633 static int commentIndex;
\r
634 static Boolean editComment = FALSE;
\r
637 char errorTitle[MSG_SIZ];
\r
638 char errorMessage[2*MSG_SIZ];
\r
639 HWND errorDialog = NULL;
\r
640 BOOLEAN moveErrorMessageUp = FALSE;
\r
641 BOOLEAN consoleEcho = TRUE;
\r
642 CHARFORMAT consoleCF;
\r
643 COLORREF consoleBackgroundColor;
\r
645 char *programVersion;
\r
651 typedef int CPKind;
\r
660 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
663 #define INPUT_SOURCE_BUF_SIZE 4096
\r
665 typedef struct _InputSource {
\r
672 char buf[INPUT_SOURCE_BUF_SIZE];
\r
676 InputCallback func;
\r
677 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
681 InputSource *consoleInputSource;
\r
686 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
687 VOID ConsoleCreate();
\r
689 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
690 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
691 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
692 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
694 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
695 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
696 void ParseIcsTextMenu(char *icsTextMenuString);
\r
697 VOID PopUpNameDialog(char firstchar);
\r
698 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
702 int GameListOptions();
\r
704 int dummy; // [HGM] for obsolete args
\r
706 HWND hwndMain = NULL; /* root window*/
\r
707 HWND hwndConsole = NULL;
\r
708 HWND commentDialog = NULL;
\r
709 HWND moveHistoryDialog = NULL;
\r
710 HWND evalGraphDialog = NULL;
\r
711 HWND engineOutputDialog = NULL;
\r
712 HWND gameListDialog = NULL;
\r
713 HWND editTagsDialog = NULL;
\r
715 int commentUp = FALSE;
\r
717 WindowPlacement wpMain;
\r
718 WindowPlacement wpConsole;
\r
719 WindowPlacement wpComment;
\r
720 WindowPlacement wpMoveHistory;
\r
721 WindowPlacement wpEvalGraph;
\r
722 WindowPlacement wpEngineOutput;
\r
723 WindowPlacement wpGameList;
\r
724 WindowPlacement wpTags;
\r
726 VOID EngineOptionsPopup(); // [HGM] settings
\r
728 VOID GothicPopUp(char *title, VariantClass variant);
\r
730 * Setting "frozen" should disable all user input other than deleting
\r
731 * the window. We do this while engines are initializing themselves.
\r
733 static int frozen = 0;
\r
734 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
740 if (frozen) return;
\r
742 hmenu = GetMenu(hwndMain);
\r
743 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
744 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
746 DrawMenuBar(hwndMain);
\r
749 /* Undo a FreezeUI */
\r
755 if (!frozen) return;
\r
757 hmenu = GetMenu(hwndMain);
\r
758 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
759 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
761 DrawMenuBar(hwndMain);
\r
764 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
766 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
772 #define JAWS_ALT_INTERCEPT
\r
773 #define JAWS_KBUP_NAVIGATION
\r
774 #define JAWS_KBDOWN_NAVIGATION
\r
775 #define JAWS_MENU_ITEMS
\r
776 #define JAWS_SILENCE
\r
777 #define JAWS_REPLAY
\r
779 #define JAWS_COPYRIGHT
\r
780 #define JAWS_DELETE(X) X
\r
781 #define SAYMACHINEMOVE()
\r
785 /*---------------------------------------------------------------------------*\
\r
789 \*---------------------------------------------------------------------------*/
\r
791 static void HandleMessage P((MSG *message));
\r
792 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
795 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
796 LPSTR lpCmdLine, int nCmdShow)
\r
799 // INITCOMMONCONTROLSEX ex;
\r
803 LoadLibrary("RICHED32.DLL");
\r
804 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
806 if (!InitApplication(hInstance)) {
\r
809 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
816 // InitCommonControlsEx(&ex);
\r
817 InitCommonControls();
\r
819 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
820 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
821 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
823 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
825 while (GetMessage(&msg, /* message structure */
\r
826 NULL, /* handle of window receiving the message */
\r
827 0, /* lowest message to examine */
\r
828 0)) /* highest message to examine */
\r
830 HandleMessage(&msg);
\r
834 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
838 HandleMessage (MSG *message)
\r
840 MSG msg = *message;
\r
842 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
843 // [HGM] navigate: switch between all windows with tab
\r
844 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
845 int i, currentElement = 0;
\r
847 // first determine what element of the chain we come from (if any)
\r
848 if(appData.icsActive) {
\r
849 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
850 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
852 if(engineOutputDialog && EngineOutputIsUp()) {
\r
853 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
854 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
856 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
857 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
859 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
860 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
861 if(msg.hwnd == e1) currentElement = 2; else
\r
862 if(msg.hwnd == e2) currentElement = 3; else
\r
863 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
864 if(msg.hwnd == mh) currentElement = 4; else
\r
865 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
866 if(msg.hwnd == hText) currentElement = 5; else
\r
867 if(msg.hwnd == hInput) currentElement = 6; else
\r
868 for (i = 0; i < N_BUTTONS; i++) {
\r
869 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
872 // determine where to go to
\r
873 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
875 currentElement = (currentElement + direction) % 7;
\r
876 switch(currentElement) {
\r
878 h = hwndMain; break; // passing this case always makes the loop exit
\r
880 h = buttonDesc[0].hwnd; break; // could be NULL
\r
882 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
885 if(!EngineOutputIsUp()) continue;
\r
888 if(!MoveHistoryIsUp()) continue;
\r
890 // case 6: // input to eval graph does not seem to get here!
\r
891 // if(!EvalGraphIsUp()) continue;
\r
892 // h = evalGraphDialog; break;
\r
894 if(!appData.icsActive) continue;
\r
898 if(!appData.icsActive) continue;
\r
904 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
905 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
908 return; // this message now has been processed
\r
912 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
913 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
914 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
915 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
916 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
917 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
918 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
919 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
920 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
921 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
922 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
923 for(i=0; i<MAX_CHAT; i++)
\r
924 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
927 if(done) return; // [HGM] chat: end patch
\r
928 TranslateMessage(&msg); /* Translates virtual key codes */
\r
929 DispatchMessage(&msg); /* Dispatches message to window */
\r
935 { /* Dispatch pending messages */
\r
937 while (PeekMessage(&msg, /* message structure */
\r
938 NULL, /* handle of window receiving the message */
\r
939 0, /* lowest message to examine */
\r
940 0, /* highest message to examine */
\r
943 HandleMessage(&msg);
\r
947 /*---------------------------------------------------------------------------*\
\r
949 * Initialization functions
\r
951 \*---------------------------------------------------------------------------*/
\r
955 { // update user logo if necessary
\r
956 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
958 if(appData.autoLogo) {
\r
959 curName = UserName();
\r
960 if(strcmp(curName, oldUserName)) {
\r
961 GetCurrentDirectory(MSG_SIZ, dir);
\r
962 SetCurrentDirectory(installDir);
\r
963 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
964 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
965 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
966 if(userLogo == NULL)
\r
967 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
968 SetCurrentDirectory(dir); /* return to prev directory */
\r
974 InitApplication(HINSTANCE hInstance)
\r
978 /* Fill in window class structure with parameters that describe the */
\r
981 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
982 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
983 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
984 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
985 wc.hInstance = hInstance; /* Owner of this class */
\r
986 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
987 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
988 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
989 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
990 wc.lpszClassName = szAppName; /* Name to register as */
\r
992 /* Register the window class and return success/failure code. */
\r
993 if (!RegisterClass(&wc)) return FALSE;
\r
995 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
996 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
998 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
999 wc.hInstance = hInstance;
\r
1000 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
1001 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1002 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1003 wc.lpszMenuName = NULL;
\r
1004 wc.lpszClassName = szConsoleName;
\r
1006 if (!RegisterClass(&wc)) return FALSE;
\r
1011 /* Set by InitInstance, used by EnsureOnScreen */
\r
1012 int screenHeight, screenWidth;
\r
1013 RECT screenGeometry;
\r
1016 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1018 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1019 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1020 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1021 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1022 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1023 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1027 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1029 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1030 GetCurrentDirectory(MSG_SIZ, dir);
\r
1031 SetCurrentDirectory(installDir);
\r
1032 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1033 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1035 if (cps->programLogo == NULL && appData.debugMode) {
\r
1036 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1038 } else if(appData.autoLogo) {
\r
1039 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1040 char *opponent = "";
\r
1041 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1042 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1043 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1044 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1045 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1046 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1049 if(appData.directory[n] && appData.directory[n][0]) {
\r
1050 SetCurrentDirectory(appData.directory[n]);
\r
1051 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1054 SetCurrentDirectory(dir); /* return to prev directory */
\r
1060 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1061 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1063 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1064 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1065 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1066 liteBackTextureMode = appData.liteBackTextureMode;
\r
1068 if (liteBackTexture == NULL && appData.debugMode) {
\r
1069 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1073 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1074 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1075 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1076 darkBackTextureMode = appData.darkBackTextureMode;
\r
1078 if (darkBackTexture == NULL && appData.debugMode) {
\r
1079 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1084 #ifndef SM_CXVIRTUALSCREEN
\r
1085 #define SM_CXVIRTUALSCREEN 78
\r
1087 #ifndef SM_CYVIRTUALSCREEN
\r
1088 #define SM_CYVIRTUALSCREEN 79
\r
1090 #ifndef SM_XVIRTUALSCREEN
\r
1091 #define SM_XVIRTUALSCREEN 76
\r
1093 #ifndef SM_YVIRTUALSCREEN
\r
1094 #define SM_YVIRTUALSCREEN 77
\r
1100 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1101 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1102 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1103 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1104 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1105 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1106 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1107 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1110 ChessProgramState broadcast;
\r
1113 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1115 HWND hwnd; /* Main window handle. */
\r
1117 WINDOWPLACEMENT wp;
\r
1120 hInst = hInstance; /* Store instance handle in our global variable */
\r
1121 programName = szAppName;
\r
1123 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1124 *filepart = NULLCHAR;
\r
1125 SetCurrentDirectory(installDir);
\r
1127 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1129 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1131 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1132 /* xboard, and older WinBoards, controlled the move sound with the
\r
1133 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1134 always turn the option on (so that the backend will call us),
\r
1135 then let the user turn the sound off by setting it to silence if
\r
1136 desired. To accommodate old winboard.ini files saved by old
\r
1137 versions of WinBoard, we also turn off the sound if the option
\r
1138 was initially set to false. [HGM] taken out of InitAppData */
\r
1139 if (!appData.ringBellAfterMoves) {
\r
1140 sounds[(int)SoundMove].name = strdup("");
\r
1141 appData.ringBellAfterMoves = TRUE;
\r
1143 if (appData.debugMode) {
\r
1144 char *c = appData.nameOfDebugFile;
\r
1145 if(strstr(c, "///") == c) {
\r
1146 broadcast.which = "broadcaster";
\r
1147 broadcast.pr = NoProc;
\r
1148 broadcast.isr = NULL;
\r
1149 broadcast.program = c + 3;
\r
1150 broadcast.dir = ".";
\r
1151 broadcast.host = "localhost";
\r
1152 StartChessProgram(&broadcast);
\r
1153 debugFP = (FILE*) _fdopen(_open_osfhandle((long)(((ChildProc*)(broadcast.pr))->hTo), _O_WRONLY), "w");
\r
1155 debugFP = fopen(c, "w");
\r
1156 setbuf(debugFP, NULL);
\r
1159 LoadLanguageFile(appData.language);
\r
1163 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1164 // InitEngineUCI( installDir, &second );
\r
1166 /* Create a main window for this application instance. */
\r
1167 hwnd = CreateWindow(szAppName, szTitle,
\r
1168 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1169 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1170 NULL, NULL, hInstance, NULL);
\r
1173 /* If window could not be created, return "failure" */
\r
1178 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1179 LoadLogo(&first, 0, FALSE);
\r
1180 LoadLogo(&second, 1, appData.icsActive);
\r
1184 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1185 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1186 iconCurrent = iconWhite;
\r
1187 InitDrawingColors();
\r
1189 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1190 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1191 /* Compute window size for each board size, and use the largest
\r
1192 size that fits on this screen as the default. */
\r
1193 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1194 if (boardSize == (BoardSize)-1 &&
\r
1195 winH <= screenHeight
\r
1196 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1197 && winW <= screenWidth) {
\r
1198 boardSize = (BoardSize)ibs;
\r
1202 InitDrawingSizes(boardSize, 0);
\r
1203 RecentEngineMenu(appData.recentEngineList);
\r
1205 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1207 /* [AS] Load textures if specified */
\r
1210 mysrandom( (unsigned) time(NULL) );
\r
1212 /* [AS] Restore layout */
\r
1213 if( wpMoveHistory.visible ) {
\r
1214 MoveHistoryPopUp();
\r
1217 if( wpEvalGraph.visible ) {
\r
1221 if( wpEngineOutput.visible ) {
\r
1222 EngineOutputPopUp();
\r
1225 /* Make the window visible; update its client area; and return "success" */
\r
1226 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1227 wp.length = sizeof(WINDOWPLACEMENT);
\r
1229 wp.showCmd = nCmdShow;
\r
1230 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1231 wp.rcNormalPosition.left = wpMain.x;
\r
1232 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1233 wp.rcNormalPosition.top = wpMain.y;
\r
1234 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1235 SetWindowPlacement(hwndMain, &wp);
\r
1237 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1239 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1240 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1242 if (hwndConsole) {
\r
1244 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1245 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1247 ShowWindow(hwndConsole, nCmdShow);
\r
1248 SetActiveWindow(hwndConsole);
\r
1250 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1251 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1260 HMENU hmenu = GetMenu(hwndMain);
\r
1262 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1263 MF_BYCOMMAND|((appData.icsActive &&
\r
1264 *appData.icsCommPort != NULLCHAR) ?
\r
1265 MF_ENABLED : MF_GRAYED));
\r
1266 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1267 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1268 MF_CHECKED : MF_UNCHECKED));
\r
1269 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1272 //---------------------------------------------------------------------------------------------------------
\r
1274 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1275 #define XBOARD FALSE
\r
1277 #define OPTCHAR "/"
\r
1278 #define SEPCHAR "="
\r
1279 #define TOPLEVEL 0
\r
1283 // front-end part of option handling
\r
1286 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1288 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1289 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1292 lf->lfEscapement = 0;
\r
1293 lf->lfOrientation = 0;
\r
1294 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1295 lf->lfItalic = mfp->italic;
\r
1296 lf->lfUnderline = mfp->underline;
\r
1297 lf->lfStrikeOut = mfp->strikeout;
\r
1298 lf->lfCharSet = mfp->charset;
\r
1299 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1303 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1304 lf->lfQuality = DEFAULT_QUALITY;
\r
1305 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1306 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1310 CreateFontInMF(MyFont *mf)
\r
1312 LFfromMFP(&mf->lf, &mf->mfp);
\r
1313 if (mf->hf) DeleteObject(mf->hf);
\r
1314 mf->hf = CreateFontIndirect(&mf->lf);
\r
1317 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1319 colorVariable[] = {
\r
1320 &whitePieceColor,
\r
1321 &blackPieceColor,
\r
1322 &lightSquareColor,
\r
1323 &darkSquareColor,
\r
1324 &highlightSquareColor,
\r
1325 &premoveHighlightColor,
\r
1327 &consoleBackgroundColor,
\r
1328 &appData.fontForeColorWhite,
\r
1329 &appData.fontBackColorWhite,
\r
1330 &appData.fontForeColorBlack,
\r
1331 &appData.fontBackColorBlack,
\r
1332 &appData.evalHistColorWhite,
\r
1333 &appData.evalHistColorBlack,
\r
1334 &appData.highlightArrowColor,
\r
1337 /* Command line font name parser. NULL name means do nothing.
\r
1338 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1339 For backward compatibility, syntax without the colon is also
\r
1340 accepted, but font names with digits in them won't work in that case.
\r
1343 ParseFontName(char *name, MyFontParams *mfp)
\r
1346 if (name == NULL) return;
\r
1348 q = strchr(p, ':');
\r
1350 if (q - p >= sizeof(mfp->faceName))
\r
1351 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1352 memcpy(mfp->faceName, p, q - p);
\r
1353 mfp->faceName[q - p] = NULLCHAR;
\r
1356 q = mfp->faceName;
\r
1358 while (*p && !isdigit(*p)) {
\r
1360 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1361 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1363 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1366 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1367 mfp->pointSize = (float) atof(p);
\r
1368 mfp->bold = (strchr(p, 'b') != NULL);
\r
1369 mfp->italic = (strchr(p, 'i') != NULL);
\r
1370 mfp->underline = (strchr(p, 'u') != NULL);
\r
1371 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1372 mfp->charset = DEFAULT_CHARSET;
\r
1373 q = strchr(p, 'c');
\r
1375 mfp->charset = (BYTE) atoi(q+1);
\r
1379 ParseFont(char *name, int number)
\r
1380 { // wrapper to shield back-end from 'font'
\r
1381 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1386 { // in WB we have a 2D array of fonts; this initializes their description
\r
1388 /* Point font array elements to structures and
\r
1389 parse default font names */
\r
1390 for (i=0; i<NUM_FONTS; i++) {
\r
1391 for (j=0; j<NUM_SIZES; j++) {
\r
1392 font[j][i] = &fontRec[j][i];
\r
1393 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1400 { // here we create the actual fonts from the selected descriptions
\r
1402 for (i=0; i<NUM_FONTS; i++) {
\r
1403 for (j=0; j<NUM_SIZES; j++) {
\r
1404 CreateFontInMF(font[j][i]);
\r
1408 /* Color name parser.
\r
1409 X version accepts X color names, but this one
\r
1410 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1412 ParseColorName(char *name)
\r
1414 int red, green, blue, count;
\r
1415 char buf[MSG_SIZ];
\r
1417 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1419 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1420 &red, &green, &blue);
\r
1423 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1424 DisplayError(buf, 0);
\r
1425 return RGB(0, 0, 0);
\r
1427 return PALETTERGB(red, green, blue);
\r
1431 ParseColor(int n, char *name)
\r
1432 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1433 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1437 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1439 char *e = argValue;
\r
1443 if (*e == 'b') eff |= CFE_BOLD;
\r
1444 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1445 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1446 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1447 else if (*e == '#' || isdigit(*e)) break;
\r
1451 *color = ParseColorName(e);
\r
1455 ParseTextAttribs(ColorClass cc, char *s)
\r
1456 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1457 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1458 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1462 ParseBoardSize(void *addr, char *name)
\r
1463 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1464 BoardSize bs = SizeTiny;
\r
1465 while (sizeInfo[bs].name != NULL) {
\r
1466 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1467 *(BoardSize *)addr = bs;
\r
1472 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1477 { // [HGM] import name from appData first
\r
1480 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1481 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1482 textAttribs[cc].sound.data = NULL;
\r
1483 MyLoadSound(&textAttribs[cc].sound);
\r
1485 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1486 textAttribs[cc].sound.name = strdup("");
\r
1487 textAttribs[cc].sound.data = NULL;
\r
1489 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1490 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1491 sounds[sc].data = NULL;
\r
1492 MyLoadSound(&sounds[sc]);
\r
1497 SetCommPortDefaults()
\r
1499 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1500 dcb.DCBlength = sizeof(DCB);
\r
1501 dcb.BaudRate = 9600;
\r
1502 dcb.fBinary = TRUE;
\r
1503 dcb.fParity = FALSE;
\r
1504 dcb.fOutxCtsFlow = FALSE;
\r
1505 dcb.fOutxDsrFlow = FALSE;
\r
1506 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1507 dcb.fDsrSensitivity = FALSE;
\r
1508 dcb.fTXContinueOnXoff = TRUE;
\r
1509 dcb.fOutX = FALSE;
\r
1511 dcb.fNull = FALSE;
\r
1512 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1513 dcb.fAbortOnError = FALSE;
\r
1515 dcb.Parity = SPACEPARITY;
\r
1516 dcb.StopBits = ONESTOPBIT;
\r
1519 // [HGM] args: these three cases taken out to stay in front-end
\r
1521 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1522 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1523 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1524 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1526 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1527 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1528 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1529 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1530 ad->argName, mfp->faceName, mfp->pointSize,
\r
1531 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1532 mfp->bold ? "b" : "",
\r
1533 mfp->italic ? "i" : "",
\r
1534 mfp->underline ? "u" : "",
\r
1535 mfp->strikeout ? "s" : "",
\r
1536 (int)mfp->charset);
\r
1542 { // [HGM] copy the names from the internal WB variables to appData
\r
1545 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1546 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1547 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1548 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1552 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1553 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1554 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1555 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1556 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1557 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1558 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1559 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1560 (ta->effects) ? " " : "",
\r
1561 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1565 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1566 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1567 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1568 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1569 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1573 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1574 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1575 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1579 ParseCommPortSettings(char *s)
\r
1580 { // wrapper to keep dcb from back-end
\r
1581 ParseCommSettings(s, &dcb);
\r
1586 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1587 GetActualPlacement(hwndMain, &wpMain);
\r
1588 GetActualPlacement(hwndConsole, &wpConsole);
\r
1589 GetActualPlacement(commentDialog, &wpComment);
\r
1590 GetActualPlacement(editTagsDialog, &wpTags);
\r
1591 GetActualPlacement(gameListDialog, &wpGameList);
\r
1592 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1593 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1594 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1598 PrintCommPortSettings(FILE *f, char *name)
\r
1599 { // wrapper to shield back-end from DCB
\r
1600 PrintCommSettings(f, name, &dcb);
\r
1604 MySearchPath(char *installDir, char *name, char *fullname)
\r
1606 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1607 if(name[0]== '%') {
\r
1608 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1609 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1610 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1611 *strchr(buf, '%') = 0;
\r
1612 strcat(fullname, getenv(buf));
\r
1613 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1615 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1616 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1617 return (int) strlen(fullname);
\r
1619 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1623 MyGetFullPathName(char *name, char *fullname)
\r
1626 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1631 { // [HGM] args: allows testing if main window is realized from back-end
\r
1632 return hwndMain != NULL;
\r
1636 PopUpStartupDialog()
\r
1640 LoadLanguageFile(appData.language);
\r
1641 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1642 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1643 FreeProcInstance(lpProc);
\r
1646 /*---------------------------------------------------------------------------*\
\r
1648 * GDI board drawing routines
\r
1650 \*---------------------------------------------------------------------------*/
\r
1652 /* [AS] Draw square using background texture */
\r
1653 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1658 return; /* Should never happen! */
\r
1661 SetGraphicsMode( dst, GM_ADVANCED );
\r
1668 /* X reflection */
\r
1673 x.eDx = (FLOAT) dw + dx - 1;
\r
1676 SetWorldTransform( dst, &x );
\r
1679 /* Y reflection */
\r
1685 x.eDy = (FLOAT) dh + dy - 1;
\r
1687 SetWorldTransform( dst, &x );
\r
1695 x.eDx = (FLOAT) dx;
\r
1696 x.eDy = (FLOAT) dy;
\r
1699 SetWorldTransform( dst, &x );
\r
1703 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1711 SetWorldTransform( dst, &x );
\r
1713 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1716 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1718 PM_WP = (int) WhitePawn,
\r
1719 PM_WN = (int) WhiteKnight,
\r
1720 PM_WB = (int) WhiteBishop,
\r
1721 PM_WR = (int) WhiteRook,
\r
1722 PM_WQ = (int) WhiteQueen,
\r
1723 PM_WF = (int) WhiteFerz,
\r
1724 PM_WW = (int) WhiteWazir,
\r
1725 PM_WE = (int) WhiteAlfil,
\r
1726 PM_WM = (int) WhiteMan,
\r
1727 PM_WO = (int) WhiteCannon,
\r
1728 PM_WU = (int) WhiteUnicorn,
\r
1729 PM_WH = (int) WhiteNightrider,
\r
1730 PM_WA = (int) WhiteAngel,
\r
1731 PM_WC = (int) WhiteMarshall,
\r
1732 PM_WAB = (int) WhiteCardinal,
\r
1733 PM_WD = (int) WhiteDragon,
\r
1734 PM_WL = (int) WhiteLance,
\r
1735 PM_WS = (int) WhiteCobra,
\r
1736 PM_WV = (int) WhiteFalcon,
\r
1737 PM_WSG = (int) WhiteSilver,
\r
1738 PM_WG = (int) WhiteGrasshopper,
\r
1739 PM_WK = (int) WhiteKing,
\r
1740 PM_BP = (int) BlackPawn,
\r
1741 PM_BN = (int) BlackKnight,
\r
1742 PM_BB = (int) BlackBishop,
\r
1743 PM_BR = (int) BlackRook,
\r
1744 PM_BQ = (int) BlackQueen,
\r
1745 PM_BF = (int) BlackFerz,
\r
1746 PM_BW = (int) BlackWazir,
\r
1747 PM_BE = (int) BlackAlfil,
\r
1748 PM_BM = (int) BlackMan,
\r
1749 PM_BO = (int) BlackCannon,
\r
1750 PM_BU = (int) BlackUnicorn,
\r
1751 PM_BH = (int) BlackNightrider,
\r
1752 PM_BA = (int) BlackAngel,
\r
1753 PM_BC = (int) BlackMarshall,
\r
1754 PM_BG = (int) BlackGrasshopper,
\r
1755 PM_BAB = (int) BlackCardinal,
\r
1756 PM_BD = (int) BlackDragon,
\r
1757 PM_BL = (int) BlackLance,
\r
1758 PM_BS = (int) BlackCobra,
\r
1759 PM_BV = (int) BlackFalcon,
\r
1760 PM_BSG = (int) BlackSilver,
\r
1761 PM_BK = (int) BlackKing
\r
1764 static HFONT hPieceFont = NULL;
\r
1765 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1766 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1767 static int fontBitmapSquareSize = 0;
\r
1768 static char pieceToFontChar[(int) EmptySquare] =
\r
1769 { 'p', 'n', 'b', 'r', 'q',
\r
1770 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1771 'k', 'o', 'm', 'v', 't', 'w',
\r
1772 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1775 extern BOOL SetCharTable( char *table, const char * map );
\r
1776 /* [HGM] moved to backend.c */
\r
1778 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1781 BYTE r1 = GetRValue( color );
\r
1782 BYTE g1 = GetGValue( color );
\r
1783 BYTE b1 = GetBValue( color );
\r
1789 /* Create a uniform background first */
\r
1790 hbrush = CreateSolidBrush( color );
\r
1791 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1792 FillRect( hdc, &rc, hbrush );
\r
1793 DeleteObject( hbrush );
\r
1796 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1797 int steps = squareSize / 2;
\r
1800 for( i=0; i<steps; i++ ) {
\r
1801 BYTE r = r1 - (r1-r2) * i / steps;
\r
1802 BYTE g = g1 - (g1-g2) * i / steps;
\r
1803 BYTE b = b1 - (b1-b2) * i / steps;
\r
1805 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1806 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1807 FillRect( hdc, &rc, hbrush );
\r
1808 DeleteObject(hbrush);
\r
1811 else if( mode == 2 ) {
\r
1812 /* Diagonal gradient, good more or less for every piece */
\r
1813 POINT triangle[3];
\r
1814 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1815 HBRUSH hbrush_old;
\r
1816 int steps = squareSize;
\r
1819 triangle[0].x = squareSize - steps;
\r
1820 triangle[0].y = squareSize;
\r
1821 triangle[1].x = squareSize;
\r
1822 triangle[1].y = squareSize;
\r
1823 triangle[2].x = squareSize;
\r
1824 triangle[2].y = squareSize - steps;
\r
1826 for( i=0; i<steps; i++ ) {
\r
1827 BYTE r = r1 - (r1-r2) * i / steps;
\r
1828 BYTE g = g1 - (g1-g2) * i / steps;
\r
1829 BYTE b = b1 - (b1-b2) * i / steps;
\r
1831 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1832 hbrush_old = SelectObject( hdc, hbrush );
\r
1833 Polygon( hdc, triangle, 3 );
\r
1834 SelectObject( hdc, hbrush_old );
\r
1835 DeleteObject(hbrush);
\r
1840 SelectObject( hdc, hpen );
\r
1845 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1846 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1847 piece: follow the steps as explained below.
\r
1849 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1853 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1859 int backColor = whitePieceColor;
\r
1860 int foreColor = blackPieceColor;
\r
1862 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1863 backColor = appData.fontBackColorWhite;
\r
1864 foreColor = appData.fontForeColorWhite;
\r
1866 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1867 backColor = appData.fontBackColorBlack;
\r
1868 foreColor = appData.fontForeColorBlack;
\r
1872 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1874 hbm_old = SelectObject( hdc, hbm );
\r
1878 rc.right = squareSize;
\r
1879 rc.bottom = squareSize;
\r
1881 /* Step 1: background is now black */
\r
1882 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1884 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1886 pt.x = (squareSize - sz.cx) / 2;
\r
1887 pt.y = (squareSize - sz.cy) / 2;
\r
1889 SetBkMode( hdc, TRANSPARENT );
\r
1890 SetTextColor( hdc, chroma );
\r
1891 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1892 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1894 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1895 /* Step 3: the area outside the piece is filled with white */
\r
1896 // FloodFill( hdc, 0, 0, chroma );
\r
1897 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1898 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1899 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1900 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1901 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1903 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1904 but if the start point is not inside the piece we're lost!
\r
1905 There should be a better way to do this... if we could create a region or path
\r
1906 from the fill operation we would be fine for example.
\r
1908 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1909 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1911 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1912 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1913 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1915 SelectObject( dc2, bm2 );
\r
1916 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1917 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1918 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1919 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1920 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1923 DeleteObject( bm2 );
\r
1926 SetTextColor( hdc, 0 );
\r
1928 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1929 draw the piece again in black for safety.
\r
1931 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1933 SelectObject( hdc, hbm_old );
\r
1935 if( hPieceMask[index] != NULL ) {
\r
1936 DeleteObject( hPieceMask[index] );
\r
1939 hPieceMask[index] = hbm;
\r
1942 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1944 SelectObject( hdc, hbm );
\r
1947 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1948 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1949 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1951 SelectObject( dc1, hPieceMask[index] );
\r
1952 SelectObject( dc2, bm2 );
\r
1953 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1954 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1957 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1958 the piece background and deletes (makes transparent) the rest.
\r
1959 Thanks to that mask, we are free to paint the background with the greates
\r
1960 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1961 We use this, to make gradients and give the pieces a "roundish" look.
\r
1963 SetPieceBackground( hdc, backColor, 2 );
\r
1964 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1968 DeleteObject( bm2 );
\r
1971 SetTextColor( hdc, foreColor );
\r
1972 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1974 SelectObject( hdc, hbm_old );
\r
1976 if( hPieceFace[index] != NULL ) {
\r
1977 DeleteObject( hPieceFace[index] );
\r
1980 hPieceFace[index] = hbm;
\r
1983 static int TranslatePieceToFontPiece( int piece )
\r
2013 case BlackMarshall:
\r
2017 case BlackNightrider:
\r
2023 case BlackUnicorn:
\r
2027 case BlackGrasshopper:
\r
2039 case BlackCardinal:
\r
2046 case WhiteMarshall:
\r
2050 case WhiteNightrider:
\r
2056 case WhiteUnicorn:
\r
2060 case WhiteGrasshopper:
\r
2072 case WhiteCardinal:
\r
2081 void CreatePiecesFromFont()
\r
2084 HDC hdc_window = NULL;
\r
2090 if( fontBitmapSquareSize < 0 ) {
\r
2091 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2095 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2096 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2097 fontBitmapSquareSize = -1;
\r
2101 if( fontBitmapSquareSize != squareSize ) {
\r
2102 hdc_window = GetDC( hwndMain );
\r
2103 hdc = CreateCompatibleDC( hdc_window );
\r
2105 if( hPieceFont != NULL ) {
\r
2106 DeleteObject( hPieceFont );
\r
2109 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2110 hPieceMask[i] = NULL;
\r
2111 hPieceFace[i] = NULL;
\r
2117 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2118 fontHeight = appData.fontPieceSize;
\r
2121 fontHeight = (fontHeight * squareSize) / 100;
\r
2123 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2125 lf.lfEscapement = 0;
\r
2126 lf.lfOrientation = 0;
\r
2127 lf.lfWeight = FW_NORMAL;
\r
2129 lf.lfUnderline = 0;
\r
2130 lf.lfStrikeOut = 0;
\r
2131 lf.lfCharSet = DEFAULT_CHARSET;
\r
2132 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2133 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2134 lf.lfQuality = PROOF_QUALITY;
\r
2135 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2136 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2137 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2139 hPieceFont = CreateFontIndirect( &lf );
\r
2141 if( hPieceFont == NULL ) {
\r
2142 fontBitmapSquareSize = -2;
\r
2145 /* Setup font-to-piece character table */
\r
2146 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2147 /* No (or wrong) global settings, try to detect the font */
\r
2148 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2150 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2152 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2153 /* DiagramTT* family */
\r
2154 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2156 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2157 /* Fairy symbols */
\r
2158 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2160 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2161 /* Good Companion (Some characters get warped as literal :-( */
\r
2162 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2163 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2164 SetCharTable(pieceToFontChar, s);
\r
2167 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2168 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2172 /* Create bitmaps */
\r
2173 hfont_old = SelectObject( hdc, hPieceFont );
\r
2174 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2175 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2176 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2178 SelectObject( hdc, hfont_old );
\r
2180 fontBitmapSquareSize = squareSize;
\r
2184 if( hdc != NULL ) {
\r
2188 if( hdc_window != NULL ) {
\r
2189 ReleaseDC( hwndMain, hdc_window );
\r
2194 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2196 char name[128], buf[MSG_SIZ];
\r
2198 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2199 if(appData.pieceDirectory[0]) {
\r
2201 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2202 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2203 if(res) return res;
\r
2205 if (gameInfo.event &&
\r
2206 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2207 strcmp(name, "k80s") == 0) {
\r
2208 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2210 return LoadBitmap(hinst, name);
\r
2214 /* Insert a color into the program's logical palette
\r
2215 structure. This code assumes the given color is
\r
2216 the result of the RGB or PALETTERGB macro, and it
\r
2217 knows how those macros work (which is documented).
\r
2220 InsertInPalette(COLORREF color)
\r
2222 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2224 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2225 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2226 pLogPal->palNumEntries--;
\r
2230 pe->peFlags = (char) 0;
\r
2231 pe->peRed = (char) (0xFF & color);
\r
2232 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2233 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2239 InitDrawingColors()
\r
2242 if (pLogPal == NULL) {
\r
2243 /* Allocate enough memory for a logical palette with
\r
2244 * PALETTESIZE entries and set the size and version fields
\r
2245 * of the logical palette structure.
\r
2247 pLogPal = (NPLOGPALETTE)
\r
2248 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2249 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2250 pLogPal->palVersion = 0x300;
\r
2252 pLogPal->palNumEntries = 0;
\r
2254 InsertInPalette(lightSquareColor);
\r
2255 InsertInPalette(darkSquareColor);
\r
2256 InsertInPalette(whitePieceColor);
\r
2257 InsertInPalette(blackPieceColor);
\r
2258 InsertInPalette(highlightSquareColor);
\r
2259 InsertInPalette(premoveHighlightColor);
\r
2261 /* create a logical color palette according the information
\r
2262 * in the LOGPALETTE structure.
\r
2264 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2266 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2267 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2268 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2269 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2270 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2271 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2272 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2273 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2275 /* [AS] Force rendering of the font-based pieces */
\r
2276 if( fontBitmapSquareSize > 0 ) {
\r
2277 fontBitmapSquareSize = 0;
\r
2283 BoardWidth(int boardSize, int n)
\r
2284 { /* [HGM] argument n added to allow different width and height */
\r
2285 int lineGap = sizeInfo[boardSize].lineGap;
\r
2287 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2288 lineGap = appData.overrideLineGap;
\r
2291 return (n + 1) * lineGap +
\r
2292 n * sizeInfo[boardSize].squareSize;
\r
2295 /* Respond to board resize by dragging edge */
\r
2297 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2299 BoardSize newSize = NUM_SIZES - 1;
\r
2300 static int recurse = 0;
\r
2301 if (IsIconic(hwndMain)) return;
\r
2302 if (recurse > 0) return;
\r
2304 while (newSize > 0) {
\r
2305 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2306 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2307 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2310 boardSize = newSize;
\r
2311 InitDrawingSizes(boardSize, flags);
\r
2316 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2319 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2321 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2322 ChessSquare piece;
\r
2323 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2325 SIZE clockSize, messageSize;
\r
2327 char buf[MSG_SIZ];
\r
2329 HMENU hmenu = GetMenu(hwndMain);
\r
2330 RECT crect, wrect, oldRect;
\r
2332 LOGBRUSH logbrush;
\r
2333 VariantClass v = gameInfo.variant;
\r
2335 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2336 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2338 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2339 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2340 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2341 oldBoardSize = boardSize;
\r
2343 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2344 { // correct board size to one where built-in pieces exist
\r
2345 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2346 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2348 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2349 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2350 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2351 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2352 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2353 boardSize = SizeMiddling;
\r
2356 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2358 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2359 oldRect.top = wpMain.y;
\r
2360 oldRect.right = wpMain.x + wpMain.width;
\r
2361 oldRect.bottom = wpMain.y + wpMain.height;
\r
2363 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2364 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2365 squareSize = sizeInfo[boardSize].squareSize;
\r
2366 lineGap = sizeInfo[boardSize].lineGap;
\r
2367 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2368 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2370 // [HGM] decide on tininess based on total board width rather than square size
\r
2371 tinyLayout = squareSize * (BOARD_WIDTH);
\r
2372 tinyLayout = tinyLayout < 35*8 ? 2 : tinyLayout < 43*8 ? 1 : 0;
\r
2374 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2375 lineGap = appData.overrideLineGap;
\r
2378 if (tinyLayout != oldTinyLayout) {
\r
2379 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2380 if (tinyLayout == 2) {
\r
2381 style &= ~WS_SYSMENU;
\r
2382 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2383 "&Minimize\tCtrl+F4");
\r
2385 style |= WS_SYSMENU;
\r
2386 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2388 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2390 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2391 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2392 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2394 DrawMenuBar(hwndMain);
\r
2397 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2398 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2400 /* Get text area sizes */
\r
2401 hdc = GetDC(hwndMain);
\r
2402 if (appData.clockMode) {
\r
2403 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2405 snprintf(buf, MSG_SIZ, _("White"));
\r
2407 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2408 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2409 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2410 str = _("We only care about the height here");
\r
2411 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2412 SelectObject(hdc, oldFont);
\r
2413 ReleaseDC(hwndMain, hdc);
\r
2415 /* Compute where everything goes */
\r
2416 if((first.programLogo || second.programLogo) && tinyLayout != 2) {
\r
2417 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2418 logoHeight = 2*clockSize.cy;
\r
2419 leftLogoRect.left = OUTER_MARGIN;
\r
2420 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2421 leftLogoRect.top = OUTER_MARGIN;
\r
2422 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2424 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2425 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2426 rightLogoRect.top = OUTER_MARGIN;
\r
2427 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2430 whiteRect.left = leftLogoRect.right;
\r
2431 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2432 whiteRect.top = OUTER_MARGIN;
\r
2433 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2435 blackRect.right = rightLogoRect.left;
\r
2436 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2437 blackRect.top = whiteRect.top;
\r
2438 blackRect.bottom = whiteRect.bottom;
\r
2440 whiteRect.left = OUTER_MARGIN;
\r
2441 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2442 whiteRect.top = OUTER_MARGIN;
\r
2443 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2445 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2446 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2447 blackRect.top = whiteRect.top;
\r
2448 blackRect.bottom = whiteRect.bottom;
\r
2450 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2453 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2454 if (appData.showButtonBar) {
\r
2455 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2456 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2458 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2460 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2461 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2463 boardRect.left = OUTER_MARGIN;
\r
2464 boardRect.right = boardRect.left + boardWidth;
\r
2465 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2466 boardRect.bottom = boardRect.top + boardHeight;
\r
2468 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2469 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2470 oldTinyLayout = tinyLayout;
\r
2471 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2472 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2473 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2474 winW *= 1 + twoBoards;
\r
2475 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2476 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2477 wpMain.height = winH; // without disturbing window attachments
\r
2478 GetWindowRect(hwndMain, &wrect);
\r
2479 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2480 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2482 // [HGM] placement: let attached windows follow size change.
\r
2483 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2484 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2485 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2486 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2487 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2489 /* compensate if menu bar wrapped */
\r
2490 GetClientRect(hwndMain, &crect);
\r
2491 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2492 wpMain.height += offby;
\r
2494 case WMSZ_TOPLEFT:
\r
2495 SetWindowPos(hwndMain, NULL,
\r
2496 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2497 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2500 case WMSZ_TOPRIGHT:
\r
2502 SetWindowPos(hwndMain, NULL,
\r
2503 wrect.left, wrect.bottom - wpMain.height,
\r
2504 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2507 case WMSZ_BOTTOMLEFT:
\r
2509 SetWindowPos(hwndMain, NULL,
\r
2510 wrect.right - wpMain.width, wrect.top,
\r
2511 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2514 case WMSZ_BOTTOMRIGHT:
\r
2518 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2519 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2524 for (i = 0; i < N_BUTTONS; i++) {
\r
2525 if (buttonDesc[i].hwnd != NULL) {
\r
2526 DestroyWindow(buttonDesc[i].hwnd);
\r
2527 buttonDesc[i].hwnd = NULL;
\r
2529 if (appData.showButtonBar) {
\r
2530 buttonDesc[i].hwnd =
\r
2531 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2532 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2533 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2534 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2535 (HMENU) buttonDesc[i].id,
\r
2536 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2537 if (tinyLayout == 2) {
\r
2538 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2539 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2540 MAKELPARAM(FALSE, 0));
\r
2542 if (buttonDesc[i].id == IDM_Pause)
\r
2543 hwndPause = buttonDesc[i].hwnd;
\r
2544 buttonDesc[i].wndproc = (WNDPROC)
\r
2545 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2548 if (gridPen != NULL) DeleteObject(gridPen);
\r
2549 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2550 if (premovePen != NULL) DeleteObject(premovePen);
\r
2551 if (lineGap != 0) {
\r
2552 logbrush.lbStyle = BS_SOLID;
\r
2553 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2555 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2556 lineGap, &logbrush, 0, NULL);
\r
2557 logbrush.lbColor = highlightSquareColor;
\r
2559 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2560 lineGap, &logbrush, 0, NULL);
\r
2562 logbrush.lbColor = premoveHighlightColor;
\r
2564 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2565 lineGap, &logbrush, 0, NULL);
\r
2567 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2568 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2569 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2570 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2571 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2572 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2573 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2574 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2576 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2577 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2578 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2579 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2580 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2581 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2582 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2583 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2587 /* [HGM] Licensing requirement */
\r
2589 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2592 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2594 GothicPopUp( "", VariantNormal);
\r
2597 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2599 /* Load piece bitmaps for this board size */
\r
2600 for (i=0; i<=2; i++) {
\r
2601 for (piece = WhitePawn;
\r
2602 (int) piece < (int) BlackPawn;
\r
2603 piece = (ChessSquare) ((int) piece + 1)) {
\r
2604 if (pieceBitmap[i][piece] != NULL)
\r
2605 DeleteObject(pieceBitmap[i][piece]);
\r
2606 pieceBitmap[i][piece] = NULL;
\r
2610 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2612 // Orthodox Chess pieces
\r
2613 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2614 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2615 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2616 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2617 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2618 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2619 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2620 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2621 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2622 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2623 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2624 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2625 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2626 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2627 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2628 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2629 // in Shogi, Hijack the unused Queen for Lance
\r
2630 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2631 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2632 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2634 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2635 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2636 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2639 if(squareSize <= 72 && squareSize >= 33) {
\r
2640 /* A & C are available in most sizes now */
\r
2641 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2642 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2645 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2646 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2647 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2648 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2651 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2652 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2653 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2654 } else { // Smirf-like
\r
2655 if(gameInfo.variant == VariantSChess) {
\r
2656 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2657 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2658 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2660 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2665 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2666 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2667 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2668 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2669 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2670 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2671 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2672 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2673 } else { // WinBoard standard
\r
2674 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2681 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2682 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2683 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2684 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2685 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2686 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2687 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2688 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2689 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2690 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2691 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2692 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2693 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2694 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2695 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2696 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2697 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2698 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2699 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2700 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2701 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2702 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2703 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2704 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2705 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2706 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2707 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2708 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2709 pieceBitmap[0][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2710 pieceBitmap[1][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2711 pieceBitmap[2][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2712 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2713 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2714 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2715 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2716 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2717 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2718 pieceBitmap[0][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2719 pieceBitmap[1][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2720 pieceBitmap[2][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2721 pieceBitmap[0][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "s");
\r
2722 pieceBitmap[1][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "o");
\r
2723 pieceBitmap[2][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "w");
\r
2724 pieceBitmap[0][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "s");
\r
2725 pieceBitmap[1][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "o");
\r
2726 pieceBitmap[2][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "w");
\r
2727 pieceBitmap[0][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "s");
\r
2728 pieceBitmap[1][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "o");
\r
2729 pieceBitmap[2][WhiteZebra] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2731 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2732 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2733 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2734 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2735 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2736 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2737 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2738 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2739 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2740 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2741 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2742 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2743 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2745 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2746 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2747 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2748 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2749 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2750 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2751 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2752 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2753 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2754 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2755 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2756 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2759 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2760 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2761 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2762 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2763 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2764 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2765 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2766 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2767 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2768 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2769 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2770 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2771 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2772 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2773 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2777 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2778 /* special Shogi support in this size */
\r
2779 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2780 for (piece = WhitePawn;
\r
2781 (int) piece < (int) BlackPawn;
\r
2782 piece = (ChessSquare) ((int) piece + 1)) {
\r
2783 if (pieceBitmap[i][piece] != NULL)
\r
2784 DeleteObject(pieceBitmap[i][piece]);
\r
2787 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2788 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2789 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2790 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2791 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2792 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2793 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2794 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2795 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2796 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2797 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2798 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2799 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2800 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2801 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2802 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2803 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2804 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2805 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2806 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2807 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2808 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2809 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2810 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2811 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2812 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2813 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2814 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2815 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2816 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2817 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2818 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2819 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2820 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2821 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2822 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2823 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2824 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2825 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2826 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2827 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2828 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2832 if(appData.pieceDirectory[0]) for(i=WhitePawn; i<BlackPawn; i++) { // try for all missing pieces with new naming convention
\r
2833 char buf[MSG_SIZ];
\r
2834 if(pieceBitmap[0][i]) continue;
\r
2835 snprintf(buf, MSG_SIZ, "piece%d_", i);
\r
2836 pieceBitmap[0][i] = DoLoadBitmap(hInst, buf, squareSize, "s");
\r
2837 pieceBitmap[1][i] = DoLoadBitmap(hInst, buf, squareSize, "o");
\r
2838 pieceBitmap[2][i] = DoLoadBitmap(hInst, buf, squareSize, "w");
\r
2843 PieceBitmap(ChessSquare p, int kind)
\r
2845 if ((int) p >= (int) BlackPawn)
\r
2846 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2848 return pieceBitmap[kind][(int) p];
\r
2851 /***************************************************************/
\r
2853 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2854 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2856 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2857 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2861 SquareToPos(int row, int column, int * x, int * y)
\r
2864 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2865 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2867 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2868 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2873 DrawCoordsOnDC(HDC hdc)
\r
2875 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2876 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2877 char str[2] = { NULLCHAR, NULLCHAR };
\r
2878 int oldMode, oldAlign, x, y, start, i;
\r
2882 if (!appData.showCoords)
\r
2885 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2887 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2888 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2889 oldAlign = GetTextAlign(hdc);
\r
2890 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2892 y = boardRect.top + lineGap;
\r
2893 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2896 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2897 x += border - lineGap - 4; y += squareSize - 6;
\r
2899 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2900 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2901 str[0] = files[start + i];
\r
2902 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2903 y += squareSize + lineGap;
\r
2906 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2909 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2910 x += -border + 4; y += border - squareSize + 6;
\r
2912 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2913 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2914 str[0] = ranks[start + i];
\r
2915 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2916 x += squareSize + lineGap;
\r
2919 SelectObject(hdc, oldBrush);
\r
2920 SetBkMode(hdc, oldMode);
\r
2921 SetTextAlign(hdc, oldAlign);
\r
2922 SelectObject(hdc, oldFont);
\r
2926 DrawGridOnDC(HDC hdc)
\r
2930 if (lineGap != 0) {
\r
2931 oldPen = SelectObject(hdc, gridPen);
\r
2932 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2933 SelectObject(hdc, oldPen);
\r
2937 #define HIGHLIGHT_PEN 0
\r
2938 #define PREMOVE_PEN 1
\r
2941 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2944 HPEN oldPen, hPen;
\r
2945 if (lineGap == 0) return;
\r
2947 x1 = boardRect.left +
\r
2948 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2949 y1 = boardRect.top +
\r
2950 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2952 x1 = boardRect.left +
\r
2953 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2954 y1 = boardRect.top +
\r
2955 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2957 hPen = pen ? premovePen : highlightPen;
\r
2958 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2959 MoveToEx(hdc, x1, y1, NULL);
\r
2960 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2961 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2962 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2963 LineTo(hdc, x1, y1);
\r
2964 SelectObject(hdc, oldPen);
\r
2968 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2971 for (i=0; i<2; i++) {
\r
2972 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2973 DrawHighlightOnDC(hdc, TRUE,
\r
2974 h->sq[i].x, h->sq[i].y,
\r
2979 /* Note: sqcolor is used only in monoMode */
\r
2980 /* Note that this code is largely duplicated in woptions.c,
\r
2981 function DrawSampleSquare, so that needs to be updated too */
\r
2983 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2985 HBITMAP oldBitmap;
\r
2989 if (appData.blindfold) return;
\r
2991 /* [AS] Use font-based pieces if needed */
\r
2992 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2993 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2994 CreatePiecesFromFont();
\r
2996 if( fontBitmapSquareSize == squareSize ) {
\r
2997 int index = TranslatePieceToFontPiece(piece);
\r
2999 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3001 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
3002 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
3006 squareSize, squareSize,
\r
3011 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3013 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
3014 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
3018 squareSize, squareSize,
\r
3027 if (appData.monoMode) {
\r
3028 SelectObject(tmphdc, PieceBitmap(piece,
\r
3029 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3030 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3031 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3033 HBRUSH xBrush = whitePieceBrush;
\r
3034 tmpSize = squareSize;
\r
3035 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
3037 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3038 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3039 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3040 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3041 x += (squareSize - minorSize)>>1;
\r
3042 y += squareSize - minorSize - 2;
\r
3043 tmpSize = minorSize;
\r
3045 if (color || appData.allWhite ) {
\r
3046 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3048 oldBrush = SelectObject(hdc, xBrush);
\r
3049 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3050 if(appData.upsideDown && color==flipView)
\r
3051 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3053 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3054 /* Use black for outline of white pieces */
\r
3055 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3056 if(appData.upsideDown && color==flipView)
\r
3057 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3059 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3060 } else if(appData.pieceDirectory[0]) {
\r
3061 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3062 oldBrush = SelectObject(hdc, xBrush);
\r
3063 if(appData.upsideDown && color==flipView)
\r
3064 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3066 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3067 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3068 if(appData.upsideDown && color==flipView)
\r
3069 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3071 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3073 /* Use square color for details of black pieces */
\r
3074 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3075 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3076 if(appData.upsideDown && !flipView)
\r
3077 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3079 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3081 SelectObject(hdc, oldBrush);
\r
3082 SelectObject(tmphdc, oldBitmap);
\r
3086 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3087 int GetBackTextureMode( int algo )
\r
3089 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3093 case BACK_TEXTURE_MODE_PLAIN:
\r
3094 result = 1; /* Always use identity map */
\r
3096 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3097 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3105 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3106 to handle redraws cleanly (as random numbers would always be different).
\r
3108 VOID RebuildTextureSquareInfo()
\r
3118 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3120 if( liteBackTexture != NULL ) {
\r
3121 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3122 lite_w = bi.bmWidth;
\r
3123 lite_h = bi.bmHeight;
\r
3127 if( darkBackTexture != NULL ) {
\r
3128 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3129 dark_w = bi.bmWidth;
\r
3130 dark_h = bi.bmHeight;
\r
3134 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3135 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3136 if( (col + row) & 1 ) {
\r
3138 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3139 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3140 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3142 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3143 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3144 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3146 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3147 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3152 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3153 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3154 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3156 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3157 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3158 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3160 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3161 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3168 /* [AS] Arrow highlighting support */
\r
3170 static double A_WIDTH = 5; /* Width of arrow body */
\r
3172 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3173 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3175 static double Sqr( double x )
\r
3180 static int Round( double x )
\r
3182 return (int) (x + 0.5);
\r
3185 /* Draw an arrow between two points using current settings */
\r
3186 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3189 double dx, dy, j, k, x, y;
\r
3191 if( d_x == s_x ) {
\r
3192 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3194 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3197 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3198 arrow[1].y = d_y - h;
\r
3200 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3201 arrow[2].y = d_y - h;
\r
3206 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3207 arrow[5].y = d_y - h;
\r
3209 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3210 arrow[4].y = d_y - h;
\r
3212 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3215 else if( d_y == s_y ) {
\r
3216 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3219 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3221 arrow[1].x = d_x - w;
\r
3222 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3224 arrow[2].x = d_x - w;
\r
3225 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3230 arrow[5].x = d_x - w;
\r
3231 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3233 arrow[4].x = d_x - w;
\r
3234 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3237 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3240 /* [AS] Needed a lot of paper for this! :-) */
\r
3241 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3242 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3244 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3246 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3251 arrow[0].x = Round(x - j);
\r
3252 arrow[0].y = Round(y + j*dx);
\r
3254 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3255 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3258 x = (double) d_x - k;
\r
3259 y = (double) d_y - k*dy;
\r
3262 x = (double) d_x + k;
\r
3263 y = (double) d_y + k*dy;
\r
3266 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3268 arrow[6].x = Round(x - j);
\r
3269 arrow[6].y = Round(y + j*dx);
\r
3271 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3272 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3274 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3275 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3280 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3281 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3284 Polygon( hdc, arrow, 7 );
\r
3287 /* [AS] Draw an arrow between two squares */
\r
3288 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3290 int s_x, s_y, d_x, d_y;
\r
3297 if( s_col == d_col && s_row == d_row ) {
\r
3301 /* Get source and destination points */
\r
3302 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3303 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3306 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3308 else if( d_y < s_y ) {
\r
3309 d_y += squareSize / 2 + squareSize / 4;
\r
3312 d_y += squareSize / 2;
\r
3316 d_x += squareSize / 2 - squareSize / 4;
\r
3318 else if( d_x < s_x ) {
\r
3319 d_x += squareSize / 2 + squareSize / 4;
\r
3322 d_x += squareSize / 2;
\r
3325 s_x += squareSize / 2;
\r
3326 s_y += squareSize / 2;
\r
3328 /* Adjust width */
\r
3329 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3332 stLB.lbStyle = BS_SOLID;
\r
3333 stLB.lbColor = appData.highlightArrowColor;
\r
3336 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3337 holdpen = SelectObject( hdc, hpen );
\r
3338 hbrush = CreateBrushIndirect( &stLB );
\r
3339 holdbrush = SelectObject( hdc, hbrush );
\r
3341 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3343 SelectObject( hdc, holdpen );
\r
3344 SelectObject( hdc, holdbrush );
\r
3345 DeleteObject( hpen );
\r
3346 DeleteObject( hbrush );
\r
3349 BOOL HasHighlightInfo()
\r
3351 BOOL result = FALSE;
\r
3353 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3354 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3365 BOOL IsDrawArrowEnabled()
\r
3367 BOOL result = FALSE;
\r
3369 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3376 VOID DrawArrowHighlight( HDC hdc )
\r
3378 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3379 DrawArrowBetweenSquares( hdc,
\r
3380 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3381 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3385 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3387 HRGN result = NULL;
\r
3389 if( HasHighlightInfo() ) {
\r
3390 int x1, y1, x2, y2;
\r
3391 int sx, sy, dx, dy;
\r
3393 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3394 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3396 sx = MIN( x1, x2 );
\r
3397 sy = MIN( y1, y2 );
\r
3398 dx = MAX( x1, x2 ) + squareSize;
\r
3399 dy = MAX( y1, y2 ) + squareSize;
\r
3401 result = CreateRectRgn( sx, sy, dx, dy );
\r
3408 Warning: this function modifies the behavior of several other functions.
\r
3410 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3411 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3412 repaint is scattered all over the place, which is not good for features such as
\r
3413 "arrow highlighting" that require a full repaint of the board.
\r
3415 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3416 user interaction, when speed is not so important) but especially to avoid errors
\r
3417 in the displayed graphics.
\r
3419 In such patched places, I always try refer to this function so there is a single
\r
3420 place to maintain knowledge.
\r
3422 To restore the original behavior, just return FALSE unconditionally.
\r
3424 BOOL IsFullRepaintPreferrable()
\r
3426 BOOL result = FALSE;
\r
3428 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3429 /* Arrow may appear on the board */
\r
3437 This function is called by DrawPosition to know whether a full repaint must
\r
3440 Only DrawPosition may directly call this function, which makes use of
\r
3441 some state information. Other function should call DrawPosition specifying
\r
3442 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3444 BOOL DrawPositionNeedsFullRepaint()
\r
3446 BOOL result = FALSE;
\r
3449 Probably a slightly better policy would be to trigger a full repaint
\r
3450 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3451 but animation is fast enough that it's difficult to notice.
\r
3453 if( animInfo.piece == EmptySquare ) {
\r
3454 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3462 static HBITMAP borderBitmap;
\r
3465 DrawBackgroundOnDC(HDC hdc)
\r
3471 static char oldBorder[MSG_SIZ];
\r
3472 int w = 600, h = 600, mode;
\r
3474 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3475 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3476 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3478 if(borderBitmap == NULL) { // loading failed, use white
\r
3479 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3482 tmphdc = CreateCompatibleDC(hdc);
\r
3483 hbm = SelectObject(tmphdc, borderBitmap);
\r
3484 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3488 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3489 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3490 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3491 SetStretchBltMode(hdc, mode);
\r
3492 SelectObject(tmphdc, hbm);
\r
3497 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3499 int row, column, x, y, square_color, piece_color;
\r
3500 ChessSquare piece;
\r
3502 HDC texture_hdc = NULL;
\r
3504 /* [AS] Initialize background textures if needed */
\r
3505 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3506 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3507 if( backTextureSquareSize != squareSize
\r
3508 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3509 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3510 backTextureSquareSize = squareSize;
\r
3511 RebuildTextureSquareInfo();
\r
3514 texture_hdc = CreateCompatibleDC( hdc );
\r
3517 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3518 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3520 SquareToPos(row, column, &x, &y);
\r
3522 piece = board[row][column];
\r
3524 square_color = ((column + row) % 2) == 1;
\r
3525 if( gameInfo.variant == VariantXiangqi ) {
\r
3526 square_color = !InPalace(row, column);
\r
3527 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3528 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3530 piece_color = (int) piece < (int) BlackPawn;
\r
3533 /* [HGM] holdings file: light square or black */
\r
3534 if(column == BOARD_LEFT-2) {
\r
3535 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3538 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3542 if(column == BOARD_RGHT + 1 ) {
\r
3543 if( row < gameInfo.holdingsSize )
\r
3546 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3550 if(column == BOARD_LEFT-1 ) /* left align */
\r
3551 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3552 else if( column == BOARD_RGHT) /* right align */
\r
3553 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3554 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3556 if (appData.monoMode) {
\r
3557 if (piece == EmptySquare) {
\r
3558 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3559 square_color ? WHITENESS : BLACKNESS);
\r
3561 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3564 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3565 /* [AS] Draw the square using a texture bitmap */
\r
3566 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3567 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3568 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3571 squareSize, squareSize,
\r
3574 backTextureSquareInfo[r][c].mode,
\r
3575 backTextureSquareInfo[r][c].x,
\r
3576 backTextureSquareInfo[r][c].y );
\r
3578 SelectObject( texture_hdc, hbm );
\r
3580 if (piece != EmptySquare) {
\r
3581 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3585 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3587 oldBrush = SelectObject(hdc, brush );
\r
3588 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3589 SelectObject(hdc, oldBrush);
\r
3590 if (piece != EmptySquare)
\r
3591 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3596 if( texture_hdc != NULL ) {
\r
3597 DeleteDC( texture_hdc );
\r
3601 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3602 void fputDW(FILE *f, int x)
\r
3604 fputc(x & 255, f);
\r
3605 fputc(x>>8 & 255, f);
\r
3606 fputc(x>>16 & 255, f);
\r
3607 fputc(x>>24 & 255, f);
\r
3610 #define MAX_CLIPS 200 /* more than enough */
\r
3613 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3615 // HBITMAP bufferBitmap;
\r
3620 int w = 100, h = 50;
\r
3622 if(logo == NULL) {
\r
3623 if(!logoHeight) return;
\r
3624 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3626 // GetClientRect(hwndMain, &Rect);
\r
3627 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3628 // Rect.bottom-Rect.top+1);
\r
3629 tmphdc = CreateCompatibleDC(hdc);
\r
3630 hbm = SelectObject(tmphdc, logo);
\r
3631 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3635 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3636 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3637 SelectObject(tmphdc, hbm);
\r
3645 HDC hdc = GetDC(hwndMain);
\r
3646 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3647 if(appData.autoLogo) {
\r
3649 switch(gameMode) { // pick logos based on game mode
\r
3650 case IcsObserving:
\r
3651 whiteLogo = second.programLogo; // ICS logo
\r
3652 blackLogo = second.programLogo;
\r
3655 case IcsPlayingWhite:
\r
3656 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3657 blackLogo = second.programLogo; // ICS logo
\r
3659 case IcsPlayingBlack:
\r
3660 whiteLogo = second.programLogo; // ICS logo
\r
3661 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3663 case TwoMachinesPlay:
\r
3664 if(first.twoMachinesColor[0] == 'b') {
\r
3665 whiteLogo = second.programLogo;
\r
3666 blackLogo = first.programLogo;
\r
3669 case MachinePlaysWhite:
\r
3670 blackLogo = userLogo;
\r
3672 case MachinePlaysBlack:
\r
3673 whiteLogo = userLogo;
\r
3674 blackLogo = first.programLogo;
\r
3677 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3678 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3679 ReleaseDC(hwndMain, hdc);
\r
3684 UpdateLogos(int display)
\r
3685 { // called after loading new engine(s), in tourney or from menu
\r
3686 LoadLogo(&first, 0, FALSE);
\r
3687 LoadLogo(&second, 1, appData.icsActive);
\r
3688 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3689 if(display) DisplayLogos();
\r
3692 static HDC hdcSeek;
\r
3694 // [HGM] seekgraph
\r
3695 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3698 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3699 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3700 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3701 SelectObject( hdcSeek, hp );
\r
3704 // front-end wrapper for drawing functions to do rectangles
\r
3705 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3710 if (hdcSeek == NULL) {
\r
3711 hdcSeek = GetDC(hwndMain);
\r
3712 if (!appData.monoMode) {
\r
3713 SelectPalette(hdcSeek, hPal, FALSE);
\r
3714 RealizePalette(hdcSeek);
\r
3717 hp = SelectObject( hdcSeek, gridPen );
\r
3718 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3719 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3720 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3721 SelectObject( hdcSeek, hp );
\r
3724 // front-end wrapper for putting text in graph
\r
3725 void DrawSeekText(char *buf, int x, int y)
\r
3728 SetBkMode( hdcSeek, TRANSPARENT );
\r
3729 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3730 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3733 void DrawSeekDot(int x, int y, int color)
\r
3735 int square = color & 0x80;
\r
3736 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3737 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3740 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3741 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3743 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3744 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3745 SelectObject(hdcSeek, oldBrush);
\r
3748 void DrawSeekOpen()
\r
3752 void DrawSeekClose()
\r
3759 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3761 static Board lastReq[2], lastDrawn[2];
\r
3762 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3763 static int lastDrawnFlipView = 0;
\r
3764 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3765 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3768 HBITMAP bufferBitmap;
\r
3769 HBITMAP oldBitmap;
\r
3771 HRGN clips[MAX_CLIPS];
\r
3772 ChessSquare dragged_piece = EmptySquare;
\r
3773 int nr = twoBoards*partnerUp;
\r
3775 /* I'm undecided on this - this function figures out whether a full
\r
3776 * repaint is necessary on its own, so there's no real reason to have the
\r
3777 * caller tell it that. I think this can safely be set to FALSE - but
\r
3778 * if we trust the callers not to request full repaints unnessesarily, then
\r
3779 * we could skip some clipping work. In other words, only request a full
\r
3780 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3781 * gamestart and similar) --Hawk
\r
3783 Boolean fullrepaint = repaint;
\r
3785 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3787 if( DrawPositionNeedsFullRepaint() ) {
\r
3788 fullrepaint = TRUE;
\r
3791 if (board == NULL) {
\r
3792 if (!lastReqValid[nr]) {
\r
3795 board = lastReq[nr];
\r
3797 CopyBoard(lastReq[nr], board);
\r
3798 lastReqValid[nr] = 1;
\r
3801 if (doingSizing) {
\r
3805 if (IsIconic(hwndMain)) {
\r
3809 if (hdc == NULL) {
\r
3810 hdc = GetDC(hwndMain);
\r
3811 if (!appData.monoMode) {
\r
3812 SelectPalette(hdc, hPal, FALSE);
\r
3813 RealizePalette(hdc);
\r
3817 releaseDC = FALSE;
\r
3820 /* Create some work-DCs */
\r
3821 hdcmem = CreateCompatibleDC(hdc);
\r
3822 tmphdc = CreateCompatibleDC(hdc);
\r
3824 /* If dragging is in progress, we temporarely remove the piece */
\r
3825 /* [HGM] or temporarily decrease count if stacked */
\r
3826 /* !! Moved to before board compare !! */
\r
3827 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3828 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3829 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3830 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3831 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3833 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3834 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3835 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3837 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3840 /* Figure out which squares need updating by comparing the
\r
3841 * newest board with the last drawn board and checking if
\r
3842 * flipping has changed.
\r
3844 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3845 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3846 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3847 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3848 SquareToPos(row, column, &x, &y);
\r
3849 clips[num_clips++] =
\r
3850 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3854 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3855 for (i=0; i<2; i++) {
\r
3856 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3857 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3858 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3859 lastDrawnHighlight.sq[i].y >= 0) {
\r
3860 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3861 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3862 clips[num_clips++] =
\r
3863 CreateRectRgn(x - lineGap, y - lineGap,
\r
3864 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3866 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3867 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3868 clips[num_clips++] =
\r
3869 CreateRectRgn(x - lineGap, y - lineGap,
\r
3870 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3874 for (i=0; i<2; i++) {
\r
3875 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3876 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3877 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3878 lastDrawnPremove.sq[i].y >= 0) {
\r
3879 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3880 lastDrawnPremove.sq[i].x, &x, &y);
\r
3881 clips[num_clips++] =
\r
3882 CreateRectRgn(x - lineGap, y - lineGap,
\r
3883 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3885 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3886 premoveHighlightInfo.sq[i].y >= 0) {
\r
3887 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3888 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3889 clips[num_clips++] =
\r
3890 CreateRectRgn(x - lineGap, y - lineGap,
\r
3891 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3895 } else { // nr == 1
\r
3896 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3897 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3898 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3899 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3900 for (i=0; i<2; i++) {
\r
3901 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3902 partnerHighlightInfo.sq[i].y >= 0) {
\r
3903 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3904 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3905 clips[num_clips++] =
\r
3906 CreateRectRgn(x - lineGap, y - lineGap,
\r
3907 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3909 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3910 oldPartnerHighlight.sq[i].y >= 0) {
\r
3911 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3912 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3913 clips[num_clips++] =
\r
3914 CreateRectRgn(x - lineGap, y - lineGap,
\r
3915 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3920 fullrepaint = TRUE;
\r
3923 /* Create a buffer bitmap - this is the actual bitmap
\r
3924 * being written to. When all the work is done, we can
\r
3925 * copy it to the real DC (the screen). This avoids
\r
3926 * the problems with flickering.
\r
3928 GetClientRect(hwndMain, &Rect);
\r
3929 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3930 Rect.bottom-Rect.top+1);
\r
3931 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3932 if (!appData.monoMode) {
\r
3933 SelectPalette(hdcmem, hPal, FALSE);
\r
3936 /* Create clips for dragging */
\r
3937 if (!fullrepaint) {
\r
3938 if (dragInfo.from.x >= 0) {
\r
3939 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3940 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3942 if (dragInfo.start.x >= 0) {
\r
3943 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3944 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3946 if (dragInfo.pos.x >= 0) {
\r
3947 x = dragInfo.pos.x - squareSize / 2;
\r
3948 y = dragInfo.pos.y - squareSize / 2;
\r
3949 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3951 if (dragInfo.lastpos.x >= 0) {
\r
3952 x = dragInfo.lastpos.x - squareSize / 2;
\r
3953 y = dragInfo.lastpos.y - squareSize / 2;
\r
3954 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3958 /* Are we animating a move?
\r
3960 * - remove the piece from the board (temporarely)
\r
3961 * - calculate the clipping region
\r
3963 if (!fullrepaint) {
\r
3964 if (animInfo.piece != EmptySquare) {
\r
3965 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3966 x = boardRect.left + animInfo.lastpos.x;
\r
3967 y = boardRect.top + animInfo.lastpos.y;
\r
3968 x2 = boardRect.left + animInfo.pos.x;
\r
3969 y2 = boardRect.top + animInfo.pos.y;
\r
3970 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3971 /* Slight kludge. The real problem is that after AnimateMove is
\r
3972 done, the position on the screen does not match lastDrawn.
\r
3973 This currently causes trouble only on e.p. captures in
\r
3974 atomic, where the piece moves to an empty square and then
\r
3975 explodes. The old and new positions both had an empty square
\r
3976 at the destination, but animation has drawn a piece there and
\r
3977 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3979 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3983 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3984 if (num_clips == 0)
\r
3985 fullrepaint = TRUE;
\r
3987 /* Set clipping on the memory DC */
\r
3988 if (!fullrepaint) {
\r
3989 SelectClipRgn(hdcmem, clips[0]);
\r
3990 for (x = 1; x < num_clips; x++) {
\r
3991 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3992 abort(); // this should never ever happen!
\r
3996 /* Do all the drawing to the memory DC */
\r
3997 if(explodeInfo.radius) { // [HGM] atomic
\r
3999 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4000 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
4001 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4002 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4003 x += squareSize/2;
\r
4004 y += squareSize/2;
\r
4005 if(!fullrepaint) {
\r
4006 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4007 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4009 DrawGridOnDC(hdcmem);
\r
4010 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
4011 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
4012 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4013 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
4014 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4015 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4016 SelectObject(hdcmem, oldBrush);
\r
4018 if(border) DrawBackgroundOnDC(hdcmem);
\r
4019 DrawGridOnDC(hdcmem);
\r
4020 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
4021 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
4022 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
4024 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
4025 oldPartnerHighlight = partnerHighlightInfo;
\r
4027 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4029 if(nr == 0) // [HGM] dual: markers only on left board
\r
4030 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4031 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4032 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
4033 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
4034 SquareToPos(row, column, &x, &y);
\r
4035 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
4036 x + 3*squareSize/4, y + 3*squareSize/4);
\r
4037 SelectObject(hdcmem, oldBrush);
\r
4042 if( appData.highlightMoveWithArrow ) {
\r
4044 DrawArrowHighlight(hdcmem);
\r
4047 DrawCoordsOnDC(hdcmem);
\r
4049 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
4050 /* to make sure lastDrawn contains what is actually drawn */
\r
4052 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4053 if (dragged_piece != EmptySquare) {
\r
4054 /* [HGM] or restack */
\r
4055 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4056 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4058 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4059 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4061 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4062 x = dragInfo.pos.x - squareSize / 2;
\r
4063 y = dragInfo.pos.y - squareSize / 2;
\r
4064 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
4065 ((int) dragInfo.piece < (int) BlackPawn),
\r
4066 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4069 /* Put the animated piece back into place and draw it */
\r
4070 if (animInfo.piece != EmptySquare) {
\r
4071 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4072 x = boardRect.left + animInfo.pos.x;
\r
4073 y = boardRect.top + animInfo.pos.y;
\r
4074 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4075 ((int) animInfo.piece < (int) BlackPawn),
\r
4076 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4079 /* Release the bufferBitmap by selecting in the old bitmap
\r
4080 * and delete the memory DC
\r
4082 SelectObject(hdcmem, oldBitmap);
\r
4085 /* Set clipping on the target DC */
\r
4086 if (!fullrepaint) {
\r
4087 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4089 GetRgnBox(clips[x], &rect);
\r
4090 DeleteObject(clips[x]);
\r
4091 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4092 rect.right + wpMain.width/2, rect.bottom);
\r
4094 SelectClipRgn(hdc, clips[0]);
\r
4095 for (x = 1; x < num_clips; x++) {
\r
4096 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4097 abort(); // this should never ever happen!
\r
4101 /* Copy the new bitmap onto the screen in one go.
\r
4102 * This way we avoid any flickering
\r
4104 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4105 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4106 boardRect.right - boardRect.left,
\r
4107 boardRect.bottom - boardRect.top,
\r
4108 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4109 if(saveDiagFlag) {
\r
4110 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4111 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4112 HBITMAP src = bufferBitmap, obmp; HDC tmp = CreateCompatibleDC(hdc);
\r
4114 bufferBitmap = CreateCompatibleBitmap(hdc, boardRect.right-boardRect.left, Rect.bottom-Rect.top-2*OUTER_MARGIN);
\r
4115 obmp = SelectObject(tmp, bufferBitmap);
\r
4116 BitBlt(tmp, 0, 0, boardRect.right - boardRect.left, Rect.bottom - Rect.top - 2*OUTER_MARGIN,
\r
4117 tmphdc, boardRect.left, OUTER_MARGIN, SRCCOPY);
\r
4118 GetObject(bufferBitmap, sizeof(b), &b);
\r
4119 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4120 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4121 bih.biWidth = b.bmWidth;
\r
4122 bih.biHeight = b.bmHeight;
\r
4124 bih.biBitCount = b.bmBitsPixel;
\r
4125 bih.biCompression = 0;
\r
4126 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4127 bih.biXPelsPerMeter = 0;
\r
4128 bih.biYPelsPerMeter = 0;
\r
4129 bih.biClrUsed = 0;
\r
4130 bih.biClrImportant = 0;
\r
4131 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4132 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4133 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4134 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4136 wb = b.bmWidthBytes;
\r
4138 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4139 int k = ((int*) pData)[i];
\r
4140 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4141 if(j >= 16) break;
\r
4143 if(j >= nrColors) nrColors = j+1;
\r
4145 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4147 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4148 for(w=0; w<(wb>>2); w+=2) {
\r
4149 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4150 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4151 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4152 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4153 pData[p++] = m | j<<4;
\r
4155 while(p&3) pData[p++] = 0;
\r
4158 wb = ((wb+31)>>5)<<2;
\r
4160 // write BITMAPFILEHEADER
\r
4161 fprintf(diagFile, "BM");
\r
4162 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4163 fputDW(diagFile, 0);
\r
4164 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4165 // write BITMAPINFOHEADER
\r
4166 fputDW(diagFile, 40);
\r
4167 fputDW(diagFile, b.bmWidth);
\r
4168 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4169 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4170 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4171 fputDW(diagFile, 0);
\r
4172 fputDW(diagFile, 0);
\r
4173 fputDW(diagFile, 0);
\r
4174 fputDW(diagFile, 0);
\r
4175 fputDW(diagFile, 0);
\r
4176 fputDW(diagFile, 0);
\r
4177 // write color table
\r
4179 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4180 // write bitmap data
\r
4181 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4182 fputc(pData[i], diagFile);
\r
4185 DeleteObject(bufferBitmap); bufferBitmap = src;
\r
4186 SelectObject(tmp, obmp);
\r
4190 SelectObject(tmphdc, oldBitmap);
\r
4192 /* Massive cleanup */
\r
4193 for (x = 0; x < num_clips; x++)
\r
4194 DeleteObject(clips[x]);
\r
4197 DeleteObject(bufferBitmap);
\r
4200 ReleaseDC(hwndMain, hdc);
\r
4202 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4204 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4206 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4209 /* CopyBoard(lastDrawn, board);*/
\r
4210 lastDrawnHighlight = highlightInfo;
\r
4211 lastDrawnPremove = premoveHighlightInfo;
\r
4212 lastDrawnFlipView = flipView;
\r
4213 lastDrawnValid[nr] = 1;
\r
4216 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4221 saveDiagFlag = 1; diagFile = f;
\r
4222 HDCDrawPosition(NULL, TRUE, NULL);
\r
4230 /*---------------------------------------------------------------------------*\
\r
4231 | CLIENT PAINT PROCEDURE
\r
4232 | This is the main event-handler for the WM_PAINT message.
\r
4234 \*---------------------------------------------------------------------------*/
\r
4236 PaintProc(HWND hwnd)
\r
4242 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4243 if (IsIconic(hwnd)) {
\r
4244 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4246 if (!appData.monoMode) {
\r
4247 SelectPalette(hdc, hPal, FALSE);
\r
4248 RealizePalette(hdc);
\r
4250 HDCDrawPosition(hdc, 1, NULL);
\r
4251 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4252 flipView = !flipView; partnerUp = !partnerUp;
\r
4253 HDCDrawPosition(hdc, 1, NULL);
\r
4254 flipView = !flipView; partnerUp = !partnerUp;
\r
4257 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4258 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4259 ETO_CLIPPED|ETO_OPAQUE,
\r
4260 &messageRect, messageText, strlen(messageText), NULL);
\r
4261 SelectObject(hdc, oldFont);
\r
4262 DisplayBothClocks();
\r
4265 EndPaint(hwnd,&ps);
\r
4273 * If the user selects on a border boundary, return -1; if off the board,
\r
4274 * return -2. Otherwise map the event coordinate to the square.
\r
4275 * The offset boardRect.left or boardRect.top must already have been
\r
4276 * subtracted from x.
\r
4278 int EventToSquare(x, limit)
\r
4283 if (x < lineGap + border)
\r
4285 x -= lineGap + border;
\r
4286 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4288 x /= (squareSize + lineGap);
\r
4300 DropEnable dropEnables[] = {
\r
4301 { 'P', DP_Pawn, N_("Pawn") },
\r
4302 { 'N', DP_Knight, N_("Knight") },
\r
4303 { 'B', DP_Bishop, N_("Bishop") },
\r
4304 { 'R', DP_Rook, N_("Rook") },
\r
4305 { 'Q', DP_Queen, N_("Queen") },
\r
4309 SetupDropMenu(HMENU hmenu)
\r
4311 int i, count, enable;
\r
4313 extern char white_holding[], black_holding[];
\r
4314 char item[MSG_SIZ];
\r
4316 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4317 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4318 dropEnables[i].piece);
\r
4320 while (p && *p++ == dropEnables[i].piece) count++;
\r
4321 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4322 enable = count > 0 || !appData.testLegality
\r
4323 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4324 && !appData.icsActive);
\r
4325 ModifyMenu(hmenu, dropEnables[i].command,
\r
4326 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4327 dropEnables[i].command, item);
\r
4331 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4333 dragInfo.lastpos.x = boardRect.left + x;
\r
4334 dragInfo.lastpos.y = boardRect.top + y;
\r
4335 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4336 dragInfo.from.x = fromX;
\r
4337 dragInfo.from.y = fromY;
\r
4338 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4339 dragInfo.start = dragInfo.from;
\r
4340 SetCapture(hwndMain);
\r
4343 void DragPieceEnd(int x, int y)
\r
4346 dragInfo.start.x = dragInfo.start.y = -1;
\r
4347 dragInfo.from = dragInfo.start;
\r
4348 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4351 void ChangeDragPiece(ChessSquare piece)
\r
4353 dragInfo.piece = piece;
\r
4356 /* Event handler for mouse messages */
\r
4358 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4362 static int recursive = 0;
\r
4364 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4367 if (message == WM_MBUTTONUP) {
\r
4368 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4369 to the middle button: we simulate pressing the left button too!
\r
4371 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4372 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4378 pt.x = LOWORD(lParam);
\r
4379 pt.y = HIWORD(lParam);
\r
4380 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4381 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4382 if (!flipView && y >= 0) {
\r
4383 y = BOARD_HEIGHT - 1 - y;
\r
4385 if (flipView && x >= 0) {
\r
4386 x = BOARD_WIDTH - 1 - x;
\r
4389 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4390 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4392 switch (message) {
\r
4393 case WM_LBUTTONDOWN:
\r
4394 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4395 ClockClick(flipClock); break;
\r
4396 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4397 ClockClick(!flipClock); break;
\r
4399 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4400 dragInfo.start.x = dragInfo.start.y = -1;
\r
4401 dragInfo.from = dragInfo.start;
\r
4403 if(fromX == -1 && frozen) { // not sure where this is for
\r
4404 fromX = fromY = -1;
\r
4405 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4408 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4409 DrawPosition(TRUE, NULL);
\r
4412 case WM_LBUTTONUP:
\r
4413 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4414 DrawPosition(TRUE, NULL);
\r
4417 case WM_MOUSEMOVE:
\r
4418 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4419 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4420 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4421 if ((appData.animateDragging || appData.highlightDragging)
\r
4422 && (wParam & MK_LBUTTON || dragging == 2)
\r
4423 && dragInfo.from.x >= 0)
\r
4425 BOOL full_repaint = FALSE;
\r
4427 if (appData.animateDragging) {
\r
4428 dragInfo.pos = pt;
\r
4430 if (appData.highlightDragging) {
\r
4431 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4432 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4433 full_repaint = TRUE;
\r
4437 DrawPosition( full_repaint, NULL);
\r
4439 dragInfo.lastpos = dragInfo.pos;
\r
4443 case WM_MOUSEWHEEL: // [DM]
\r
4444 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4445 /* Mouse Wheel is being rolled forward
\r
4446 * Play moves forward
\r
4448 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4449 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4450 /* Mouse Wheel is being rolled backward
\r
4451 * Play moves backward
\r
4453 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4454 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4458 case WM_MBUTTONUP:
\r
4459 case WM_RBUTTONUP:
\r
4461 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4464 case WM_MBUTTONDOWN:
\r
4465 case WM_RBUTTONDOWN:
\r
4468 fromX = fromY = -1;
\r
4469 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4470 dragInfo.start.x = dragInfo.start.y = -1;
\r
4471 dragInfo.from = dragInfo.start;
\r
4472 dragInfo.lastpos = dragInfo.pos;
\r
4473 if (appData.highlightDragging) {
\r
4474 ClearHighlights();
\r
4477 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4478 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4479 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4480 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4481 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4485 DrawPosition(TRUE, NULL);
\r
4487 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4490 if (message == WM_MBUTTONDOWN) {
\r
4491 buttonCount = 3; /* even if system didn't think so */
\r
4492 if (wParam & MK_SHIFT)
\r
4493 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4495 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4496 } else { /* message == WM_RBUTTONDOWN */
\r
4497 /* Just have one menu, on the right button. Windows users don't
\r
4498 think to try the middle one, and sometimes other software steals
\r
4499 it, or it doesn't really exist. */
\r
4500 if(gameInfo.variant != VariantShogi)
\r
4501 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4503 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4507 SetCapture(hwndMain);
\r
4510 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4511 SetupDropMenu(hmenu);
\r
4512 MenuPopup(hwnd, pt, hmenu, -1);
\r
4522 /* Preprocess messages for buttons in main window */
\r
4524 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4526 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4529 for (i=0; i<N_BUTTONS; i++) {
\r
4530 if (buttonDesc[i].id == id) break;
\r
4532 if (i == N_BUTTONS) return 0;
\r
4533 switch (message) {
\r
4538 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4539 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4546 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4549 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4550 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4551 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4552 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4554 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4556 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4557 TypeInEvent((char)wParam);
\r
4563 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4566 static int promoStyle;
\r
4568 /* Process messages for Promotion dialog box */
\r
4570 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4575 switch (message) {
\r
4577 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4578 /* Center the dialog over the application window */
\r
4579 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4580 Translate(hDlg, DLG_PromotionKing);
\r
4581 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4582 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4583 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4584 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4585 SW_SHOW : SW_HIDE);
\r
4586 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4587 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4588 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4589 PieceToChar(WhiteAngel) != '~') ||
\r
4590 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4591 PieceToChar(BlackAngel) != '~') ) ?
\r
4592 SW_SHOW : SW_HIDE);
\r
4593 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4594 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4595 PieceToChar(WhiteMarshall) != '~') ||
\r
4596 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4597 PieceToChar(BlackMarshall) != '~') ) ?
\r
4598 SW_SHOW : SW_HIDE);
\r
4599 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4600 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4601 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4603 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4604 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4605 SetWindowText(hDlg, "Promote?");
\r
4607 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4608 gameInfo.variant == VariantSuper ?
\r
4609 SW_SHOW : SW_HIDE);
\r
4612 case WM_COMMAND: /* message: received a command */
\r
4613 switch (LOWORD(wParam)) {
\r
4615 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4616 ClearHighlights();
\r
4617 DrawPosition(FALSE, NULL);
\r
4620 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4623 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4626 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4627 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4630 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4631 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4633 case PB_Chancellor:
\r
4634 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4636 case PB_Archbishop:
\r
4637 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4640 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4641 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4646 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4647 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4648 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4649 fromX = fromY = -1;
\r
4650 if (!appData.highlightLastMove) {
\r
4651 ClearHighlights();
\r
4652 DrawPosition(FALSE, NULL);
\r
4659 /* Pop up promotion dialog */
\r
4661 PromotionPopup(HWND hwnd)
\r
4665 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4666 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4667 hwnd, (DLGPROC)lpProc);
\r
4668 FreeProcInstance(lpProc);
\r
4672 PromotionPopUp(char choice)
\r
4674 promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant));
\r
4675 DrawPosition(TRUE, NULL);
\r
4676 PromotionPopup(hwndMain);
\r
4680 LoadGameDialog(HWND hwnd, char* title)
\r
4684 char fileTitle[MSG_SIZ];
\r
4685 f = OpenFileDialog(hwnd, "rb", "",
\r
4686 appData.oldSaveStyle ? "gam" : "pgn",
\r
4688 title, &number, fileTitle, NULL);
\r
4690 cmailMsgLoaded = FALSE;
\r
4691 if (number == 0) {
\r
4692 int error = GameListBuild(f);
\r
4694 DisplayError(_("Cannot build game list"), error);
\r
4695 } else if (!ListEmpty(&gameList) &&
\r
4696 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4697 GameListPopUp(f, fileTitle);
\r
4700 GameListDestroy();
\r
4703 LoadGame(f, number, fileTitle, FALSE);
\r
4707 int get_term_width()
\r
4712 HFONT hfont, hold_font;
\r
4717 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4721 // get the text metrics
\r
4722 hdc = GetDC(hText);
\r
4723 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4724 if (consoleCF.dwEffects & CFE_BOLD)
\r
4725 lf.lfWeight = FW_BOLD;
\r
4726 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4727 lf.lfItalic = TRUE;
\r
4728 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4729 lf.lfStrikeOut = TRUE;
\r
4730 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4731 lf.lfUnderline = TRUE;
\r
4732 hfont = CreateFontIndirect(&lf);
\r
4733 hold_font = SelectObject(hdc, hfont);
\r
4734 GetTextMetrics(hdc, &tm);
\r
4735 SelectObject(hdc, hold_font);
\r
4736 DeleteObject(hfont);
\r
4737 ReleaseDC(hText, hdc);
\r
4739 // get the rectangle
\r
4740 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4742 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4745 void UpdateICSWidth(HWND hText)
\r
4747 LONG old_width, new_width;
\r
4749 new_width = get_term_width(hText, FALSE);
\r
4750 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4751 if (new_width != old_width)
\r
4753 ics_update_width(new_width);
\r
4754 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4759 ChangedConsoleFont()
\r
4762 CHARRANGE tmpsel, sel;
\r
4763 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4764 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4765 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4768 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4769 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4770 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4771 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4772 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4773 * size. This was undocumented in the version of MSVC++ that I had
\r
4774 * when I wrote the code, but is apparently documented now.
\r
4776 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4777 cfmt.bCharSet = f->lf.lfCharSet;
\r
4778 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4779 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4780 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4781 /* Why are the following seemingly needed too? */
\r
4782 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4783 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4784 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4786 tmpsel.cpMax = -1; /*999999?*/
\r
4787 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4788 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4789 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4790 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4792 paraf.cbSize = sizeof(paraf);
\r
4793 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4794 paraf.dxStartIndent = 0;
\r
4795 paraf.dxOffset = WRAP_INDENT;
\r
4796 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4797 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4798 UpdateICSWidth(hText);
\r
4801 /*---------------------------------------------------------------------------*\
\r
4803 * Window Proc for main window
\r
4805 \*---------------------------------------------------------------------------*/
\r
4807 /* Process messages for main window, etc. */
\r
4809 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4816 char fileTitle[MSG_SIZ];
\r
4817 static SnapData sd;
\r
4818 static int peek=0;
\r
4820 switch (message) {
\r
4822 case WM_PAINT: /* message: repaint portion of window */
\r
4826 case WM_ERASEBKGND:
\r
4827 if (IsIconic(hwnd)) {
\r
4828 /* Cheat; change the message */
\r
4829 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4831 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4835 case WM_LBUTTONDOWN:
\r
4836 case WM_MBUTTONDOWN:
\r
4837 case WM_RBUTTONDOWN:
\r
4838 case WM_LBUTTONUP:
\r
4839 case WM_MBUTTONUP:
\r
4840 case WM_RBUTTONUP:
\r
4841 case WM_MOUSEMOVE:
\r
4842 case WM_MOUSEWHEEL:
\r
4843 MouseEvent(hwnd, message, wParam, lParam);
\r
4847 if((char)wParam == '\b') {
\r
4848 ForwardEvent(); peek = 0;
\r
4851 JAWS_KBUP_NAVIGATION
\r
4856 if((char)wParam == '\b') {
\r
4857 if(!peek) BackwardEvent(), peek = 1;
\r
4860 JAWS_KBDOWN_NAVIGATION
\r
4866 JAWS_ALT_INTERCEPT
\r
4868 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4869 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4870 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4871 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4873 SendMessage(h, message, wParam, lParam);
\r
4874 } else if(lParam != KF_REPEAT) {
\r
4875 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4876 TypeInEvent((char)wParam);
\r
4877 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4878 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4883 case WM_PALETTECHANGED:
\r
4884 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4886 HDC hdc = GetDC(hwndMain);
\r
4887 SelectPalette(hdc, hPal, TRUE);
\r
4888 nnew = RealizePalette(hdc);
\r
4890 paletteChanged = TRUE;
\r
4892 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4894 ReleaseDC(hwnd, hdc);
\r
4898 case WM_QUERYNEWPALETTE:
\r
4899 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4901 HDC hdc = GetDC(hwndMain);
\r
4902 paletteChanged = FALSE;
\r
4903 SelectPalette(hdc, hPal, FALSE);
\r
4904 nnew = RealizePalette(hdc);
\r
4906 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4908 ReleaseDC(hwnd, hdc);
\r
4913 case WM_COMMAND: /* message: command from application menu */
\r
4914 wmId = LOWORD(wParam);
\r
4919 SAY("new game enter a move to play against the computer with white");
\r
4922 case IDM_NewGameFRC:
\r
4923 if( NewGameFRC() == 0 ) {
\r
4928 case IDM_NewVariant:
\r
4929 NewVariantPopup(hwnd);
\r
4932 case IDM_LoadGame:
\r
4933 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4936 case IDM_LoadNextGame:
\r
4940 case IDM_LoadPrevGame:
\r
4944 case IDM_ReloadGame:
\r
4948 case IDM_LoadPosition:
\r
4949 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4950 Reset(FALSE, TRUE);
\r
4953 f = OpenFileDialog(hwnd, "rb", "",
\r
4954 appData.oldSaveStyle ? "pos" : "fen",
\r
4956 _("Load Position from File"), &number, fileTitle, NULL);
\r
4958 LoadPosition(f, number, fileTitle);
\r
4962 case IDM_LoadNextPosition:
\r
4963 ReloadPosition(1);
\r
4966 case IDM_LoadPrevPosition:
\r
4967 ReloadPosition(-1);
\r
4970 case IDM_ReloadPosition:
\r
4971 ReloadPosition(0);
\r
4974 case IDM_SaveGame:
\r
4975 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4976 f = OpenFileDialog(hwnd, "a", defName,
\r
4977 appData.oldSaveStyle ? "gam" : "pgn",
\r
4979 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4981 SaveGame(f, 0, "");
\r
4985 case IDM_SavePosition:
\r
4986 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4987 f = OpenFileDialog(hwnd, "a", defName,
\r
4988 appData.oldSaveStyle ? "pos" : "fen",
\r
4990 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4992 SavePosition(f, 0, "");
\r
4996 case IDM_SaveDiagram:
\r
4997 defName = "diagram";
\r
4998 f = OpenFileDialog(hwnd, "wb", defName,
\r
5001 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
5007 case IDM_SaveSelected:
\r
5008 f = OpenFileDialog(hwnd, "a", "",
\r
5011 _("Save Game to File"), NULL, fileTitle, NULL);
\r
5013 SaveSelected(f, 0, "");
\r
5017 case IDM_CreateBook:
\r
5018 CreateBookEvent();
\r
5021 case IDM_CopyGame:
\r
5022 CopyGameToClipboard();
\r
5025 case IDM_PasteGame:
\r
5026 PasteGameFromClipboard();
\r
5029 case IDM_CopyGameListToClipboard:
\r
5030 CopyGameListToClipboard();
\r
5033 /* [AS] Autodetect FEN or PGN data */
\r
5034 case IDM_PasteAny:
\r
5035 PasteGameOrFENFromClipboard();
\r
5038 /* [AS] Move history */
\r
5039 case IDM_ShowMoveHistory:
\r
5040 if( MoveHistoryIsUp() ) {
\r
5041 MoveHistoryPopDown();
\r
5044 MoveHistoryPopUp();
\r
5048 /* [AS] Eval graph */
\r
5049 case IDM_ShowEvalGraph:
\r
5050 if( EvalGraphIsUp() ) {
\r
5051 EvalGraphPopDown();
\r
5055 SetFocus(hwndMain);
\r
5059 /* [AS] Engine output */
\r
5060 case IDM_ShowEngineOutput:
\r
5061 if( EngineOutputIsUp() ) {
\r
5062 EngineOutputPopDown();
\r
5065 EngineOutputPopUp();
\r
5069 /* [AS] User adjudication */
\r
5070 case IDM_UserAdjudication_White:
\r
5071 UserAdjudicationEvent( +1 );
\r
5074 case IDM_UserAdjudication_Black:
\r
5075 UserAdjudicationEvent( -1 );
\r
5078 case IDM_UserAdjudication_Draw:
\r
5079 UserAdjudicationEvent( 0 );
\r
5082 /* [AS] Game list options dialog */
\r
5083 case IDM_GameListOptions:
\r
5084 GameListOptions();
\r
5091 case IDM_CopyPosition:
\r
5092 CopyFENToClipboard();
\r
5095 case IDM_PastePosition:
\r
5096 PasteFENFromClipboard();
\r
5099 case IDM_MailMove:
\r
5103 case IDM_ReloadCMailMsg:
\r
5104 Reset(TRUE, TRUE);
\r
5105 ReloadCmailMsgEvent(FALSE);
\r
5108 case IDM_Minimize:
\r
5109 ShowWindow(hwnd, SW_MINIMIZE);
\r
5116 case IDM_MachineWhite:
\r
5117 MachineWhiteEvent();
\r
5119 * refresh the tags dialog only if it's visible
\r
5121 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5123 tags = PGNTags(&gameInfo);
\r
5124 TagsPopUp(tags, CmailMsg());
\r
5127 SAY("computer starts playing white");
\r
5130 case IDM_MachineBlack:
\r
5131 MachineBlackEvent();
\r
5133 * refresh the tags dialog only if it's visible
\r
5135 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5137 tags = PGNTags(&gameInfo);
\r
5138 TagsPopUp(tags, CmailMsg());
\r
5141 SAY("computer starts playing black");
\r
5144 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5145 if(matchMode) EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_GRAYED);
\r
5146 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5149 case IDM_TwoMachines:
\r
5150 TwoMachinesEvent();
\r
5153 * refresh the tags dialog only if it's visible
\r
5155 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5157 tags = PGNTags(&gameInfo);
\r
5158 TagsPopUp(tags, CmailMsg());
\r
5161 SAY("computer starts playing both sides");
\r
5164 case IDM_AnalysisMode:
\r
5165 if(AnalyzeModeEvent()) {
\r
5166 SAY("analyzing current position");
\r
5170 case IDM_AnalyzeFile:
\r
5171 AnalyzeFileEvent();
\r
5174 case IDM_IcsClient:
\r
5178 case IDM_EditGame:
\r
5179 case IDM_EditGame2:
\r
5184 case IDM_EditPosition:
\r
5185 case IDM_EditPosition2:
\r
5186 EditPositionEvent();
\r
5187 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5190 case IDM_Training:
\r
5194 case IDM_ShowGameList:
\r
5195 ShowGameListProc();
\r
5198 case IDM_EditProgs1:
\r
5199 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5202 case IDM_LoadProg1:
\r
5203 LoadEnginePopUp(hwndMain, 0);
\r
5206 case IDM_LoadProg2:
\r
5207 LoadEnginePopUp(hwndMain, 1);
\r
5210 case IDM_EditServers:
\r
5211 EditTagsPopUp(icsNames, &icsNames);
\r
5214 case IDM_EditTags:
\r
5219 case IDM_EditBook:
\r
5223 case IDM_EditComment:
\r
5225 if (commentUp && editComment) {
\r
5228 EditCommentEvent();
\r
5249 case IDM_CallFlag:
\r
5269 case IDM_StopObserving:
\r
5270 StopObservingEvent();
\r
5273 case IDM_StopExamining:
\r
5274 StopExaminingEvent();
\r
5278 UploadGameEvent();
\r
5281 case IDM_TypeInMove:
\r
5282 TypeInEvent('\000');
\r
5285 case IDM_TypeInName:
\r
5286 PopUpNameDialog('\000');
\r
5289 case IDM_Backward:
\r
5291 SetFocus(hwndMain);
\r
5298 SetFocus(hwndMain);
\r
5303 SetFocus(hwndMain);
\r
5308 SetFocus(hwndMain);
\r
5311 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5312 case OPT_GameListPrev:
\r
5313 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5317 RevertEvent(FALSE);
\r
5320 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5321 RevertEvent(TRUE);
\r
5324 case IDM_TruncateGame:
\r
5325 TruncateGameEvent();
\r
5332 case IDM_RetractMove:
\r
5333 RetractMoveEvent();
\r
5336 case IDM_FlipView:
\r
5337 flipView = !flipView;
\r
5338 DrawPosition(FALSE, NULL);
\r
5341 case IDM_FlipClock:
\r
5342 flipClock = !flipClock;
\r
5343 DisplayBothClocks();
\r
5347 case IDM_MuteSounds:
\r
5348 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5349 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5350 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5353 case IDM_GeneralOptions:
\r
5354 GeneralOptionsPopup(hwnd);
\r
5355 DrawPosition(TRUE, NULL);
\r
5358 case IDM_BoardOptions:
\r
5359 BoardOptionsPopup(hwnd);
\r
5362 case IDM_ThemeOptions:
\r
5363 ThemeOptionsPopup(hwnd);
\r
5366 case IDM_EnginePlayOptions:
\r
5367 EnginePlayOptionsPopup(hwnd);
\r
5370 case IDM_Engine1Options:
\r
5371 EngineOptionsPopup(hwnd, &first);
\r
5374 case IDM_Engine2Options:
\r
5376 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5377 EngineOptionsPopup(hwnd, &second);
\r
5380 case IDM_OptionsUCI:
\r
5381 UciOptionsPopup(hwnd);
\r
5385 TourneyPopup(hwnd);
\r
5388 case IDM_IcsOptions:
\r
5389 IcsOptionsPopup(hwnd);
\r
5393 FontsOptionsPopup(hwnd);
\r
5397 SoundOptionsPopup(hwnd);
\r
5400 case IDM_CommPort:
\r
5401 CommPortOptionsPopup(hwnd);
\r
5404 case IDM_LoadOptions:
\r
5405 LoadOptionsPopup(hwnd);
\r
5408 case IDM_SaveOptions:
\r
5409 SaveOptionsPopup(hwnd);
\r
5412 case IDM_TimeControl:
\r
5413 TimeControlOptionsPopup(hwnd);
\r
5416 case IDM_SaveSettings:
\r
5417 SaveSettings(settingsFileName);
\r
5420 case IDM_SaveSettingsOnExit:
\r
5421 saveSettingsOnExit = !saveSettingsOnExit;
\r
5422 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5423 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5424 MF_CHECKED : MF_UNCHECKED));
\r
5435 case IDM_AboutGame:
\r
5440 appData.debugMode = !appData.debugMode;
\r
5441 if (appData.debugMode) {
\r
5442 char dir[MSG_SIZ];
\r
5443 GetCurrentDirectory(MSG_SIZ, dir);
\r
5444 SetCurrentDirectory(installDir);
\r
5445 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5446 SetCurrentDirectory(dir);
\r
5447 setbuf(debugFP, NULL);
\r
5454 case IDM_HELPCONTENTS:
\r
5455 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5456 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5457 MessageBox (GetFocus(),
\r
5458 _("Unable to activate help"),
\r
5459 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5463 case IDM_HELPSEARCH:
\r
5464 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5465 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5466 MessageBox (GetFocus(),
\r
5467 _("Unable to activate help"),
\r
5468 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5472 case IDM_HELPHELP:
\r
5473 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5474 MessageBox (GetFocus(),
\r
5475 _("Unable to activate help"),
\r
5476 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5481 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5483 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5484 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5485 FreeProcInstance(lpProc);
\r
5488 case IDM_DirectCommand1:
\r
5489 AskQuestionEvent(_("Direct Command"),
\r
5490 _("Send to chess program:"), "", "1");
\r
5492 case IDM_DirectCommand2:
\r
5493 AskQuestionEvent(_("Direct Command"),
\r
5494 _("Send to second chess program:"), "", "2");
\r
5497 case EP_WhitePawn:
\r
5498 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5499 fromX = fromY = -1;
\r
5502 case EP_WhiteKnight:
\r
5503 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5504 fromX = fromY = -1;
\r
5507 case EP_WhiteBishop:
\r
5508 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5509 fromX = fromY = -1;
\r
5512 case EP_WhiteRook:
\r
5513 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5514 fromX = fromY = -1;
\r
5517 case EP_WhiteQueen:
\r
5518 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5519 fromX = fromY = -1;
\r
5522 case EP_WhiteFerz:
\r
5523 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5524 fromX = fromY = -1;
\r
5527 case EP_WhiteWazir:
\r
5528 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5529 fromX = fromY = -1;
\r
5532 case EP_WhiteAlfil:
\r
5533 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5534 fromX = fromY = -1;
\r
5537 case EP_WhiteCannon:
\r
5538 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5539 fromX = fromY = -1;
\r
5542 case EP_WhiteCardinal:
\r
5543 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5544 fromX = fromY = -1;
\r
5547 case EP_WhiteMarshall:
\r
5548 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5549 fromX = fromY = -1;
\r
5552 case EP_WhiteKing:
\r
5553 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5554 fromX = fromY = -1;
\r
5557 case EP_BlackPawn:
\r
5558 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5559 fromX = fromY = -1;
\r
5562 case EP_BlackKnight:
\r
5563 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5564 fromX = fromY = -1;
\r
5567 case EP_BlackBishop:
\r
5568 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5569 fromX = fromY = -1;
\r
5572 case EP_BlackRook:
\r
5573 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5574 fromX = fromY = -1;
\r
5577 case EP_BlackQueen:
\r
5578 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5579 fromX = fromY = -1;
\r
5582 case EP_BlackFerz:
\r
5583 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5584 fromX = fromY = -1;
\r
5587 case EP_BlackWazir:
\r
5588 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5589 fromX = fromY = -1;
\r
5592 case EP_BlackAlfil:
\r
5593 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5594 fromX = fromY = -1;
\r
5597 case EP_BlackCannon:
\r
5598 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5599 fromX = fromY = -1;
\r
5602 case EP_BlackCardinal:
\r
5603 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5604 fromX = fromY = -1;
\r
5607 case EP_BlackMarshall:
\r
5608 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5609 fromX = fromY = -1;
\r
5612 case EP_BlackKing:
\r
5613 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5614 fromX = fromY = -1;
\r
5617 case EP_EmptySquare:
\r
5618 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5619 fromX = fromY = -1;
\r
5622 case EP_ClearBoard:
\r
5623 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5624 fromX = fromY = -1;
\r
5628 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5629 fromX = fromY = -1;
\r
5633 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5634 fromX = fromY = -1;
\r
5638 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5639 fromX = fromY = -1;
\r
5643 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5644 fromX = fromY = -1;
\r
5648 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5649 fromX = fromY = -1;
\r
5653 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5654 fromX = fromY = -1;
\r
5658 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5659 fromX = fromY = -1;
\r
5663 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5664 fromX = fromY = -1;
\r
5668 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5669 fromX = fromY = -1;
\r
5673 barbaric = 0; appData.language = "";
\r
5674 TranslateMenus(0);
\r
5675 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5676 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5677 lastChecked = wmId;
\r
5681 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5682 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5684 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5685 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5686 TranslateMenus(0);
\r
5687 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5688 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5689 lastChecked = wmId;
\r
5692 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5698 case CLOCK_TIMER_ID:
\r
5699 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5700 clockTimerEvent = 0;
\r
5701 DecrementClocks(); /* call into back end */
\r
5703 case LOAD_GAME_TIMER_ID:
\r
5704 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5705 loadGameTimerEvent = 0;
\r
5706 AutoPlayGameLoop(); /* call into back end */
\r
5708 case ANALYSIS_TIMER_ID:
\r
5709 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5710 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5711 AnalysisPeriodicEvent(0);
\r
5713 KillTimer(hwnd, analysisTimerEvent);
\r
5714 analysisTimerEvent = 0;
\r
5717 case DELAYED_TIMER_ID:
\r
5718 KillTimer(hwnd, delayedTimerEvent);
\r
5719 delayedTimerEvent = 0;
\r
5720 delayedTimerCallback();
\r
5725 case WM_USER_Input:
\r
5726 InputEvent(hwnd, message, wParam, lParam);
\r
5729 /* [AS] Also move "attached" child windows */
\r
5730 case WM_WINDOWPOSCHANGING:
\r
5732 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5733 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5735 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5736 /* Window is moving */
\r
5739 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5740 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5741 rcMain.right = wpMain.x + wpMain.width;
\r
5742 rcMain.top = wpMain.y;
\r
5743 rcMain.bottom = wpMain.y + wpMain.height;
\r
5745 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5746 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5747 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5748 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5749 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5750 wpMain.x = lpwp->x;
\r
5751 wpMain.y = lpwp->y;
\r
5757 /* [AS] Snapping */
\r
5758 case WM_ENTERSIZEMOVE:
\r
5759 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5760 if (hwnd == hwndMain) {
\r
5761 doingSizing = TRUE;
\r
5764 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5768 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5769 if (hwnd == hwndMain) {
\r
5770 lastSizing = wParam;
\r
5775 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5776 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5778 case WM_EXITSIZEMOVE:
\r
5779 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5780 if (hwnd == hwndMain) {
\r
5782 doingSizing = FALSE;
\r
5783 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5784 GetClientRect(hwnd, &client);
\r
5785 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5787 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5789 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5792 case WM_DESTROY: /* message: window being destroyed */
\r
5793 PostQuitMessage(0);
\r
5797 if (hwnd == hwndMain) {
\r
5802 default: /* Passes it on if unprocessed */
\r
5803 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5810 /*---------------------------------------------------------------------------*\
\r
5812 * Misc utility routines
\r
5814 \*---------------------------------------------------------------------------*/
\r
5817 * Decent random number generator, at least not as bad as Windows
\r
5818 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5820 unsigned int randstate;
\r
5825 randstate = randstate * 1664525 + 1013904223;
\r
5826 return (int) randstate & 0x7fffffff;
\r
5830 mysrandom(unsigned int seed)
\r
5837 * returns TRUE if user selects a different color, FALSE otherwise
\r
5841 ChangeColor(HWND hwnd, COLORREF *which)
\r
5843 static BOOL firstTime = TRUE;
\r
5844 static DWORD customColors[16];
\r
5846 COLORREF newcolor;
\r
5851 /* Make initial colors in use available as custom colors */
\r
5852 /* Should we put the compiled-in defaults here instead? */
\r
5854 customColors[i++] = lightSquareColor & 0xffffff;
\r
5855 customColors[i++] = darkSquareColor & 0xffffff;
\r
5856 customColors[i++] = whitePieceColor & 0xffffff;
\r
5857 customColors[i++] = blackPieceColor & 0xffffff;
\r
5858 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5859 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5861 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5862 customColors[i++] = textAttribs[ccl].color;
\r
5864 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5865 firstTime = FALSE;
\r
5868 cc.lStructSize = sizeof(cc);
\r
5869 cc.hwndOwner = hwnd;
\r
5870 cc.hInstance = NULL;
\r
5871 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5872 cc.lpCustColors = (LPDWORD) customColors;
\r
5873 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5875 if (!ChooseColor(&cc)) return FALSE;
\r
5877 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5878 if (newcolor == *which) return FALSE;
\r
5879 *which = newcolor;
\r
5883 InitDrawingColors();
\r
5884 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5889 MyLoadSound(MySound *ms)
\r
5895 if (ms->data && ms->flag) free(ms->data);
\r
5898 switch (ms->name[0]) {
\r
5904 /* System sound from Control Panel. Don't preload here. */
\r
5908 if (ms->name[1] == NULLCHAR) {
\r
5909 /* "!" alone = silence */
\r
5912 /* Builtin wave resource. Error if not found. */
\r
5913 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5914 if (h == NULL) break;
\r
5915 ms->data = (void *)LoadResource(hInst, h);
\r
5916 ms->flag = 0; // not maloced, so cannot be freed!
\r
5917 if (h == NULL) break;
\r
5922 /* .wav file. Error if not found. */
\r
5923 f = fopen(ms->name, "rb");
\r
5924 if (f == NULL) break;
\r
5925 if (fstat(fileno(f), &st) < 0) break;
\r
5926 ms->data = malloc(st.st_size);
\r
5928 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5934 char buf[MSG_SIZ];
\r
5935 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5936 DisplayError(buf, GetLastError());
\r
5942 MyPlaySound(MySound *ms)
\r
5944 BOOLEAN ok = FALSE;
\r
5946 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5947 switch (ms->name[0]) {
\r
5949 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5954 /* System sound from Control Panel (deprecated feature).
\r
5955 "$" alone or an unset sound name gets default beep (still in use). */
\r
5956 if (ms->name[1]) {
\r
5957 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5959 if (!ok) ok = MessageBeep(MB_OK);
\r
5962 /* Builtin wave resource, or "!" alone for silence */
\r
5963 if (ms->name[1]) {
\r
5964 if (ms->data == NULL) return FALSE;
\r
5965 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5971 /* .wav file. Error if not found. */
\r
5972 if (ms->data == NULL) return FALSE;
\r
5973 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5976 /* Don't print an error: this can happen innocently if the sound driver
\r
5977 is busy; for instance, if another instance of WinBoard is playing
\r
5978 a sound at about the same time. */
\r
5984 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5987 OPENFILENAME *ofn;
\r
5988 static UINT *number; /* gross that this is static */
\r
5990 switch (message) {
\r
5991 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5992 /* Center the dialog over the application window */
\r
5993 ofn = (OPENFILENAME *) lParam;
\r
5994 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5995 number = (UINT *) ofn->lCustData;
\r
5996 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6000 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6001 Translate(hDlg, 1536);
\r
6002 return FALSE; /* Allow for further processing */
\r
6005 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6006 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6008 return FALSE; /* Allow for further processing */
\r
6014 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6016 static UINT *number;
\r
6017 OPENFILENAME *ofname;
\r
6020 case WM_INITDIALOG:
\r
6021 Translate(hdlg, DLG_IndexNumber);
\r
6022 ofname = (OPENFILENAME *)lParam;
\r
6023 number = (UINT *)(ofname->lCustData);
\r
6026 ofnot = (OFNOTIFY *)lParam;
\r
6027 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6028 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6037 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6038 char *nameFilt, char *dlgTitle, UINT *number,
\r
6039 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6041 OPENFILENAME openFileName;
\r
6042 char buf1[MSG_SIZ];
\r
6045 if (fileName == NULL) fileName = buf1;
\r
6046 if (defName == NULL) {
\r
6047 safeStrCpy(fileName, "*.", 3 );
\r
6048 strcat(fileName, defExt);
\r
6050 safeStrCpy(fileName, defName, MSG_SIZ );
\r
6052 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
6053 if (number) *number = 0;
\r
6055 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6056 openFileName.hwndOwner = hwnd;
\r
6057 openFileName.hInstance = (HANDLE) hInst;
\r
6058 openFileName.lpstrFilter = nameFilt;
\r
6059 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6060 openFileName.nMaxCustFilter = 0L;
\r
6061 openFileName.nFilterIndex = 1L;
\r
6062 openFileName.lpstrFile = fileName;
\r
6063 openFileName.nMaxFile = MSG_SIZ;
\r
6064 openFileName.lpstrFileTitle = fileTitle;
\r
6065 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6066 openFileName.lpstrInitialDir = NULL;
\r
6067 openFileName.lpstrTitle = dlgTitle;
\r
6068 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6069 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6070 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6071 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6072 openFileName.nFileOffset = 0;
\r
6073 openFileName.nFileExtension = 0;
\r
6074 openFileName.lpstrDefExt = defExt;
\r
6075 openFileName.lCustData = (LONG) number;
\r
6076 openFileName.lpfnHook = oldDialog ?
\r
6077 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6078 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6080 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6081 GetOpenFileName(&openFileName)) {
\r
6082 /* open the file */
\r
6083 f = fopen(openFileName.lpstrFile, write);
\r
6085 MessageBox(hwnd, _("File open failed"), NULL,
\r
6086 MB_OK|MB_ICONEXCLAMATION);
\r
6090 int err = CommDlgExtendedError();
\r
6091 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6100 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6102 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6105 * Get the first pop-up menu in the menu template. This is the
\r
6106 * menu that TrackPopupMenu displays.
\r
6108 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6109 TranslateOneMenu(10, hmenuTrackPopup);
\r
6111 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6114 * TrackPopup uses screen coordinates, so convert the
\r
6115 * coordinates of the mouse click to screen coordinates.
\r
6117 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6119 /* Draw and track the floating pop-up menu. */
\r
6120 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6121 pt.x, pt.y, 0, hwnd, NULL);
\r
6123 /* Destroy the menu.*/
\r
6124 DestroyMenu(hmenu);
\r
6129 int sizeX, sizeY, newSizeX, newSizeY;
\r
6131 } ResizeEditPlusButtonsClosure;
\r
6134 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6136 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6140 if (hChild == cl->hText) return TRUE;
\r
6141 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6142 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6143 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6144 ScreenToClient(cl->hDlg, &pt);
\r
6145 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6146 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6150 /* Resize a dialog that has a (rich) edit field filling most of
\r
6151 the top, with a row of buttons below */
\r
6153 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6156 int newTextHeight, newTextWidth;
\r
6157 ResizeEditPlusButtonsClosure cl;
\r
6159 /*if (IsIconic(hDlg)) return;*/
\r
6160 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6162 cl.hdwp = BeginDeferWindowPos(8);
\r
6164 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6165 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6166 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6167 if (newTextHeight < 0) {
\r
6168 newSizeY += -newTextHeight;
\r
6169 newTextHeight = 0;
\r
6171 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6172 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6178 cl.newSizeX = newSizeX;
\r
6179 cl.newSizeY = newSizeY;
\r
6180 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6182 EndDeferWindowPos(cl.hdwp);
\r
6185 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6187 RECT rChild, rParent;
\r
6188 int wChild, hChild, wParent, hParent;
\r
6189 int wScreen, hScreen, xNew, yNew;
\r
6192 /* Get the Height and Width of the child window */
\r
6193 GetWindowRect (hwndChild, &rChild);
\r
6194 wChild = rChild.right - rChild.left;
\r
6195 hChild = rChild.bottom - rChild.top;
\r
6197 /* Get the Height and Width of the parent window */
\r
6198 GetWindowRect (hwndParent, &rParent);
\r
6199 wParent = rParent.right - rParent.left;
\r
6200 hParent = rParent.bottom - rParent.top;
\r
6202 /* Get the display limits */
\r
6203 hdc = GetDC (hwndChild);
\r
6204 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6205 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6206 ReleaseDC(hwndChild, hdc);
\r
6208 /* Calculate new X position, then adjust for screen */
\r
6209 xNew = rParent.left + ((wParent - wChild) /2);
\r
6212 } else if ((xNew+wChild) > wScreen) {
\r
6213 xNew = wScreen - wChild;
\r
6216 /* Calculate new Y position, then adjust for screen */
\r
6218 yNew = rParent.top + ((hParent - hChild) /2);
\r
6221 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6226 } else if ((yNew+hChild) > hScreen) {
\r
6227 yNew = hScreen - hChild;
\r
6230 /* Set it, and return */
\r
6231 return SetWindowPos (hwndChild, NULL,
\r
6232 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6235 /* Center one window over another */
\r
6236 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6238 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6241 /*---------------------------------------------------------------------------*\
\r
6243 * Startup Dialog functions
\r
6245 \*---------------------------------------------------------------------------*/
\r
6247 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6249 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6251 while (*cd != NULL) {
\r
6252 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6258 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6260 char buf1[MAX_ARG_LEN];
\r
6263 if (str[0] == '@') {
\r
6264 FILE* f = fopen(str + 1, "r");
\r
6266 DisplayFatalError(str + 1, errno, 2);
\r
6269 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6271 buf1[len] = NULLCHAR;
\r
6275 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6278 char buf[MSG_SIZ];
\r
6279 char *end = strchr(str, '\n');
\r
6280 if (end == NULL) return;
\r
6281 memcpy(buf, str, end - str);
\r
6282 buf[end - str] = NULLCHAR;
\r
6283 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6289 SetStartupDialogEnables(HWND hDlg)
\r
6291 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6292 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6293 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6294 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6295 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6296 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6297 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6298 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6299 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6300 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6301 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6302 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6303 IsDlgButtonChecked(hDlg, OPT_View));
\r
6307 QuoteForFilename(char *filename)
\r
6309 int dquote, space;
\r
6310 dquote = strchr(filename, '"') != NULL;
\r
6311 space = strchr(filename, ' ') != NULL;
\r
6312 if (dquote || space) {
\r
6324 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6326 char buf[MSG_SIZ];
\r
6329 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6330 q = QuoteForFilename(nthcp);
\r
6331 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6332 if (*nthdir != NULLCHAR) {
\r
6333 q = QuoteForFilename(nthdir);
\r
6334 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6336 if (*nthcp == NULLCHAR) {
\r
6337 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6338 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6339 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6340 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6345 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6347 char buf[MSG_SIZ];
\r
6351 switch (message) {
\r
6352 case WM_INITDIALOG:
\r
6353 /* Center the dialog */
\r
6354 CenterWindow (hDlg, GetDesktopWindow());
\r
6355 Translate(hDlg, DLG_Startup);
\r
6356 /* Initialize the dialog items */
\r
6357 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6358 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6359 firstChessProgramNames);
\r
6360 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6361 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6362 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6363 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6364 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6365 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6366 if (*appData.icsHelper != NULLCHAR) {
\r
6367 char *q = QuoteForFilename(appData.icsHelper);
\r
6368 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6370 if (*appData.icsHost == NULLCHAR) {
\r
6371 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6372 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6373 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6374 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6375 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6378 if (appData.icsActive) {
\r
6379 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6381 else if (appData.noChessProgram) {
\r
6382 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6385 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6388 SetStartupDialogEnables(hDlg);
\r
6392 switch (LOWORD(wParam)) {
\r
6394 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6395 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6396 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6398 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6399 ParseArgs(StringGet, &p);
\r
6400 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6401 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6403 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6404 ParseArgs(StringGet, &p);
\r
6405 SwapEngines(singleList); // ... and then make it 'second'
\r
6407 appData.noChessProgram = FALSE;
\r
6408 appData.icsActive = FALSE;
\r
6409 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6410 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6411 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6413 ParseArgs(StringGet, &p);
\r
6414 if (appData.zippyPlay) {
\r
6415 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6416 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6418 ParseArgs(StringGet, &p);
\r
6420 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6421 appData.noChessProgram = TRUE;
\r
6422 appData.icsActive = FALSE;
\r
6424 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6425 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6428 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6429 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6431 ParseArgs(StringGet, &p);
\r
6433 EndDialog(hDlg, TRUE);
\r
6440 case IDM_HELPCONTENTS:
\r
6441 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6442 MessageBox (GetFocus(),
\r
6443 _("Unable to activate help"),
\r
6444 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6449 SetStartupDialogEnables(hDlg);
\r
6457 /*---------------------------------------------------------------------------*\
\r
6459 * About box dialog functions
\r
6461 \*---------------------------------------------------------------------------*/
\r
6463 /* Process messages for "About" dialog box */
\r
6465 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6467 switch (message) {
\r
6468 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6469 /* Center the dialog over the application window */
\r
6470 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6471 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6472 Translate(hDlg, ABOUTBOX);
\r
6476 case WM_COMMAND: /* message: received a command */
\r
6477 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6478 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6479 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6487 /*---------------------------------------------------------------------------*\
\r
6489 * Comment Dialog functions
\r
6491 \*---------------------------------------------------------------------------*/
\r
6494 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6496 static HANDLE hwndText = NULL;
\r
6497 int len, newSizeX, newSizeY;
\r
6498 static int sizeX, sizeY;
\r
6503 switch (message) {
\r
6504 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6505 /* Initialize the dialog items */
\r
6506 Translate(hDlg, DLG_EditComment);
\r
6507 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6508 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6509 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6510 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6511 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6512 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6513 SetWindowText(hDlg, commentTitle);
\r
6514 if (editComment) {
\r
6515 SetFocus(hwndText);
\r
6517 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6519 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6520 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6521 MAKELPARAM(FALSE, 0));
\r
6522 /* Size and position the dialog */
\r
6523 if (!commentDialog) {
\r
6524 commentDialog = hDlg;
\r
6525 GetClientRect(hDlg, &rect);
\r
6526 sizeX = rect.right;
\r
6527 sizeY = rect.bottom;
\r
6528 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6529 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6530 WINDOWPLACEMENT wp;
\r
6531 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6532 wp.length = sizeof(WINDOWPLACEMENT);
\r
6534 wp.showCmd = SW_SHOW;
\r
6535 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6536 wp.rcNormalPosition.left = wpComment.x;
\r
6537 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6538 wp.rcNormalPosition.top = wpComment.y;
\r
6539 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6540 SetWindowPlacement(hDlg, &wp);
\r
6542 GetClientRect(hDlg, &rect);
\r
6543 newSizeX = rect.right;
\r
6544 newSizeY = rect.bottom;
\r
6545 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6546 newSizeX, newSizeY);
\r
6551 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6554 case WM_COMMAND: /* message: received a command */
\r
6555 switch (LOWORD(wParam)) {
\r
6557 if (editComment) {
\r
6559 /* Read changed options from the dialog box */
\r
6560 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6561 len = GetWindowTextLength(hwndText);
\r
6562 str = (char *) malloc(len + 1);
\r
6563 GetWindowText(hwndText, str, len + 1);
\r
6572 ReplaceComment(commentIndex, str);
\r
6579 case OPT_CancelComment:
\r
6583 case OPT_ClearComment:
\r
6584 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6587 case OPT_EditComment:
\r
6588 EditCommentEvent();
\r
6596 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6597 if( wParam == OPT_CommentText ) {
\r
6598 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6600 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6601 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6605 pt.x = LOWORD( lpMF->lParam );
\r
6606 pt.y = HIWORD( lpMF->lParam );
\r
6608 if(lpMF->msg == WM_CHAR) {
\r
6610 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6611 index = sel.cpMin;
\r
6613 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6615 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6616 len = GetWindowTextLength(hwndText);
\r
6617 str = (char *) malloc(len + 1);
\r
6618 GetWindowText(hwndText, str, len + 1);
\r
6619 ReplaceComment(commentIndex, str);
\r
6620 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6621 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6624 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6625 lpMF->msg = WM_USER;
\r
6633 newSizeX = LOWORD(lParam);
\r
6634 newSizeY = HIWORD(lParam);
\r
6635 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6640 case WM_GETMINMAXINFO:
\r
6641 /* Prevent resizing window too small */
\r
6642 mmi = (MINMAXINFO *) lParam;
\r
6643 mmi->ptMinTrackSize.x = 100;
\r
6644 mmi->ptMinTrackSize.y = 100;
\r
6651 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6656 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6658 if (str == NULL) str = "";
\r
6659 p = (char *) malloc(2 * strlen(str) + 2);
\r
6662 if (*str == '\n') *q++ = '\r';
\r
6666 if (commentText != NULL) free(commentText);
\r
6668 commentIndex = index;
\r
6669 commentTitle = title;
\r
6671 editComment = edit;
\r
6673 if (commentDialog) {
\r
6674 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6675 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6677 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6678 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6679 hwndMain, (DLGPROC)lpProc);
\r
6680 FreeProcInstance(lpProc);
\r
6686 /*---------------------------------------------------------------------------*\
\r
6688 * Type-in move dialog functions
\r
6690 \*---------------------------------------------------------------------------*/
\r
6693 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6695 char move[MSG_SIZ];
\r
6698 switch (message) {
\r
6699 case WM_INITDIALOG:
\r
6700 move[0] = (char) lParam;
\r
6701 move[1] = NULLCHAR;
\r
6702 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6703 Translate(hDlg, DLG_TypeInMove);
\r
6704 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6705 SetWindowText(hInput, move);
\r
6707 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6711 switch (LOWORD(wParam)) {
\r
6714 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6715 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6716 TypeInDoneEvent(move);
\r
6717 EndDialog(hDlg, TRUE);
\r
6720 EndDialog(hDlg, FALSE);
\r
6731 PopUpMoveDialog(char firstchar)
\r
6735 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6736 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6737 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6738 FreeProcInstance(lpProc);
\r
6741 /*---------------------------------------------------------------------------*\
\r
6743 * Type-in name dialog functions
\r
6745 \*---------------------------------------------------------------------------*/
\r
6748 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6750 char move[MSG_SIZ];
\r
6753 switch (message) {
\r
6754 case WM_INITDIALOG:
\r
6755 move[0] = (char) lParam;
\r
6756 move[1] = NULLCHAR;
\r
6757 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6758 Translate(hDlg, DLG_TypeInName);
\r
6759 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6760 SetWindowText(hInput, move);
\r
6762 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6766 switch (LOWORD(wParam)) {
\r
6768 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6769 appData.userName = strdup(move);
\r
6770 SetUserLogo(); DisplayLogos();
\r
6772 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6773 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6774 DisplayTitle(move);
\r
6778 EndDialog(hDlg, TRUE);
\r
6781 EndDialog(hDlg, FALSE);
\r
6792 PopUpNameDialog(char firstchar)
\r
6796 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6797 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6798 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6799 FreeProcInstance(lpProc);
\r
6802 /*---------------------------------------------------------------------------*\
\r
6806 \*---------------------------------------------------------------------------*/
\r
6808 /* Nonmodal error box */
\r
6809 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6810 WPARAM wParam, LPARAM lParam);
\r
6813 ErrorPopUp(char *title, char *content)
\r
6817 BOOLEAN modal = hwndMain == NULL;
\r
6835 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6836 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6839 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6841 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6842 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6843 hwndMain, (DLGPROC)lpProc);
\r
6844 FreeProcInstance(lpProc);
\r
6851 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6852 if (errorDialog == NULL) return;
\r
6853 DestroyWindow(errorDialog);
\r
6854 errorDialog = NULL;
\r
6855 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6859 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6863 switch (message) {
\r
6864 case WM_INITDIALOG:
\r
6865 GetWindowRect(hDlg, &rChild);
\r
6868 SetWindowPos(hDlg, NULL, rChild.left,
\r
6869 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6870 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6874 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6875 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6876 and it doesn't work when you resize the dialog.
\r
6877 For now, just give it a default position.
\r
6879 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6880 Translate(hDlg, DLG_Error);
\r
6882 errorDialog = hDlg;
\r
6883 SetWindowText(hDlg, errorTitle);
\r
6884 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6888 switch (LOWORD(wParam)) {
\r
6891 if (errorDialog == hDlg) errorDialog = NULL;
\r
6892 DestroyWindow(hDlg);
\r
6904 HWND gothicDialog = NULL;
\r
6907 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6910 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6912 switch (message) {
\r
6913 case WM_INITDIALOG:
\r
6914 GetWindowRect(hDlg, &rChild);
\r
6916 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6920 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6921 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6922 and it doesn't work when you resize the dialog.
\r
6923 For now, just give it a default position.
\r
6925 gothicDialog = hDlg;
\r
6926 SetWindowText(hDlg, errorTitle);
\r
6927 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6931 switch (LOWORD(wParam)) {
\r
6934 if (errorDialog == hDlg) errorDialog = NULL;
\r
6935 DestroyWindow(hDlg);
\r
6947 GothicPopUp(char *title, VariantClass variant)
\r
6950 static char *lastTitle;
\r
6952 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6953 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6955 if(lastTitle != title && gothicDialog != NULL) {
\r
6956 DestroyWindow(gothicDialog);
\r
6957 gothicDialog = NULL;
\r
6959 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6960 title = lastTitle;
\r
6961 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6962 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6963 hwndMain, (DLGPROC)lpProc);
\r
6964 FreeProcInstance(lpProc);
\r
6969 /*---------------------------------------------------------------------------*\
\r
6971 * Ics Interaction console functions
\r
6973 \*---------------------------------------------------------------------------*/
\r
6975 #define HISTORY_SIZE 64
\r
6976 static char *history[HISTORY_SIZE];
\r
6977 int histIn = 0, histP = 0;
\r
6981 SaveInHistory(char *cmd)
\r
6983 if (history[histIn] != NULL) {
\r
6984 free(history[histIn]);
\r
6985 history[histIn] = NULL;
\r
6987 if (*cmd == NULLCHAR) return;
\r
6988 history[histIn] = StrSave(cmd);
\r
6989 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6990 if (history[histIn] != NULL) {
\r
6991 free(history[histIn]);
\r
6993 history[histIn] = NULL;
\r
6999 PrevInHistory(char *cmd)
\r
7002 if (histP == histIn) {
\r
7003 if (history[histIn] != NULL) free(history[histIn]);
\r
7004 history[histIn] = StrSave(cmd);
\r
7006 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7007 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7009 return history[histP];
\r
7015 if (histP == histIn) return NULL;
\r
7016 histP = (histP + 1) % HISTORY_SIZE;
\r
7017 return history[histP];
\r
7021 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7025 hmenu = LoadMenu(hInst, "TextMenu");
\r
7026 h = GetSubMenu(hmenu, 0);
\r
7028 if (strcmp(e->item, "-") == 0) {
\r
7029 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7030 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
7031 int flags = MF_STRING, j = 0;
\r
7032 if (e->item[0] == '|') {
\r
7033 flags |= MF_MENUBARBREAK;
\r
7036 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
7037 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
7045 WNDPROC consoleTextWindowProc;
\r
7048 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7050 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7051 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7055 SetWindowText(hInput, command);
\r
7057 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7059 sel.cpMin = 999999;
\r
7060 sel.cpMax = 999999;
\r
7061 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7066 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7067 if (sel.cpMin == sel.cpMax) {
\r
7068 /* Expand to surrounding word */
\r
7071 tr.chrg.cpMax = sel.cpMin;
\r
7072 tr.chrg.cpMin = --sel.cpMin;
\r
7073 if (sel.cpMin < 0) break;
\r
7074 tr.lpstrText = name;
\r
7075 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7076 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7080 tr.chrg.cpMin = sel.cpMax;
\r
7081 tr.chrg.cpMax = ++sel.cpMax;
\r
7082 tr.lpstrText = name;
\r
7083 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7084 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7087 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7088 MessageBeep(MB_ICONEXCLAMATION);
\r
7092 tr.lpstrText = name;
\r
7093 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7095 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7096 MessageBeep(MB_ICONEXCLAMATION);
\r
7099 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7102 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7103 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7104 SetWindowText(hInput, buf);
\r
7105 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7107 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7108 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7109 SetWindowText(hInput, buf);
\r
7110 sel.cpMin = 999999;
\r
7111 sel.cpMax = 999999;
\r
7112 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7118 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7123 switch (message) {
\r
7125 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7126 if(wParam=='R') return 0;
\r
7129 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7132 sel.cpMin = 999999;
\r
7133 sel.cpMax = 999999;
\r
7134 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7135 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7140 if(wParam != '\022') {
\r
7141 if (wParam == '\t') {
\r
7142 if (GetKeyState(VK_SHIFT) < 0) {
\r
7144 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7145 if (buttonDesc[0].hwnd) {
\r
7146 SetFocus(buttonDesc[0].hwnd);
\r
7148 SetFocus(hwndMain);
\r
7152 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7155 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7156 JAWS_DELETE( SetFocus(hInput); )
\r
7157 SendMessage(hInput, message, wParam, lParam);
\r
7160 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7162 case WM_RBUTTONDOWN:
\r
7163 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7164 /* Move selection here if it was empty */
\r
7166 pt.x = LOWORD(lParam);
\r
7167 pt.y = HIWORD(lParam);
\r
7168 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7169 if (sel.cpMin == sel.cpMax) {
\r
7170 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7171 sel.cpMax = sel.cpMin;
\r
7172 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7174 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7175 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7177 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7178 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7179 if (sel.cpMin == sel.cpMax) {
\r
7180 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7181 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7183 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7184 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7186 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7187 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7188 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7189 MenuPopup(hwnd, pt, hmenu, -1);
\r
7193 case WM_RBUTTONUP:
\r
7194 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7195 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7196 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7200 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7202 return SendMessage(hInput, message, wParam, lParam);
\r
7203 case WM_MBUTTONDOWN:
\r
7204 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7206 switch (LOWORD(wParam)) {
\r
7207 case IDM_QuickPaste:
\r
7209 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7210 if (sel.cpMin == sel.cpMax) {
\r
7211 MessageBeep(MB_ICONEXCLAMATION);
\r
7214 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7215 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7216 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7221 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7224 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7227 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7231 int i = LOWORD(wParam) - IDM_CommandX;
\r
7232 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7233 icsTextMenuEntry[i].command != NULL) {
\r
7234 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7235 icsTextMenuEntry[i].getname,
\r
7236 icsTextMenuEntry[i].immediate);
\r
7244 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7247 WNDPROC consoleInputWindowProc;
\r
7250 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7252 char buf[MSG_SIZ];
\r
7254 static BOOL sendNextChar = FALSE;
\r
7255 static BOOL quoteNextChar = FALSE;
\r
7256 InputSource *is = consoleInputSource;
\r
7260 switch (message) {
\r
7262 if (!appData.localLineEditing || sendNextChar) {
\r
7263 is->buf[0] = (CHAR) wParam;
\r
7265 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7266 sendNextChar = FALSE;
\r
7269 if (quoteNextChar) {
\r
7270 buf[0] = (char) wParam;
\r
7271 buf[1] = NULLCHAR;
\r
7272 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7273 quoteNextChar = FALSE;
\r
7277 case '\r': /* Enter key */
\r
7278 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7279 if (consoleEcho) SaveInHistory(is->buf);
\r
7280 is->buf[is->count++] = '\n';
\r
7281 is->buf[is->count] = NULLCHAR;
\r
7282 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7283 if (consoleEcho) {
\r
7284 ConsoleOutput(is->buf, is->count, TRUE);
\r
7285 } else if (appData.localLineEditing) {
\r
7286 ConsoleOutput("\n", 1, TRUE);
\r
7289 case '\033': /* Escape key */
\r
7290 SetWindowText(hwnd, "");
\r
7291 cf.cbSize = sizeof(CHARFORMAT);
\r
7292 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7293 if (consoleEcho) {
\r
7294 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7296 cf.crTextColor = COLOR_ECHOOFF;
\r
7298 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7299 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7301 case '\t': /* Tab key */
\r
7302 if (GetKeyState(VK_SHIFT) < 0) {
\r
7304 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7307 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7308 if (buttonDesc[0].hwnd) {
\r
7309 SetFocus(buttonDesc[0].hwnd);
\r
7311 SetFocus(hwndMain);
\r
7315 case '\023': /* Ctrl+S */
\r
7316 sendNextChar = TRUE;
\r
7318 case '\021': /* Ctrl+Q */
\r
7319 quoteNextChar = TRUE;
\r
7329 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7330 p = PrevInHistory(buf);
\r
7332 SetWindowText(hwnd, p);
\r
7333 sel.cpMin = 999999;
\r
7334 sel.cpMax = 999999;
\r
7335 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7340 p = NextInHistory();
\r
7342 SetWindowText(hwnd, p);
\r
7343 sel.cpMin = 999999;
\r
7344 sel.cpMax = 999999;
\r
7345 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7351 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7355 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7359 case WM_MBUTTONDOWN:
\r
7360 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7361 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7363 case WM_RBUTTONUP:
\r
7364 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7365 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7366 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7370 hmenu = LoadMenu(hInst, "InputMenu");
\r
7371 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7372 if (sel.cpMin == sel.cpMax) {
\r
7373 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7374 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7376 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7377 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7379 pt.x = LOWORD(lParam);
\r
7380 pt.y = HIWORD(lParam);
\r
7381 MenuPopup(hwnd, pt, hmenu, -1);
\r
7385 switch (LOWORD(wParam)) {
\r
7387 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7389 case IDM_SelectAll:
\r
7391 sel.cpMax = -1; /*999999?*/
\r
7392 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7395 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7398 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7401 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7406 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7409 #define CO_MAX 100000
\r
7410 #define CO_TRIM 1000
\r
7413 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7415 static SnapData sd;
\r
7416 HWND hText, hInput;
\r
7418 static int sizeX, sizeY;
\r
7419 int newSizeX, newSizeY;
\r
7423 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7424 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7426 switch (message) {
\r
7428 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7430 ENLINK *pLink = (ENLINK*)lParam;
\r
7431 if (pLink->msg == WM_LBUTTONUP)
\r
7435 tr.chrg = pLink->chrg;
\r
7436 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7437 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7438 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7439 free(tr.lpstrText);
\r
7443 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7444 hwndConsole = hDlg;
\r
7446 consoleTextWindowProc = (WNDPROC)
\r
7447 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7448 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7449 consoleInputWindowProc = (WNDPROC)
\r
7450 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7451 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7452 Colorize(ColorNormal, TRUE);
\r
7453 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7454 ChangedConsoleFont();
\r
7455 GetClientRect(hDlg, &rect);
\r
7456 sizeX = rect.right;
\r
7457 sizeY = rect.bottom;
\r
7458 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7459 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7460 WINDOWPLACEMENT wp;
\r
7461 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7462 wp.length = sizeof(WINDOWPLACEMENT);
\r
7464 wp.showCmd = SW_SHOW;
\r
7465 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7466 wp.rcNormalPosition.left = wpConsole.x;
\r
7467 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7468 wp.rcNormalPosition.top = wpConsole.y;
\r
7469 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7470 SetWindowPlacement(hDlg, &wp);
\r
7473 // [HGM] Chessknight's change 2004-07-13
\r
7474 else { /* Determine Defaults */
\r
7475 WINDOWPLACEMENT wp;
\r
7476 wpConsole.x = wpMain.width + 1;
\r
7477 wpConsole.y = wpMain.y;
\r
7478 wpConsole.width = screenWidth - wpMain.width;
\r
7479 wpConsole.height = wpMain.height;
\r
7480 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7481 wp.length = sizeof(WINDOWPLACEMENT);
\r
7483 wp.showCmd = SW_SHOW;
\r
7484 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7485 wp.rcNormalPosition.left = wpConsole.x;
\r
7486 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7487 wp.rcNormalPosition.top = wpConsole.y;
\r
7488 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7489 SetWindowPlacement(hDlg, &wp);
\r
7492 // Allow hText to highlight URLs and send notifications on them
\r
7493 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7494 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7495 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7496 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7510 if (IsIconic(hDlg)) break;
\r
7511 newSizeX = LOWORD(lParam);
\r
7512 newSizeY = HIWORD(lParam);
\r
7513 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7514 RECT rectText, rectInput;
\r
7516 int newTextHeight, newTextWidth;
\r
7517 GetWindowRect(hText, &rectText);
\r
7518 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7519 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7520 if (newTextHeight < 0) {
\r
7521 newSizeY += -newTextHeight;
\r
7522 newTextHeight = 0;
\r
7524 SetWindowPos(hText, NULL, 0, 0,
\r
7525 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7526 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7527 pt.x = rectInput.left;
\r
7528 pt.y = rectInput.top + newSizeY - sizeY;
\r
7529 ScreenToClient(hDlg, &pt);
\r
7530 SetWindowPos(hInput, NULL,
\r
7531 pt.x, pt.y, /* needs client coords */
\r
7532 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7533 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7539 case WM_GETMINMAXINFO:
\r
7540 /* Prevent resizing window too small */
\r
7541 mmi = (MINMAXINFO *) lParam;
\r
7542 mmi->ptMinTrackSize.x = 100;
\r
7543 mmi->ptMinTrackSize.y = 100;
\r
7546 /* [AS] Snapping */
\r
7547 case WM_ENTERSIZEMOVE:
\r
7548 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7551 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7554 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7556 case WM_EXITSIZEMOVE:
\r
7557 UpdateICSWidth(hText);
\r
7558 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7561 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7569 if (hwndConsole) return;
\r
7570 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7571 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7576 ConsoleOutput(char* data, int length, int forceVisible)
\r
7581 char buf[CO_MAX+1];
\r
7584 static int delayLF = 0;
\r
7585 CHARRANGE savesel, sel;
\r
7587 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7595 while (length--) {
\r
7603 } else if (*p == '\007') {
\r
7604 MyPlaySound(&sounds[(int)SoundBell]);
\r
7611 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7612 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7613 /* Save current selection */
\r
7614 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7615 exlen = GetWindowTextLength(hText);
\r
7616 /* Find out whether current end of text is visible */
\r
7617 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7618 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7619 /* Trim existing text if it's too long */
\r
7620 if (exlen + (q - buf) > CO_MAX) {
\r
7621 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7624 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7625 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7627 savesel.cpMin -= trim;
\r
7628 savesel.cpMax -= trim;
\r
7629 if (exlen < 0) exlen = 0;
\r
7630 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7631 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7633 /* Append the new text */
\r
7634 sel.cpMin = exlen;
\r
7635 sel.cpMax = exlen;
\r
7636 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7637 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7638 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7639 if (forceVisible || exlen == 0 ||
\r
7640 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7641 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7642 /* Scroll to make new end of text visible if old end of text
\r
7643 was visible or new text is an echo of user typein */
\r
7644 sel.cpMin = 9999999;
\r
7645 sel.cpMax = 9999999;
\r
7646 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7647 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7648 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7649 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7651 if (savesel.cpMax == exlen || forceVisible) {
\r
7652 /* Move insert point to new end of text if it was at the old
\r
7653 end of text or if the new text is an echo of user typein */
\r
7654 sel.cpMin = 9999999;
\r
7655 sel.cpMax = 9999999;
\r
7656 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7658 /* Restore previous selection */
\r
7659 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7661 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7668 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7672 COLORREF oldFg, oldBg;
\r
7676 if(copyNumber > 1)
\r
7677 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7679 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7680 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7681 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7684 rect.right = x + squareSize;
\r
7686 rect.bottom = y + squareSize;
\r
7689 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7690 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7691 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7692 &rect, str, strlen(str), NULL);
\r
7694 (void) SetTextColor(hdc, oldFg);
\r
7695 (void) SetBkColor(hdc, oldBg);
\r
7696 (void) SelectObject(hdc, oldFont);
\r
7700 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7701 RECT *rect, char *color, char *flagFell)
\r
7705 COLORREF oldFg, oldBg;
\r
7708 if (twoBoards && partnerUp) return;
\r
7709 if (appData.clockMode) {
\r
7710 if (tinyLayout == 2)
\r
7711 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7713 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7720 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7721 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7723 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7724 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7727 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7731 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7732 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7733 rect, str, strlen(str), NULL);
\r
7734 if(logoHeight > 0 && appData.clockMode) {
\r
7736 str += strlen(color)+2;
\r
7737 r.top = rect->top + logoHeight/2;
\r
7738 r.left = rect->left;
\r
7739 r.right = rect->right;
\r
7740 r.bottom = rect->bottom;
\r
7741 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7742 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7743 &r, str, strlen(str), NULL);
\r
7745 (void) SetTextColor(hdc, oldFg);
\r
7746 (void) SetBkColor(hdc, oldBg);
\r
7747 (void) SelectObject(hdc, oldFont);
\r
7752 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7758 if( count <= 0 ) {
\r
7759 if (appData.debugMode) {
\r
7760 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7763 return ERROR_INVALID_USER_BUFFER;
\r
7766 ResetEvent(ovl->hEvent);
\r
7767 ovl->Offset = ovl->OffsetHigh = 0;
\r
7768 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7772 err = GetLastError();
\r
7773 if (err == ERROR_IO_PENDING) {
\r
7774 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7778 err = GetLastError();
\r
7785 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7790 ResetEvent(ovl->hEvent);
\r
7791 ovl->Offset = ovl->OffsetHigh = 0;
\r
7792 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7796 err = GetLastError();
\r
7797 if (err == ERROR_IO_PENDING) {
\r
7798 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7802 err = GetLastError();
\r
7809 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7810 void CheckForInputBufferFull( InputSource * is )
\r
7812 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7813 /* Look for end of line */
\r
7814 char * p = is->buf;
\r
7816 while( p < is->next && *p != '\n' ) {
\r
7820 if( p >= is->next ) {
\r
7821 if (appData.debugMode) {
\r
7822 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7825 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7826 is->count = (DWORD) -1;
\r
7827 is->next = is->buf;
\r
7833 InputThread(LPVOID arg)
\r
7838 is = (InputSource *) arg;
\r
7839 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7840 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7841 while (is->hThread != NULL) {
\r
7842 is->error = DoReadFile(is->hFile, is->next,
\r
7843 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7844 &is->count, &ovl);
\r
7845 if (is->error == NO_ERROR) {
\r
7846 is->next += is->count;
\r
7848 if (is->error == ERROR_BROKEN_PIPE) {
\r
7849 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7852 is->count = (DWORD) -1;
\r
7853 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7858 CheckForInputBufferFull( is );
\r
7860 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7862 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7864 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7867 CloseHandle(ovl.hEvent);
\r
7868 CloseHandle(is->hFile);
\r
7870 if (appData.debugMode) {
\r
7871 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7878 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7880 NonOvlInputThread(LPVOID arg)
\r
7887 is = (InputSource *) arg;
\r
7888 while (is->hThread != NULL) {
\r
7889 is->error = ReadFile(is->hFile, is->next,
\r
7890 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7891 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7892 if (is->error == NO_ERROR) {
\r
7893 /* Change CRLF to LF */
\r
7894 if (is->next > is->buf) {
\r
7896 i = is->count + 1;
\r
7904 if (prev == '\r' && *p == '\n') {
\r
7916 if (is->error == ERROR_BROKEN_PIPE) {
\r
7917 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7920 is->count = (DWORD) -1;
\r
7924 CheckForInputBufferFull( is );
\r
7926 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7928 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7930 if (is->count < 0) break; /* Quit on error */
\r
7932 CloseHandle(is->hFile);
\r
7937 SocketInputThread(LPVOID arg)
\r
7941 is = (InputSource *) arg;
\r
7942 while (is->hThread != NULL) {
\r
7943 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7944 if ((int)is->count == SOCKET_ERROR) {
\r
7945 is->count = (DWORD) -1;
\r
7946 is->error = WSAGetLastError();
\r
7948 is->error = NO_ERROR;
\r
7949 is->next += is->count;
\r
7950 if (is->count == 0 && is->second == is) {
\r
7951 /* End of file on stderr; quit with no message */
\r
7955 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7957 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7959 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7965 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7969 is = (InputSource *) lParam;
\r
7970 if (is->lineByLine) {
\r
7971 /* Feed in lines one by one */
\r
7972 char *p = is->buf;
\r
7974 while (q < is->next) {
\r
7975 if (*q++ == '\n') {
\r
7976 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7981 /* Move any partial line to the start of the buffer */
\r
7983 while (p < is->next) {
\r
7988 if (is->error != NO_ERROR || is->count == 0) {
\r
7989 /* Notify backend of the error. Note: If there was a partial
\r
7990 line at the end, it is not flushed through. */
\r
7991 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7994 /* Feed in the whole chunk of input at once */
\r
7995 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7996 is->next = is->buf;
\r
8000 /*---------------------------------------------------------------------------*\
\r
8002 * Menu enables. Used when setting various modes.
\r
8004 \*---------------------------------------------------------------------------*/
\r
8012 GreyRevert(Boolean grey)
\r
8013 { // [HGM] vari: for retracting variations in local mode
\r
8014 HMENU hmenu = GetMenu(hwndMain);
\r
8015 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
8016 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
8020 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8022 while (enab->item > 0) {
\r
8023 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8028 Enables gnuEnables[] = {
\r
8029 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8030 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8031 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8032 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8033 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8034 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8035 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8036 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8037 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8038 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
8039 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8040 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8041 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8044 // Needed to switch from ncp to GNU mode on Engine Load
\r
8045 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8046 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8047 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8048 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8049 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8050 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8051 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
8052 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8053 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
8054 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
8055 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8056 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8057 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8058 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8062 Enables icsEnables[] = {
\r
8063 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8064 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8065 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8066 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8067 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8068 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8069 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8070 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8071 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8072 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8073 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8074 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8075 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8076 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8077 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8078 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8079 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8080 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8081 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8082 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8087 Enables zippyEnables[] = {
\r
8088 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8089 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8090 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8091 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8096 Enables ncpEnables[] = {
\r
8097 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8098 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8099 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8100 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8101 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8102 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8103 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8104 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8105 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8106 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8107 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8109 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8110 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8111 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8112 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8113 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8114 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8115 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8116 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8117 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8118 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8122 Enables trainingOnEnables[] = {
\r
8123 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8124 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8125 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8126 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8127 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8128 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8129 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8130 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8131 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8135 Enables trainingOffEnables[] = {
\r
8136 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8137 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8138 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8139 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8140 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8141 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8142 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8143 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8144 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8148 /* These modify either ncpEnables or gnuEnables */
\r
8149 Enables cmailEnables[] = {
\r
8150 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8151 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8152 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8153 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8154 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8155 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8156 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8160 Enables machineThinkingEnables[] = {
\r
8161 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8162 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8163 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8164 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8165 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8166 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8167 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8168 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8169 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8170 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8171 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8172 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8173 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8174 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8175 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8176 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8180 Enables userThinkingEnables[] = {
\r
8181 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8182 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8183 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8184 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8185 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8186 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8187 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8188 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8189 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8190 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8191 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8192 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8193 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8194 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8195 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8196 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8200 /*---------------------------------------------------------------------------*\
\r
8202 * Front-end interface functions exported by XBoard.
\r
8203 * Functions appear in same order as prototypes in frontend.h.
\r
8205 \*---------------------------------------------------------------------------*/
\r
8207 CheckMark(UINT item, int state)
\r
8209 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8215 static UINT prevChecked = 0;
\r
8216 static int prevPausing = 0;
\r
8219 if (pausing != prevPausing) {
\r
8220 prevPausing = pausing;
\r
8221 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8222 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8223 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8226 switch (gameMode) {
\r
8227 case BeginningOfGame:
\r
8228 if (appData.icsActive)
\r
8229 nowChecked = IDM_IcsClient;
\r
8230 else if (appData.noChessProgram)
\r
8231 nowChecked = IDM_EditGame;
\r
8233 nowChecked = IDM_MachineBlack;
\r
8235 case MachinePlaysBlack:
\r
8236 nowChecked = IDM_MachineBlack;
\r
8238 case MachinePlaysWhite:
\r
8239 nowChecked = IDM_MachineWhite;
\r
8241 case TwoMachinesPlay:
\r
8242 nowChecked = IDM_TwoMachines;
\r
8245 nowChecked = IDM_AnalysisMode;
\r
8248 nowChecked = IDM_AnalyzeFile;
\r
8251 nowChecked = IDM_EditGame;
\r
8253 case PlayFromGameFile:
\r
8254 nowChecked = IDM_LoadGame;
\r
8256 case EditPosition:
\r
8257 nowChecked = IDM_EditPosition;
\r
8260 nowChecked = IDM_Training;
\r
8262 case IcsPlayingWhite:
\r
8263 case IcsPlayingBlack:
\r
8264 case IcsObserving:
\r
8266 nowChecked = IDM_IcsClient;
\r
8273 if(prevChecked == IDM_TwoMachines) // [HGM] 'Machine Match' might have gotten disabled when stopping match
\r
8274 EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_ENABLED);
\r
8275 CheckMark(prevChecked, MF_UNCHECKED);
\r
8276 CheckMark(nowChecked, MF_CHECKED);
\r
8277 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8279 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8280 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8281 MF_BYCOMMAND|MF_ENABLED);
\r
8283 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8284 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8287 prevChecked = nowChecked;
\r
8289 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8290 if (appData.icsActive) {
\r
8291 if (appData.icsEngineAnalyze) {
\r
8292 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8294 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8297 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8303 HMENU hmenu = GetMenu(hwndMain);
\r
8304 SetMenuEnables(hmenu, icsEnables);
\r
8305 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8306 MF_BYCOMMAND|MF_ENABLED);
\r
8308 if (appData.zippyPlay) {
\r
8309 SetMenuEnables(hmenu, zippyEnables);
\r
8310 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8311 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8312 MF_BYCOMMAND|MF_ENABLED);
\r
8320 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8326 HMENU hmenu = GetMenu(hwndMain);
\r
8327 SetMenuEnables(hmenu, ncpEnables);
\r
8328 DrawMenuBar(hwndMain);
\r
8334 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8338 SetTrainingModeOn()
\r
8341 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8342 for (i = 0; i < N_BUTTONS; i++) {
\r
8343 if (buttonDesc[i].hwnd != NULL)
\r
8344 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8349 VOID SetTrainingModeOff()
\r
8352 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8353 for (i = 0; i < N_BUTTONS; i++) {
\r
8354 if (buttonDesc[i].hwnd != NULL)
\r
8355 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8361 SetUserThinkingEnables()
\r
8363 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8367 SetMachineThinkingEnables()
\r
8369 HMENU hMenu = GetMenu(hwndMain);
\r
8370 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8372 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8374 if (gameMode == MachinePlaysBlack) {
\r
8375 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8376 } else if (gameMode == MachinePlaysWhite) {
\r
8377 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8378 } else if (gameMode == TwoMachinesPlay) {
\r
8379 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8385 DisplayTitle(char *str)
\r
8387 char title[MSG_SIZ], *host;
\r
8388 if (str[0] != NULLCHAR) {
\r
8389 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8390 } else if (appData.icsActive) {
\r
8391 if (appData.icsCommPort[0] != NULLCHAR)
\r
8394 host = appData.icsHost;
\r
8395 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8396 } else if (appData.noChessProgram) {
\r
8397 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8399 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8400 strcat(title, ": ");
\r
8401 strcat(title, first.tidy);
\r
8403 SetWindowText(hwndMain, title);
\r
8408 DisplayMessage(char *str1, char *str2)
\r
8412 int remain = MESSAGE_TEXT_MAX - 1;
\r
8415 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8416 messageText[0] = NULLCHAR;
\r
8418 len = strlen(str1);
\r
8419 if (len > remain) len = remain;
\r
8420 strncpy(messageText, str1, len);
\r
8421 messageText[len] = NULLCHAR;
\r
8424 if (*str2 && remain >= 2) {
\r
8426 strcat(messageText, " ");
\r
8429 len = strlen(str2);
\r
8430 if (len > remain) len = remain;
\r
8431 strncat(messageText, str2, len);
\r
8433 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8434 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8436 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8440 hdc = GetDC(hwndMain);
\r
8441 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8442 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8443 &messageRect, messageText, strlen(messageText), NULL);
\r
8444 (void) SelectObject(hdc, oldFont);
\r
8445 (void) ReleaseDC(hwndMain, hdc);
\r
8449 DisplayError(char *str, int error)
\r
8451 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8455 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8457 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8458 NULL, error, LANG_NEUTRAL,
\r
8459 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8461 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8463 ErrorMap *em = errmap;
\r
8464 while (em->err != 0 && em->err != error) em++;
\r
8465 if (em->err != 0) {
\r
8466 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8468 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8473 ErrorPopUp(_("Error"), buf);
\r
8478 DisplayMoveError(char *str)
\r
8480 fromX = fromY = -1;
\r
8481 ClearHighlights();
\r
8482 DrawPosition(FALSE, NULL);
\r
8483 if (appData.popupMoveErrors) {
\r
8484 ErrorPopUp(_("Error"), str);
\r
8486 DisplayMessage(str, "");
\r
8487 moveErrorMessageUp = TRUE;
\r
8492 DisplayFatalError(char *str, int error, int exitStatus)
\r
8494 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8496 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8499 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8500 NULL, error, LANG_NEUTRAL,
\r
8501 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8503 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8505 ErrorMap *em = errmap;
\r
8506 while (em->err != 0 && em->err != error) em++;
\r
8507 if (em->err != 0) {
\r
8508 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8510 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8515 if (appData.debugMode) {
\r
8516 fprintf(debugFP, "%s: %s\n", label, str);
\r
8518 if (appData.popupExitMessage) {
\r
8519 if(appData.icsActive) SendToICS("logout\n"); // [HGM] make sure no new games will be started!
\r
8520 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8521 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8523 ExitEvent(exitStatus);
\r
8528 DisplayInformation(char *str)
\r
8530 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8535 DisplayNote(char *str)
\r
8537 ErrorPopUp(_("Note"), str);
\r
8542 char *title, *question, *replyPrefix;
\r
8547 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8549 static QuestionParams *qp;
\r
8550 char reply[MSG_SIZ];
\r
8553 switch (message) {
\r
8554 case WM_INITDIALOG:
\r
8555 qp = (QuestionParams *) lParam;
\r
8556 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8557 Translate(hDlg, DLG_Question);
\r
8558 SetWindowText(hDlg, qp->title);
\r
8559 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8560 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8564 switch (LOWORD(wParam)) {
\r
8566 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8567 if (*reply) strcat(reply, " ");
\r
8568 len = strlen(reply);
\r
8569 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8570 strcat(reply, "\n");
\r
8571 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8572 EndDialog(hDlg, TRUE);
\r
8573 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8576 EndDialog(hDlg, FALSE);
\r
8587 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8589 QuestionParams qp;
\r
8593 qp.question = question;
\r
8594 qp.replyPrefix = replyPrefix;
\r
8596 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8597 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8598 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8599 FreeProcInstance(lpProc);
\r
8602 /* [AS] Pick FRC position */
\r
8603 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8605 static int * lpIndexFRC;
\r
8611 case WM_INITDIALOG:
\r
8612 lpIndexFRC = (int *) lParam;
\r
8614 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8615 Translate(hDlg, DLG_NewGameFRC);
\r
8617 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8618 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8619 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8620 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8625 switch( LOWORD(wParam) ) {
\r
8627 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8628 EndDialog( hDlg, 0 );
\r
8629 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8632 EndDialog( hDlg, 1 );
\r
8634 case IDC_NFG_Edit:
\r
8635 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8636 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8638 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8641 case IDC_NFG_Random:
\r
8642 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8643 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8656 int index = appData.defaultFrcPosition;
\r
8657 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8659 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8661 if( result == 0 ) {
\r
8662 appData.defaultFrcPosition = index;
\r
8668 /* [AS] Game list options. Refactored by HGM */
\r
8670 HWND gameListOptionsDialog;
\r
8672 // low-level front-end: clear text edit / list widget
\r
8677 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8680 // low-level front-end: clear text edit / list widget
\r
8682 GLT_DeSelectList()
\r
8684 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8687 // low-level front-end: append line to text edit / list widget
\r
8689 GLT_AddToList( char *name )
\r
8692 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8696 // low-level front-end: get line from text edit / list widget
\r
8698 GLT_GetFromList( int index, char *name )
\r
8701 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8707 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8709 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8710 int idx2 = idx1 + delta;
\r
8711 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8713 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8716 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8717 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8718 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8719 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8723 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8727 case WM_INITDIALOG:
\r
8728 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8730 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8731 Translate(hDlg, DLG_GameListOptions);
\r
8733 /* Initialize list */
\r
8734 GLT_TagsToList( lpUserGLT );
\r
8736 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8741 switch( LOWORD(wParam) ) {
\r
8744 EndDialog( hDlg, 0 );
\r
8747 EndDialog( hDlg, 1 );
\r
8750 case IDC_GLT_Default:
\r
8751 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8754 case IDC_GLT_Restore:
\r
8755 GLT_TagsToList( appData.gameListTags );
\r
8759 GLT_MoveSelection( hDlg, -1 );
\r
8762 case IDC_GLT_Down:
\r
8763 GLT_MoveSelection( hDlg, +1 );
\r
8773 int GameListOptions()
\r
8776 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8778 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8780 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8782 if( result == 0 ) {
\r
8783 char *oldTags = appData.gameListTags;
\r
8784 /* [AS] Memory leak here! */
\r
8785 appData.gameListTags = strdup( lpUserGLT );
\r
8786 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8787 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8794 DisplayIcsInteractionTitle(char *str)
\r
8796 char consoleTitle[MSG_SIZ];
\r
8798 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8799 SetWindowText(hwndConsole, consoleTitle);
\r
8801 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8802 char buf[MSG_SIZ], *p = buf, *q;
\r
8803 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8805 q = strchr(p, ';');
\r
8807 if(*p) ChatPopUp(p);
\r
8811 SetActiveWindow(hwndMain);
\r
8815 DrawPosition(int fullRedraw, Board board)
\r
8817 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8820 void NotifyFrontendLogin()
\r
8823 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8829 fromX = fromY = -1;
\r
8830 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8831 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8832 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8833 dragInfo.lastpos = dragInfo.pos;
\r
8834 dragInfo.start.x = dragInfo.start.y = -1;
\r
8835 dragInfo.from = dragInfo.start;
\r
8837 DrawPosition(TRUE, NULL);
\r
8844 CommentPopUp(char *title, char *str)
\r
8846 HWND hwnd = GetActiveWindow();
\r
8847 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8849 SetActiveWindow(hwnd);
\r
8853 CommentPopDown(void)
\r
8855 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8856 if (commentDialog) {
\r
8857 ShowWindow(commentDialog, SW_HIDE);
\r
8859 commentUp = FALSE;
\r
8863 EditCommentPopUp(int index, char *title, char *str)
\r
8865 EitherCommentPopUp(index, title, str, TRUE);
\r
8872 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8879 MyPlaySound(&sounds[(int)SoundMove]);
\r
8882 VOID PlayIcsWinSound()
\r
8884 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8887 VOID PlayIcsLossSound()
\r
8889 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8892 VOID PlayIcsDrawSound()
\r
8894 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8897 VOID PlayIcsUnfinishedSound()
\r
8899 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8905 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8911 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8919 consoleEcho = TRUE;
\r
8920 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8921 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8922 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8931 consoleEcho = FALSE;
\r
8932 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8933 /* This works OK: set text and background both to the same color */
\r
8935 cf.crTextColor = COLOR_ECHOOFF;
\r
8936 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8937 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8940 /* No Raw()...? */
\r
8942 void Colorize(ColorClass cc, int continuation)
\r
8944 currentColorClass = cc;
\r
8945 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8946 consoleCF.crTextColor = textAttribs[cc].color;
\r
8947 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8948 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8954 static char buf[MSG_SIZ];
\r
8955 DWORD bufsiz = MSG_SIZ;
\r
8957 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8958 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8960 if (!GetUserName(buf, &bufsiz)) {
\r
8961 /*DisplayError("Error getting user name", GetLastError());*/
\r
8962 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8970 static char buf[MSG_SIZ];
\r
8971 DWORD bufsiz = MSG_SIZ;
\r
8973 if (!GetComputerName(buf, &bufsiz)) {
\r
8974 /*DisplayError("Error getting host name", GetLastError());*/
\r
8975 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8982 ClockTimerRunning()
\r
8984 return clockTimerEvent != 0;
\r
8990 if (clockTimerEvent == 0) return FALSE;
\r
8991 KillTimer(hwndMain, clockTimerEvent);
\r
8992 clockTimerEvent = 0;
\r
8997 StartClockTimer(long millisec)
\r
8999 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9000 (UINT) millisec, NULL);
\r
9004 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9007 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9009 if(appData.noGUI) return;
\r
9010 hdc = GetDC(hwndMain);
\r
9011 if (!IsIconic(hwndMain)) {
\r
9012 DisplayAClock(hdc, timeRemaining, highlight,
\r
9013 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
9015 if (highlight && iconCurrent == iconBlack) {
\r
9016 iconCurrent = iconWhite;
\r
9017 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9018 if (IsIconic(hwndMain)) {
\r
9019 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9022 (void) ReleaseDC(hwndMain, hdc);
\r
9024 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9028 DisplayBlackClock(long timeRemaining, int highlight)
\r
9031 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9034 if(appData.noGUI) return;
\r
9035 hdc = GetDC(hwndMain);
\r
9036 if (!IsIconic(hwndMain)) {
\r
9037 DisplayAClock(hdc, timeRemaining, highlight,
\r
9038 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
9040 if (highlight && iconCurrent == iconWhite) {
\r
9041 iconCurrent = iconBlack;
\r
9042 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9043 if (IsIconic(hwndMain)) {
\r
9044 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9047 (void) ReleaseDC(hwndMain, hdc);
\r
9049 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9054 LoadGameTimerRunning()
\r
9056 return loadGameTimerEvent != 0;
\r
9060 StopLoadGameTimer()
\r
9062 if (loadGameTimerEvent == 0) return FALSE;
\r
9063 KillTimer(hwndMain, loadGameTimerEvent);
\r
9064 loadGameTimerEvent = 0;
\r
9069 StartLoadGameTimer(long millisec)
\r
9071 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9072 (UINT) millisec, NULL);
\r
9080 char fileTitle[MSG_SIZ];
\r
9082 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9083 f = OpenFileDialog(hwndMain, "a", defName,
\r
9084 appData.oldSaveStyle ? "gam" : "pgn",
\r
9086 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9088 SaveGame(f, 0, "");
\r
9095 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9097 if (delayedTimerEvent != 0) {
\r
9098 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9099 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9101 KillTimer(hwndMain, delayedTimerEvent);
\r
9102 delayedTimerEvent = 0;
\r
9103 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9104 delayedTimerCallback();
\r
9106 delayedTimerCallback = cb;
\r
9107 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9108 (UINT) millisec, NULL);
\r
9111 DelayedEventCallback
\r
9114 if (delayedTimerEvent) {
\r
9115 return delayedTimerCallback;
\r
9122 CancelDelayedEvent()
\r
9124 if (delayedTimerEvent) {
\r
9125 KillTimer(hwndMain, delayedTimerEvent);
\r
9126 delayedTimerEvent = 0;
\r
9130 DWORD GetWin32Priority(int nice)
\r
9131 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9133 REALTIME_PRIORITY_CLASS 0x00000100
\r
9134 HIGH_PRIORITY_CLASS 0x00000080
\r
9135 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9136 NORMAL_PRIORITY_CLASS 0x00000020
\r
9137 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9138 IDLE_PRIORITY_CLASS 0x00000040
\r
9140 if (nice < -15) return 0x00000080;
\r
9141 if (nice < 0) return 0x00008000;
\r
9143 if (nice == 0) return 0x00000020;
\r
9144 if (nice < 15) return 0x00004000;
\r
9145 return 0x00000040;
\r
9148 void RunCommand(char *cmdLine)
\r
9150 /* Now create the child process. */
\r
9151 STARTUPINFO siStartInfo;
\r
9152 PROCESS_INFORMATION piProcInfo;
\r
9154 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9155 siStartInfo.lpReserved = NULL;
\r
9156 siStartInfo.lpDesktop = NULL;
\r
9157 siStartInfo.lpTitle = NULL;
\r
9158 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9159 siStartInfo.cbReserved2 = 0;
\r
9160 siStartInfo.lpReserved2 = NULL;
\r
9161 siStartInfo.hStdInput = NULL;
\r
9162 siStartInfo.hStdOutput = NULL;
\r
9163 siStartInfo.hStdError = NULL;
\r
9165 CreateProcess(NULL,
\r
9166 cmdLine, /* command line */
\r
9167 NULL, /* process security attributes */
\r
9168 NULL, /* primary thread security attrs */
\r
9169 TRUE, /* handles are inherited */
\r
9170 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9171 NULL, /* use parent's environment */
\r
9173 &siStartInfo, /* STARTUPINFO pointer */
\r
9174 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9176 CloseHandle(piProcInfo.hThread);
\r
9179 /* Start a child process running the given program.
\r
9180 The process's standard output can be read from "from", and its
\r
9181 standard input can be written to "to".
\r
9182 Exit with fatal error if anything goes wrong.
\r
9183 Returns an opaque pointer that can be used to destroy the process
\r
9187 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9189 #define BUFSIZE 4096
\r
9191 HANDLE hChildStdinRd, hChildStdinWr,
\r
9192 hChildStdoutRd, hChildStdoutWr;
\r
9193 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9194 SECURITY_ATTRIBUTES saAttr;
\r
9196 PROCESS_INFORMATION piProcInfo;
\r
9197 STARTUPINFO siStartInfo;
\r
9199 char buf[MSG_SIZ];
\r
9202 if (appData.debugMode) {
\r
9203 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9208 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9209 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9210 saAttr.bInheritHandle = TRUE;
\r
9211 saAttr.lpSecurityDescriptor = NULL;
\r
9214 * The steps for redirecting child's STDOUT:
\r
9215 * 1. Create anonymous pipe to be STDOUT for child.
\r
9216 * 2. Create a noninheritable duplicate of read handle,
\r
9217 * and close the inheritable read handle.
\r
9220 /* Create a pipe for the child's STDOUT. */
\r
9221 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9222 return GetLastError();
\r
9225 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9226 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9227 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9228 FALSE, /* not inherited */
\r
9229 DUPLICATE_SAME_ACCESS);
\r
9231 return GetLastError();
\r
9233 CloseHandle(hChildStdoutRd);
\r
9236 * The steps for redirecting child's STDIN:
\r
9237 * 1. Create anonymous pipe to be STDIN for child.
\r
9238 * 2. Create a noninheritable duplicate of write handle,
\r
9239 * and close the inheritable write handle.
\r
9242 /* Create a pipe for the child's STDIN. */
\r
9243 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9244 return GetLastError();
\r
9247 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9248 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9249 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9250 FALSE, /* not inherited */
\r
9251 DUPLICATE_SAME_ACCESS);
\r
9253 return GetLastError();
\r
9255 CloseHandle(hChildStdinWr);
\r
9257 /* Arrange to (1) look in dir for the child .exe file, and
\r
9258 * (2) have dir be the child's working directory. Interpret
\r
9259 * dir relative to the directory WinBoard loaded from. */
\r
9260 GetCurrentDirectory(MSG_SIZ, buf);
\r
9261 SetCurrentDirectory(installDir);
\r
9262 SetCurrentDirectory(dir);
\r
9264 /* Now create the child process. */
\r
9266 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9267 siStartInfo.lpReserved = NULL;
\r
9268 siStartInfo.lpDesktop = NULL;
\r
9269 siStartInfo.lpTitle = NULL;
\r
9270 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9271 siStartInfo.cbReserved2 = 0;
\r
9272 siStartInfo.lpReserved2 = NULL;
\r
9273 siStartInfo.hStdInput = hChildStdinRd;
\r
9274 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9275 siStartInfo.hStdError = hChildStdoutWr;
\r
9277 fSuccess = CreateProcess(NULL,
\r
9278 cmdLine, /* command line */
\r
9279 NULL, /* process security attributes */
\r
9280 NULL, /* primary thread security attrs */
\r
9281 TRUE, /* handles are inherited */
\r
9282 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9283 NULL, /* use parent's environment */
\r
9285 &siStartInfo, /* STARTUPINFO pointer */
\r
9286 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9288 err = GetLastError();
\r
9289 SetCurrentDirectory(buf); /* return to prev directory */
\r
9294 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9295 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9296 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9299 /* Close the handles we don't need in the parent */
\r
9300 CloseHandle(piProcInfo.hThread);
\r
9301 CloseHandle(hChildStdinRd);
\r
9302 CloseHandle(hChildStdoutWr);
\r
9304 /* Prepare return value */
\r
9305 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9306 cp->kind = CPReal;
\r
9307 cp->hProcess = piProcInfo.hProcess;
\r
9308 cp->pid = piProcInfo.dwProcessId;
\r
9309 cp->hFrom = hChildStdoutRdDup;
\r
9310 cp->hTo = hChildStdinWrDup;
\r
9312 *pr = (void *) cp;
\r
9314 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9315 2000 where engines sometimes don't see the initial command(s)
\r
9316 from WinBoard and hang. I don't understand how that can happen,
\r
9317 but the Sleep is harmless, so I've put it in. Others have also
\r
9318 reported what may be the same problem, so hopefully this will fix
\r
9319 it for them too. */
\r
9327 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9329 ChildProc *cp; int result;
\r
9331 cp = (ChildProc *) pr;
\r
9332 if (cp == NULL) return;
\r
9334 switch (cp->kind) {
\r
9336 /* TerminateProcess is considered harmful, so... */
\r
9337 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9338 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9339 /* The following doesn't work because the chess program
\r
9340 doesn't "have the same console" as WinBoard. Maybe
\r
9341 we could arrange for this even though neither WinBoard
\r
9342 nor the chess program uses a console for stdio? */
\r
9343 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9345 /* [AS] Special termination modes for misbehaving programs... */
\r
9346 if( signal & 8 ) {
\r
9347 result = TerminateProcess( cp->hProcess, 0 );
\r
9349 if ( appData.debugMode) {
\r
9350 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9353 else if( signal & 4 ) {
\r
9354 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9356 if( dw != WAIT_OBJECT_0 ) {
\r
9357 result = TerminateProcess( cp->hProcess, 0 );
\r
9359 if ( appData.debugMode) {
\r
9360 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9366 CloseHandle(cp->hProcess);
\r
9370 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9374 closesocket(cp->sock);
\r
9379 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9380 closesocket(cp->sock);
\r
9381 closesocket(cp->sock2);
\r
9389 InterruptChildProcess(ProcRef pr)
\r
9393 cp = (ChildProc *) pr;
\r
9394 if (cp == NULL) return;
\r
9395 switch (cp->kind) {
\r
9397 /* The following doesn't work because the chess program
\r
9398 doesn't "have the same console" as WinBoard. Maybe
\r
9399 we could arrange for this even though neither WinBoard
\r
9400 nor the chess program uses a console for stdio */
\r
9401 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9406 /* Can't interrupt */
\r
9410 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9417 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9419 char cmdLine[MSG_SIZ];
\r
9421 if (port[0] == NULLCHAR) {
\r
9422 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9424 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9426 return StartChildProcess(cmdLine, "", pr);
\r
9430 /* Code to open TCP sockets */
\r
9433 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9439 struct sockaddr_in sa, mysa;
\r
9440 struct hostent FAR *hp;
\r
9441 unsigned short uport;
\r
9442 WORD wVersionRequested;
\r
9445 /* Initialize socket DLL */
\r
9446 wVersionRequested = MAKEWORD(1, 1);
\r
9447 err = WSAStartup(wVersionRequested, &wsaData);
\r
9448 if (err != 0) return err;
\r
9451 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9452 err = WSAGetLastError();
\r
9457 /* Bind local address using (mostly) don't-care values.
\r
9459 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9460 mysa.sin_family = AF_INET;
\r
9461 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9462 uport = (unsigned short) 0;
\r
9463 mysa.sin_port = htons(uport);
\r
9464 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9465 == SOCKET_ERROR) {
\r
9466 err = WSAGetLastError();
\r
9471 /* Resolve remote host name */
\r
9472 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9473 if (!(hp = gethostbyname(host))) {
\r
9474 unsigned int b0, b1, b2, b3;
\r
9476 err = WSAGetLastError();
\r
9478 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9479 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9480 hp->h_addrtype = AF_INET;
\r
9482 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9483 hp->h_addr_list[0] = (char *) malloc(4);
\r
9484 hp->h_addr_list[0][0] = (char) b0;
\r
9485 hp->h_addr_list[0][1] = (char) b1;
\r
9486 hp->h_addr_list[0][2] = (char) b2;
\r
9487 hp->h_addr_list[0][3] = (char) b3;
\r
9493 sa.sin_family = hp->h_addrtype;
\r
9494 uport = (unsigned short) atoi(port);
\r
9495 sa.sin_port = htons(uport);
\r
9496 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9498 /* Make connection */
\r
9499 if (connect(s, (struct sockaddr *) &sa,
\r
9500 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9501 err = WSAGetLastError();
\r
9506 /* Prepare return value */
\r
9507 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9508 cp->kind = CPSock;
\r
9510 *pr = (ProcRef *) cp;
\r
9516 OpenCommPort(char *name, ProcRef *pr)
\r
9521 char fullname[MSG_SIZ];
\r
9523 if (*name != '\\')
\r
9524 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9526 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9528 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9529 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9530 if (h == (HANDLE) -1) {
\r
9531 return GetLastError();
\r
9535 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9537 /* Accumulate characters until a 100ms pause, then parse */
\r
9538 ct.ReadIntervalTimeout = 100;
\r
9539 ct.ReadTotalTimeoutMultiplier = 0;
\r
9540 ct.ReadTotalTimeoutConstant = 0;
\r
9541 ct.WriteTotalTimeoutMultiplier = 0;
\r
9542 ct.WriteTotalTimeoutConstant = 0;
\r
9543 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9545 /* Prepare return value */
\r
9546 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9547 cp->kind = CPComm;
\r
9550 *pr = (ProcRef *) cp;
\r
9556 OpenLoopback(ProcRef *pr)
\r
9558 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9564 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9569 struct sockaddr_in sa, mysa;
\r
9570 struct hostent FAR *hp;
\r
9571 unsigned short uport;
\r
9572 WORD wVersionRequested;
\r
9575 char stderrPortStr[MSG_SIZ];
\r
9577 /* Initialize socket DLL */
\r
9578 wVersionRequested = MAKEWORD(1, 1);
\r
9579 err = WSAStartup(wVersionRequested, &wsaData);
\r
9580 if (err != 0) return err;
\r
9582 /* Resolve remote host name */
\r
9583 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9584 if (!(hp = gethostbyname(host))) {
\r
9585 unsigned int b0, b1, b2, b3;
\r
9587 err = WSAGetLastError();
\r
9589 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9590 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9591 hp->h_addrtype = AF_INET;
\r
9593 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9594 hp->h_addr_list[0] = (char *) malloc(4);
\r
9595 hp->h_addr_list[0][0] = (char) b0;
\r
9596 hp->h_addr_list[0][1] = (char) b1;
\r
9597 hp->h_addr_list[0][2] = (char) b2;
\r
9598 hp->h_addr_list[0][3] = (char) b3;
\r
9604 sa.sin_family = hp->h_addrtype;
\r
9605 uport = (unsigned short) 514;
\r
9606 sa.sin_port = htons(uport);
\r
9607 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9609 /* Bind local socket to unused "privileged" port address
\r
9611 s = INVALID_SOCKET;
\r
9612 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9613 mysa.sin_family = AF_INET;
\r
9614 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9615 for (fromPort = 1023;; fromPort--) {
\r
9616 if (fromPort < 0) {
\r
9618 return WSAEADDRINUSE;
\r
9620 if (s == INVALID_SOCKET) {
\r
9621 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9622 err = WSAGetLastError();
\r
9627 uport = (unsigned short) fromPort;
\r
9628 mysa.sin_port = htons(uport);
\r
9629 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9630 == SOCKET_ERROR) {
\r
9631 err = WSAGetLastError();
\r
9632 if (err == WSAEADDRINUSE) continue;
\r
9636 if (connect(s, (struct sockaddr *) &sa,
\r
9637 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9638 err = WSAGetLastError();
\r
9639 if (err == WSAEADDRINUSE) {
\r
9650 /* Bind stderr local socket to unused "privileged" port address
\r
9652 s2 = INVALID_SOCKET;
\r
9653 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9654 mysa.sin_family = AF_INET;
\r
9655 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9656 for (fromPort = 1023;; fromPort--) {
\r
9657 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9658 if (fromPort < 0) {
\r
9659 (void) closesocket(s);
\r
9661 return WSAEADDRINUSE;
\r
9663 if (s2 == INVALID_SOCKET) {
\r
9664 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9665 err = WSAGetLastError();
\r
9671 uport = (unsigned short) fromPort;
\r
9672 mysa.sin_port = htons(uport);
\r
9673 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9674 == SOCKET_ERROR) {
\r
9675 err = WSAGetLastError();
\r
9676 if (err == WSAEADDRINUSE) continue;
\r
9677 (void) closesocket(s);
\r
9681 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9682 err = WSAGetLastError();
\r
9683 if (err == WSAEADDRINUSE) {
\r
9685 s2 = INVALID_SOCKET;
\r
9688 (void) closesocket(s);
\r
9689 (void) closesocket(s2);
\r
9695 prevStderrPort = fromPort; // remember port used
\r
9696 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9698 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9699 err = WSAGetLastError();
\r
9700 (void) closesocket(s);
\r
9701 (void) closesocket(s2);
\r
9706 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9707 err = WSAGetLastError();
\r
9708 (void) closesocket(s);
\r
9709 (void) closesocket(s2);
\r
9713 if (*user == NULLCHAR) user = UserName();
\r
9714 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9715 err = WSAGetLastError();
\r
9716 (void) closesocket(s);
\r
9717 (void) closesocket(s2);
\r
9721 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9722 err = WSAGetLastError();
\r
9723 (void) closesocket(s);
\r
9724 (void) closesocket(s2);
\r
9729 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9730 err = WSAGetLastError();
\r
9731 (void) closesocket(s);
\r
9732 (void) closesocket(s2);
\r
9736 (void) closesocket(s2); /* Stop listening */
\r
9738 /* Prepare return value */
\r
9739 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9740 cp->kind = CPRcmd;
\r
9743 *pr = (ProcRef *) cp;
\r
9750 AddInputSource(ProcRef pr, int lineByLine,
\r
9751 InputCallback func, VOIDSTAR closure)
\r
9753 InputSource *is, *is2 = NULL;
\r
9754 ChildProc *cp = (ChildProc *) pr;
\r
9756 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9757 is->lineByLine = lineByLine;
\r
9759 is->closure = closure;
\r
9760 is->second = NULL;
\r
9761 is->next = is->buf;
\r
9762 if (pr == NoProc) {
\r
9763 is->kind = CPReal;
\r
9764 consoleInputSource = is;
\r
9766 is->kind = cp->kind;
\r
9768 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9769 we create all threads suspended so that the is->hThread variable can be
\r
9770 safely assigned, then let the threads start with ResumeThread.
\r
9772 switch (cp->kind) {
\r
9774 is->hFile = cp->hFrom;
\r
9775 cp->hFrom = NULL; /* now owned by InputThread */
\r
9777 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9778 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9782 is->hFile = cp->hFrom;
\r
9783 cp->hFrom = NULL; /* now owned by InputThread */
\r
9785 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9786 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9790 is->sock = cp->sock;
\r
9792 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9793 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9797 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9799 is->sock = cp->sock;
\r
9801 is2->sock = cp->sock2;
\r
9802 is2->second = is2;
\r
9804 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9805 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9807 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9808 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9812 if( is->hThread != NULL ) {
\r
9813 ResumeThread( is->hThread );
\r
9816 if( is2 != NULL && is2->hThread != NULL ) {
\r
9817 ResumeThread( is2->hThread );
\r
9821 return (InputSourceRef) is;
\r
9825 RemoveInputSource(InputSourceRef isr)
\r
9829 is = (InputSource *) isr;
\r
9830 is->hThread = NULL; /* tell thread to stop */
\r
9831 CloseHandle(is->hThread);
\r
9832 if (is->second != NULL) {
\r
9833 is->second->hThread = NULL;
\r
9834 CloseHandle(is->second->hThread);
\r
9838 int no_wrap(char *message, int count)
\r
9840 ConsoleOutput(message, count, FALSE);
\r
9845 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9848 int outCount = SOCKET_ERROR;
\r
9849 ChildProc *cp = (ChildProc *) pr;
\r
9850 static OVERLAPPED ovl;
\r
9852 static int line = 0;
\r
9856 if (appData.noJoin || !appData.useInternalWrap)
\r
9857 return no_wrap(message, count);
\r
9860 int width = get_term_width();
\r
9861 int len = wrap(NULL, message, count, width, &line);
\r
9862 char *msg = malloc(len);
\r
9866 return no_wrap(message, count);
\r
9869 dbgchk = wrap(msg, message, count, width, &line);
\r
9870 if (dbgchk != len && appData.debugMode)
\r
9871 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9872 ConsoleOutput(msg, len, FALSE);
\r
9879 if (ovl.hEvent == NULL) {
\r
9880 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9882 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9884 switch (cp->kind) {
\r
9887 outCount = send(cp->sock, message, count, 0);
\r
9888 if (outCount == SOCKET_ERROR) {
\r
9889 *outError = WSAGetLastError();
\r
9891 *outError = NO_ERROR;
\r
9896 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9897 &dOutCount, NULL)) {
\r
9898 *outError = NO_ERROR;
\r
9899 outCount = (int) dOutCount;
\r
9901 *outError = GetLastError();
\r
9906 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9907 &dOutCount, &ovl);
\r
9908 if (*outError == NO_ERROR) {
\r
9909 outCount = (int) dOutCount;
\r
9919 if(n != 0) Sleep(n);
\r
9923 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9926 /* Ignore delay, not implemented for WinBoard */
\r
9927 return OutputToProcess(pr, message, count, outError);
\r
9932 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9933 char *buf, int count, int error)
\r
9935 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9938 /* see wgamelist.c for Game List functions */
\r
9939 /* see wedittags.c for Edit Tags functions */
\r
9946 char buf[MSG_SIZ];
\r
9949 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9950 f = fopen(buf, "r");
\r
9952 ProcessICSInitScript(f);
\r
9962 StartAnalysisClock()
\r
9964 if (analysisTimerEvent) return;
\r
9965 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9966 (UINT) 2000, NULL);
\r
9970 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9972 highlightInfo.sq[0].x = fromX;
\r
9973 highlightInfo.sq[0].y = fromY;
\r
9974 highlightInfo.sq[1].x = toX;
\r
9975 highlightInfo.sq[1].y = toY;
\r
9981 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9982 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9986 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9988 premoveHighlightInfo.sq[0].x = fromX;
\r
9989 premoveHighlightInfo.sq[0].y = fromY;
\r
9990 premoveHighlightInfo.sq[1].x = toX;
\r
9991 premoveHighlightInfo.sq[1].y = toY;
\r
9995 ClearPremoveHighlights()
\r
9997 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9998 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10002 ShutDownFrontEnd()
\r
10004 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10005 DeleteClipboardTempFiles();
\r
10011 if (IsIconic(hwndMain))
\r
10012 ShowWindow(hwndMain, SW_RESTORE);
\r
10014 SetActiveWindow(hwndMain);
\r
10018 * Prototypes for animation support routines
\r
10020 static void ScreenSquare(int column, int row, POINT * pt);
\r
10021 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10022 POINT frames[], int * nFrames);
\r
10025 #define kFactor 4
\r
10028 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
10029 { // [HGM] atomic: animate blast wave
\r
10032 explodeInfo.fromX = fromX;
\r
10033 explodeInfo.fromY = fromY;
\r
10034 explodeInfo.toX = toX;
\r
10035 explodeInfo.toY = toY;
\r
10036 for(i=1; i<4*kFactor; i++) {
\r
10037 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
10038 DrawPosition(FALSE, board);
\r
10039 Sleep(appData.animSpeed);
\r
10041 explodeInfo.radius = 0;
\r
10042 DrawPosition(TRUE, board);
\r
10046 AnimateMove(board, fromX, fromY, toX, toY)
\r
10053 ChessSquare piece, victim = EmptySquare, victim2 = EmptySquare;
\r
10054 int x = toX, y = toY, x2 = kill2X;
\r
10055 POINT start, finish, mid;
\r
10056 POINT frames[kFactor * 2 + 1];
\r
10059 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
10061 if (!appData.animate) return;
\r
10062 if (doingSizing) return;
\r
10063 if (fromY < 0 || fromX < 0) return;
\r
10064 piece = board[fromY][fromX];
\r
10065 if (piece >= EmptySquare) return;
\r
10067 if(x2 >= 0) toX = kill2X, toY = kill2Y, victim = board[killY][killX], victim2 = board[kill2Y][kill2X]; else
\r
10068 if(killX >= 0) toX = killX, toY = killY, victim = board[killY][killX]; // [HGM] lion: first to kill square
\r
10070 animInfo.from.x = fromX;
\r
10071 animInfo.from.y = fromY;
\r
10075 ScreenSquare(fromX, fromY, &start);
\r
10076 ScreenSquare(toX, toY, &finish);
\r
10078 /* All moves except knight jumps move in straight line */
\r
10079 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10080 mid.x = start.x + (finish.x - start.x) / 2;
\r
10081 mid.y = start.y + (finish.y - start.y) / 2;
\r
10083 /* Knight: make straight movement then diagonal */
\r
10084 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10085 mid.x = start.x + (finish.x - start.x) / 2;
\r
10089 mid.y = start.y + (finish.y - start.y) / 2;
\r
10093 /* Don't use as many frames for very short moves */
\r
10094 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10095 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10097 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10099 animInfo.to.x = toX;
\r
10100 animInfo.to.y = toY;
\r
10101 animInfo.lastpos = start;
\r
10102 animInfo.piece = piece;
\r
10103 for (n = 0; n < nFrames; n++) {
\r
10104 animInfo.pos = frames[n];
\r
10105 DrawPosition(FALSE, board);
\r
10106 animInfo.lastpos = animInfo.pos;
\r
10107 Sleep(appData.animSpeed);
\r
10109 animInfo.pos = finish;
\r
10110 DrawPosition(FALSE, board);
\r
10112 if(toX == x2 && toY == kill2Y) {
\r
10113 fromX = toX; fromY = toY; toX = killX; toY = killY; x2 = -1;
\r
10114 board[kill2Y][kill2X] = EmptySquare; goto again;
\r
10116 if(toX != x || toY != y) {
\r
10117 fromX = toX; fromY = toY; toX = x; toY = y;
\r
10118 board[killY][killX] = EmptySquare; goto again;
\r
10121 if(victim2 != EmptySquare) board[kill2Y][kill2X] = victim2;
\r
10122 if(victim != EmptySquare) board[killY][killX] = victim;
\r
10124 animInfo.piece = EmptySquare;
\r
10125 Explode(board, fromX, fromY, toX, toY);
\r
10128 /* Convert board position to corner of screen rect and color */
\r
10131 ScreenSquare(column, row, pt)
\r
10132 int column; int row; POINT * pt;
\r
10135 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10136 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10138 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10139 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10143 /* Generate a series of frame coords from start->mid->finish.
\r
10144 The movement rate doubles until the half way point is
\r
10145 reached, then halves back down to the final destination,
\r
10146 which gives a nice slow in/out effect. The algorithmn
\r
10147 may seem to generate too many intermediates for short
\r
10148 moves, but remember that the purpose is to attract the
\r
10149 viewers attention to the piece about to be moved and
\r
10150 then to where it ends up. Too few frames would be less
\r
10154 Tween(start, mid, finish, factor, frames, nFrames)
\r
10155 POINT * start; POINT * mid;
\r
10156 POINT * finish; int factor;
\r
10157 POINT frames[]; int * nFrames;
\r
10159 int n, fraction = 1, count = 0;
\r
10161 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10162 for (n = 0; n < factor; n++)
\r
10164 for (n = 0; n < factor; n++) {
\r
10165 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10166 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10168 fraction = fraction / 2;
\r
10172 frames[count] = *mid;
\r
10175 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10177 for (n = 0; n < factor; n++) {
\r
10178 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10179 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10181 fraction = fraction * 2;
\r
10183 *nFrames = count;
\r
10187 SettingsPopUp(ChessProgramState *cps)
\r
10188 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10189 EngineOptionsPopup(savedHwnd, cps);
\r
10192 int flock(int fid, int code)
\r
10194 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10196 ov.hEvent = NULL;
\r
10198 ov.OffsetHigh = 0;
\r
10200 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10202 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10203 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10204 default: return -1;
\r
10213 static char col[8][20];
\r
10214 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10216 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10221 ActivateTheme (int new)
\r
10222 { // Redo initialization of features depending on options that can occur in themes
\r
10224 if(new) InitDrawingColors();
\r
10225 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10226 InitDrawingSizes(boardSize, 0);
\r
10227 InvalidateRect(hwndMain, NULL, TRUE);
\r