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 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
95 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
98 void mysrandom(unsigned int seed);
\r
100 extern int whiteFlag, blackFlag;
\r
101 Boolean flipClock = FALSE;
\r
102 extern HANDLE chatHandle[];
\r
103 extern enum ICS_TYPE ics_type;
\r
105 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
106 int MyGetFullPathName P((char *name, char *fullname));
\r
107 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
108 VOID NewVariantPopup(HWND hwnd);
\r
109 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
110 /*char*/int promoChar));
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P((char *s));
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
132 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
135 POINT sq[2]; /* board coordinates of from, to squares */
\r
138 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
139 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
143 typedef struct { // [HGM] atomic
\r
144 int fromX, fromY, toX, toY, radius;
\r
147 static ExplodeInfo explodeInfo;
\r
149 /* Window class names */
\r
150 char szAppName[] = "WinBoard";
\r
151 char szConsoleName[] = "WBConsole";
\r
153 /* Title bar text */
\r
154 char szTitle[] = "WinBoard";
\r
155 char szConsoleTitle[] = "I C S Interaction";
\r
158 char *settingsFileName;
\r
159 Boolean saveSettingsOnExit;
\r
160 char installDir[MSG_SIZ];
\r
161 int errorExitStatus;
\r
163 BoardSize boardSize;
\r
164 Boolean chessProgram;
\r
165 //static int boardX, boardY;
\r
166 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
167 int squareSize, lineGap, minorSize;
\r
168 static int winW, winH;
\r
169 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
170 static int logoHeight = 0;
\r
171 static char messageText[MESSAGE_TEXT_MAX];
\r
172 static int clockTimerEvent = 0;
\r
173 static int loadGameTimerEvent = 0;
\r
174 static int analysisTimerEvent = 0;
\r
175 static DelayedEventCallback delayedTimerCallback;
\r
176 static int delayedTimerEvent = 0;
\r
177 static int buttonCount = 2;
\r
178 char *icsTextMenuString;
\r
180 char *firstChessProgramNames;
\r
181 char *secondChessProgramNames;
\r
183 #define PALETTESIZE 256
\r
185 HINSTANCE hInst; /* current instance */
\r
186 Boolean alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 static HWND savedHwnd;
\r
194 HWND hCommPort = NULL; /* currently open comm port */
\r
195 static HWND hwndPause; /* pause button */
\r
196 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
197 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
198 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
199 explodeBrush, /* [HGM] atomic */
\r
200 markerBrush, /* [HGM] markers */
\r
201 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
202 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
203 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
204 static HPEN gridPen = NULL;
\r
205 static HPEN highlightPen = NULL;
\r
206 static HPEN premovePen = NULL;
\r
207 static NPLOGPALETTE pLogPal;
\r
208 static BOOL paletteChanged = FALSE;
\r
209 static HICON iconWhite, iconBlack, iconCurrent;
\r
210 static int doingSizing = FALSE;
\r
211 static int lastSizing = 0;
\r
212 static int prevStderrPort;
\r
213 static HBITMAP userLogo;
\r
215 static HBITMAP liteBackTexture = NULL;
\r
216 static HBITMAP darkBackTexture = NULL;
\r
217 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
219 static int backTextureSquareSize = 0;
\r
220 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
222 #if __GNUC__ && !defined(_winmajor)
\r
223 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
225 #if defined(_winmajor)
\r
226 #define oldDialog (_winmajor < 4)
\r
228 #define oldDialog 0
\r
232 #define INTERNATIONAL
\r
234 #ifdef INTERNATIONAL
\r
235 # define _(s) T_(s)
\r
241 # define Translate(x, y)
\r
242 # define LoadLanguageFile(s)
\r
245 #ifdef INTERNATIONAL
\r
247 Boolean barbaric; // flag indicating if translation is needed
\r
249 // list of item numbers used in each dialog (used to alter language at run time)
\r
251 #define ABOUTBOX -1 /* not sure why these are needed */
\r
252 #define ABOUTBOX2 -1
\r
254 int dialogItems[][42] = {
\r
255 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
256 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
257 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
258 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
259 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
260 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
261 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
262 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
263 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
264 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
265 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
266 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
267 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
268 { ABOUTBOX2, IDC_ChessBoard },
\r
269 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
270 OPT_GameListClose, IDC_GameListDoFilter },
\r
271 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
272 { DLG_Error, IDOK },
\r
273 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
274 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
275 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
276 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
277 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
278 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
279 { DLG_IndexNumber, IDC_Index },
\r
280 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
281 { DLG_TypeInName, IDOK, IDCANCEL },
\r
282 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
283 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
284 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
285 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
286 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
287 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
288 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
289 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
290 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
291 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
292 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
293 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
294 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
295 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
296 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
297 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
298 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
299 GPB_General, GPB_Alarm },
\r
300 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
301 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
302 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
303 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
304 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
305 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
306 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
307 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
308 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
309 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
310 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
311 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
312 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
313 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
314 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
315 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
316 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
317 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
318 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
319 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
320 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
321 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
322 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
323 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
324 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
325 { DLG_MoveHistory },
\r
326 { DLG_EvalGraph },
\r
327 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
328 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
329 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
330 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
331 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
332 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
333 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
334 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
335 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
339 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
340 static int lastChecked;
\r
341 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
342 extern int tinyLayout;
\r
343 extern char * menuBarText[][10];
\r
346 LoadLanguageFile(char *name)
\r
347 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
349 int i=0, j=0, n=0, k;
\r
352 if(!name || name[0] == NULLCHAR) return;
\r
353 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
354 appData.language = oldLanguage;
\r
355 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
356 if((f = fopen(buf, "r")) == NULL) return;
\r
357 while((k = fgetc(f)) != EOF) {
\r
358 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
359 languageBuf[i] = k;
\r
361 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
363 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
364 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
365 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
366 english[j] = languageBuf + n + 1; *p = 0;
\r
367 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
368 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
373 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
375 case 'n': k = '\n'; break;
\r
376 case 'r': k = '\r'; break;
\r
377 case 't': k = '\t'; break;
\r
379 languageBuf[--i] = k;
\r
384 barbaric = (j != 0);
\r
385 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
390 { // return the translation of the given string
\r
391 // efficiency can be improved a lot...
\r
393 static char buf[MSG_SIZ];
\r
394 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
395 if(!barbaric) return s;
\r
396 if(!s) return ""; // sanity
\r
397 while(english[i]) {
\r
398 if(!strcmp(s, english[i])) return foreign[i];
\r
399 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
400 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
409 Translate(HWND hDlg, int dialogID)
\r
410 { // translate all text items in the given dialog
\r
412 char buf[MSG_SIZ], *s;
\r
413 if(!barbaric) return;
\r
414 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
415 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
416 GetWindowText( hDlg, buf, MSG_SIZ );
\r
418 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
419 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
420 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
421 if(strlen(buf) == 0) continue;
\r
423 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
428 TranslateOneMenu(int i, HMENU subMenu)
\r
431 static MENUITEMINFO info;
\r
433 info.cbSize = sizeof(MENUITEMINFO);
\r
434 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
435 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
437 info.dwTypeData = buf;
\r
438 info.cch = sizeof(buf);
\r
439 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
441 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
442 else menuText[i][j] = strdup(buf); // remember original on first change
\r
444 if(buf[0] == NULLCHAR) continue;
\r
445 info.dwTypeData = T_(buf);
\r
446 info.cch = strlen(buf)+1;
\r
447 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
453 TranslateMenus(int addLanguage)
\r
456 WIN32_FIND_DATA fileData;
\r
458 #define IDM_English 1970
\r
460 HMENU mainMenu = GetMenu(hwndMain);
\r
461 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
462 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
463 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
464 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
465 TranslateOneMenu(i, subMenu);
\r
467 DrawMenuBar(hwndMain);
\r
470 if(!addLanguage) return;
\r
471 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
472 HMENU mainMenu = GetMenu(hwndMain);
\r
473 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
474 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
475 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
476 i = 0; lastChecked = IDM_English;
\r
478 char *p, *q = fileData.cFileName;
\r
479 int checkFlag = MF_UNCHECKED;
\r
480 languageFile[i] = strdup(q);
\r
481 if(barbaric && !strcmp(oldLanguage, q)) {
\r
482 checkFlag = MF_CHECKED;
\r
483 lastChecked = IDM_English + i + 1;
\r
484 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
486 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
487 p = strstr(fileData.cFileName, ".lng");
\r
489 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
490 } while(FindNextFile(hFind, &fileData));
\r
497 #define IDM_RecentEngines 3000
\r
500 RecentEngineMenu (char *s)
\r
502 if(appData.icsActive) return;
\r
503 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
504 HMENU mainMenu = GetMenu(hwndMain);
\r
505 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
506 int i=IDM_RecentEngines;
\r
507 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
508 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
510 char *p = strchr(s, '\n');
\r
511 if(p == NULL) return; // malformed!
\r
513 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
527 int cliWidth, cliHeight;
\r
530 SizeInfo sizeInfo[] =
\r
532 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
533 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
534 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
535 { "petite", 33, 1, 1, 1, 0, 0 },
\r
536 { "slim", 37, 2, 1, 0, 0, 0 },
\r
537 { "small", 40, 2, 1, 0, 0, 0 },
\r
538 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
539 { "middling", 49, 2, 0, 0, 0, 0 },
\r
540 { "average", 54, 2, 0, 0, 0, 0 },
\r
541 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
542 { "medium", 64, 3, 0, 0, 0, 0 },
\r
543 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
544 { "large", 80, 3, 0, 0, 0, 0 },
\r
545 { "big", 87, 3, 0, 0, 0, 0 },
\r
546 { "huge", 95, 3, 0, 0, 0, 0 },
\r
547 { "giant", 108, 3, 0, 0, 0, 0 },
\r
548 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
549 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
550 { NULL, 0, 0, 0, 0, 0, 0 }
\r
553 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
554 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
556 { 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
557 { 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
558 { 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
559 { 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
560 { 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
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
576 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
585 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
586 #define N_BUTTONS 5
\r
588 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
590 {"<<", IDM_ToStart, NULL, NULL},
\r
591 {"<", IDM_Backward, NULL, NULL},
\r
592 {"P", IDM_Pause, NULL, NULL},
\r
593 {">", IDM_Forward, NULL, NULL},
\r
594 {">>", IDM_ToEnd, NULL, NULL},
\r
597 int tinyLayout = 0, smallLayout = 0;
\r
598 #define MENU_BAR_ITEMS 9
\r
599 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
600 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
601 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
605 MySound sounds[(int)NSoundClasses];
\r
606 MyTextAttribs textAttribs[(int)NColorClasses];
\r
608 MyColorizeAttribs colorizeAttribs[] = {
\r
609 { (COLORREF)0, 0, N_("Shout Text") },
\r
610 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
611 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
612 { (COLORREF)0, 0, N_("Channel Text") },
\r
613 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
614 { (COLORREF)0, 0, N_("Tell Text") },
\r
615 { (COLORREF)0, 0, N_("Challenge Text") },
\r
616 { (COLORREF)0, 0, N_("Request Text") },
\r
617 { (COLORREF)0, 0, N_("Seek Text") },
\r
618 { (COLORREF)0, 0, N_("Normal Text") },
\r
619 { (COLORREF)0, 0, N_("None") }
\r
624 static char *commentTitle;
\r
625 static char *commentText;
\r
626 static int commentIndex;
\r
627 static Boolean editComment = FALSE;
\r
630 char errorTitle[MSG_SIZ];
\r
631 char errorMessage[2*MSG_SIZ];
\r
632 HWND errorDialog = NULL;
\r
633 BOOLEAN moveErrorMessageUp = FALSE;
\r
634 BOOLEAN consoleEcho = TRUE;
\r
635 CHARFORMAT consoleCF;
\r
636 COLORREF consoleBackgroundColor;
\r
638 char *programVersion;
\r
644 typedef int CPKind;
\r
653 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
656 #define INPUT_SOURCE_BUF_SIZE 4096
\r
658 typedef struct _InputSource {
\r
665 char buf[INPUT_SOURCE_BUF_SIZE];
\r
669 InputCallback func;
\r
670 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
674 InputSource *consoleInputSource;
\r
679 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
680 VOID ConsoleCreate();
\r
682 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
683 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
684 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
685 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
687 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
688 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
689 void ParseIcsTextMenu(char *icsTextMenuString);
\r
690 VOID PopUpNameDialog(char firstchar);
\r
691 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
695 int GameListOptions();
\r
697 int dummy; // [HGM] for obsolete args
\r
699 HWND hwndMain = NULL; /* root window*/
\r
700 HWND hwndConsole = NULL;
\r
701 HWND commentDialog = NULL;
\r
702 HWND moveHistoryDialog = NULL;
\r
703 HWND evalGraphDialog = NULL;
\r
704 HWND engineOutputDialog = NULL;
\r
705 HWND gameListDialog = NULL;
\r
706 HWND editTagsDialog = NULL;
\r
708 int commentUp = FALSE;
\r
710 WindowPlacement wpMain;
\r
711 WindowPlacement wpConsole;
\r
712 WindowPlacement wpComment;
\r
713 WindowPlacement wpMoveHistory;
\r
714 WindowPlacement wpEvalGraph;
\r
715 WindowPlacement wpEngineOutput;
\r
716 WindowPlacement wpGameList;
\r
717 WindowPlacement wpTags;
\r
719 VOID EngineOptionsPopup(); // [HGM] settings
\r
721 VOID GothicPopUp(char *title, VariantClass variant);
\r
723 * Setting "frozen" should disable all user input other than deleting
\r
724 * the window. We do this while engines are initializing themselves.
\r
726 static int frozen = 0;
\r
727 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
733 if (frozen) return;
\r
735 hmenu = GetMenu(hwndMain);
\r
736 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
737 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
739 DrawMenuBar(hwndMain);
\r
742 /* Undo a FreezeUI */
\r
748 if (!frozen) return;
\r
750 hmenu = GetMenu(hwndMain);
\r
751 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
752 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
754 DrawMenuBar(hwndMain);
\r
757 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
759 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
765 #define JAWS_ALT_INTERCEPT
\r
766 #define JAWS_KBUP_NAVIGATION
\r
767 #define JAWS_KBDOWN_NAVIGATION
\r
768 #define JAWS_MENU_ITEMS
\r
769 #define JAWS_SILENCE
\r
770 #define JAWS_REPLAY
\r
772 #define JAWS_COPYRIGHT
\r
773 #define JAWS_DELETE(X) X
\r
774 #define SAYMACHINEMOVE()
\r
778 /*---------------------------------------------------------------------------*\
\r
782 \*---------------------------------------------------------------------------*/
\r
785 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
786 LPSTR lpCmdLine, int nCmdShow)
\r
789 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
790 // INITCOMMONCONTROLSEX ex;
\r
794 LoadLibrary("RICHED32.DLL");
\r
795 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
797 if (!InitApplication(hInstance)) {
\r
800 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
807 // InitCommonControlsEx(&ex);
\r
808 InitCommonControls();
\r
810 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
811 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
812 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
814 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
816 while (GetMessage(&msg, /* message structure */
\r
817 NULL, /* handle of window receiving the message */
\r
818 0, /* lowest message to examine */
\r
819 0)) /* highest message to examine */
\r
822 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
823 // [HGM] navigate: switch between all windows with tab
\r
824 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
825 int i, currentElement = 0;
\r
827 // first determine what element of the chain we come from (if any)
\r
828 if(appData.icsActive) {
\r
829 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
830 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
832 if(engineOutputDialog && EngineOutputIsUp()) {
\r
833 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
834 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
836 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
837 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
839 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
840 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
841 if(msg.hwnd == e1) currentElement = 2; else
\r
842 if(msg.hwnd == e2) currentElement = 3; else
\r
843 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
844 if(msg.hwnd == mh) currentElement = 4; else
\r
845 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
846 if(msg.hwnd == hText) currentElement = 5; else
\r
847 if(msg.hwnd == hInput) currentElement = 6; else
\r
848 for (i = 0; i < N_BUTTONS; i++) {
\r
849 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
852 // determine where to go to
\r
853 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
855 currentElement = (currentElement + direction) % 7;
\r
856 switch(currentElement) {
\r
858 h = hwndMain; break; // passing this case always makes the loop exit
\r
860 h = buttonDesc[0].hwnd; break; // could be NULL
\r
862 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
865 if(!EngineOutputIsUp()) continue;
\r
868 if(!MoveHistoryIsUp()) continue;
\r
870 // case 6: // input to eval graph does not seem to get here!
\r
871 // if(!EvalGraphIsUp()) continue;
\r
872 // h = evalGraphDialog; break;
\r
874 if(!appData.icsActive) continue;
\r
878 if(!appData.icsActive) continue;
\r
884 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
885 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
888 continue; // this message now has been processed
\r
892 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
893 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
894 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
895 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
896 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
897 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
898 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
899 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
900 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
901 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
902 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
903 for(i=0; i<MAX_CHAT; i++)
\r
904 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
907 if(done) continue; // [HGM] chat: end patch
\r
908 TranslateMessage(&msg); /* Translates virtual key codes */
\r
909 DispatchMessage(&msg); /* Dispatches message to window */
\r
914 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
917 /*---------------------------------------------------------------------------*\
\r
919 * Initialization functions
\r
921 \*---------------------------------------------------------------------------*/
\r
925 { // update user logo if necessary
\r
926 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
928 if(appData.autoLogo) {
\r
929 curName = UserName();
\r
930 if(strcmp(curName, oldUserName)) {
\r
931 GetCurrentDirectory(MSG_SIZ, dir);
\r
932 SetCurrentDirectory(installDir);
\r
933 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
934 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
935 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
936 if(userLogo == NULL)
\r
937 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
938 SetCurrentDirectory(dir); /* return to prev directory */
\r
944 InitApplication(HINSTANCE hInstance)
\r
948 /* Fill in window class structure with parameters that describe the */
\r
951 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
952 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
953 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
954 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
955 wc.hInstance = hInstance; /* Owner of this class */
\r
956 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
957 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
958 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
959 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
960 wc.lpszClassName = szAppName; /* Name to register as */
\r
962 /* Register the window class and return success/failure code. */
\r
963 if (!RegisterClass(&wc)) return FALSE;
\r
965 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
966 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
968 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
969 wc.hInstance = hInstance;
\r
970 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
971 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
972 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
973 wc.lpszMenuName = NULL;
\r
974 wc.lpszClassName = szConsoleName;
\r
976 if (!RegisterClass(&wc)) return FALSE;
\r
981 /* Set by InitInstance, used by EnsureOnScreen */
\r
982 int screenHeight, screenWidth;
\r
985 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
987 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
988 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
989 if (*x > screenWidth - 32) *x = 0;
\r
990 if (*y > screenHeight - 32) *y = 0;
\r
991 if (*x < minX) *x = minX;
\r
992 if (*y < minY) *y = minY;
\r
996 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
998 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
999 GetCurrentDirectory(MSG_SIZ, dir);
\r
1000 SetCurrentDirectory(installDir);
\r
1001 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1002 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1004 if (cps->programLogo == NULL && appData.debugMode) {
\r
1005 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1007 } else if(appData.autoLogo) {
\r
1008 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1009 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1010 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1012 if(appData.directory[n] && appData.directory[n][0]) {
\r
1013 SetCurrentDirectory(appData.directory[n]);
\r
1014 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1017 SetCurrentDirectory(dir); /* return to prev directory */
\r
1023 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1024 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1026 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1027 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1028 liteBackTextureMode = appData.liteBackTextureMode;
\r
1030 if (liteBackTexture == NULL && appData.debugMode) {
\r
1031 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1035 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1036 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1037 darkBackTextureMode = appData.darkBackTextureMode;
\r
1039 if (darkBackTexture == NULL && appData.debugMode) {
\r
1040 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1046 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1048 HWND hwnd; /* Main window handle. */
\r
1050 WINDOWPLACEMENT wp;
\r
1053 hInst = hInstance; /* Store instance handle in our global variable */
\r
1054 programName = szAppName;
\r
1056 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1057 *filepart = NULLCHAR;
\r
1059 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1061 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1062 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1063 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1064 /* xboard, and older WinBoards, controlled the move sound with the
\r
1065 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1066 always turn the option on (so that the backend will call us),
\r
1067 then let the user turn the sound off by setting it to silence if
\r
1068 desired. To accommodate old winboard.ini files saved by old
\r
1069 versions of WinBoard, we also turn off the sound if the option
\r
1070 was initially set to false. [HGM] taken out of InitAppData */
\r
1071 if (!appData.ringBellAfterMoves) {
\r
1072 sounds[(int)SoundMove].name = strdup("");
\r
1073 appData.ringBellAfterMoves = TRUE;
\r
1075 if (appData.debugMode) {
\r
1076 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1077 setbuf(debugFP, NULL);
\r
1080 LoadLanguageFile(appData.language);
\r
1084 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1085 // InitEngineUCI( installDir, &second );
\r
1087 /* Create a main window for this application instance. */
\r
1088 hwnd = CreateWindow(szAppName, szTitle,
\r
1089 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1090 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1091 NULL, NULL, hInstance, NULL);
\r
1094 /* If window could not be created, return "failure" */
\r
1099 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1100 LoadLogo(&first, 0, FALSE);
\r
1101 LoadLogo(&second, 1, appData.icsActive);
\r
1105 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1106 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1107 iconCurrent = iconWhite;
\r
1108 InitDrawingColors();
\r
1109 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1110 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1111 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1112 /* Compute window size for each board size, and use the largest
\r
1113 size that fits on this screen as the default. */
\r
1114 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1115 if (boardSize == (BoardSize)-1 &&
\r
1116 winH <= screenHeight
\r
1117 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1118 && winW <= screenWidth) {
\r
1119 boardSize = (BoardSize)ibs;
\r
1123 InitDrawingSizes(boardSize, 0);
\r
1124 RecentEngineMenu(appData.recentEngineList);
\r
1126 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1128 /* [AS] Load textures if specified */
\r
1131 mysrandom( (unsigned) time(NULL) );
\r
1133 /* [AS] Restore layout */
\r
1134 if( wpMoveHistory.visible ) {
\r
1135 MoveHistoryPopUp();
\r
1138 if( wpEvalGraph.visible ) {
\r
1142 if( wpEngineOutput.visible ) {
\r
1143 EngineOutputPopUp();
\r
1146 /* Make the window visible; update its client area; and return "success" */
\r
1147 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1148 wp.length = sizeof(WINDOWPLACEMENT);
\r
1150 wp.showCmd = nCmdShow;
\r
1151 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1152 wp.rcNormalPosition.left = wpMain.x;
\r
1153 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1154 wp.rcNormalPosition.top = wpMain.y;
\r
1155 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1156 SetWindowPlacement(hwndMain, &wp);
\r
1158 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1160 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1161 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1163 if (hwndConsole) {
\r
1165 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1166 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1168 ShowWindow(hwndConsole, nCmdShow);
\r
1169 SetActiveWindow(hwndConsole);
\r
1171 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1172 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1181 HMENU hmenu = GetMenu(hwndMain);
\r
1183 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1184 MF_BYCOMMAND|((appData.icsActive &&
\r
1185 *appData.icsCommPort != NULLCHAR) ?
\r
1186 MF_ENABLED : MF_GRAYED));
\r
1187 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1188 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1189 MF_CHECKED : MF_UNCHECKED));
\r
1192 //---------------------------------------------------------------------------------------------------------
\r
1194 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1195 #define XBOARD FALSE
\r
1197 #define OPTCHAR "/"
\r
1198 #define SEPCHAR "="
\r
1199 #define TOPLEVEL 0
\r
1203 // front-end part of option handling
\r
1206 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1208 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1209 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1212 lf->lfEscapement = 0;
\r
1213 lf->lfOrientation = 0;
\r
1214 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1215 lf->lfItalic = mfp->italic;
\r
1216 lf->lfUnderline = mfp->underline;
\r
1217 lf->lfStrikeOut = mfp->strikeout;
\r
1218 lf->lfCharSet = mfp->charset;
\r
1219 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1220 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1221 lf->lfQuality = DEFAULT_QUALITY;
\r
1222 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1223 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1227 CreateFontInMF(MyFont *mf)
\r
1229 LFfromMFP(&mf->lf, &mf->mfp);
\r
1230 if (mf->hf) DeleteObject(mf->hf);
\r
1231 mf->hf = CreateFontIndirect(&mf->lf);
\r
1234 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1236 colorVariable[] = {
\r
1237 &whitePieceColor,
\r
1238 &blackPieceColor,
\r
1239 &lightSquareColor,
\r
1240 &darkSquareColor,
\r
1241 &highlightSquareColor,
\r
1242 &premoveHighlightColor,
\r
1244 &consoleBackgroundColor,
\r
1245 &appData.fontForeColorWhite,
\r
1246 &appData.fontBackColorWhite,
\r
1247 &appData.fontForeColorBlack,
\r
1248 &appData.fontBackColorBlack,
\r
1249 &appData.evalHistColorWhite,
\r
1250 &appData.evalHistColorBlack,
\r
1251 &appData.highlightArrowColor,
\r
1254 /* Command line font name parser. NULL name means do nothing.
\r
1255 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1256 For backward compatibility, syntax without the colon is also
\r
1257 accepted, but font names with digits in them won't work in that case.
\r
1260 ParseFontName(char *name, MyFontParams *mfp)
\r
1263 if (name == NULL) return;
\r
1265 q = strchr(p, ':');
\r
1267 if (q - p >= sizeof(mfp->faceName))
\r
1268 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1269 memcpy(mfp->faceName, p, q - p);
\r
1270 mfp->faceName[q - p] = NULLCHAR;
\r
1273 q = mfp->faceName;
\r
1274 while (*p && !isdigit(*p)) {
\r
1276 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1277 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1279 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1282 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1283 mfp->pointSize = (float) atof(p);
\r
1284 mfp->bold = (strchr(p, 'b') != NULL);
\r
1285 mfp->italic = (strchr(p, 'i') != NULL);
\r
1286 mfp->underline = (strchr(p, 'u') != NULL);
\r
1287 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1288 mfp->charset = DEFAULT_CHARSET;
\r
1289 q = strchr(p, 'c');
\r
1291 mfp->charset = (BYTE) atoi(q+1);
\r
1295 ParseFont(char *name, int number)
\r
1296 { // wrapper to shield back-end from 'font'
\r
1297 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1302 { // in WB we have a 2D array of fonts; this initializes their description
\r
1304 /* Point font array elements to structures and
\r
1305 parse default font names */
\r
1306 for (i=0; i<NUM_FONTS; i++) {
\r
1307 for (j=0; j<NUM_SIZES; j++) {
\r
1308 font[j][i] = &fontRec[j][i];
\r
1309 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1316 { // here we create the actual fonts from the selected descriptions
\r
1318 for (i=0; i<NUM_FONTS; i++) {
\r
1319 for (j=0; j<NUM_SIZES; j++) {
\r
1320 CreateFontInMF(font[j][i]);
\r
1324 /* Color name parser.
\r
1325 X version accepts X color names, but this one
\r
1326 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1328 ParseColorName(char *name)
\r
1330 int red, green, blue, count;
\r
1331 char buf[MSG_SIZ];
\r
1333 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1335 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1336 &red, &green, &blue);
\r
1339 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1340 DisplayError(buf, 0);
\r
1341 return RGB(0, 0, 0);
\r
1343 return PALETTERGB(red, green, blue);
\r
1347 ParseColor(int n, char *name)
\r
1348 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1349 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1353 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1355 char *e = argValue;
\r
1359 if (*e == 'b') eff |= CFE_BOLD;
\r
1360 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1361 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1362 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1363 else if (*e == '#' || isdigit(*e)) break;
\r
1367 *color = ParseColorName(e);
\r
1371 ParseTextAttribs(ColorClass cc, char *s)
\r
1372 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1373 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1374 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1378 ParseBoardSize(void *addr, char *name)
\r
1379 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1380 BoardSize bs = SizeTiny;
\r
1381 while (sizeInfo[bs].name != NULL) {
\r
1382 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1383 *(BoardSize *)addr = bs;
\r
1388 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1393 { // [HGM] import name from appData first
\r
1396 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1397 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1398 textAttribs[cc].sound.data = NULL;
\r
1399 MyLoadSound(&textAttribs[cc].sound);
\r
1401 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1402 textAttribs[cc].sound.name = strdup("");
\r
1403 textAttribs[cc].sound.data = NULL;
\r
1405 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1406 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1407 sounds[sc].data = NULL;
\r
1408 MyLoadSound(&sounds[sc]);
\r
1413 SetCommPortDefaults()
\r
1415 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1416 dcb.DCBlength = sizeof(DCB);
\r
1417 dcb.BaudRate = 9600;
\r
1418 dcb.fBinary = TRUE;
\r
1419 dcb.fParity = FALSE;
\r
1420 dcb.fOutxCtsFlow = FALSE;
\r
1421 dcb.fOutxDsrFlow = FALSE;
\r
1422 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1423 dcb.fDsrSensitivity = FALSE;
\r
1424 dcb.fTXContinueOnXoff = TRUE;
\r
1425 dcb.fOutX = FALSE;
\r
1427 dcb.fNull = FALSE;
\r
1428 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1429 dcb.fAbortOnError = FALSE;
\r
1431 dcb.Parity = SPACEPARITY;
\r
1432 dcb.StopBits = ONESTOPBIT;
\r
1435 // [HGM] args: these three cases taken out to stay in front-end
\r
1437 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1438 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1439 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1440 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1442 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1443 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1444 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1445 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1446 ad->argName, mfp->faceName, mfp->pointSize,
\r
1447 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1448 mfp->bold ? "b" : "",
\r
1449 mfp->italic ? "i" : "",
\r
1450 mfp->underline ? "u" : "",
\r
1451 mfp->strikeout ? "s" : "",
\r
1452 (int)mfp->charset);
\r
1458 { // [HGM] copy the names from the internal WB variables to appData
\r
1461 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1462 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1463 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1464 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1468 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1469 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1470 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1471 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1472 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1473 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1474 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1475 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1476 (ta->effects) ? " " : "",
\r
1477 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1481 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1482 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1483 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1484 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1485 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1489 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1490 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1491 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1495 ParseCommPortSettings(char *s)
\r
1496 { // wrapper to keep dcb from back-end
\r
1497 ParseCommSettings(s, &dcb);
\r
1502 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1503 GetActualPlacement(hwndMain, &wpMain);
\r
1504 GetActualPlacement(hwndConsole, &wpConsole);
\r
1505 GetActualPlacement(commentDialog, &wpComment);
\r
1506 GetActualPlacement(editTagsDialog, &wpTags);
\r
1507 GetActualPlacement(gameListDialog, &wpGameList);
\r
1508 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1509 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1510 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1514 PrintCommPortSettings(FILE *f, char *name)
\r
1515 { // wrapper to shield back-end from DCB
\r
1516 PrintCommSettings(f, name, &dcb);
\r
1520 MySearchPath(char *installDir, char *name, char *fullname)
\r
1522 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1523 if(name[0]== '%') {
\r
1524 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1525 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1526 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1527 *strchr(buf, '%') = 0;
\r
1528 strcat(fullname, getenv(buf));
\r
1529 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1531 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1532 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1533 return (int) strlen(fullname);
\r
1535 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1539 MyGetFullPathName(char *name, char *fullname)
\r
1542 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1547 { // [HGM] args: allows testing if main window is realized from back-end
\r
1548 return hwndMain != NULL;
\r
1552 PopUpStartupDialog()
\r
1556 LoadLanguageFile(appData.language);
\r
1557 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1558 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1559 FreeProcInstance(lpProc);
\r
1562 /*---------------------------------------------------------------------------*\
\r
1564 * GDI board drawing routines
\r
1566 \*---------------------------------------------------------------------------*/
\r
1568 /* [AS] Draw square using background texture */
\r
1569 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1574 return; /* Should never happen! */
\r
1577 SetGraphicsMode( dst, GM_ADVANCED );
\r
1584 /* X reflection */
\r
1589 x.eDx = (FLOAT) dw + dx - 1;
\r
1592 SetWorldTransform( dst, &x );
\r
1595 /* Y reflection */
\r
1601 x.eDy = (FLOAT) dh + dy - 1;
\r
1603 SetWorldTransform( dst, &x );
\r
1611 x.eDx = (FLOAT) dx;
\r
1612 x.eDy = (FLOAT) dy;
\r
1615 SetWorldTransform( dst, &x );
\r
1619 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1627 SetWorldTransform( dst, &x );
\r
1629 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1632 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1634 PM_WP = (int) WhitePawn,
\r
1635 PM_WN = (int) WhiteKnight,
\r
1636 PM_WB = (int) WhiteBishop,
\r
1637 PM_WR = (int) WhiteRook,
\r
1638 PM_WQ = (int) WhiteQueen,
\r
1639 PM_WF = (int) WhiteFerz,
\r
1640 PM_WW = (int) WhiteWazir,
\r
1641 PM_WE = (int) WhiteAlfil,
\r
1642 PM_WM = (int) WhiteMan,
\r
1643 PM_WO = (int) WhiteCannon,
\r
1644 PM_WU = (int) WhiteUnicorn,
\r
1645 PM_WH = (int) WhiteNightrider,
\r
1646 PM_WA = (int) WhiteAngel,
\r
1647 PM_WC = (int) WhiteMarshall,
\r
1648 PM_WAB = (int) WhiteCardinal,
\r
1649 PM_WD = (int) WhiteDragon,
\r
1650 PM_WL = (int) WhiteLance,
\r
1651 PM_WS = (int) WhiteCobra,
\r
1652 PM_WV = (int) WhiteFalcon,
\r
1653 PM_WSG = (int) WhiteSilver,
\r
1654 PM_WG = (int) WhiteGrasshopper,
\r
1655 PM_WK = (int) WhiteKing,
\r
1656 PM_BP = (int) BlackPawn,
\r
1657 PM_BN = (int) BlackKnight,
\r
1658 PM_BB = (int) BlackBishop,
\r
1659 PM_BR = (int) BlackRook,
\r
1660 PM_BQ = (int) BlackQueen,
\r
1661 PM_BF = (int) BlackFerz,
\r
1662 PM_BW = (int) BlackWazir,
\r
1663 PM_BE = (int) BlackAlfil,
\r
1664 PM_BM = (int) BlackMan,
\r
1665 PM_BO = (int) BlackCannon,
\r
1666 PM_BU = (int) BlackUnicorn,
\r
1667 PM_BH = (int) BlackNightrider,
\r
1668 PM_BA = (int) BlackAngel,
\r
1669 PM_BC = (int) BlackMarshall,
\r
1670 PM_BG = (int) BlackGrasshopper,
\r
1671 PM_BAB = (int) BlackCardinal,
\r
1672 PM_BD = (int) BlackDragon,
\r
1673 PM_BL = (int) BlackLance,
\r
1674 PM_BS = (int) BlackCobra,
\r
1675 PM_BV = (int) BlackFalcon,
\r
1676 PM_BSG = (int) BlackSilver,
\r
1677 PM_BK = (int) BlackKing
\r
1680 static HFONT hPieceFont = NULL;
\r
1681 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1682 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1683 static int fontBitmapSquareSize = 0;
\r
1684 static char pieceToFontChar[(int) EmptySquare] =
\r
1685 { 'p', 'n', 'b', 'r', 'q',
\r
1686 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1687 'k', 'o', 'm', 'v', 't', 'w',
\r
1688 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1691 extern BOOL SetCharTable( char *table, const char * map );
\r
1692 /* [HGM] moved to backend.c */
\r
1694 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1697 BYTE r1 = GetRValue( color );
\r
1698 BYTE g1 = GetGValue( color );
\r
1699 BYTE b1 = GetBValue( color );
\r
1705 /* Create a uniform background first */
\r
1706 hbrush = CreateSolidBrush( color );
\r
1707 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1708 FillRect( hdc, &rc, hbrush );
\r
1709 DeleteObject( hbrush );
\r
1712 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1713 int steps = squareSize / 2;
\r
1716 for( i=0; i<steps; i++ ) {
\r
1717 BYTE r = r1 - (r1-r2) * i / steps;
\r
1718 BYTE g = g1 - (g1-g2) * i / steps;
\r
1719 BYTE b = b1 - (b1-b2) * i / steps;
\r
1721 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1722 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1723 FillRect( hdc, &rc, hbrush );
\r
1724 DeleteObject(hbrush);
\r
1727 else if( mode == 2 ) {
\r
1728 /* Diagonal gradient, good more or less for every piece */
\r
1729 POINT triangle[3];
\r
1730 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1731 HBRUSH hbrush_old;
\r
1732 int steps = squareSize;
\r
1735 triangle[0].x = squareSize - steps;
\r
1736 triangle[0].y = squareSize;
\r
1737 triangle[1].x = squareSize;
\r
1738 triangle[1].y = squareSize;
\r
1739 triangle[2].x = squareSize;
\r
1740 triangle[2].y = squareSize - steps;
\r
1742 for( i=0; i<steps; i++ ) {
\r
1743 BYTE r = r1 - (r1-r2) * i / steps;
\r
1744 BYTE g = g1 - (g1-g2) * i / steps;
\r
1745 BYTE b = b1 - (b1-b2) * i / steps;
\r
1747 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1748 hbrush_old = SelectObject( hdc, hbrush );
\r
1749 Polygon( hdc, triangle, 3 );
\r
1750 SelectObject( hdc, hbrush_old );
\r
1751 DeleteObject(hbrush);
\r
1756 SelectObject( hdc, hpen );
\r
1761 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1762 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1763 piece: follow the steps as explained below.
\r
1765 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1769 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1773 int backColor = whitePieceColor;
\r
1774 int foreColor = blackPieceColor;
\r
1776 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1777 backColor = appData.fontBackColorWhite;
\r
1778 foreColor = appData.fontForeColorWhite;
\r
1780 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1781 backColor = appData.fontBackColorBlack;
\r
1782 foreColor = appData.fontForeColorBlack;
\r
1786 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1788 hbm_old = SelectObject( hdc, hbm );
\r
1792 rc.right = squareSize;
\r
1793 rc.bottom = squareSize;
\r
1795 /* Step 1: background is now black */
\r
1796 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1798 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1800 pt.x = (squareSize - sz.cx) / 2;
\r
1801 pt.y = (squareSize - sz.cy) / 2;
\r
1803 SetBkMode( hdc, TRANSPARENT );
\r
1804 SetTextColor( hdc, chroma );
\r
1805 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1806 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1808 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1809 /* Step 3: the area outside the piece is filled with white */
\r
1810 // FloodFill( hdc, 0, 0, chroma );
\r
1811 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1812 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1813 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1814 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1815 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1817 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1818 but if the start point is not inside the piece we're lost!
\r
1819 There should be a better way to do this... if we could create a region or path
\r
1820 from the fill operation we would be fine for example.
\r
1822 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1823 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1825 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1826 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1827 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1829 SelectObject( dc2, bm2 );
\r
1830 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1831 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1832 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1833 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1834 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1837 DeleteObject( bm2 );
\r
1840 SetTextColor( hdc, 0 );
\r
1842 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1843 draw the piece again in black for safety.
\r
1845 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1847 SelectObject( hdc, hbm_old );
\r
1849 if( hPieceMask[index] != NULL ) {
\r
1850 DeleteObject( hPieceMask[index] );
\r
1853 hPieceMask[index] = hbm;
\r
1856 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1858 SelectObject( hdc, hbm );
\r
1861 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1862 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1863 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1865 SelectObject( dc1, hPieceMask[index] );
\r
1866 SelectObject( dc2, bm2 );
\r
1867 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1868 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1871 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1872 the piece background and deletes (makes transparent) the rest.
\r
1873 Thanks to that mask, we are free to paint the background with the greates
\r
1874 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1875 We use this, to make gradients and give the pieces a "roundish" look.
\r
1877 SetPieceBackground( hdc, backColor, 2 );
\r
1878 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1882 DeleteObject( bm2 );
\r
1885 SetTextColor( hdc, foreColor );
\r
1886 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1888 SelectObject( hdc, hbm_old );
\r
1890 if( hPieceFace[index] != NULL ) {
\r
1891 DeleteObject( hPieceFace[index] );
\r
1894 hPieceFace[index] = hbm;
\r
1897 static int TranslatePieceToFontPiece( int piece )
\r
1927 case BlackMarshall:
\r
1931 case BlackNightrider:
\r
1937 case BlackUnicorn:
\r
1941 case BlackGrasshopper:
\r
1953 case BlackCardinal:
\r
1960 case WhiteMarshall:
\r
1964 case WhiteNightrider:
\r
1970 case WhiteUnicorn:
\r
1974 case WhiteGrasshopper:
\r
1986 case WhiteCardinal:
\r
1995 void CreatePiecesFromFont()
\r
1998 HDC hdc_window = NULL;
\r
2004 if( fontBitmapSquareSize < 0 ) {
\r
2005 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2009 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2010 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2011 fontBitmapSquareSize = -1;
\r
2015 if( fontBitmapSquareSize != squareSize ) {
\r
2016 hdc_window = GetDC( hwndMain );
\r
2017 hdc = CreateCompatibleDC( hdc_window );
\r
2019 if( hPieceFont != NULL ) {
\r
2020 DeleteObject( hPieceFont );
\r
2023 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2024 hPieceMask[i] = NULL;
\r
2025 hPieceFace[i] = NULL;
\r
2031 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2032 fontHeight = appData.fontPieceSize;
\r
2035 fontHeight = (fontHeight * squareSize) / 100;
\r
2037 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2039 lf.lfEscapement = 0;
\r
2040 lf.lfOrientation = 0;
\r
2041 lf.lfWeight = FW_NORMAL;
\r
2043 lf.lfUnderline = 0;
\r
2044 lf.lfStrikeOut = 0;
\r
2045 lf.lfCharSet = DEFAULT_CHARSET;
\r
2046 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2047 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2048 lf.lfQuality = PROOF_QUALITY;
\r
2049 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2050 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2051 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2053 hPieceFont = CreateFontIndirect( &lf );
\r
2055 if( hPieceFont == NULL ) {
\r
2056 fontBitmapSquareSize = -2;
\r
2059 /* Setup font-to-piece character table */
\r
2060 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2061 /* No (or wrong) global settings, try to detect the font */
\r
2062 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2064 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2066 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2067 /* DiagramTT* family */
\r
2068 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2070 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2071 /* Fairy symbols */
\r
2072 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2074 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2075 /* Good Companion (Some characters get warped as literal :-( */
\r
2076 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2077 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2078 SetCharTable(pieceToFontChar, s);
\r
2081 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2082 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2086 /* Create bitmaps */
\r
2087 hfont_old = SelectObject( hdc, hPieceFont );
\r
2088 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2089 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2090 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2092 SelectObject( hdc, hfont_old );
\r
2094 fontBitmapSquareSize = squareSize;
\r
2098 if( hdc != NULL ) {
\r
2102 if( hdc_window != NULL ) {
\r
2103 ReleaseDC( hwndMain, hdc_window );
\r
2108 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2112 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2113 if (gameInfo.event &&
\r
2114 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2115 strcmp(name, "k80s") == 0) {
\r
2116 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2118 return LoadBitmap(hinst, name);
\r
2122 /* Insert a color into the program's logical palette
\r
2123 structure. This code assumes the given color is
\r
2124 the result of the RGB or PALETTERGB macro, and it
\r
2125 knows how those macros work (which is documented).
\r
2128 InsertInPalette(COLORREF color)
\r
2130 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2132 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2133 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2134 pLogPal->palNumEntries--;
\r
2138 pe->peFlags = (char) 0;
\r
2139 pe->peRed = (char) (0xFF & color);
\r
2140 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2141 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2147 InitDrawingColors()
\r
2149 if (pLogPal == NULL) {
\r
2150 /* Allocate enough memory for a logical palette with
\r
2151 * PALETTESIZE entries and set the size and version fields
\r
2152 * of the logical palette structure.
\r
2154 pLogPal = (NPLOGPALETTE)
\r
2155 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2156 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2157 pLogPal->palVersion = 0x300;
\r
2159 pLogPal->palNumEntries = 0;
\r
2161 InsertInPalette(lightSquareColor);
\r
2162 InsertInPalette(darkSquareColor);
\r
2163 InsertInPalette(whitePieceColor);
\r
2164 InsertInPalette(blackPieceColor);
\r
2165 InsertInPalette(highlightSquareColor);
\r
2166 InsertInPalette(premoveHighlightColor);
\r
2168 /* create a logical color palette according the information
\r
2169 * in the LOGPALETTE structure.
\r
2171 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2173 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2174 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2175 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2176 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2177 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2178 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2179 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2180 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2181 /* [AS] Force rendering of the font-based pieces */
\r
2182 if( fontBitmapSquareSize > 0 ) {
\r
2183 fontBitmapSquareSize = 0;
\r
2189 BoardWidth(int boardSize, int n)
\r
2190 { /* [HGM] argument n added to allow different width and height */
\r
2191 int lineGap = sizeInfo[boardSize].lineGap;
\r
2193 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2194 lineGap = appData.overrideLineGap;
\r
2197 return (n + 1) * lineGap +
\r
2198 n * sizeInfo[boardSize].squareSize;
\r
2201 /* Respond to board resize by dragging edge */
\r
2203 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2205 BoardSize newSize = NUM_SIZES - 1;
\r
2206 static int recurse = 0;
\r
2207 if (IsIconic(hwndMain)) return;
\r
2208 if (recurse > 0) return;
\r
2210 while (newSize > 0) {
\r
2211 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2212 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2213 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2216 boardSize = newSize;
\r
2217 InitDrawingSizes(boardSize, flags);
\r
2222 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2225 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2227 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2228 ChessSquare piece;
\r
2229 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2231 SIZE clockSize, messageSize;
\r
2233 char buf[MSG_SIZ];
\r
2235 HMENU hmenu = GetMenu(hwndMain);
\r
2236 RECT crect, wrect, oldRect;
\r
2238 LOGBRUSH logbrush;
\r
2239 VariantClass v = gameInfo.variant;
\r
2241 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2242 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2244 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2245 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2246 oldBoardSize = boardSize;
\r
2248 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2249 { // correct board size to one where built-in pieces exist
\r
2250 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2251 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2252 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2253 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2254 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {
\r
2255 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2256 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2257 boardSize = SizeMiddling;
\r
2260 if(!appData.useFont && boardSize == SizePetite && (v == VariantShogi || v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2262 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2263 oldRect.top = wpMain.y;
\r
2264 oldRect.right = wpMain.x + wpMain.width;
\r
2265 oldRect.bottom = wpMain.y + wpMain.height;
\r
2267 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2268 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2269 squareSize = sizeInfo[boardSize].squareSize;
\r
2270 lineGap = sizeInfo[boardSize].lineGap;
\r
2271 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2273 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2274 lineGap = appData.overrideLineGap;
\r
2277 if (tinyLayout != oldTinyLayout) {
\r
2278 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2280 style &= ~WS_SYSMENU;
\r
2281 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2282 "&Minimize\tCtrl+F4");
\r
2284 style |= WS_SYSMENU;
\r
2285 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2287 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2289 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2290 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2291 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2293 DrawMenuBar(hwndMain);
\r
2296 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2297 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2299 /* Get text area sizes */
\r
2300 hdc = GetDC(hwndMain);
\r
2301 if (appData.clockMode) {
\r
2302 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2304 snprintf(buf, MSG_SIZ, _("White"));
\r
2306 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2307 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2308 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2309 str = _("We only care about the height here");
\r
2310 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2311 SelectObject(hdc, oldFont);
\r
2312 ReleaseDC(hwndMain, hdc);
\r
2314 /* Compute where everything goes */
\r
2315 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2316 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2317 logoHeight = 2*clockSize.cy;
\r
2318 leftLogoRect.left = OUTER_MARGIN;
\r
2319 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2320 leftLogoRect.top = OUTER_MARGIN;
\r
2321 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2323 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2324 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2325 rightLogoRect.top = OUTER_MARGIN;
\r
2326 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2329 whiteRect.left = leftLogoRect.right;
\r
2330 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2331 whiteRect.top = OUTER_MARGIN;
\r
2332 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2334 blackRect.right = rightLogoRect.left;
\r
2335 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2336 blackRect.top = whiteRect.top;
\r
2337 blackRect.bottom = whiteRect.bottom;
\r
2339 whiteRect.left = OUTER_MARGIN;
\r
2340 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2341 whiteRect.top = OUTER_MARGIN;
\r
2342 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2344 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2345 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2346 blackRect.top = whiteRect.top;
\r
2347 blackRect.bottom = whiteRect.bottom;
\r
2349 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2352 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2353 if (appData.showButtonBar) {
\r
2354 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2355 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2357 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2359 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2360 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2362 boardRect.left = OUTER_MARGIN;
\r
2363 boardRect.right = boardRect.left + boardWidth;
\r
2364 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2365 boardRect.bottom = boardRect.top + boardHeight;
\r
2367 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2368 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2369 oldTinyLayout = tinyLayout;
\r
2370 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2371 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2372 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2373 winW *= 1 + twoBoards;
\r
2374 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2375 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2376 wpMain.height = winH; // without disturbing window attachments
\r
2377 GetWindowRect(hwndMain, &wrect);
\r
2378 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2379 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2381 // [HGM] placement: let attached windows follow size change.
\r
2382 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2383 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2384 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2385 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2386 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2388 /* compensate if menu bar wrapped */
\r
2389 GetClientRect(hwndMain, &crect);
\r
2390 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2391 wpMain.height += offby;
\r
2393 case WMSZ_TOPLEFT:
\r
2394 SetWindowPos(hwndMain, NULL,
\r
2395 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2396 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2399 case WMSZ_TOPRIGHT:
\r
2401 SetWindowPos(hwndMain, NULL,
\r
2402 wrect.left, wrect.bottom - wpMain.height,
\r
2403 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2406 case WMSZ_BOTTOMLEFT:
\r
2408 SetWindowPos(hwndMain, NULL,
\r
2409 wrect.right - wpMain.width, wrect.top,
\r
2410 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2413 case WMSZ_BOTTOMRIGHT:
\r
2417 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2418 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2423 for (i = 0; i < N_BUTTONS; i++) {
\r
2424 if (buttonDesc[i].hwnd != NULL) {
\r
2425 DestroyWindow(buttonDesc[i].hwnd);
\r
2426 buttonDesc[i].hwnd = NULL;
\r
2428 if (appData.showButtonBar) {
\r
2429 buttonDesc[i].hwnd =
\r
2430 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2431 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2432 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2433 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2434 (HMENU) buttonDesc[i].id,
\r
2435 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2437 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2438 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2439 MAKELPARAM(FALSE, 0));
\r
2441 if (buttonDesc[i].id == IDM_Pause)
\r
2442 hwndPause = buttonDesc[i].hwnd;
\r
2443 buttonDesc[i].wndproc = (WNDPROC)
\r
2444 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2447 if (gridPen != NULL) DeleteObject(gridPen);
\r
2448 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2449 if (premovePen != NULL) DeleteObject(premovePen);
\r
2450 if (lineGap != 0) {
\r
2451 logbrush.lbStyle = BS_SOLID;
\r
2452 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2454 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2455 lineGap, &logbrush, 0, NULL);
\r
2456 logbrush.lbColor = highlightSquareColor;
\r
2458 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2459 lineGap, &logbrush, 0, NULL);
\r
2461 logbrush.lbColor = premoveHighlightColor;
\r
2463 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2464 lineGap, &logbrush, 0, NULL);
\r
2466 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2467 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2468 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2469 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2470 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2471 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2472 BOARD_WIDTH * (squareSize + lineGap);
\r
2473 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2475 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2476 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2477 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2478 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2479 lineGap / 2 + (i * (squareSize + lineGap));
\r
2480 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2481 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2482 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2486 /* [HGM] Licensing requirement */
\r
2488 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2491 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2493 GothicPopUp( "", VariantNormal);
\r
2496 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2498 /* Load piece bitmaps for this board size */
\r
2499 for (i=0; i<=2; i++) {
\r
2500 for (piece = WhitePawn;
\r
2501 (int) piece < (int) BlackPawn;
\r
2502 piece = (ChessSquare) ((int) piece + 1)) {
\r
2503 if (pieceBitmap[i][piece] != NULL)
\r
2504 DeleteObject(pieceBitmap[i][piece]);
\r
2508 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2509 // Orthodox Chess pieces
\r
2510 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2511 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2512 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2513 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2514 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2515 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2516 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2517 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2518 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2519 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2520 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2521 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2522 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2523 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2524 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2525 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2526 // in Shogi, Hijack the unused Queen for Lance
\r
2527 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2528 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2529 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2531 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2532 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2533 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2536 if(squareSize <= 72 && squareSize >= 33) {
\r
2537 /* A & C are available in most sizes now */
\r
2538 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2539 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2540 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2541 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2542 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2543 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2544 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2545 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2546 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2547 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2548 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2549 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2550 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2551 } else { // Smirf-like
\r
2552 if(gameInfo.variant == VariantSChess) {
\r
2553 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2554 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2555 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2557 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2558 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2559 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2562 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2563 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2564 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2565 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2566 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2567 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2568 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2569 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2570 } else { // WinBoard standard
\r
2571 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2572 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2573 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2578 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2579 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2580 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2581 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2582 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2583 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2584 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2585 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2586 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2587 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2588 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2589 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2590 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2591 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2592 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2593 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2594 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2595 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2596 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2597 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2598 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2599 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2600 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2601 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2602 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2603 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2604 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2605 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2606 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2607 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2608 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2610 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2611 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2612 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2613 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2614 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2617 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2618 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2619 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2620 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2621 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2622 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2624 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2625 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2626 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2627 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2628 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2629 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2630 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2631 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2632 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2633 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2634 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2635 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2638 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2639 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2640 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2641 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2642 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2643 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2644 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2645 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2646 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2647 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2648 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2649 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2650 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2651 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2652 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2656 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2657 /* special Shogi support in this size */
\r
2658 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2659 for (piece = WhitePawn;
\r
2660 (int) piece < (int) BlackPawn;
\r
2661 piece = (ChessSquare) ((int) piece + 1)) {
\r
2662 if (pieceBitmap[i][piece] != NULL)
\r
2663 DeleteObject(pieceBitmap[i][piece]);
\r
2666 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2667 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2668 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2669 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2670 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2671 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2672 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2673 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2674 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2675 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2676 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2677 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2678 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2679 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2680 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2681 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2682 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2683 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2684 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2685 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2686 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2687 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2688 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2689 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2690 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2691 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2692 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2693 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2694 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2695 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2696 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2697 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2698 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2699 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2700 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2701 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2702 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2703 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2704 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2705 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2706 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2707 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2713 PieceBitmap(ChessSquare p, int kind)
\r
2715 if ((int) p >= (int) BlackPawn)
\r
2716 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2718 return pieceBitmap[kind][(int) p];
\r
2721 /***************************************************************/
\r
2723 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2724 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2726 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2727 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2731 SquareToPos(int row, int column, int * x, int * y)
\r
2734 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2735 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2737 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2738 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2743 DrawCoordsOnDC(HDC hdc)
\r
2745 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2746 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2747 char str[2] = { NULLCHAR, NULLCHAR };
\r
2748 int oldMode, oldAlign, x, y, start, i;
\r
2752 if (!appData.showCoords)
\r
2755 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2757 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2758 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2759 oldAlign = GetTextAlign(hdc);
\r
2760 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2762 y = boardRect.top + lineGap;
\r
2763 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2765 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2766 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2767 str[0] = files[start + i];
\r
2768 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2769 y += squareSize + lineGap;
\r
2772 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2774 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2775 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2776 str[0] = ranks[start + i];
\r
2777 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2778 x += squareSize + lineGap;
\r
2781 SelectObject(hdc, oldBrush);
\r
2782 SetBkMode(hdc, oldMode);
\r
2783 SetTextAlign(hdc, oldAlign);
\r
2784 SelectObject(hdc, oldFont);
\r
2788 DrawGridOnDC(HDC hdc)
\r
2792 if (lineGap != 0) {
\r
2793 oldPen = SelectObject(hdc, gridPen);
\r
2794 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2795 SelectObject(hdc, oldPen);
\r
2799 #define HIGHLIGHT_PEN 0
\r
2800 #define PREMOVE_PEN 1
\r
2803 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2806 HPEN oldPen, hPen;
\r
2807 if (lineGap == 0) return;
\r
2809 x1 = boardRect.left +
\r
2810 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2811 y1 = boardRect.top +
\r
2812 lineGap/2 + y * (squareSize + lineGap);
\r
2814 x1 = boardRect.left +
\r
2815 lineGap/2 + x * (squareSize + lineGap);
\r
2816 y1 = boardRect.top +
\r
2817 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2819 hPen = pen ? premovePen : highlightPen;
\r
2820 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2821 MoveToEx(hdc, x1, y1, NULL);
\r
2822 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2823 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2824 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2825 LineTo(hdc, x1, y1);
\r
2826 SelectObject(hdc, oldPen);
\r
2830 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2833 for (i=0; i<2; i++) {
\r
2834 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2835 DrawHighlightOnDC(hdc, TRUE,
\r
2836 h->sq[i].x, h->sq[i].y,
\r
2841 /* Note: sqcolor is used only in monoMode */
\r
2842 /* Note that this code is largely duplicated in woptions.c,
\r
2843 function DrawSampleSquare, so that needs to be updated too */
\r
2845 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2847 HBITMAP oldBitmap;
\r
2851 if (appData.blindfold) return;
\r
2853 /* [AS] Use font-based pieces if needed */
\r
2854 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2855 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2856 CreatePiecesFromFont();
\r
2858 if( fontBitmapSquareSize == squareSize ) {
\r
2859 int index = TranslatePieceToFontPiece(piece);
\r
2861 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2863 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2864 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2868 squareSize, squareSize,
\r
2873 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2875 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2876 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2880 squareSize, squareSize,
\r
2889 if (appData.monoMode) {
\r
2890 SelectObject(tmphdc, PieceBitmap(piece,
\r
2891 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2892 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2893 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2895 tmpSize = squareSize;
\r
2897 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2898 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2899 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2900 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2901 x += (squareSize - minorSize)>>1;
\r
2902 y += squareSize - minorSize - 2;
\r
2903 tmpSize = minorSize;
\r
2905 if (color || appData.allWhite ) {
\r
2906 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2908 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2909 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2910 if(appData.upsideDown && color==flipView)
\r
2911 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2913 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2914 /* Use black for outline of white pieces */
\r
2915 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2916 if(appData.upsideDown && color==flipView)
\r
2917 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2919 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2921 /* Use square color for details of black pieces */
\r
2922 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2923 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2924 if(appData.upsideDown && !flipView)
\r
2925 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2927 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2929 SelectObject(hdc, oldBrush);
\r
2930 SelectObject(tmphdc, oldBitmap);
\r
2934 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2935 int GetBackTextureMode( int algo )
\r
2937 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2941 case BACK_TEXTURE_MODE_PLAIN:
\r
2942 result = 1; /* Always use identity map */
\r
2944 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2945 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2953 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2954 to handle redraws cleanly (as random numbers would always be different).
\r
2956 VOID RebuildTextureSquareInfo()
\r
2966 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2968 if( liteBackTexture != NULL ) {
\r
2969 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2970 lite_w = bi.bmWidth;
\r
2971 lite_h = bi.bmHeight;
\r
2975 if( darkBackTexture != NULL ) {
\r
2976 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2977 dark_w = bi.bmWidth;
\r
2978 dark_h = bi.bmHeight;
\r
2982 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2983 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2984 if( (col + row) & 1 ) {
\r
2986 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2987 if( lite_w >= squareSize*BOARD_WIDTH )
\r
2988 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
2990 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2991 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
2992 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
2994 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2995 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3000 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3001 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3002 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3004 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3005 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3006 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3008 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3009 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3016 /* [AS] Arrow highlighting support */
\r
3018 static double A_WIDTH = 5; /* Width of arrow body */
\r
3020 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3021 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3023 static double Sqr( double x )
\r
3028 static int Round( double x )
\r
3030 return (int) (x + 0.5);
\r
3033 /* Draw an arrow between two points using current settings */
\r
3034 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3037 double dx, dy, j, k, x, y;
\r
3039 if( d_x == s_x ) {
\r
3040 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3042 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3045 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3046 arrow[1].y = d_y - h;
\r
3048 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3049 arrow[2].y = d_y - h;
\r
3054 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3055 arrow[5].y = d_y - h;
\r
3057 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3058 arrow[4].y = d_y - h;
\r
3060 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3063 else if( d_y == s_y ) {
\r
3064 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3067 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3069 arrow[1].x = d_x - w;
\r
3070 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3072 arrow[2].x = d_x - w;
\r
3073 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3078 arrow[5].x = d_x - w;
\r
3079 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3081 arrow[4].x = d_x - w;
\r
3082 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3085 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3088 /* [AS] Needed a lot of paper for this! :-) */
\r
3089 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3090 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3092 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3094 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3099 arrow[0].x = Round(x - j);
\r
3100 arrow[0].y = Round(y + j*dx);
\r
3102 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3103 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3106 x = (double) d_x - k;
\r
3107 y = (double) d_y - k*dy;
\r
3110 x = (double) d_x + k;
\r
3111 y = (double) d_y + k*dy;
\r
3114 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3116 arrow[6].x = Round(x - j);
\r
3117 arrow[6].y = Round(y + j*dx);
\r
3119 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3120 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3122 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3123 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3128 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3129 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3132 Polygon( hdc, arrow, 7 );
\r
3135 /* [AS] Draw an arrow between two squares */
\r
3136 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3138 int s_x, s_y, d_x, d_y;
\r
3145 if( s_col == d_col && s_row == d_row ) {
\r
3149 /* Get source and destination points */
\r
3150 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3151 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3154 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3156 else if( d_y < s_y ) {
\r
3157 d_y += squareSize / 2 + squareSize / 4;
\r
3160 d_y += squareSize / 2;
\r
3164 d_x += squareSize / 2 - squareSize / 4;
\r
3166 else if( d_x < s_x ) {
\r
3167 d_x += squareSize / 2 + squareSize / 4;
\r
3170 d_x += squareSize / 2;
\r
3173 s_x += squareSize / 2;
\r
3174 s_y += squareSize / 2;
\r
3176 /* Adjust width */
\r
3177 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3180 stLB.lbStyle = BS_SOLID;
\r
3181 stLB.lbColor = appData.highlightArrowColor;
\r
3184 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3185 holdpen = SelectObject( hdc, hpen );
\r
3186 hbrush = CreateBrushIndirect( &stLB );
\r
3187 holdbrush = SelectObject( hdc, hbrush );
\r
3189 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3191 SelectObject( hdc, holdpen );
\r
3192 SelectObject( hdc, holdbrush );
\r
3193 DeleteObject( hpen );
\r
3194 DeleteObject( hbrush );
\r
3197 BOOL HasHighlightInfo()
\r
3199 BOOL result = FALSE;
\r
3201 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3202 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3210 BOOL IsDrawArrowEnabled()
\r
3212 BOOL result = FALSE;
\r
3214 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3221 VOID DrawArrowHighlight( HDC hdc )
\r
3223 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3224 DrawArrowBetweenSquares( hdc,
\r
3225 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3226 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3230 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3232 HRGN result = NULL;
\r
3234 if( HasHighlightInfo() ) {
\r
3235 int x1, y1, x2, y2;
\r
3236 int sx, sy, dx, dy;
\r
3238 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3239 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3241 sx = MIN( x1, x2 );
\r
3242 sy = MIN( y1, y2 );
\r
3243 dx = MAX( x1, x2 ) + squareSize;
\r
3244 dy = MAX( y1, y2 ) + squareSize;
\r
3246 result = CreateRectRgn( sx, sy, dx, dy );
\r
3253 Warning: this function modifies the behavior of several other functions.
\r
3255 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3256 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3257 repaint is scattered all over the place, which is not good for features such as
\r
3258 "arrow highlighting" that require a full repaint of the board.
\r
3260 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3261 user interaction, when speed is not so important) but especially to avoid errors
\r
3262 in the displayed graphics.
\r
3264 In such patched places, I always try refer to this function so there is a single
\r
3265 place to maintain knowledge.
\r
3267 To restore the original behavior, just return FALSE unconditionally.
\r
3269 BOOL IsFullRepaintPreferrable()
\r
3271 BOOL result = FALSE;
\r
3273 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3274 /* Arrow may appear on the board */
\r
3282 This function is called by DrawPosition to know whether a full repaint must
\r
3285 Only DrawPosition may directly call this function, which makes use of
\r
3286 some state information. Other function should call DrawPosition specifying
\r
3287 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3289 BOOL DrawPositionNeedsFullRepaint()
\r
3291 BOOL result = FALSE;
\r
3294 Probably a slightly better policy would be to trigger a full repaint
\r
3295 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3296 but animation is fast enough that it's difficult to notice.
\r
3298 if( animInfo.piece == EmptySquare ) {
\r
3299 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3308 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3310 int row, column, x, y, square_color, piece_color;
\r
3311 ChessSquare piece;
\r
3313 HDC texture_hdc = NULL;
\r
3315 /* [AS] Initialize background textures if needed */
\r
3316 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3317 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3318 if( backTextureSquareSize != squareSize
\r
3319 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3320 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3321 backTextureSquareSize = squareSize;
\r
3322 RebuildTextureSquareInfo();
\r
3325 texture_hdc = CreateCompatibleDC( hdc );
\r
3328 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3329 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3331 SquareToPos(row, column, &x, &y);
\r
3333 piece = board[row][column];
\r
3335 square_color = ((column + row) % 2) == 1;
\r
3336 if( gameInfo.variant == VariantXiangqi ) {
\r
3337 square_color = !InPalace(row, column);
\r
3338 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3339 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3341 piece_color = (int) piece < (int) BlackPawn;
\r
3344 /* [HGM] holdings file: light square or black */
\r
3345 if(column == BOARD_LEFT-2) {
\r
3346 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3349 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3353 if(column == BOARD_RGHT + 1 ) {
\r
3354 if( row < gameInfo.holdingsSize )
\r
3357 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3361 if(column == BOARD_LEFT-1 ) /* left align */
\r
3362 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3363 else if( column == BOARD_RGHT) /* right align */
\r
3364 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3366 if (appData.monoMode) {
\r
3367 if (piece == EmptySquare) {
\r
3368 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3369 square_color ? WHITENESS : BLACKNESS);
\r
3371 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3374 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3375 /* [AS] Draw the square using a texture bitmap */
\r
3376 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3377 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3378 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3381 squareSize, squareSize,
\r
3384 backTextureSquareInfo[r][c].mode,
\r
3385 backTextureSquareInfo[r][c].x,
\r
3386 backTextureSquareInfo[r][c].y );
\r
3388 SelectObject( texture_hdc, hbm );
\r
3390 if (piece != EmptySquare) {
\r
3391 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3395 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3397 oldBrush = SelectObject(hdc, brush );
\r
3398 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3399 SelectObject(hdc, oldBrush);
\r
3400 if (piece != EmptySquare)
\r
3401 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3406 if( texture_hdc != NULL ) {
\r
3407 DeleteDC( texture_hdc );
\r
3411 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3412 void fputDW(FILE *f, int x)
\r
3414 fputc(x & 255, f);
\r
3415 fputc(x>>8 & 255, f);
\r
3416 fputc(x>>16 & 255, f);
\r
3417 fputc(x>>24 & 255, f);
\r
3420 #define MAX_CLIPS 200 /* more than enough */
\r
3423 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3425 // HBITMAP bufferBitmap;
\r
3430 int w = 100, h = 50;
\r
3432 if(logo == NULL) {
\r
3433 if(!logoHeight) return;
\r
3434 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3436 // GetClientRect(hwndMain, &Rect);
\r
3437 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3438 // Rect.bottom-Rect.top+1);
\r
3439 tmphdc = CreateCompatibleDC(hdc);
\r
3440 hbm = SelectObject(tmphdc, logo);
\r
3441 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3445 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3446 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3447 SelectObject(tmphdc, hbm);
\r
3455 HDC hdc = GetDC(hwndMain);
\r
3456 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3457 if(appData.autoLogo) {
\r
3459 switch(gameMode) { // pick logos based on game mode
\r
3460 case IcsObserving:
\r
3461 whiteLogo = second.programLogo; // ICS logo
\r
3462 blackLogo = second.programLogo;
\r
3465 case IcsPlayingWhite:
\r
3466 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3467 blackLogo = second.programLogo; // ICS logo
\r
3469 case IcsPlayingBlack:
\r
3470 whiteLogo = second.programLogo; // ICS logo
\r
3471 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3473 case TwoMachinesPlay:
\r
3474 if(first.twoMachinesColor[0] == 'b') {
\r
3475 whiteLogo = second.programLogo;
\r
3476 blackLogo = first.programLogo;
\r
3479 case MachinePlaysWhite:
\r
3480 blackLogo = userLogo;
\r
3482 case MachinePlaysBlack:
\r
3483 whiteLogo = userLogo;
\r
3484 blackLogo = first.programLogo;
\r
3487 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3488 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3489 ReleaseDC(hwndMain, hdc);
\r
3494 UpdateLogos(int display)
\r
3495 { // called after loading new engine(s), in tourney or from menu
\r
3496 LoadLogo(&first, 0, FALSE);
\r
3497 LoadLogo(&second, 1, appData.icsActive);
\r
3498 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3499 if(display) DisplayLogos();
\r
3502 static HDC hdcSeek;
\r
3504 // [HGM] seekgraph
\r
3505 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3508 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3509 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3510 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3511 SelectObject( hdcSeek, hp );
\r
3514 // front-end wrapper for drawing functions to do rectangles
\r
3515 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3520 if (hdcSeek == NULL) {
\r
3521 hdcSeek = GetDC(hwndMain);
\r
3522 if (!appData.monoMode) {
\r
3523 SelectPalette(hdcSeek, hPal, FALSE);
\r
3524 RealizePalette(hdcSeek);
\r
3527 hp = SelectObject( hdcSeek, gridPen );
\r
3528 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3529 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3530 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3531 SelectObject( hdcSeek, hp );
\r
3534 // front-end wrapper for putting text in graph
\r
3535 void DrawSeekText(char *buf, int x, int y)
\r
3538 SetBkMode( hdcSeek, TRANSPARENT );
\r
3539 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3540 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3543 void DrawSeekDot(int x, int y, int color)
\r
3545 int square = color & 0x80;
\r
3546 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3547 color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);
\r
3550 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3551 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3553 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3554 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3555 SelectObject(hdcSeek, oldBrush);
\r
3558 void DrawSeekOpen()
\r
3562 void DrawSeekClose()
\r
3567 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3569 static Board lastReq[2], lastDrawn[2];
\r
3570 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3571 static int lastDrawnFlipView = 0;
\r
3572 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3573 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3576 HBITMAP bufferBitmap;
\r
3577 HBITMAP oldBitmap;
\r
3579 HRGN clips[MAX_CLIPS];
\r
3580 ChessSquare dragged_piece = EmptySquare;
\r
3581 int nr = twoBoards*partnerUp;
\r
3583 /* I'm undecided on this - this function figures out whether a full
\r
3584 * repaint is necessary on its own, so there's no real reason to have the
\r
3585 * caller tell it that. I think this can safely be set to FALSE - but
\r
3586 * if we trust the callers not to request full repaints unnessesarily, then
\r
3587 * we could skip some clipping work. In other words, only request a full
\r
3588 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3589 * gamestart and similar) --Hawk
\r
3591 Boolean fullrepaint = repaint;
\r
3593 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3595 if( DrawPositionNeedsFullRepaint() ) {
\r
3596 fullrepaint = TRUE;
\r
3599 if (board == NULL) {
\r
3600 if (!lastReqValid[nr]) {
\r
3603 board = lastReq[nr];
\r
3605 CopyBoard(lastReq[nr], board);
\r
3606 lastReqValid[nr] = 1;
\r
3609 if (doingSizing) {
\r
3613 if (IsIconic(hwndMain)) {
\r
3617 if (hdc == NULL) {
\r
3618 hdc = GetDC(hwndMain);
\r
3619 if (!appData.monoMode) {
\r
3620 SelectPalette(hdc, hPal, FALSE);
\r
3621 RealizePalette(hdc);
\r
3625 releaseDC = FALSE;
\r
3628 /* Create some work-DCs */
\r
3629 hdcmem = CreateCompatibleDC(hdc);
\r
3630 tmphdc = CreateCompatibleDC(hdc);
\r
3632 /* If dragging is in progress, we temporarely remove the piece */
\r
3633 /* [HGM] or temporarily decrease count if stacked */
\r
3634 /* !! Moved to before board compare !! */
\r
3635 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3636 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3637 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3638 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3639 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3641 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3642 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3643 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3645 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3648 /* Figure out which squares need updating by comparing the
\r
3649 * newest board with the last drawn board and checking if
\r
3650 * flipping has changed.
\r
3652 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3653 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3654 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3655 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3656 SquareToPos(row, column, &x, &y);
\r
3657 clips[num_clips++] =
\r
3658 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3662 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3663 for (i=0; i<2; i++) {
\r
3664 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3665 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3666 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3667 lastDrawnHighlight.sq[i].y >= 0) {
\r
3668 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3669 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3670 clips[num_clips++] =
\r
3671 CreateRectRgn(x - lineGap, y - lineGap,
\r
3672 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3674 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3675 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3676 clips[num_clips++] =
\r
3677 CreateRectRgn(x - lineGap, y - lineGap,
\r
3678 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3682 for (i=0; i<2; i++) {
\r
3683 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3684 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3685 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3686 lastDrawnPremove.sq[i].y >= 0) {
\r
3687 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3688 lastDrawnPremove.sq[i].x, &x, &y);
\r
3689 clips[num_clips++] =
\r
3690 CreateRectRgn(x - lineGap, y - lineGap,
\r
3691 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3693 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3694 premoveHighlightInfo.sq[i].y >= 0) {
\r
3695 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3696 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3697 clips[num_clips++] =
\r
3698 CreateRectRgn(x - lineGap, y - lineGap,
\r
3699 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3703 } else { // nr == 1
\r
3704 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3705 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3706 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3707 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3708 for (i=0; i<2; i++) {
\r
3709 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3710 partnerHighlightInfo.sq[i].y >= 0) {
\r
3711 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3712 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3713 clips[num_clips++] =
\r
3714 CreateRectRgn(x - lineGap, y - lineGap,
\r
3715 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3717 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3718 oldPartnerHighlight.sq[i].y >= 0) {
\r
3719 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3720 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3721 clips[num_clips++] =
\r
3722 CreateRectRgn(x - lineGap, y - lineGap,
\r
3723 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3728 fullrepaint = TRUE;
\r
3731 /* Create a buffer bitmap - this is the actual bitmap
\r
3732 * being written to. When all the work is done, we can
\r
3733 * copy it to the real DC (the screen). This avoids
\r
3734 * the problems with flickering.
\r
3736 GetClientRect(hwndMain, &Rect);
\r
3737 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3738 Rect.bottom-Rect.top+1);
\r
3739 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3740 if (!appData.monoMode) {
\r
3741 SelectPalette(hdcmem, hPal, FALSE);
\r
3744 /* Create clips for dragging */
\r
3745 if (!fullrepaint) {
\r
3746 if (dragInfo.from.x >= 0) {
\r
3747 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3748 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3750 if (dragInfo.start.x >= 0) {
\r
3751 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3752 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3754 if (dragInfo.pos.x >= 0) {
\r
3755 x = dragInfo.pos.x - squareSize / 2;
\r
3756 y = dragInfo.pos.y - squareSize / 2;
\r
3757 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3759 if (dragInfo.lastpos.x >= 0) {
\r
3760 x = dragInfo.lastpos.x - squareSize / 2;
\r
3761 y = dragInfo.lastpos.y - squareSize / 2;
\r
3762 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3766 /* Are we animating a move?
\r
3768 * - remove the piece from the board (temporarely)
\r
3769 * - calculate the clipping region
\r
3771 if (!fullrepaint) {
\r
3772 if (animInfo.piece != EmptySquare) {
\r
3773 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3774 x = boardRect.left + animInfo.lastpos.x;
\r
3775 y = boardRect.top + animInfo.lastpos.y;
\r
3776 x2 = boardRect.left + animInfo.pos.x;
\r
3777 y2 = boardRect.top + animInfo.pos.y;
\r
3778 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3779 /* Slight kludge. The real problem is that after AnimateMove is
\r
3780 done, the position on the screen does not match lastDrawn.
\r
3781 This currently causes trouble only on e.p. captures in
\r
3782 atomic, where the piece moves to an empty square and then
\r
3783 explodes. The old and new positions both had an empty square
\r
3784 at the destination, but animation has drawn a piece there and
\r
3785 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3786 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3790 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3791 if (num_clips == 0)
\r
3792 fullrepaint = TRUE;
\r
3794 /* Set clipping on the memory DC */
\r
3795 if (!fullrepaint) {
\r
3796 SelectClipRgn(hdcmem, clips[0]);
\r
3797 for (x = 1; x < num_clips; x++) {
\r
3798 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3799 abort(); // this should never ever happen!
\r
3803 /* Do all the drawing to the memory DC */
\r
3804 if(explodeInfo.radius) { // [HGM] atomic
\r
3806 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3807 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3808 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3809 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3810 x += squareSize/2;
\r
3811 y += squareSize/2;
\r
3812 if(!fullrepaint) {
\r
3813 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3814 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3816 DrawGridOnDC(hdcmem);
\r
3817 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3818 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3819 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3820 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3821 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3822 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3823 SelectObject(hdcmem, oldBrush);
\r
3825 DrawGridOnDC(hdcmem);
\r
3826 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3827 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3828 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3830 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3831 oldPartnerHighlight = partnerHighlightInfo;
\r
3833 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3835 if(nr == 0) // [HGM] dual: markers only on left board
\r
3836 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3837 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3838 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3839 HBRUSH oldBrush = SelectObject(hdcmem,
\r
3840 marker[row][column] == 2 ? markerBrush : explodeBrush);
\r
3841 SquareToPos(row, column, &x, &y);
\r
3842 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3843 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3844 SelectObject(hdcmem, oldBrush);
\r
3849 if( appData.highlightMoveWithArrow ) {
\r
3850 DrawArrowHighlight(hdcmem);
\r
3853 DrawCoordsOnDC(hdcmem);
\r
3855 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
3856 /* to make sure lastDrawn contains what is actually drawn */
\r
3858 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3859 if (dragged_piece != EmptySquare) {
\r
3860 /* [HGM] or restack */
\r
3861 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3862 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3864 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3865 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3866 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3867 x = dragInfo.pos.x - squareSize / 2;
\r
3868 y = dragInfo.pos.y - squareSize / 2;
\r
3869 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
3870 ((int) dragInfo.piece < (int) BlackPawn),
\r
3871 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3874 /* Put the animated piece back into place and draw it */
\r
3875 if (animInfo.piece != EmptySquare) {
\r
3876 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3877 x = boardRect.left + animInfo.pos.x;
\r
3878 y = boardRect.top + animInfo.pos.y;
\r
3879 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3880 ((int) animInfo.piece < (int) BlackPawn),
\r
3881 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3884 /* Release the bufferBitmap by selecting in the old bitmap
\r
3885 * and delete the memory DC
\r
3887 SelectObject(hdcmem, oldBitmap);
\r
3890 /* Set clipping on the target DC */
\r
3891 if (!fullrepaint) {
\r
3892 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
3894 GetRgnBox(clips[x], &rect);
\r
3895 DeleteObject(clips[x]);
\r
3896 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
3897 rect.right + wpMain.width/2, rect.bottom);
\r
3899 SelectClipRgn(hdc, clips[0]);
\r
3900 for (x = 1; x < num_clips; x++) {
\r
3901 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3902 abort(); // this should never ever happen!
\r
3906 /* Copy the new bitmap onto the screen in one go.
\r
3907 * This way we avoid any flickering
\r
3909 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3910 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
3911 boardRect.right - boardRect.left,
\r
3912 boardRect.bottom - boardRect.top,
\r
3913 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3914 if(saveDiagFlag) {
\r
3915 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
3916 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
3918 GetObject(bufferBitmap, sizeof(b), &b);
\r
3919 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
3920 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
3921 bih.biWidth = b.bmWidth;
\r
3922 bih.biHeight = b.bmHeight;
\r
3924 bih.biBitCount = b.bmBitsPixel;
\r
3925 bih.biCompression = 0;
\r
3926 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
3927 bih.biXPelsPerMeter = 0;
\r
3928 bih.biYPelsPerMeter = 0;
\r
3929 bih.biClrUsed = 0;
\r
3930 bih.biClrImportant = 0;
\r
3931 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
3932 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
3933 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
3934 // fprintf(diagFile, "%8x\n", (int) pData);
\r
3936 wb = b.bmWidthBytes;
\r
3938 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
3939 int k = ((int*) pData)[i];
\r
3940 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3941 if(j >= 16) break;
\r
3943 if(j >= nrColors) nrColors = j+1;
\r
3945 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
3947 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
3948 for(w=0; w<(wb>>2); w+=2) {
\r
3949 int k = ((int*) pData)[(wb*i>>2) + w];
\r
3950 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3951 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
3952 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
3953 pData[p++] = m | j<<4;
\r
3955 while(p&3) pData[p++] = 0;
\r
3958 wb = ((wb+31)>>5)<<2;
\r
3960 // write BITMAPFILEHEADER
\r
3961 fprintf(diagFile, "BM");
\r
3962 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
3963 fputDW(diagFile, 0);
\r
3964 fputDW(diagFile, 0x36 + (fac?64:0));
\r
3965 // write BITMAPINFOHEADER
\r
3966 fputDW(diagFile, 40);
\r
3967 fputDW(diagFile, b.bmWidth);
\r
3968 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
3969 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
3970 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
3971 fputDW(diagFile, 0);
\r
3972 fputDW(diagFile, 0);
\r
3973 fputDW(diagFile, 0);
\r
3974 fputDW(diagFile, 0);
\r
3975 fputDW(diagFile, 0);
\r
3976 fputDW(diagFile, 0);
\r
3977 // write color table
\r
3979 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
3980 // write bitmap data
\r
3981 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
3982 fputc(pData[i], diagFile);
\r
3987 SelectObject(tmphdc, oldBitmap);
\r
3989 /* Massive cleanup */
\r
3990 for (x = 0; x < num_clips; x++)
\r
3991 DeleteObject(clips[x]);
\r
3994 DeleteObject(bufferBitmap);
\r
3997 ReleaseDC(hwndMain, hdc);
\r
3999 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4001 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4003 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4006 /* CopyBoard(lastDrawn, board);*/
\r
4007 lastDrawnHighlight = highlightInfo;
\r
4008 lastDrawnPremove = premoveHighlightInfo;
\r
4009 lastDrawnFlipView = flipView;
\r
4010 lastDrawnValid[nr] = 1;
\r
4013 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4018 saveDiagFlag = 1; diagFile = f;
\r
4019 HDCDrawPosition(NULL, TRUE, NULL);
\r
4027 /*---------------------------------------------------------------------------*\
\r
4028 | CLIENT PAINT PROCEDURE
\r
4029 | This is the main event-handler for the WM_PAINT message.
\r
4031 \*---------------------------------------------------------------------------*/
\r
4033 PaintProc(HWND hwnd)
\r
4039 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4040 if (IsIconic(hwnd)) {
\r
4041 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4043 if (!appData.monoMode) {
\r
4044 SelectPalette(hdc, hPal, FALSE);
\r
4045 RealizePalette(hdc);
\r
4047 HDCDrawPosition(hdc, 1, NULL);
\r
4048 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4049 flipView = !flipView; partnerUp = !partnerUp;
\r
4050 HDCDrawPosition(hdc, 1, NULL);
\r
4051 flipView = !flipView; partnerUp = !partnerUp;
\r
4054 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4055 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4056 ETO_CLIPPED|ETO_OPAQUE,
\r
4057 &messageRect, messageText, strlen(messageText), NULL);
\r
4058 SelectObject(hdc, oldFont);
\r
4059 DisplayBothClocks();
\r
4062 EndPaint(hwnd,&ps);
\r
4070 * If the user selects on a border boundary, return -1; if off the board,
\r
4071 * return -2. Otherwise map the event coordinate to the square.
\r
4072 * The offset boardRect.left or boardRect.top must already have been
\r
4073 * subtracted from x.
\r
4075 int EventToSquare(x, limit)
\r
4083 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4085 x /= (squareSize + lineGap);
\r
4097 DropEnable dropEnables[] = {
\r
4098 { 'P', DP_Pawn, N_("Pawn") },
\r
4099 { 'N', DP_Knight, N_("Knight") },
\r
4100 { 'B', DP_Bishop, N_("Bishop") },
\r
4101 { 'R', DP_Rook, N_("Rook") },
\r
4102 { 'Q', DP_Queen, N_("Queen") },
\r
4106 SetupDropMenu(HMENU hmenu)
\r
4108 int i, count, enable;
\r
4110 extern char white_holding[], black_holding[];
\r
4111 char item[MSG_SIZ];
\r
4113 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4114 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4115 dropEnables[i].piece);
\r
4117 while (p && *p++ == dropEnables[i].piece) count++;
\r
4118 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4119 enable = count > 0 || !appData.testLegality
\r
4120 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4121 && !appData.icsActive);
\r
4122 ModifyMenu(hmenu, dropEnables[i].command,
\r
4123 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4124 dropEnables[i].command, item);
\r
4128 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4130 dragInfo.lastpos.x = boardRect.left + x;
\r
4131 dragInfo.lastpos.y = boardRect.top + y;
\r
4132 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4133 dragInfo.from.x = fromX;
\r
4134 dragInfo.from.y = fromY;
\r
4135 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4136 dragInfo.start = dragInfo.from;
\r
4137 SetCapture(hwndMain);
\r
4140 void DragPieceEnd(int x, int y)
\r
4143 dragInfo.start.x = dragInfo.start.y = -1;
\r
4144 dragInfo.from = dragInfo.start;
\r
4145 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4148 void ChangeDragPiece(ChessSquare piece)
\r
4150 dragInfo.piece = piece;
\r
4153 /* Event handler for mouse messages */
\r
4155 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4159 static int recursive = 0;
\r
4161 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4164 if (message == WM_MBUTTONUP) {
\r
4165 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4166 to the middle button: we simulate pressing the left button too!
\r
4168 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4169 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4175 pt.x = LOWORD(lParam);
\r
4176 pt.y = HIWORD(lParam);
\r
4177 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4178 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4179 if (!flipView && y >= 0) {
\r
4180 y = BOARD_HEIGHT - 1 - y;
\r
4182 if (flipView && x >= 0) {
\r
4183 x = BOARD_WIDTH - 1 - x;
\r
4186 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4188 switch (message) {
\r
4189 case WM_LBUTTONDOWN:
\r
4190 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4191 ClockClick(flipClock); break;
\r
4192 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4193 ClockClick(!flipClock); break;
\r
4195 dragInfo.start.x = dragInfo.start.y = -1;
\r
4196 dragInfo.from = dragInfo.start;
\r
4197 if(fromX == -1 && frozen) { // not sure where this is for
\r
4198 fromX = fromY = -1;
\r
4199 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4202 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4203 DrawPosition(TRUE, NULL);
\r
4206 case WM_LBUTTONUP:
\r
4207 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4208 DrawPosition(TRUE, NULL);
\r
4211 case WM_MOUSEMOVE:
\r
4212 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4213 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4214 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4215 if ((appData.animateDragging || appData.highlightDragging)
\r
4216 && (wParam & MK_LBUTTON)
\r
4217 && dragInfo.from.x >= 0)
\r
4219 BOOL full_repaint = FALSE;
\r
4221 if (appData.animateDragging) {
\r
4222 dragInfo.pos = pt;
\r
4224 if (appData.highlightDragging) {
\r
4225 SetHighlights(fromX, fromY, x, y);
\r
4226 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4227 full_repaint = TRUE;
\r
4231 DrawPosition( full_repaint, NULL);
\r
4233 dragInfo.lastpos = dragInfo.pos;
\r
4237 case WM_MOUSEWHEEL: // [DM]
\r
4238 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4239 /* Mouse Wheel is being rolled forward
\r
4240 * Play moves forward
\r
4242 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4243 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4244 /* Mouse Wheel is being rolled backward
\r
4245 * Play moves backward
\r
4247 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4248 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4252 case WM_MBUTTONUP:
\r
4253 case WM_RBUTTONUP:
\r
4255 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4258 case WM_MBUTTONDOWN:
\r
4259 case WM_RBUTTONDOWN:
\r
4262 fromX = fromY = -1;
\r
4263 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4264 dragInfo.start.x = dragInfo.start.y = -1;
\r
4265 dragInfo.from = dragInfo.start;
\r
4266 dragInfo.lastpos = dragInfo.pos;
\r
4267 if (appData.highlightDragging) {
\r
4268 ClearHighlights();
\r
4271 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4272 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4273 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4274 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4275 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4279 DrawPosition(TRUE, NULL);
\r
4281 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4284 if (message == WM_MBUTTONDOWN) {
\r
4285 buttonCount = 3; /* even if system didn't think so */
\r
4286 if (wParam & MK_SHIFT)
\r
4287 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4289 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4290 } else { /* message == WM_RBUTTONDOWN */
\r
4291 /* Just have one menu, on the right button. Windows users don't
\r
4292 think to try the middle one, and sometimes other software steals
\r
4293 it, or it doesn't really exist. */
\r
4294 if(gameInfo.variant != VariantShogi)
\r
4295 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4297 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4301 SetCapture(hwndMain);
\r
4304 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4305 SetupDropMenu(hmenu);
\r
4306 MenuPopup(hwnd, pt, hmenu, -1);
\r
4316 /* Preprocess messages for buttons in main window */
\r
4318 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4320 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4323 for (i=0; i<N_BUTTONS; i++) {
\r
4324 if (buttonDesc[i].id == id) break;
\r
4326 if (i == N_BUTTONS) return 0;
\r
4327 switch (message) {
\r
4332 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4333 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4340 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4343 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4344 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4345 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4346 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4348 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4350 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4351 TypeInEvent((char)wParam);
\r
4357 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4360 /* Process messages for Promotion dialog box */
\r
4362 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4366 switch (message) {
\r
4367 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4368 /* Center the dialog over the application window */
\r
4369 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4370 Translate(hDlg, DLG_PromotionKing);
\r
4371 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4372 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4373 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4374 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4375 SW_SHOW : SW_HIDE);
\r
4376 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4377 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4378 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4379 PieceToChar(WhiteAngel) != '~') ||
\r
4380 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4381 PieceToChar(BlackAngel) != '~') ) ?
\r
4382 SW_SHOW : SW_HIDE);
\r
4383 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4384 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4385 PieceToChar(WhiteMarshall) != '~') ||
\r
4386 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4387 PieceToChar(BlackMarshall) != '~') ) ?
\r
4388 SW_SHOW : SW_HIDE);
\r
4389 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4390 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4391 gameInfo.variant != VariantShogi ?
\r
4392 SW_SHOW : SW_HIDE);
\r
4393 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4394 gameInfo.variant != VariantShogi ?
\r
4395 SW_SHOW : SW_HIDE);
\r
4396 if(gameInfo.variant == VariantShogi) {
\r
4397 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4398 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4399 SetWindowText(hDlg, "Promote?");
\r
4401 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4402 gameInfo.variant == VariantSuper ?
\r
4403 SW_SHOW : SW_HIDE);
\r
4406 case WM_COMMAND: /* message: received a command */
\r
4407 switch (LOWORD(wParam)) {
\r
4409 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4410 ClearHighlights();
\r
4411 DrawPosition(FALSE, NULL);
\r
4414 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4417 promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4420 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4421 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4424 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4425 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4427 case PB_Chancellor:
\r
4428 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4430 case PB_Archbishop:
\r
4431 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4434 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);
\r
4439 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4440 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4441 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4442 fromX = fromY = -1;
\r
4443 if (!appData.highlightLastMove) {
\r
4444 ClearHighlights();
\r
4445 DrawPosition(FALSE, NULL);
\r
4452 /* Pop up promotion dialog */
\r
4454 PromotionPopup(HWND hwnd)
\r
4458 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4459 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4460 hwnd, (DLGPROC)lpProc);
\r
4461 FreeProcInstance(lpProc);
\r
4467 DrawPosition(TRUE, NULL);
\r
4468 PromotionPopup(hwndMain);
\r
4471 /* Toggle ShowThinking */
\r
4473 ToggleShowThinking()
\r
4475 appData.showThinking = !appData.showThinking;
\r
4476 ShowThinkingEvent();
\r
4480 LoadGameDialog(HWND hwnd, char* title)
\r
4484 char fileTitle[MSG_SIZ];
\r
4485 f = OpenFileDialog(hwnd, "rb", "",
\r
4486 appData.oldSaveStyle ? "gam" : "pgn",
\r
4488 title, &number, fileTitle, NULL);
\r
4490 cmailMsgLoaded = FALSE;
\r
4491 if (number == 0) {
\r
4492 int error = GameListBuild(f);
\r
4494 DisplayError(_("Cannot build game list"), error);
\r
4495 } else if (!ListEmpty(&gameList) &&
\r
4496 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4497 GameListPopUp(f, fileTitle);
\r
4500 GameListDestroy();
\r
4503 LoadGame(f, number, fileTitle, FALSE);
\r
4507 int get_term_width()
\r
4512 HFONT hfont, hold_font;
\r
4517 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4521 // get the text metrics
\r
4522 hdc = GetDC(hText);
\r
4523 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4524 if (consoleCF.dwEffects & CFE_BOLD)
\r
4525 lf.lfWeight = FW_BOLD;
\r
4526 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4527 lf.lfItalic = TRUE;
\r
4528 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4529 lf.lfStrikeOut = TRUE;
\r
4530 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4531 lf.lfUnderline = TRUE;
\r
4532 hfont = CreateFontIndirect(&lf);
\r
4533 hold_font = SelectObject(hdc, hfont);
\r
4534 GetTextMetrics(hdc, &tm);
\r
4535 SelectObject(hdc, hold_font);
\r
4536 DeleteObject(hfont);
\r
4537 ReleaseDC(hText, hdc);
\r
4539 // get the rectangle
\r
4540 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4542 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4545 void UpdateICSWidth(HWND hText)
\r
4547 LONG old_width, new_width;
\r
4549 new_width = get_term_width(hText, FALSE);
\r
4550 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4551 if (new_width != old_width)
\r
4553 ics_update_width(new_width);
\r
4554 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4559 ChangedConsoleFont()
\r
4562 CHARRANGE tmpsel, sel;
\r
4563 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4564 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4565 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4568 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4569 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4570 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4571 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4572 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4573 * size. This was undocumented in the version of MSVC++ that I had
\r
4574 * when I wrote the code, but is apparently documented now.
\r
4576 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4577 cfmt.bCharSet = f->lf.lfCharSet;
\r
4578 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4579 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4580 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4581 /* Why are the following seemingly needed too? */
\r
4582 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4583 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4584 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4586 tmpsel.cpMax = -1; /*999999?*/
\r
4587 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4588 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4589 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4590 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4592 paraf.cbSize = sizeof(paraf);
\r
4593 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4594 paraf.dxStartIndent = 0;
\r
4595 paraf.dxOffset = WRAP_INDENT;
\r
4596 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4597 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4598 UpdateICSWidth(hText);
\r
4601 /*---------------------------------------------------------------------------*\
\r
4603 * Window Proc for main window
\r
4605 \*---------------------------------------------------------------------------*/
\r
4607 /* Process messages for main window, etc. */
\r
4609 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4612 int wmId, wmEvent;
\r
4616 char fileTitle[MSG_SIZ];
\r
4617 char buf[MSG_SIZ];
\r
4618 static SnapData sd;
\r
4619 static int peek=0;
\r
4621 switch (message) {
\r
4623 case WM_PAINT: /* message: repaint portion of window */
\r
4627 case WM_ERASEBKGND:
\r
4628 if (IsIconic(hwnd)) {
\r
4629 /* Cheat; change the message */
\r
4630 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4632 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4636 case WM_LBUTTONDOWN:
\r
4637 case WM_MBUTTONDOWN:
\r
4638 case WM_RBUTTONDOWN:
\r
4639 case WM_LBUTTONUP:
\r
4640 case WM_MBUTTONUP:
\r
4641 case WM_RBUTTONUP:
\r
4642 case WM_MOUSEMOVE:
\r
4643 case WM_MOUSEWHEEL:
\r
4644 MouseEvent(hwnd, message, wParam, lParam);
\r
4648 if((char)wParam == '\b') {
\r
4649 ForwardEvent(); peek = 0;
\r
4652 JAWS_KBUP_NAVIGATION
\r
4657 if((char)wParam == '\b') {
\r
4658 if(!peek) BackwardEvent(), peek = 1;
\r
4661 JAWS_KBDOWN_NAVIGATION
\r
4667 JAWS_ALT_INTERCEPT
\r
4669 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4670 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4671 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4672 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4674 SendMessage(h, message, wParam, lParam);
\r
4675 } else if(lParam != KF_REPEAT) {
\r
4676 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4677 TypeInEvent((char)wParam);
\r
4678 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4679 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4684 case WM_PALETTECHANGED:
\r
4685 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4687 HDC hdc = GetDC(hwndMain);
\r
4688 SelectPalette(hdc, hPal, TRUE);
\r
4689 nnew = RealizePalette(hdc);
\r
4691 paletteChanged = TRUE;
\r
4692 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4694 ReleaseDC(hwnd, hdc);
\r
4698 case WM_QUERYNEWPALETTE:
\r
4699 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4701 HDC hdc = GetDC(hwndMain);
\r
4702 paletteChanged = FALSE;
\r
4703 SelectPalette(hdc, hPal, FALSE);
\r
4704 nnew = RealizePalette(hdc);
\r
4706 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4708 ReleaseDC(hwnd, hdc);
\r
4713 case WM_COMMAND: /* message: command from application menu */
\r
4714 wmId = LOWORD(wParam);
\r
4715 wmEvent = HIWORD(wParam);
\r
4720 SAY("new game enter a move to play against the computer with white");
\r
4723 case IDM_NewGameFRC:
\r
4724 if( NewGameFRC() == 0 ) {
\r
4729 case IDM_NewVariant:
\r
4730 NewVariantPopup(hwnd);
\r
4733 case IDM_LoadGame:
\r
4734 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4737 case IDM_LoadNextGame:
\r
4741 case IDM_LoadPrevGame:
\r
4745 case IDM_ReloadGame:
\r
4749 case IDM_LoadPosition:
\r
4750 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4751 Reset(FALSE, TRUE);
\r
4754 f = OpenFileDialog(hwnd, "rb", "",
\r
4755 appData.oldSaveStyle ? "pos" : "fen",
\r
4757 _("Load Position from File"), &number, fileTitle, NULL);
\r
4759 LoadPosition(f, number, fileTitle);
\r
4763 case IDM_LoadNextPosition:
\r
4764 ReloadPosition(1);
\r
4767 case IDM_LoadPrevPosition:
\r
4768 ReloadPosition(-1);
\r
4771 case IDM_ReloadPosition:
\r
4772 ReloadPosition(0);
\r
4775 case IDM_SaveGame:
\r
4776 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4777 f = OpenFileDialog(hwnd, "a", defName,
\r
4778 appData.oldSaveStyle ? "gam" : "pgn",
\r
4780 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4782 SaveGame(f, 0, "");
\r
4786 case IDM_SavePosition:
\r
4787 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4788 f = OpenFileDialog(hwnd, "a", defName,
\r
4789 appData.oldSaveStyle ? "pos" : "fen",
\r
4791 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4793 SavePosition(f, 0, "");
\r
4797 case IDM_SaveDiagram:
\r
4798 defName = "diagram";
\r
4799 f = OpenFileDialog(hwnd, "wb", defName,
\r
4802 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4808 case IDM_CopyGame:
\r
4809 CopyGameToClipboard();
\r
4812 case IDM_PasteGame:
\r
4813 PasteGameFromClipboard();
\r
4816 case IDM_CopyGameListToClipboard:
\r
4817 CopyGameListToClipboard();
\r
4820 /* [AS] Autodetect FEN or PGN data */
\r
4821 case IDM_PasteAny:
\r
4822 PasteGameOrFENFromClipboard();
\r
4825 /* [AS] Move history */
\r
4826 case IDM_ShowMoveHistory:
\r
4827 if( MoveHistoryIsUp() ) {
\r
4828 MoveHistoryPopDown();
\r
4831 MoveHistoryPopUp();
\r
4835 /* [AS] Eval graph */
\r
4836 case IDM_ShowEvalGraph:
\r
4837 if( EvalGraphIsUp() ) {
\r
4838 EvalGraphPopDown();
\r
4842 SetFocus(hwndMain);
\r
4846 /* [AS] Engine output */
\r
4847 case IDM_ShowEngineOutput:
\r
4848 if( EngineOutputIsUp() ) {
\r
4849 EngineOutputPopDown();
\r
4852 EngineOutputPopUp();
\r
4856 /* [AS] User adjudication */
\r
4857 case IDM_UserAdjudication_White:
\r
4858 UserAdjudicationEvent( +1 );
\r
4861 case IDM_UserAdjudication_Black:
\r
4862 UserAdjudicationEvent( -1 );
\r
4865 case IDM_UserAdjudication_Draw:
\r
4866 UserAdjudicationEvent( 0 );
\r
4869 /* [AS] Game list options dialog */
\r
4870 case IDM_GameListOptions:
\r
4871 GameListOptions();
\r
4878 case IDM_CopyPosition:
\r
4879 CopyFENToClipboard();
\r
4882 case IDM_PastePosition:
\r
4883 PasteFENFromClipboard();
\r
4886 case IDM_MailMove:
\r
4890 case IDM_ReloadCMailMsg:
\r
4891 Reset(TRUE, TRUE);
\r
4892 ReloadCmailMsgEvent(FALSE);
\r
4895 case IDM_Minimize:
\r
4896 ShowWindow(hwnd, SW_MINIMIZE);
\r
4903 case IDM_MachineWhite:
\r
4904 MachineWhiteEvent();
\r
4906 * refresh the tags dialog only if it's visible
\r
4908 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4910 tags = PGNTags(&gameInfo);
\r
4911 TagsPopUp(tags, CmailMsg());
\r
4914 SAY("computer starts playing white");
\r
4917 case IDM_MachineBlack:
\r
4918 MachineBlackEvent();
\r
4920 * refresh the tags dialog only if it's visible
\r
4922 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4924 tags = PGNTags(&gameInfo);
\r
4925 TagsPopUp(tags, CmailMsg());
\r
4928 SAY("computer starts playing black");
\r
4931 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
4932 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
4935 case IDM_TwoMachines:
\r
4936 TwoMachinesEvent();
\r
4938 * refresh the tags dialog only if it's visible
\r
4940 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4942 tags = PGNTags(&gameInfo);
\r
4943 TagsPopUp(tags, CmailMsg());
\r
4946 SAY("computer starts playing both sides");
\r
4949 case IDM_AnalysisMode:
\r
4950 if (!first.analysisSupport) {
\r
4951 snprintf(buf, MSG_SIZ, _("%s does not support analysis"), first.tidy);
\r
4952 DisplayError(buf, 0);
\r
4954 SAY("analyzing current position");
\r
4955 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
4956 if (appData.icsActive) {
\r
4957 if (gameMode != IcsObserving) {
\r
4958 snprintf(buf, MSG_SIZ, "You are not observing a game");
\r
4959 DisplayError(buf, 0);
\r
4960 /* secure check */
\r
4961 if (appData.icsEngineAnalyze) {
\r
4962 if (appData.debugMode)
\r
4963 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
4964 ExitAnalyzeMode();
\r
4970 /* if enable, user want disable icsEngineAnalyze */
\r
4971 if (appData.icsEngineAnalyze) {
\r
4972 ExitAnalyzeMode();
\r
4976 appData.icsEngineAnalyze = TRUE;
\r
4977 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
4980 if (!appData.showThinking) ToggleShowThinking();
\r
4981 AnalyzeModeEvent();
\r
4985 case IDM_AnalyzeFile:
\r
4986 if (!first.analysisSupport) {
\r
4987 char buf[MSG_SIZ];
\r
4988 snprintf(buf, MSG_SIZ, _("%s does not support analysis"), first.tidy);
\r
4989 DisplayError(buf, 0);
\r
4991 if (!appData.showThinking) ToggleShowThinking();
\r
4992 AnalyzeFileEvent();
\r
4993 // LoadGameDialog(hwnd, _("Analyze Game from File"));
\r
4994 AnalysisPeriodicEvent(1);
\r
4998 case IDM_IcsClient:
\r
5002 case IDM_EditGame:
\r
5003 case IDM_EditGame2:
\r
5008 case IDM_EditPosition:
\r
5009 case IDM_EditPosition2:
\r
5010 EditPositionEvent();
\r
5011 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5014 case IDM_Training:
\r
5018 case IDM_ShowGameList:
\r
5019 ShowGameListProc();
\r
5022 case IDM_EditProgs1:
\r
5023 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5026 case IDM_LoadProg1:
\r
5027 LoadEnginePopUp(hwndMain, 0);
\r
5030 case IDM_LoadProg2:
\r
5031 LoadEnginePopUp(hwndMain, 1);
\r
5034 case IDM_EditServers:
\r
5035 EditTagsPopUp(icsNames, &icsNames);
\r
5038 case IDM_EditTags:
\r
5043 case IDM_EditBook:
\r
5047 case IDM_EditComment:
\r
5049 if (commentUp && editComment) {
\r
5052 EditCommentEvent();
\r
5072 case IDM_CallFlag:
\r
5092 case IDM_StopObserving:
\r
5093 StopObservingEvent();
\r
5096 case IDM_StopExamining:
\r
5097 StopExaminingEvent();
\r
5101 UploadGameEvent();
\r
5104 case IDM_TypeInMove:
\r
5105 TypeInEvent('\000');
\r
5108 case IDM_TypeInName:
\r
5109 PopUpNameDialog('\000');
\r
5112 case IDM_Backward:
\r
5114 SetFocus(hwndMain);
\r
5121 SetFocus(hwndMain);
\r
5126 SetFocus(hwndMain);
\r
5131 SetFocus(hwndMain);
\r
5134 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5135 case OPT_GameListPrev:
\r
5136 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5140 RevertEvent(FALSE);
\r
5143 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5144 RevertEvent(TRUE);
\r
5147 case IDM_TruncateGame:
\r
5148 TruncateGameEvent();
\r
5155 case IDM_RetractMove:
\r
5156 RetractMoveEvent();
\r
5159 case IDM_FlipView:
\r
5160 flipView = !flipView;
\r
5161 DrawPosition(FALSE, NULL);
\r
5164 case IDM_FlipClock:
\r
5165 flipClock = !flipClock;
\r
5166 DisplayBothClocks();
\r
5170 case IDM_MuteSounds:
\r
5171 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5172 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5173 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5176 case IDM_GeneralOptions:
\r
5177 GeneralOptionsPopup(hwnd);
\r
5178 DrawPosition(TRUE, NULL);
\r
5181 case IDM_BoardOptions:
\r
5182 BoardOptionsPopup(hwnd);
\r
5185 case IDM_EnginePlayOptions:
\r
5186 EnginePlayOptionsPopup(hwnd);
\r
5189 case IDM_Engine1Options:
\r
5190 EngineOptionsPopup(hwnd, &first);
\r
5193 case IDM_Engine2Options:
\r
5195 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5196 EngineOptionsPopup(hwnd, &second);
\r
5199 case IDM_OptionsUCI:
\r
5200 UciOptionsPopup(hwnd);
\r
5204 TourneyPopup(hwnd);
\r
5207 case IDM_IcsOptions:
\r
5208 IcsOptionsPopup(hwnd);
\r
5212 FontsOptionsPopup(hwnd);
\r
5216 SoundOptionsPopup(hwnd);
\r
5219 case IDM_CommPort:
\r
5220 CommPortOptionsPopup(hwnd);
\r
5223 case IDM_LoadOptions:
\r
5224 LoadOptionsPopup(hwnd);
\r
5227 case IDM_SaveOptions:
\r
5228 SaveOptionsPopup(hwnd);
\r
5231 case IDM_TimeControl:
\r
5232 TimeControlOptionsPopup(hwnd);
\r
5235 case IDM_SaveSettings:
\r
5236 SaveSettings(settingsFileName);
\r
5239 case IDM_SaveSettingsOnExit:
\r
5240 saveSettingsOnExit = !saveSettingsOnExit;
\r
5241 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5242 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5243 MF_CHECKED : MF_UNCHECKED));
\r
5254 case IDM_AboutGame:
\r
5259 appData.debugMode = !appData.debugMode;
\r
5260 if (appData.debugMode) {
\r
5261 char dir[MSG_SIZ];
\r
5262 GetCurrentDirectory(MSG_SIZ, dir);
\r
5263 SetCurrentDirectory(installDir);
\r
5264 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5265 SetCurrentDirectory(dir);
\r
5266 setbuf(debugFP, NULL);
\r
5273 case IDM_HELPCONTENTS:
\r
5274 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5275 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5276 MessageBox (GetFocus(),
\r
5277 _("Unable to activate help"),
\r
5278 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5282 case IDM_HELPSEARCH:
\r
5283 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5284 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5285 MessageBox (GetFocus(),
\r
5286 _("Unable to activate help"),
\r
5287 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5291 case IDM_HELPHELP:
\r
5292 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5293 MessageBox (GetFocus(),
\r
5294 _("Unable to activate help"),
\r
5295 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5300 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5302 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5303 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5304 FreeProcInstance(lpProc);
\r
5307 case IDM_DirectCommand1:
\r
5308 AskQuestionEvent(_("Direct Command"),
\r
5309 _("Send to chess program:"), "", "1");
\r
5311 case IDM_DirectCommand2:
\r
5312 AskQuestionEvent(_("Direct Command"),
\r
5313 _("Send to second chess program:"), "", "2");
\r
5316 case EP_WhitePawn:
\r
5317 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5318 fromX = fromY = -1;
\r
5321 case EP_WhiteKnight:
\r
5322 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5323 fromX = fromY = -1;
\r
5326 case EP_WhiteBishop:
\r
5327 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5328 fromX = fromY = -1;
\r
5331 case EP_WhiteRook:
\r
5332 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5333 fromX = fromY = -1;
\r
5336 case EP_WhiteQueen:
\r
5337 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5338 fromX = fromY = -1;
\r
5341 case EP_WhiteFerz:
\r
5342 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5343 fromX = fromY = -1;
\r
5346 case EP_WhiteWazir:
\r
5347 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5348 fromX = fromY = -1;
\r
5351 case EP_WhiteAlfil:
\r
5352 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5353 fromX = fromY = -1;
\r
5356 case EP_WhiteCannon:
\r
5357 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5358 fromX = fromY = -1;
\r
5361 case EP_WhiteCardinal:
\r
5362 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5363 fromX = fromY = -1;
\r
5366 case EP_WhiteMarshall:
\r
5367 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5368 fromX = fromY = -1;
\r
5371 case EP_WhiteKing:
\r
5372 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5373 fromX = fromY = -1;
\r
5376 case EP_BlackPawn:
\r
5377 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5378 fromX = fromY = -1;
\r
5381 case EP_BlackKnight:
\r
5382 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5383 fromX = fromY = -1;
\r
5386 case EP_BlackBishop:
\r
5387 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5388 fromX = fromY = -1;
\r
5391 case EP_BlackRook:
\r
5392 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5393 fromX = fromY = -1;
\r
5396 case EP_BlackQueen:
\r
5397 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5398 fromX = fromY = -1;
\r
5401 case EP_BlackFerz:
\r
5402 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5403 fromX = fromY = -1;
\r
5406 case EP_BlackWazir:
\r
5407 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5408 fromX = fromY = -1;
\r
5411 case EP_BlackAlfil:
\r
5412 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5413 fromX = fromY = -1;
\r
5416 case EP_BlackCannon:
\r
5417 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5418 fromX = fromY = -1;
\r
5421 case EP_BlackCardinal:
\r
5422 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5423 fromX = fromY = -1;
\r
5426 case EP_BlackMarshall:
\r
5427 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5428 fromX = fromY = -1;
\r
5431 case EP_BlackKing:
\r
5432 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5433 fromX = fromY = -1;
\r
5436 case EP_EmptySquare:
\r
5437 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5438 fromX = fromY = -1;
\r
5441 case EP_ClearBoard:
\r
5442 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5443 fromX = fromY = -1;
\r
5447 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5448 fromX = fromY = -1;
\r
5452 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5453 fromX = fromY = -1;
\r
5457 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5458 fromX = fromY = -1;
\r
5462 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5463 fromX = fromY = -1;
\r
5467 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5468 fromX = fromY = -1;
\r
5472 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5473 fromX = fromY = -1;
\r
5477 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5478 fromX = fromY = -1;
\r
5482 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5483 fromX = fromY = -1;
\r
5487 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5488 fromX = fromY = -1;
\r
5492 barbaric = 0; appData.language = "";
\r
5493 TranslateMenus(0);
\r
5494 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5495 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5496 lastChecked = wmId;
\r
5500 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5501 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5503 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5504 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5505 TranslateMenus(0);
\r
5506 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5507 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5508 lastChecked = wmId;
\r
5511 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5517 case CLOCK_TIMER_ID:
\r
5518 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5519 clockTimerEvent = 0;
\r
5520 DecrementClocks(); /* call into back end */
\r
5522 case LOAD_GAME_TIMER_ID:
\r
5523 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5524 loadGameTimerEvent = 0;
\r
5525 AutoPlayGameLoop(); /* call into back end */
\r
5527 case ANALYSIS_TIMER_ID:
\r
5528 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5529 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5530 AnalysisPeriodicEvent(0);
\r
5532 KillTimer(hwnd, analysisTimerEvent);
\r
5533 analysisTimerEvent = 0;
\r
5536 case DELAYED_TIMER_ID:
\r
5537 KillTimer(hwnd, delayedTimerEvent);
\r
5538 delayedTimerEvent = 0;
\r
5539 delayedTimerCallback();
\r
5544 case WM_USER_Input:
\r
5545 InputEvent(hwnd, message, wParam, lParam);
\r
5548 /* [AS] Also move "attached" child windows */
\r
5549 case WM_WINDOWPOSCHANGING:
\r
5551 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5552 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5554 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5555 /* Window is moving */
\r
5558 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5559 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5560 rcMain.right = wpMain.x + wpMain.width;
\r
5561 rcMain.top = wpMain.y;
\r
5562 rcMain.bottom = wpMain.y + wpMain.height;
\r
5564 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5565 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5566 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5567 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5568 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5569 wpMain.x = lpwp->x;
\r
5570 wpMain.y = lpwp->y;
\r
5575 /* [AS] Snapping */
\r
5576 case WM_ENTERSIZEMOVE:
\r
5577 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5578 if (hwnd == hwndMain) {
\r
5579 doingSizing = TRUE;
\r
5582 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5586 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5587 if (hwnd == hwndMain) {
\r
5588 lastSizing = wParam;
\r
5593 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5594 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5596 case WM_EXITSIZEMOVE:
\r
5597 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5598 if (hwnd == hwndMain) {
\r
5600 doingSizing = FALSE;
\r
5601 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5602 GetClientRect(hwnd, &client);
\r
5603 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5605 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5607 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5610 case WM_DESTROY: /* message: window being destroyed */
\r
5611 PostQuitMessage(0);
\r
5615 if (hwnd == hwndMain) {
\r
5620 default: /* Passes it on if unprocessed */
\r
5621 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5626 /*---------------------------------------------------------------------------*\
\r
5628 * Misc utility routines
\r
5630 \*---------------------------------------------------------------------------*/
\r
5633 * Decent random number generator, at least not as bad as Windows
\r
5634 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5636 unsigned int randstate;
\r
5641 randstate = randstate * 1664525 + 1013904223;
\r
5642 return (int) randstate & 0x7fffffff;
\r
5646 mysrandom(unsigned int seed)
\r
5653 * returns TRUE if user selects a different color, FALSE otherwise
\r
5657 ChangeColor(HWND hwnd, COLORREF *which)
\r
5659 static BOOL firstTime = TRUE;
\r
5660 static DWORD customColors[16];
\r
5662 COLORREF newcolor;
\r
5667 /* Make initial colors in use available as custom colors */
\r
5668 /* Should we put the compiled-in defaults here instead? */
\r
5670 customColors[i++] = lightSquareColor & 0xffffff;
\r
5671 customColors[i++] = darkSquareColor & 0xffffff;
\r
5672 customColors[i++] = whitePieceColor & 0xffffff;
\r
5673 customColors[i++] = blackPieceColor & 0xffffff;
\r
5674 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5675 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5677 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5678 customColors[i++] = textAttribs[ccl].color;
\r
5680 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5681 firstTime = FALSE;
\r
5684 cc.lStructSize = sizeof(cc);
\r
5685 cc.hwndOwner = hwnd;
\r
5686 cc.hInstance = NULL;
\r
5687 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5688 cc.lpCustColors = (LPDWORD) customColors;
\r
5689 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5691 if (!ChooseColor(&cc)) return FALSE;
\r
5693 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5694 if (newcolor == *which) return FALSE;
\r
5695 *which = newcolor;
\r
5699 InitDrawingColors();
\r
5700 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5705 MyLoadSound(MySound *ms)
\r
5711 if (ms->data && ms->flag) free(ms->data);
\r
5714 switch (ms->name[0]) {
\r
5720 /* System sound from Control Panel. Don't preload here. */
\r
5724 if (ms->name[1] == NULLCHAR) {
\r
5725 /* "!" alone = silence */
\r
5728 /* Builtin wave resource. Error if not found. */
\r
5729 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5730 if (h == NULL) break;
\r
5731 ms->data = (void *)LoadResource(hInst, h);
\r
5732 ms->flag = 0; // not maloced, so cannot be freed!
\r
5733 if (h == NULL) break;
\r
5738 /* .wav file. Error if not found. */
\r
5739 f = fopen(ms->name, "rb");
\r
5740 if (f == NULL) break;
\r
5741 if (fstat(fileno(f), &st) < 0) break;
\r
5742 ms->data = malloc(st.st_size);
\r
5744 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5750 char buf[MSG_SIZ];
\r
5751 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5752 DisplayError(buf, GetLastError());
\r
5758 MyPlaySound(MySound *ms)
\r
5760 BOOLEAN ok = FALSE;
\r
5762 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5763 switch (ms->name[0]) {
\r
5765 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5770 /* System sound from Control Panel (deprecated feature).
\r
5771 "$" alone or an unset sound name gets default beep (still in use). */
\r
5772 if (ms->name[1]) {
\r
5773 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5775 if (!ok) ok = MessageBeep(MB_OK);
\r
5778 /* Builtin wave resource, or "!" alone for silence */
\r
5779 if (ms->name[1]) {
\r
5780 if (ms->data == NULL) return FALSE;
\r
5781 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5787 /* .wav file. Error if not found. */
\r
5788 if (ms->data == NULL) return FALSE;
\r
5789 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5792 /* Don't print an error: this can happen innocently if the sound driver
\r
5793 is busy; for instance, if another instance of WinBoard is playing
\r
5794 a sound at about the same time. */
\r
5800 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5803 OPENFILENAME *ofn;
\r
5804 static UINT *number; /* gross that this is static */
\r
5806 switch (message) {
\r
5807 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5808 /* Center the dialog over the application window */
\r
5809 ofn = (OPENFILENAME *) lParam;
\r
5810 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5811 number = (UINT *) ofn->lCustData;
\r
5812 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5816 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5817 Translate(hDlg, 1536);
\r
5818 return FALSE; /* Allow for further processing */
\r
5821 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5822 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5824 return FALSE; /* Allow for further processing */
\r
5830 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5832 static UINT *number;
\r
5833 OPENFILENAME *ofname;
\r
5836 case WM_INITDIALOG:
\r
5837 Translate(hdlg, DLG_IndexNumber);
\r
5838 ofname = (OPENFILENAME *)lParam;
\r
5839 number = (UINT *)(ofname->lCustData);
\r
5842 ofnot = (OFNOTIFY *)lParam;
\r
5843 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5844 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5853 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5854 char *nameFilt, char *dlgTitle, UINT *number,
\r
5855 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5857 OPENFILENAME openFileName;
\r
5858 char buf1[MSG_SIZ];
\r
5861 if (fileName == NULL) fileName = buf1;
\r
5862 if (defName == NULL) {
\r
5863 safeStrCpy(fileName, "*.", 3 );
\r
5864 strcat(fileName, defExt);
\r
5866 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5868 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5869 if (number) *number = 0;
\r
5871 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5872 openFileName.hwndOwner = hwnd;
\r
5873 openFileName.hInstance = (HANDLE) hInst;
\r
5874 openFileName.lpstrFilter = nameFilt;
\r
5875 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5876 openFileName.nMaxCustFilter = 0L;
\r
5877 openFileName.nFilterIndex = 1L;
\r
5878 openFileName.lpstrFile = fileName;
\r
5879 openFileName.nMaxFile = MSG_SIZ;
\r
5880 openFileName.lpstrFileTitle = fileTitle;
\r
5881 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5882 openFileName.lpstrInitialDir = NULL;
\r
5883 openFileName.lpstrTitle = dlgTitle;
\r
5884 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5885 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5886 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5887 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5888 openFileName.nFileOffset = 0;
\r
5889 openFileName.nFileExtension = 0;
\r
5890 openFileName.lpstrDefExt = defExt;
\r
5891 openFileName.lCustData = (LONG) number;
\r
5892 openFileName.lpfnHook = oldDialog ?
\r
5893 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5894 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5896 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5897 GetOpenFileName(&openFileName)) {
\r
5898 /* open the file */
\r
5899 f = fopen(openFileName.lpstrFile, write);
\r
5901 MessageBox(hwnd, _("File open failed"), NULL,
\r
5902 MB_OK|MB_ICONEXCLAMATION);
\r
5906 int err = CommDlgExtendedError();
\r
5907 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
5916 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5918 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5921 * Get the first pop-up menu in the menu template. This is the
\r
5922 * menu that TrackPopupMenu displays.
\r
5924 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5925 TranslateOneMenu(10, hmenuTrackPopup);
\r
5927 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5930 * TrackPopup uses screen coordinates, so convert the
\r
5931 * coordinates of the mouse click to screen coordinates.
\r
5933 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5935 /* Draw and track the floating pop-up menu. */
\r
5936 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5937 pt.x, pt.y, 0, hwnd, NULL);
\r
5939 /* Destroy the menu.*/
\r
5940 DestroyMenu(hmenu);
\r
5945 int sizeX, sizeY, newSizeX, newSizeY;
\r
5947 } ResizeEditPlusButtonsClosure;
\r
5950 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5952 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5956 if (hChild == cl->hText) return TRUE;
\r
5957 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5958 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5959 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5960 ScreenToClient(cl->hDlg, &pt);
\r
5961 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5962 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5966 /* Resize a dialog that has a (rich) edit field filling most of
\r
5967 the top, with a row of buttons below */
\r
5969 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5972 int newTextHeight, newTextWidth;
\r
5973 ResizeEditPlusButtonsClosure cl;
\r
5975 /*if (IsIconic(hDlg)) return;*/
\r
5976 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5978 cl.hdwp = BeginDeferWindowPos(8);
\r
5980 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5981 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5982 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5983 if (newTextHeight < 0) {
\r
5984 newSizeY += -newTextHeight;
\r
5985 newTextHeight = 0;
\r
5987 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5988 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5994 cl.newSizeX = newSizeX;
\r
5995 cl.newSizeY = newSizeY;
\r
5996 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5998 EndDeferWindowPos(cl.hdwp);
\r
6001 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6003 RECT rChild, rParent;
\r
6004 int wChild, hChild, wParent, hParent;
\r
6005 int wScreen, hScreen, xNew, yNew;
\r
6008 /* Get the Height and Width of the child window */
\r
6009 GetWindowRect (hwndChild, &rChild);
\r
6010 wChild = rChild.right - rChild.left;
\r
6011 hChild = rChild.bottom - rChild.top;
\r
6013 /* Get the Height and Width of the parent window */
\r
6014 GetWindowRect (hwndParent, &rParent);
\r
6015 wParent = rParent.right - rParent.left;
\r
6016 hParent = rParent.bottom - rParent.top;
\r
6018 /* Get the display limits */
\r
6019 hdc = GetDC (hwndChild);
\r
6020 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6021 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6022 ReleaseDC(hwndChild, hdc);
\r
6024 /* Calculate new X position, then adjust for screen */
\r
6025 xNew = rParent.left + ((wParent - wChild) /2);
\r
6028 } else if ((xNew+wChild) > wScreen) {
\r
6029 xNew = wScreen - wChild;
\r
6032 /* Calculate new Y position, then adjust for screen */
\r
6034 yNew = rParent.top + ((hParent - hChild) /2);
\r
6037 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6042 } else if ((yNew+hChild) > hScreen) {
\r
6043 yNew = hScreen - hChild;
\r
6046 /* Set it, and return */
\r
6047 return SetWindowPos (hwndChild, NULL,
\r
6048 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6051 /* Center one window over another */
\r
6052 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6054 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6057 /*---------------------------------------------------------------------------*\
\r
6059 * Startup Dialog functions
\r
6061 \*---------------------------------------------------------------------------*/
\r
6063 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6065 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6067 while (*cd != NULL) {
\r
6068 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6074 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6076 char buf1[MAX_ARG_LEN];
\r
6079 if (str[0] == '@') {
\r
6080 FILE* f = fopen(str + 1, "r");
\r
6082 DisplayFatalError(str + 1, errno, 2);
\r
6085 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6087 buf1[len] = NULLCHAR;
\r
6091 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6094 char buf[MSG_SIZ];
\r
6095 char *end = strchr(str, '\n');
\r
6096 if (end == NULL) return;
\r
6097 memcpy(buf, str, end - str);
\r
6098 buf[end - str] = NULLCHAR;
\r
6099 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6105 SetStartupDialogEnables(HWND hDlg)
\r
6107 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6108 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6109 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6110 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6111 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6112 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6113 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6114 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6115 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6116 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6117 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6118 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6119 IsDlgButtonChecked(hDlg, OPT_View));
\r
6123 QuoteForFilename(char *filename)
\r
6125 int dquote, space;
\r
6126 dquote = strchr(filename, '"') != NULL;
\r
6127 space = strchr(filename, ' ') != NULL;
\r
6128 if (dquote || space) {
\r
6140 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6142 char buf[MSG_SIZ];
\r
6145 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6146 q = QuoteForFilename(nthcp);
\r
6147 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6148 if (*nthdir != NULLCHAR) {
\r
6149 q = QuoteForFilename(nthdir);
\r
6150 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6152 if (*nthcp == NULLCHAR) {
\r
6153 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6154 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6155 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6156 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6161 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6163 char buf[MSG_SIZ];
\r
6167 switch (message) {
\r
6168 case WM_INITDIALOG:
\r
6169 /* Center the dialog */
\r
6170 CenterWindow (hDlg, GetDesktopWindow());
\r
6171 Translate(hDlg, DLG_Startup);
\r
6172 /* Initialize the dialog items */
\r
6173 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6174 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6175 firstChessProgramNames);
\r
6176 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6177 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6178 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6179 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6180 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6181 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6182 if (*appData.icsHelper != NULLCHAR) {
\r
6183 char *q = QuoteForFilename(appData.icsHelper);
\r
6184 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6186 if (*appData.icsHost == NULLCHAR) {
\r
6187 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6188 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6189 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6190 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6191 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6194 if (appData.icsActive) {
\r
6195 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6197 else if (appData.noChessProgram) {
\r
6198 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6201 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6204 SetStartupDialogEnables(hDlg);
\r
6208 switch (LOWORD(wParam)) {
\r
6210 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6211 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6212 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6214 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6215 ParseArgs(StringGet, &p);
\r
6216 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6217 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6219 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6220 ParseArgs(StringGet, &p);
\r
6221 SwapEngines(singleList); // ... and then make it 'second'
\r
6222 appData.noChessProgram = FALSE;
\r
6223 appData.icsActive = FALSE;
\r
6224 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6225 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6226 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6228 ParseArgs(StringGet, &p);
\r
6229 if (appData.zippyPlay) {
\r
6230 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6231 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6233 ParseArgs(StringGet, &p);
\r
6235 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6236 appData.noChessProgram = TRUE;
\r
6237 appData.icsActive = FALSE;
\r
6239 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6240 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6243 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6244 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6246 ParseArgs(StringGet, &p);
\r
6248 EndDialog(hDlg, TRUE);
\r
6255 case IDM_HELPCONTENTS:
\r
6256 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6257 MessageBox (GetFocus(),
\r
6258 _("Unable to activate help"),
\r
6259 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6264 SetStartupDialogEnables(hDlg);
\r
6272 /*---------------------------------------------------------------------------*\
\r
6274 * About box dialog functions
\r
6276 \*---------------------------------------------------------------------------*/
\r
6278 /* Process messages for "About" dialog box */
\r
6280 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6282 switch (message) {
\r
6283 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6284 /* Center the dialog over the application window */
\r
6285 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6286 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6287 Translate(hDlg, ABOUTBOX);
\r
6291 case WM_COMMAND: /* message: received a command */
\r
6292 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6293 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6294 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6302 /*---------------------------------------------------------------------------*\
\r
6304 * Comment Dialog functions
\r
6306 \*---------------------------------------------------------------------------*/
\r
6309 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6311 static HANDLE hwndText = NULL;
\r
6312 int len, newSizeX, newSizeY, flags;
\r
6313 static int sizeX, sizeY;
\r
6318 switch (message) {
\r
6319 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6320 /* Initialize the dialog items */
\r
6321 Translate(hDlg, DLG_EditComment);
\r
6322 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6323 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6324 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6325 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6326 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6327 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6328 SetWindowText(hDlg, commentTitle);
\r
6329 if (editComment) {
\r
6330 SetFocus(hwndText);
\r
6332 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6334 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6335 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6336 MAKELPARAM(FALSE, 0));
\r
6337 /* Size and position the dialog */
\r
6338 if (!commentDialog) {
\r
6339 commentDialog = hDlg;
\r
6340 flags = SWP_NOZORDER;
\r
6341 GetClientRect(hDlg, &rect);
\r
6342 sizeX = rect.right;
\r
6343 sizeY = rect.bottom;
\r
6344 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6345 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6346 WINDOWPLACEMENT wp;
\r
6347 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6348 wp.length = sizeof(WINDOWPLACEMENT);
\r
6350 wp.showCmd = SW_SHOW;
\r
6351 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6352 wp.rcNormalPosition.left = wpComment.x;
\r
6353 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6354 wp.rcNormalPosition.top = wpComment.y;
\r
6355 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6356 SetWindowPlacement(hDlg, &wp);
\r
6358 GetClientRect(hDlg, &rect);
\r
6359 newSizeX = rect.right;
\r
6360 newSizeY = rect.bottom;
\r
6361 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6362 newSizeX, newSizeY);
\r
6367 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6370 case WM_COMMAND: /* message: received a command */
\r
6371 switch (LOWORD(wParam)) {
\r
6373 if (editComment) {
\r
6375 /* Read changed options from the dialog box */
\r
6376 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6377 len = GetWindowTextLength(hwndText);
\r
6378 str = (char *) malloc(len + 1);
\r
6379 GetWindowText(hwndText, str, len + 1);
\r
6388 ReplaceComment(commentIndex, str);
\r
6395 case OPT_CancelComment:
\r
6399 case OPT_ClearComment:
\r
6400 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6403 case OPT_EditComment:
\r
6404 EditCommentEvent();
\r
6412 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6413 if( wParam == OPT_CommentText ) {
\r
6414 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6416 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6417 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6421 pt.x = LOWORD( lpMF->lParam );
\r
6422 pt.y = HIWORD( lpMF->lParam );
\r
6424 if(lpMF->msg == WM_CHAR) {
\r
6426 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6427 index = sel.cpMin;
\r
6429 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6431 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6432 len = GetWindowTextLength(hwndText);
\r
6433 str = (char *) malloc(len + 1);
\r
6434 GetWindowText(hwndText, str, len + 1);
\r
6435 ReplaceComment(commentIndex, str);
\r
6436 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6437 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6440 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6441 lpMF->msg = WM_USER;
\r
6449 newSizeX = LOWORD(lParam);
\r
6450 newSizeY = HIWORD(lParam);
\r
6451 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6456 case WM_GETMINMAXINFO:
\r
6457 /* Prevent resizing window too small */
\r
6458 mmi = (MINMAXINFO *) lParam;
\r
6459 mmi->ptMinTrackSize.x = 100;
\r
6460 mmi->ptMinTrackSize.y = 100;
\r
6467 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6472 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6474 if (str == NULL) str = "";
\r
6475 p = (char *) malloc(2 * strlen(str) + 2);
\r
6478 if (*str == '\n') *q++ = '\r';
\r
6482 if (commentText != NULL) free(commentText);
\r
6484 commentIndex = index;
\r
6485 commentTitle = title;
\r
6487 editComment = edit;
\r
6489 if (commentDialog) {
\r
6490 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6491 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6493 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6494 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6495 hwndMain, (DLGPROC)lpProc);
\r
6496 FreeProcInstance(lpProc);
\r
6502 /*---------------------------------------------------------------------------*\
\r
6504 * Type-in move dialog functions
\r
6506 \*---------------------------------------------------------------------------*/
\r
6509 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6511 char move[MSG_SIZ];
\r
6514 switch (message) {
\r
6515 case WM_INITDIALOG:
\r
6516 move[0] = (char) lParam;
\r
6517 move[1] = NULLCHAR;
\r
6518 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6519 Translate(hDlg, DLG_TypeInMove);
\r
6520 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6521 SetWindowText(hInput, move);
\r
6523 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6527 switch (LOWORD(wParam)) {
\r
6530 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6531 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6532 TypeInDoneEvent(move);
\r
6533 EndDialog(hDlg, TRUE);
\r
6536 EndDialog(hDlg, FALSE);
\r
6547 PopUpMoveDialog(char firstchar)
\r
6551 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6552 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6553 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6554 FreeProcInstance(lpProc);
\r
6557 /*---------------------------------------------------------------------------*\
\r
6559 * Type-in name dialog functions
\r
6561 \*---------------------------------------------------------------------------*/
\r
6564 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6566 char move[MSG_SIZ];
\r
6569 switch (message) {
\r
6570 case WM_INITDIALOG:
\r
6571 move[0] = (char) lParam;
\r
6572 move[1] = NULLCHAR;
\r
6573 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6574 Translate(hDlg, DLG_TypeInName);
\r
6575 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6576 SetWindowText(hInput, move);
\r
6578 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6582 switch (LOWORD(wParam)) {
\r
6584 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6585 appData.userName = strdup(move);
\r
6588 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6589 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6590 DisplayTitle(move);
\r
6594 EndDialog(hDlg, TRUE);
\r
6597 EndDialog(hDlg, FALSE);
\r
6608 PopUpNameDialog(char firstchar)
\r
6612 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6613 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6614 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6615 FreeProcInstance(lpProc);
\r
6618 /*---------------------------------------------------------------------------*\
\r
6622 \*---------------------------------------------------------------------------*/
\r
6624 /* Nonmodal error box */
\r
6625 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6626 WPARAM wParam, LPARAM lParam);
\r
6629 ErrorPopUp(char *title, char *content)
\r
6633 BOOLEAN modal = hwndMain == NULL;
\r
6651 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6652 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6655 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6657 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6658 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6659 hwndMain, (DLGPROC)lpProc);
\r
6660 FreeProcInstance(lpProc);
\r
6667 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6668 if (errorDialog == NULL) return;
\r
6669 DestroyWindow(errorDialog);
\r
6670 errorDialog = NULL;
\r
6671 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6675 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6680 switch (message) {
\r
6681 case WM_INITDIALOG:
\r
6682 GetWindowRect(hDlg, &rChild);
\r
6685 SetWindowPos(hDlg, NULL, rChild.left,
\r
6686 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6687 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6691 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6692 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6693 and it doesn't work when you resize the dialog.
\r
6694 For now, just give it a default position.
\r
6696 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6697 Translate(hDlg, DLG_Error);
\r
6699 errorDialog = hDlg;
\r
6700 SetWindowText(hDlg, errorTitle);
\r
6701 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6702 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6706 switch (LOWORD(wParam)) {
\r
6709 if (errorDialog == hDlg) errorDialog = NULL;
\r
6710 DestroyWindow(hDlg);
\r
6722 HWND gothicDialog = NULL;
\r
6725 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6729 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6731 switch (message) {
\r
6732 case WM_INITDIALOG:
\r
6733 GetWindowRect(hDlg, &rChild);
\r
6735 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6739 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6740 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6741 and it doesn't work when you resize the dialog.
\r
6742 For now, just give it a default position.
\r
6744 gothicDialog = hDlg;
\r
6745 SetWindowText(hDlg, errorTitle);
\r
6746 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6747 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6751 switch (LOWORD(wParam)) {
\r
6754 if (errorDialog == hDlg) errorDialog = NULL;
\r
6755 DestroyWindow(hDlg);
\r
6767 GothicPopUp(char *title, VariantClass variant)
\r
6770 static char *lastTitle;
\r
6772 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6773 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6775 if(lastTitle != title && gothicDialog != NULL) {
\r
6776 DestroyWindow(gothicDialog);
\r
6777 gothicDialog = NULL;
\r
6779 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6780 title = lastTitle;
\r
6781 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6782 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6783 hwndMain, (DLGPROC)lpProc);
\r
6784 FreeProcInstance(lpProc);
\r
6789 /*---------------------------------------------------------------------------*\
\r
6791 * Ics Interaction console functions
\r
6793 \*---------------------------------------------------------------------------*/
\r
6795 #define HISTORY_SIZE 64
\r
6796 static char *history[HISTORY_SIZE];
\r
6797 int histIn = 0, histP = 0;
\r
6800 SaveInHistory(char *cmd)
\r
6802 if (history[histIn] != NULL) {
\r
6803 free(history[histIn]);
\r
6804 history[histIn] = NULL;
\r
6806 if (*cmd == NULLCHAR) return;
\r
6807 history[histIn] = StrSave(cmd);
\r
6808 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6809 if (history[histIn] != NULL) {
\r
6810 free(history[histIn]);
\r
6811 history[histIn] = NULL;
\r
6817 PrevInHistory(char *cmd)
\r
6820 if (histP == histIn) {
\r
6821 if (history[histIn] != NULL) free(history[histIn]);
\r
6822 history[histIn] = StrSave(cmd);
\r
6824 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6825 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6827 return history[histP];
\r
6833 if (histP == histIn) return NULL;
\r
6834 histP = (histP + 1) % HISTORY_SIZE;
\r
6835 return history[histP];
\r
6839 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6843 hmenu = LoadMenu(hInst, "TextMenu");
\r
6844 h = GetSubMenu(hmenu, 0);
\r
6846 if (strcmp(e->item, "-") == 0) {
\r
6847 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6848 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6849 int flags = MF_STRING, j = 0;
\r
6850 if (e->item[0] == '|') {
\r
6851 flags |= MF_MENUBARBREAK;
\r
6854 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6855 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6863 WNDPROC consoleTextWindowProc;
\r
6866 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6868 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6869 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6873 SetWindowText(hInput, command);
\r
6875 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6877 sel.cpMin = 999999;
\r
6878 sel.cpMax = 999999;
\r
6879 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6884 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6885 if (sel.cpMin == sel.cpMax) {
\r
6886 /* Expand to surrounding word */
\r
6889 tr.chrg.cpMax = sel.cpMin;
\r
6890 tr.chrg.cpMin = --sel.cpMin;
\r
6891 if (sel.cpMin < 0) break;
\r
6892 tr.lpstrText = name;
\r
6893 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6894 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6898 tr.chrg.cpMin = sel.cpMax;
\r
6899 tr.chrg.cpMax = ++sel.cpMax;
\r
6900 tr.lpstrText = name;
\r
6901 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6902 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6905 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6906 MessageBeep(MB_ICONEXCLAMATION);
\r
6910 tr.lpstrText = name;
\r
6911 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6913 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6914 MessageBeep(MB_ICONEXCLAMATION);
\r
6917 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6920 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
6921 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
6922 SetWindowText(hInput, buf);
\r
6923 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6925 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
6926 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
6927 SetWindowText(hInput, buf);
\r
6928 sel.cpMin = 999999;
\r
6929 sel.cpMax = 999999;
\r
6930 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6936 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6941 switch (message) {
\r
6943 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6944 if(wParam=='R') return 0;
\r
6947 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6950 sel.cpMin = 999999;
\r
6951 sel.cpMax = 999999;
\r
6952 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6953 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6958 if(wParam != '\022') {
\r
6959 if (wParam == '\t') {
\r
6960 if (GetKeyState(VK_SHIFT) < 0) {
\r
6962 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6963 if (buttonDesc[0].hwnd) {
\r
6964 SetFocus(buttonDesc[0].hwnd);
\r
6966 SetFocus(hwndMain);
\r
6970 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6973 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6974 JAWS_DELETE( SetFocus(hInput); )
\r
6975 SendMessage(hInput, message, wParam, lParam);
\r
6978 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
6980 case WM_RBUTTONDOWN:
\r
6981 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6982 /* Move selection here if it was empty */
\r
6984 pt.x = LOWORD(lParam);
\r
6985 pt.y = HIWORD(lParam);
\r
6986 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6987 if (sel.cpMin == sel.cpMax) {
\r
6988 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6989 sel.cpMax = sel.cpMin;
\r
6990 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6992 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6993 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
6995 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6996 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6997 if (sel.cpMin == sel.cpMax) {
\r
6998 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6999 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7001 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7002 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7004 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7005 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7006 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7007 MenuPopup(hwnd, pt, hmenu, -1);
\r
7011 case WM_RBUTTONUP:
\r
7012 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7013 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7014 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7018 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7020 return SendMessage(hInput, message, wParam, lParam);
\r
7021 case WM_MBUTTONDOWN:
\r
7022 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7024 switch (LOWORD(wParam)) {
\r
7025 case IDM_QuickPaste:
\r
7027 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7028 if (sel.cpMin == sel.cpMax) {
\r
7029 MessageBeep(MB_ICONEXCLAMATION);
\r
7032 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7033 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7034 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7039 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7042 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7045 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7049 int i = LOWORD(wParam) - IDM_CommandX;
\r
7050 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7051 icsTextMenuEntry[i].command != NULL) {
\r
7052 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7053 icsTextMenuEntry[i].getname,
\r
7054 icsTextMenuEntry[i].immediate);
\r
7062 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7065 WNDPROC consoleInputWindowProc;
\r
7068 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7070 char buf[MSG_SIZ];
\r
7072 static BOOL sendNextChar = FALSE;
\r
7073 static BOOL quoteNextChar = FALSE;
\r
7074 InputSource *is = consoleInputSource;
\r
7078 switch (message) {
\r
7080 if (!appData.localLineEditing || sendNextChar) {
\r
7081 is->buf[0] = (CHAR) wParam;
\r
7083 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7084 sendNextChar = FALSE;
\r
7087 if (quoteNextChar) {
\r
7088 buf[0] = (char) wParam;
\r
7089 buf[1] = NULLCHAR;
\r
7090 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7091 quoteNextChar = FALSE;
\r
7095 case '\r': /* Enter key */
\r
7096 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7097 if (consoleEcho) SaveInHistory(is->buf);
\r
7098 is->buf[is->count++] = '\n';
\r
7099 is->buf[is->count] = NULLCHAR;
\r
7100 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7101 if (consoleEcho) {
\r
7102 ConsoleOutput(is->buf, is->count, TRUE);
\r
7103 } else if (appData.localLineEditing) {
\r
7104 ConsoleOutput("\n", 1, TRUE);
\r
7107 case '\033': /* Escape key */
\r
7108 SetWindowText(hwnd, "");
\r
7109 cf.cbSize = sizeof(CHARFORMAT);
\r
7110 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7111 if (consoleEcho) {
\r
7112 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7114 cf.crTextColor = COLOR_ECHOOFF;
\r
7116 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7117 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7119 case '\t': /* Tab key */
\r
7120 if (GetKeyState(VK_SHIFT) < 0) {
\r
7122 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7125 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7126 if (buttonDesc[0].hwnd) {
\r
7127 SetFocus(buttonDesc[0].hwnd);
\r
7129 SetFocus(hwndMain);
\r
7133 case '\023': /* Ctrl+S */
\r
7134 sendNextChar = TRUE;
\r
7136 case '\021': /* Ctrl+Q */
\r
7137 quoteNextChar = TRUE;
\r
7147 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7148 p = PrevInHistory(buf);
\r
7150 SetWindowText(hwnd, p);
\r
7151 sel.cpMin = 999999;
\r
7152 sel.cpMax = 999999;
\r
7153 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7158 p = NextInHistory();
\r
7160 SetWindowText(hwnd, p);
\r
7161 sel.cpMin = 999999;
\r
7162 sel.cpMax = 999999;
\r
7163 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7169 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7173 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7177 case WM_MBUTTONDOWN:
\r
7178 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7179 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7181 case WM_RBUTTONUP:
\r
7182 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7183 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7184 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7188 hmenu = LoadMenu(hInst, "InputMenu");
\r
7189 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7190 if (sel.cpMin == sel.cpMax) {
\r
7191 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7192 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7194 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7195 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7197 pt.x = LOWORD(lParam);
\r
7198 pt.y = HIWORD(lParam);
\r
7199 MenuPopup(hwnd, pt, hmenu, -1);
\r
7203 switch (LOWORD(wParam)) {
\r
7205 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7207 case IDM_SelectAll:
\r
7209 sel.cpMax = -1; /*999999?*/
\r
7210 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7213 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7216 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7219 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7224 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7227 #define CO_MAX 100000
\r
7228 #define CO_TRIM 1000
\r
7231 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7233 static SnapData sd;
\r
7234 HWND hText, hInput;
\r
7236 static int sizeX, sizeY;
\r
7237 int newSizeX, newSizeY;
\r
7241 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7242 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7244 switch (message) {
\r
7246 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7248 ENLINK *pLink = (ENLINK*)lParam;
\r
7249 if (pLink->msg == WM_LBUTTONUP)
\r
7253 tr.chrg = pLink->chrg;
\r
7254 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7255 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7256 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7257 free(tr.lpstrText);
\r
7261 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7262 hwndConsole = hDlg;
\r
7264 consoleTextWindowProc = (WNDPROC)
\r
7265 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7266 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7267 consoleInputWindowProc = (WNDPROC)
\r
7268 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7269 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7270 Colorize(ColorNormal, TRUE);
\r
7271 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7272 ChangedConsoleFont();
\r
7273 GetClientRect(hDlg, &rect);
\r
7274 sizeX = rect.right;
\r
7275 sizeY = rect.bottom;
\r
7276 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7277 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7278 WINDOWPLACEMENT wp;
\r
7279 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7280 wp.length = sizeof(WINDOWPLACEMENT);
\r
7282 wp.showCmd = SW_SHOW;
\r
7283 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7284 wp.rcNormalPosition.left = wpConsole.x;
\r
7285 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7286 wp.rcNormalPosition.top = wpConsole.y;
\r
7287 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7288 SetWindowPlacement(hDlg, &wp);
\r
7291 // [HGM] Chessknight's change 2004-07-13
\r
7292 else { /* Determine Defaults */
\r
7293 WINDOWPLACEMENT wp;
\r
7294 wpConsole.x = wpMain.width + 1;
\r
7295 wpConsole.y = wpMain.y;
\r
7296 wpConsole.width = screenWidth - wpMain.width;
\r
7297 wpConsole.height = wpMain.height;
\r
7298 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7299 wp.length = sizeof(WINDOWPLACEMENT);
\r
7301 wp.showCmd = SW_SHOW;
\r
7302 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7303 wp.rcNormalPosition.left = wpConsole.x;
\r
7304 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7305 wp.rcNormalPosition.top = wpConsole.y;
\r
7306 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7307 SetWindowPlacement(hDlg, &wp);
\r
7310 // Allow hText to highlight URLs and send notifications on them
\r
7311 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7312 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7313 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7314 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7328 if (IsIconic(hDlg)) break;
\r
7329 newSizeX = LOWORD(lParam);
\r
7330 newSizeY = HIWORD(lParam);
\r
7331 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7332 RECT rectText, rectInput;
\r
7334 int newTextHeight, newTextWidth;
\r
7335 GetWindowRect(hText, &rectText);
\r
7336 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7337 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7338 if (newTextHeight < 0) {
\r
7339 newSizeY += -newTextHeight;
\r
7340 newTextHeight = 0;
\r
7342 SetWindowPos(hText, NULL, 0, 0,
\r
7343 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7344 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7345 pt.x = rectInput.left;
\r
7346 pt.y = rectInput.top + newSizeY - sizeY;
\r
7347 ScreenToClient(hDlg, &pt);
\r
7348 SetWindowPos(hInput, NULL,
\r
7349 pt.x, pt.y, /* needs client coords */
\r
7350 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7351 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7357 case WM_GETMINMAXINFO:
\r
7358 /* Prevent resizing window too small */
\r
7359 mmi = (MINMAXINFO *) lParam;
\r
7360 mmi->ptMinTrackSize.x = 100;
\r
7361 mmi->ptMinTrackSize.y = 100;
\r
7364 /* [AS] Snapping */
\r
7365 case WM_ENTERSIZEMOVE:
\r
7366 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7369 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7372 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7374 case WM_EXITSIZEMOVE:
\r
7375 UpdateICSWidth(hText);
\r
7376 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7379 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7387 if (hwndConsole) return;
\r
7388 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7389 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7394 ConsoleOutput(char* data, int length, int forceVisible)
\r
7399 char buf[CO_MAX+1];
\r
7402 static int delayLF = 0;
\r
7403 CHARRANGE savesel, sel;
\r
7405 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7413 while (length--) {
\r
7421 } else if (*p == '\007') {
\r
7422 MyPlaySound(&sounds[(int)SoundBell]);
\r
7429 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7430 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7431 /* Save current selection */
\r
7432 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7433 exlen = GetWindowTextLength(hText);
\r
7434 /* Find out whether current end of text is visible */
\r
7435 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7436 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7437 /* Trim existing text if it's too long */
\r
7438 if (exlen + (q - buf) > CO_MAX) {
\r
7439 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7442 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7443 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7445 savesel.cpMin -= trim;
\r
7446 savesel.cpMax -= trim;
\r
7447 if (exlen < 0) exlen = 0;
\r
7448 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7449 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7451 /* Append the new text */
\r
7452 sel.cpMin = exlen;
\r
7453 sel.cpMax = exlen;
\r
7454 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7455 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7456 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7457 if (forceVisible || exlen == 0 ||
\r
7458 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7459 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7460 /* Scroll to make new end of text visible if old end of text
\r
7461 was visible or new text is an echo of user typein */
\r
7462 sel.cpMin = 9999999;
\r
7463 sel.cpMax = 9999999;
\r
7464 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7465 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7466 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7467 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7469 if (savesel.cpMax == exlen || forceVisible) {
\r
7470 /* Move insert point to new end of text if it was at the old
\r
7471 end of text or if the new text is an echo of user typein */
\r
7472 sel.cpMin = 9999999;
\r
7473 sel.cpMax = 9999999;
\r
7474 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7476 /* Restore previous selection */
\r
7477 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7479 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7486 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7490 COLORREF oldFg, oldBg;
\r
7494 if(copyNumber > 1)
\r
7495 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7497 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7498 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7499 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7502 rect.right = x + squareSize;
\r
7504 rect.bottom = y + squareSize;
\r
7507 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7508 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7509 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7510 &rect, str, strlen(str), NULL);
\r
7512 (void) SetTextColor(hdc, oldFg);
\r
7513 (void) SetBkColor(hdc, oldBg);
\r
7514 (void) SelectObject(hdc, oldFont);
\r
7518 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7519 RECT *rect, char *color, char *flagFell)
\r
7523 COLORREF oldFg, oldBg;
\r
7526 if (twoBoards && partnerUp) return;
\r
7527 if (appData.clockMode) {
\r
7529 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7531 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7538 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7539 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7541 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7542 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7544 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7548 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7549 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7550 rect, str, strlen(str), NULL);
\r
7551 if(logoHeight > 0 && appData.clockMode) {
\r
7553 str += strlen(color)+2;
\r
7554 r.top = rect->top + logoHeight/2;
\r
7555 r.left = rect->left;
\r
7556 r.right = rect->right;
\r
7557 r.bottom = rect->bottom;
\r
7558 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7559 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7560 &r, str, strlen(str), NULL);
\r
7562 (void) SetTextColor(hdc, oldFg);
\r
7563 (void) SetBkColor(hdc, oldBg);
\r
7564 (void) SelectObject(hdc, oldFont);
\r
7569 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7575 if( count <= 0 ) {
\r
7576 if (appData.debugMode) {
\r
7577 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7580 return ERROR_INVALID_USER_BUFFER;
\r
7583 ResetEvent(ovl->hEvent);
\r
7584 ovl->Offset = ovl->OffsetHigh = 0;
\r
7585 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7589 err = GetLastError();
\r
7590 if (err == ERROR_IO_PENDING) {
\r
7591 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7595 err = GetLastError();
\r
7602 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7607 ResetEvent(ovl->hEvent);
\r
7608 ovl->Offset = ovl->OffsetHigh = 0;
\r
7609 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7613 err = GetLastError();
\r
7614 if (err == ERROR_IO_PENDING) {
\r
7615 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7619 err = GetLastError();
\r
7625 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7626 void CheckForInputBufferFull( InputSource * is )
\r
7628 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7629 /* Look for end of line */
\r
7630 char * p = is->buf;
\r
7632 while( p < is->next && *p != '\n' ) {
\r
7636 if( p >= is->next ) {
\r
7637 if (appData.debugMode) {
\r
7638 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7641 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7642 is->count = (DWORD) -1;
\r
7643 is->next = is->buf;
\r
7649 InputThread(LPVOID arg)
\r
7654 is = (InputSource *) arg;
\r
7655 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7656 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7657 while (is->hThread != NULL) {
\r
7658 is->error = DoReadFile(is->hFile, is->next,
\r
7659 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7660 &is->count, &ovl);
\r
7661 if (is->error == NO_ERROR) {
\r
7662 is->next += is->count;
\r
7664 if (is->error == ERROR_BROKEN_PIPE) {
\r
7665 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7668 is->count = (DWORD) -1;
\r
7669 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7674 CheckForInputBufferFull( is );
\r
7676 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7678 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7680 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7683 CloseHandle(ovl.hEvent);
\r
7684 CloseHandle(is->hFile);
\r
7686 if (appData.debugMode) {
\r
7687 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7694 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7696 NonOvlInputThread(LPVOID arg)
\r
7703 is = (InputSource *) arg;
\r
7704 while (is->hThread != NULL) {
\r
7705 is->error = ReadFile(is->hFile, is->next,
\r
7706 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7707 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7708 if (is->error == NO_ERROR) {
\r
7709 /* Change CRLF to LF */
\r
7710 if (is->next > is->buf) {
\r
7712 i = is->count + 1;
\r
7720 if (prev == '\r' && *p == '\n') {
\r
7732 if (is->error == ERROR_BROKEN_PIPE) {
\r
7733 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7736 is->count = (DWORD) -1;
\r
7740 CheckForInputBufferFull( is );
\r
7742 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7744 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7746 if (is->count < 0) break; /* Quit on error */
\r
7748 CloseHandle(is->hFile);
\r
7753 SocketInputThread(LPVOID arg)
\r
7757 is = (InputSource *) arg;
\r
7758 while (is->hThread != NULL) {
\r
7759 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7760 if ((int)is->count == SOCKET_ERROR) {
\r
7761 is->count = (DWORD) -1;
\r
7762 is->error = WSAGetLastError();
\r
7764 is->error = NO_ERROR;
\r
7765 is->next += is->count;
\r
7766 if (is->count == 0 && is->second == is) {
\r
7767 /* End of file on stderr; quit with no message */
\r
7771 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7773 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7775 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7781 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7785 is = (InputSource *) lParam;
\r
7786 if (is->lineByLine) {
\r
7787 /* Feed in lines one by one */
\r
7788 char *p = is->buf;
\r
7790 while (q < is->next) {
\r
7791 if (*q++ == '\n') {
\r
7792 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7797 /* Move any partial line to the start of the buffer */
\r
7799 while (p < is->next) {
\r
7804 if (is->error != NO_ERROR || is->count == 0) {
\r
7805 /* Notify backend of the error. Note: If there was a partial
\r
7806 line at the end, it is not flushed through. */
\r
7807 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7810 /* Feed in the whole chunk of input at once */
\r
7811 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7812 is->next = is->buf;
\r
7816 /*---------------------------------------------------------------------------*\
\r
7818 * Menu enables. Used when setting various modes.
\r
7820 \*---------------------------------------------------------------------------*/
\r
7828 GreyRevert(Boolean grey)
\r
7829 { // [HGM] vari: for retracting variations in local mode
\r
7830 HMENU hmenu = GetMenu(hwndMain);
\r
7831 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7832 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7836 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7838 while (enab->item > 0) {
\r
7839 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7844 Enables gnuEnables[] = {
\r
7845 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7846 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7847 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7848 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7849 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7850 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7851 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7852 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7853 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7854 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7855 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7856 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7857 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7859 // Needed to switch from ncp to GNU mode on Engine Load
\r
7860 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7861 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7862 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7863 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7864 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7865 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7866 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7867 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7868 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7869 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7870 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7871 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7872 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7873 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7877 Enables icsEnables[] = {
\r
7878 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7879 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7880 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7881 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7882 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7883 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7884 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7885 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7886 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7887 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7888 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7889 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7890 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7891 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
7892 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
7893 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7894 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7895 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7896 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7897 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
7902 Enables zippyEnables[] = {
\r
7903 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7904 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7905 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7906 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7911 Enables ncpEnables[] = {
\r
7912 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7913 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7914 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7915 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7916 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7917 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7918 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7919 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7920 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7921 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7922 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7923 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7924 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7925 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7926 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7927 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7928 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7929 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7930 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7931 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7932 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7933 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
7937 Enables trainingOnEnables[] = {
\r
7938 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7939 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
7940 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7941 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7942 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7943 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7944 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7945 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7946 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7950 Enables trainingOffEnables[] = {
\r
7951 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7952 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
7953 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7954 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7955 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7956 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7957 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7958 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7959 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7963 /* These modify either ncpEnables or gnuEnables */
\r
7964 Enables cmailEnables[] = {
\r
7965 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7966 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7967 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7968 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7969 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7970 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7971 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7975 Enables machineThinkingEnables[] = {
\r
7976 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7980 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7981 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7982 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7983 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7984 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7985 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7986 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7987 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7988 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7989 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7990 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7991 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7995 Enables userThinkingEnables[] = {
\r
7996 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7997 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7998 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7999 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8000 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8001 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8002 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8003 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8004 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8005 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8006 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8007 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8008 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8009 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8010 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8011 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8015 /*---------------------------------------------------------------------------*\
\r
8017 * Front-end interface functions exported by XBoard.
\r
8018 * Functions appear in same order as prototypes in frontend.h.
\r
8020 \*---------------------------------------------------------------------------*/
\r
8022 CheckMark(UINT item, int state)
\r
8024 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8030 static UINT prevChecked = 0;
\r
8031 static int prevPausing = 0;
\r
8034 if (pausing != prevPausing) {
\r
8035 prevPausing = pausing;
\r
8036 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8037 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8038 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8041 switch (gameMode) {
\r
8042 case BeginningOfGame:
\r
8043 if (appData.icsActive)
\r
8044 nowChecked = IDM_IcsClient;
\r
8045 else if (appData.noChessProgram)
\r
8046 nowChecked = IDM_EditGame;
\r
8048 nowChecked = IDM_MachineBlack;
\r
8050 case MachinePlaysBlack:
\r
8051 nowChecked = IDM_MachineBlack;
\r
8053 case MachinePlaysWhite:
\r
8054 nowChecked = IDM_MachineWhite;
\r
8056 case TwoMachinesPlay:
\r
8057 nowChecked = IDM_TwoMachines;
\r
8060 nowChecked = IDM_AnalysisMode;
\r
8063 nowChecked = IDM_AnalyzeFile;
\r
8066 nowChecked = IDM_EditGame;
\r
8068 case PlayFromGameFile:
\r
8069 nowChecked = IDM_LoadGame;
\r
8071 case EditPosition:
\r
8072 nowChecked = IDM_EditPosition;
\r
8075 nowChecked = IDM_Training;
\r
8077 case IcsPlayingWhite:
\r
8078 case IcsPlayingBlack:
\r
8079 case IcsObserving:
\r
8081 nowChecked = IDM_IcsClient;
\r
8088 CheckMark(prevChecked, MF_UNCHECKED);
\r
8089 CheckMark(nowChecked, MF_CHECKED);
\r
8090 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8092 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8093 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8094 MF_BYCOMMAND|MF_ENABLED);
\r
8096 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8097 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8100 prevChecked = nowChecked;
\r
8102 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8103 if (appData.icsActive) {
\r
8104 if (appData.icsEngineAnalyze) {
\r
8105 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8107 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8110 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8116 HMENU hmenu = GetMenu(hwndMain);
\r
8117 SetMenuEnables(hmenu, icsEnables);
\r
8118 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8119 MF_BYCOMMAND|MF_ENABLED);
\r
8121 if (appData.zippyPlay) {
\r
8122 SetMenuEnables(hmenu, zippyEnables);
\r
8123 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8124 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8125 MF_BYCOMMAND|MF_ENABLED);
\r
8133 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8139 HMENU hmenu = GetMenu(hwndMain);
\r
8140 SetMenuEnables(hmenu, ncpEnables);
\r
8141 DrawMenuBar(hwndMain);
\r
8147 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8151 SetTrainingModeOn()
\r
8154 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8155 for (i = 0; i < N_BUTTONS; i++) {
\r
8156 if (buttonDesc[i].hwnd != NULL)
\r
8157 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8162 VOID SetTrainingModeOff()
\r
8165 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8166 for (i = 0; i < N_BUTTONS; i++) {
\r
8167 if (buttonDesc[i].hwnd != NULL)
\r
8168 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8174 SetUserThinkingEnables()
\r
8176 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8180 SetMachineThinkingEnables()
\r
8182 HMENU hMenu = GetMenu(hwndMain);
\r
8183 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8185 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8187 if (gameMode == MachinePlaysBlack) {
\r
8188 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8189 } else if (gameMode == MachinePlaysWhite) {
\r
8190 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8191 } else if (gameMode == TwoMachinesPlay) {
\r
8192 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8198 DisplayTitle(char *str)
\r
8200 char title[MSG_SIZ], *host;
\r
8201 if (str[0] != NULLCHAR) {
\r
8202 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8203 } else if (appData.icsActive) {
\r
8204 if (appData.icsCommPort[0] != NULLCHAR)
\r
8207 host = appData.icsHost;
\r
8208 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8209 } else if (appData.noChessProgram) {
\r
8210 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8212 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8213 strcat(title, ": ");
\r
8214 strcat(title, first.tidy);
\r
8216 SetWindowText(hwndMain, title);
\r
8221 DisplayMessage(char *str1, char *str2)
\r
8225 int remain = MESSAGE_TEXT_MAX - 1;
\r
8228 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8229 messageText[0] = NULLCHAR;
\r
8231 len = strlen(str1);
\r
8232 if (len > remain) len = remain;
\r
8233 strncpy(messageText, str1, len);
\r
8234 messageText[len] = NULLCHAR;
\r
8237 if (*str2 && remain >= 2) {
\r
8239 strcat(messageText, " ");
\r
8242 len = strlen(str2);
\r
8243 if (len > remain) len = remain;
\r
8244 strncat(messageText, str2, len);
\r
8246 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8247 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8249 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8253 hdc = GetDC(hwndMain);
\r
8254 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8255 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8256 &messageRect, messageText, strlen(messageText), NULL);
\r
8257 (void) SelectObject(hdc, oldFont);
\r
8258 (void) ReleaseDC(hwndMain, hdc);
\r
8262 DisplayError(char *str, int error)
\r
8264 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8268 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8270 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8271 NULL, error, LANG_NEUTRAL,
\r
8272 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8274 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8276 ErrorMap *em = errmap;
\r
8277 while (em->err != 0 && em->err != error) em++;
\r
8278 if (em->err != 0) {
\r
8279 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8281 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8286 ErrorPopUp(_("Error"), buf);
\r
8291 DisplayMoveError(char *str)
\r
8293 fromX = fromY = -1;
\r
8294 ClearHighlights();
\r
8295 DrawPosition(FALSE, NULL);
\r
8296 if (appData.popupMoveErrors) {
\r
8297 ErrorPopUp(_("Error"), str);
\r
8299 DisplayMessage(str, "");
\r
8300 moveErrorMessageUp = TRUE;
\r
8305 DisplayFatalError(char *str, int error, int exitStatus)
\r
8307 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8309 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8312 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8313 NULL, error, LANG_NEUTRAL,
\r
8314 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8316 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8318 ErrorMap *em = errmap;
\r
8319 while (em->err != 0 && em->err != error) em++;
\r
8320 if (em->err != 0) {
\r
8321 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8323 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8328 if (appData.debugMode) {
\r
8329 fprintf(debugFP, "%s: %s\n", label, str);
\r
8331 if (appData.popupExitMessage) {
\r
8332 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8333 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8335 ExitEvent(exitStatus);
\r
8340 DisplayInformation(char *str)
\r
8342 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8347 DisplayNote(char *str)
\r
8349 ErrorPopUp(_("Note"), str);
\r
8354 char *title, *question, *replyPrefix;
\r
8359 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8361 static QuestionParams *qp;
\r
8362 char reply[MSG_SIZ];
\r
8365 switch (message) {
\r
8366 case WM_INITDIALOG:
\r
8367 qp = (QuestionParams *) lParam;
\r
8368 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8369 Translate(hDlg, DLG_Question);
\r
8370 SetWindowText(hDlg, qp->title);
\r
8371 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8372 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8376 switch (LOWORD(wParam)) {
\r
8378 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8379 if (*reply) strcat(reply, " ");
\r
8380 len = strlen(reply);
\r
8381 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8382 strcat(reply, "\n");
\r
8383 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8384 EndDialog(hDlg, TRUE);
\r
8385 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8388 EndDialog(hDlg, FALSE);
\r
8399 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8401 QuestionParams qp;
\r
8405 qp.question = question;
\r
8406 qp.replyPrefix = replyPrefix;
\r
8408 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8409 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8410 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8411 FreeProcInstance(lpProc);
\r
8414 /* [AS] Pick FRC position */
\r
8415 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8417 static int * lpIndexFRC;
\r
8423 case WM_INITDIALOG:
\r
8424 lpIndexFRC = (int *) lParam;
\r
8426 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8427 Translate(hDlg, DLG_NewGameFRC);
\r
8429 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8430 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8431 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8432 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8437 switch( LOWORD(wParam) ) {
\r
8439 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8440 EndDialog( hDlg, 0 );
\r
8441 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8444 EndDialog( hDlg, 1 );
\r
8446 case IDC_NFG_Edit:
\r
8447 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8448 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8450 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8453 case IDC_NFG_Random:
\r
8454 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8455 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8468 int index = appData.defaultFrcPosition;
\r
8469 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8471 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8473 if( result == 0 ) {
\r
8474 appData.defaultFrcPosition = index;
\r
8480 /* [AS] Game list options. Refactored by HGM */
\r
8482 HWND gameListOptionsDialog;
\r
8484 // low-level front-end: clear text edit / list widget
\r
8488 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8491 // low-level front-end: clear text edit / list widget
\r
8493 GLT_DeSelectList()
\r
8495 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8498 // low-level front-end: append line to text edit / list widget
\r
8500 GLT_AddToList( char *name )
\r
8503 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8507 // low-level front-end: get line from text edit / list widget
\r
8509 GLT_GetFromList( int index, char *name )
\r
8512 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8518 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8520 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8521 int idx2 = idx1 + delta;
\r
8522 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8524 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8527 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8528 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8529 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8530 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8534 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8538 case WM_INITDIALOG:
\r
8539 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8541 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8542 Translate(hDlg, DLG_GameListOptions);
\r
8544 /* Initialize list */
\r
8545 GLT_TagsToList( lpUserGLT );
\r
8547 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8552 switch( LOWORD(wParam) ) {
\r
8555 EndDialog( hDlg, 0 );
\r
8558 EndDialog( hDlg, 1 );
\r
8561 case IDC_GLT_Default:
\r
8562 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8565 case IDC_GLT_Restore:
\r
8566 GLT_TagsToList( appData.gameListTags );
\r
8570 GLT_MoveSelection( hDlg, -1 );
\r
8573 case IDC_GLT_Down:
\r
8574 GLT_MoveSelection( hDlg, +1 );
\r
8584 int GameListOptions()
\r
8587 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8589 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8591 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8593 if( result == 0 ) {
\r
8594 /* [AS] Memory leak here! */
\r
8595 appData.gameListTags = strdup( lpUserGLT );
\r
8602 DisplayIcsInteractionTitle(char *str)
\r
8604 char consoleTitle[MSG_SIZ];
\r
8606 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8607 SetWindowText(hwndConsole, consoleTitle);
\r
8609 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8610 char buf[MSG_SIZ], *p = buf, *q;
\r
8611 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8613 q = strchr(p, ';');
\r
8615 if(*p) ChatPopUp(p);
\r
8619 SetActiveWindow(hwndMain);
\r
8623 DrawPosition(int fullRedraw, Board board)
\r
8625 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8628 void NotifyFrontendLogin()
\r
8631 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8637 fromX = fromY = -1;
\r
8638 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8639 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8640 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8641 dragInfo.lastpos = dragInfo.pos;
\r
8642 dragInfo.start.x = dragInfo.start.y = -1;
\r
8643 dragInfo.from = dragInfo.start;
\r
8645 DrawPosition(TRUE, NULL);
\r
8652 CommentPopUp(char *title, char *str)
\r
8654 HWND hwnd = GetActiveWindow();
\r
8655 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8657 SetActiveWindow(hwnd);
\r
8661 CommentPopDown(void)
\r
8663 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8664 if (commentDialog) {
\r
8665 ShowWindow(commentDialog, SW_HIDE);
\r
8667 commentUp = FALSE;
\r
8671 EditCommentPopUp(int index, char *title, char *str)
\r
8673 EitherCommentPopUp(index, title, str, TRUE);
\r
8680 MyPlaySound(&sounds[(int)SoundMove]);
\r
8683 VOID PlayIcsWinSound()
\r
8685 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8688 VOID PlayIcsLossSound()
\r
8690 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8693 VOID PlayIcsDrawSound()
\r
8695 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8698 VOID PlayIcsUnfinishedSound()
\r
8700 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8706 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8712 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8720 consoleEcho = TRUE;
\r
8721 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8722 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8723 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8732 consoleEcho = FALSE;
\r
8733 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8734 /* This works OK: set text and background both to the same color */
\r
8736 cf.crTextColor = COLOR_ECHOOFF;
\r
8737 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8738 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8741 /* No Raw()...? */
\r
8743 void Colorize(ColorClass cc, int continuation)
\r
8745 currentColorClass = cc;
\r
8746 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8747 consoleCF.crTextColor = textAttribs[cc].color;
\r
8748 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8749 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8755 static char buf[MSG_SIZ];
\r
8756 DWORD bufsiz = MSG_SIZ;
\r
8758 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8759 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8761 if (!GetUserName(buf, &bufsiz)) {
\r
8762 /*DisplayError("Error getting user name", GetLastError());*/
\r
8763 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8771 static char buf[MSG_SIZ];
\r
8772 DWORD bufsiz = MSG_SIZ;
\r
8774 if (!GetComputerName(buf, &bufsiz)) {
\r
8775 /*DisplayError("Error getting host name", GetLastError());*/
\r
8776 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8783 ClockTimerRunning()
\r
8785 return clockTimerEvent != 0;
\r
8791 if (clockTimerEvent == 0) return FALSE;
\r
8792 KillTimer(hwndMain, clockTimerEvent);
\r
8793 clockTimerEvent = 0;
\r
8798 StartClockTimer(long millisec)
\r
8800 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8801 (UINT) millisec, NULL);
\r
8805 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8808 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8810 if(appData.noGUI) return;
\r
8811 hdc = GetDC(hwndMain);
\r
8812 if (!IsIconic(hwndMain)) {
\r
8813 DisplayAClock(hdc, timeRemaining, highlight,
\r
8814 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8816 if (highlight && iconCurrent == iconBlack) {
\r
8817 iconCurrent = iconWhite;
\r
8818 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8819 if (IsIconic(hwndMain)) {
\r
8820 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8823 (void) ReleaseDC(hwndMain, hdc);
\r
8825 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8829 DisplayBlackClock(long timeRemaining, int highlight)
\r
8832 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8834 if(appData.noGUI) return;
\r
8835 hdc = GetDC(hwndMain);
\r
8836 if (!IsIconic(hwndMain)) {
\r
8837 DisplayAClock(hdc, timeRemaining, highlight,
\r
8838 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8840 if (highlight && iconCurrent == iconWhite) {
\r
8841 iconCurrent = iconBlack;
\r
8842 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8843 if (IsIconic(hwndMain)) {
\r
8844 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8847 (void) ReleaseDC(hwndMain, hdc);
\r
8849 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8854 LoadGameTimerRunning()
\r
8856 return loadGameTimerEvent != 0;
\r
8860 StopLoadGameTimer()
\r
8862 if (loadGameTimerEvent == 0) return FALSE;
\r
8863 KillTimer(hwndMain, loadGameTimerEvent);
\r
8864 loadGameTimerEvent = 0;
\r
8869 StartLoadGameTimer(long millisec)
\r
8871 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8872 (UINT) millisec, NULL);
\r
8880 char fileTitle[MSG_SIZ];
\r
8882 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8883 f = OpenFileDialog(hwndMain, "a", defName,
\r
8884 appData.oldSaveStyle ? "gam" : "pgn",
\r
8886 _("Save Game to File"), NULL, fileTitle, NULL);
\r
8888 SaveGame(f, 0, "");
\r
8895 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8897 if (delayedTimerEvent != 0) {
\r
8898 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8899 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8901 KillTimer(hwndMain, delayedTimerEvent);
\r
8902 delayedTimerEvent = 0;
\r
8903 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8904 delayedTimerCallback();
\r
8906 delayedTimerCallback = cb;
\r
8907 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8908 (UINT) millisec, NULL);
\r
8911 DelayedEventCallback
\r
8914 if (delayedTimerEvent) {
\r
8915 return delayedTimerCallback;
\r
8922 CancelDelayedEvent()
\r
8924 if (delayedTimerEvent) {
\r
8925 KillTimer(hwndMain, delayedTimerEvent);
\r
8926 delayedTimerEvent = 0;
\r
8930 DWORD GetWin32Priority(int nice)
\r
8931 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8933 REALTIME_PRIORITY_CLASS 0x00000100
\r
8934 HIGH_PRIORITY_CLASS 0x00000080
\r
8935 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8936 NORMAL_PRIORITY_CLASS 0x00000020
\r
8937 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8938 IDLE_PRIORITY_CLASS 0x00000040
\r
8940 if (nice < -15) return 0x00000080;
\r
8941 if (nice < 0) return 0x00008000;
\r
8942 if (nice == 0) return 0x00000020;
\r
8943 if (nice < 15) return 0x00004000;
\r
8944 return 0x00000040;
\r
8947 void RunCommand(char *cmdLine)
\r
8949 /* Now create the child process. */
\r
8950 STARTUPINFO siStartInfo;
\r
8951 PROCESS_INFORMATION piProcInfo;
\r
8953 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8954 siStartInfo.lpReserved = NULL;
\r
8955 siStartInfo.lpDesktop = NULL;
\r
8956 siStartInfo.lpTitle = NULL;
\r
8957 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8958 siStartInfo.cbReserved2 = 0;
\r
8959 siStartInfo.lpReserved2 = NULL;
\r
8960 siStartInfo.hStdInput = NULL;
\r
8961 siStartInfo.hStdOutput = NULL;
\r
8962 siStartInfo.hStdError = NULL;
\r
8964 CreateProcess(NULL,
\r
8965 cmdLine, /* command line */
\r
8966 NULL, /* process security attributes */
\r
8967 NULL, /* primary thread security attrs */
\r
8968 TRUE, /* handles are inherited */
\r
8969 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8970 NULL, /* use parent's environment */
\r
8972 &siStartInfo, /* STARTUPINFO pointer */
\r
8973 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8975 CloseHandle(piProcInfo.hThread);
\r
8978 /* Start a child process running the given program.
\r
8979 The process's standard output can be read from "from", and its
\r
8980 standard input can be written to "to".
\r
8981 Exit with fatal error if anything goes wrong.
\r
8982 Returns an opaque pointer that can be used to destroy the process
\r
8986 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8988 #define BUFSIZE 4096
\r
8990 HANDLE hChildStdinRd, hChildStdinWr,
\r
8991 hChildStdoutRd, hChildStdoutWr;
\r
8992 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8993 SECURITY_ATTRIBUTES saAttr;
\r
8995 PROCESS_INFORMATION piProcInfo;
\r
8996 STARTUPINFO siStartInfo;
\r
8998 char buf[MSG_SIZ];
\r
9001 if (appData.debugMode) {
\r
9002 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9007 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9008 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9009 saAttr.bInheritHandle = TRUE;
\r
9010 saAttr.lpSecurityDescriptor = NULL;
\r
9013 * The steps for redirecting child's STDOUT:
\r
9014 * 1. Create anonymous pipe to be STDOUT for child.
\r
9015 * 2. Create a noninheritable duplicate of read handle,
\r
9016 * and close the inheritable read handle.
\r
9019 /* Create a pipe for the child's STDOUT. */
\r
9020 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9021 return GetLastError();
\r
9024 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9025 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9026 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9027 FALSE, /* not inherited */
\r
9028 DUPLICATE_SAME_ACCESS);
\r
9030 return GetLastError();
\r
9032 CloseHandle(hChildStdoutRd);
\r
9035 * The steps for redirecting child's STDIN:
\r
9036 * 1. Create anonymous pipe to be STDIN for child.
\r
9037 * 2. Create a noninheritable duplicate of write handle,
\r
9038 * and close the inheritable write handle.
\r
9041 /* Create a pipe for the child's STDIN. */
\r
9042 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9043 return GetLastError();
\r
9046 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9047 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9048 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9049 FALSE, /* not inherited */
\r
9050 DUPLICATE_SAME_ACCESS);
\r
9052 return GetLastError();
\r
9054 CloseHandle(hChildStdinWr);
\r
9056 /* Arrange to (1) look in dir for the child .exe file, and
\r
9057 * (2) have dir be the child's working directory. Interpret
\r
9058 * dir relative to the directory WinBoard loaded from. */
\r
9059 GetCurrentDirectory(MSG_SIZ, buf);
\r
9060 SetCurrentDirectory(installDir);
\r
9061 SetCurrentDirectory(dir);
\r
9063 /* Now create the child process. */
\r
9065 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9066 siStartInfo.lpReserved = NULL;
\r
9067 siStartInfo.lpDesktop = NULL;
\r
9068 siStartInfo.lpTitle = NULL;
\r
9069 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9070 siStartInfo.cbReserved2 = 0;
\r
9071 siStartInfo.lpReserved2 = NULL;
\r
9072 siStartInfo.hStdInput = hChildStdinRd;
\r
9073 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9074 siStartInfo.hStdError = hChildStdoutWr;
\r
9076 fSuccess = CreateProcess(NULL,
\r
9077 cmdLine, /* command line */
\r
9078 NULL, /* process security attributes */
\r
9079 NULL, /* primary thread security attrs */
\r
9080 TRUE, /* handles are inherited */
\r
9081 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9082 NULL, /* use parent's environment */
\r
9084 &siStartInfo, /* STARTUPINFO pointer */
\r
9085 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9087 err = GetLastError();
\r
9088 SetCurrentDirectory(buf); /* return to prev directory */
\r
9093 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9094 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9095 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9098 /* Close the handles we don't need in the parent */
\r
9099 CloseHandle(piProcInfo.hThread);
\r
9100 CloseHandle(hChildStdinRd);
\r
9101 CloseHandle(hChildStdoutWr);
\r
9103 /* Prepare return value */
\r
9104 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9105 cp->kind = CPReal;
\r
9106 cp->hProcess = piProcInfo.hProcess;
\r
9107 cp->pid = piProcInfo.dwProcessId;
\r
9108 cp->hFrom = hChildStdoutRdDup;
\r
9109 cp->hTo = hChildStdinWrDup;
\r
9111 *pr = (void *) cp;
\r
9113 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9114 2000 where engines sometimes don't see the initial command(s)
\r
9115 from WinBoard and hang. I don't understand how that can happen,
\r
9116 but the Sleep is harmless, so I've put it in. Others have also
\r
9117 reported what may be the same problem, so hopefully this will fix
\r
9118 it for them too. */
\r
9126 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9128 ChildProc *cp; int result;
\r
9130 cp = (ChildProc *) pr;
\r
9131 if (cp == NULL) return;
\r
9133 switch (cp->kind) {
\r
9135 /* TerminateProcess is considered harmful, so... */
\r
9136 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9137 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9138 /* The following doesn't work because the chess program
\r
9139 doesn't "have the same console" as WinBoard. Maybe
\r
9140 we could arrange for this even though neither WinBoard
\r
9141 nor the chess program uses a console for stdio? */
\r
9142 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9144 /* [AS] Special termination modes for misbehaving programs... */
\r
9145 if( signal == 9 ) {
\r
9146 result = TerminateProcess( cp->hProcess, 0 );
\r
9148 if ( appData.debugMode) {
\r
9149 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9152 else if( signal == 10 ) {
\r
9153 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9155 if( dw != WAIT_OBJECT_0 ) {
\r
9156 result = TerminateProcess( cp->hProcess, 0 );
\r
9158 if ( appData.debugMode) {
\r
9159 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9165 CloseHandle(cp->hProcess);
\r
9169 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9173 closesocket(cp->sock);
\r
9178 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9179 closesocket(cp->sock);
\r
9180 closesocket(cp->sock2);
\r
9188 InterruptChildProcess(ProcRef pr)
\r
9192 cp = (ChildProc *) pr;
\r
9193 if (cp == NULL) return;
\r
9194 switch (cp->kind) {
\r
9196 /* The following doesn't work because the chess program
\r
9197 doesn't "have the same console" as WinBoard. Maybe
\r
9198 we could arrange for this even though neither WinBoard
\r
9199 nor the chess program uses a console for stdio */
\r
9200 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9205 /* Can't interrupt */
\r
9209 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9216 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9218 char cmdLine[MSG_SIZ];
\r
9220 if (port[0] == NULLCHAR) {
\r
9221 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9223 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9225 return StartChildProcess(cmdLine, "", pr);
\r
9229 /* Code to open TCP sockets */
\r
9232 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9238 struct sockaddr_in sa, mysa;
\r
9239 struct hostent FAR *hp;
\r
9240 unsigned short uport;
\r
9241 WORD wVersionRequested;
\r
9244 /* Initialize socket DLL */
\r
9245 wVersionRequested = MAKEWORD(1, 1);
\r
9246 err = WSAStartup(wVersionRequested, &wsaData);
\r
9247 if (err != 0) return err;
\r
9250 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9251 err = WSAGetLastError();
\r
9256 /* Bind local address using (mostly) don't-care values.
\r
9258 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9259 mysa.sin_family = AF_INET;
\r
9260 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9261 uport = (unsigned short) 0;
\r
9262 mysa.sin_port = htons(uport);
\r
9263 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9264 == SOCKET_ERROR) {
\r
9265 err = WSAGetLastError();
\r
9270 /* Resolve remote host name */
\r
9271 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9272 if (!(hp = gethostbyname(host))) {
\r
9273 unsigned int b0, b1, b2, b3;
\r
9275 err = WSAGetLastError();
\r
9277 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9278 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9279 hp->h_addrtype = AF_INET;
\r
9281 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9282 hp->h_addr_list[0] = (char *) malloc(4);
\r
9283 hp->h_addr_list[0][0] = (char) b0;
\r
9284 hp->h_addr_list[0][1] = (char) b1;
\r
9285 hp->h_addr_list[0][2] = (char) b2;
\r
9286 hp->h_addr_list[0][3] = (char) b3;
\r
9292 sa.sin_family = hp->h_addrtype;
\r
9293 uport = (unsigned short) atoi(port);
\r
9294 sa.sin_port = htons(uport);
\r
9295 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9297 /* Make connection */
\r
9298 if (connect(s, (struct sockaddr *) &sa,
\r
9299 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9300 err = WSAGetLastError();
\r
9305 /* Prepare return value */
\r
9306 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9307 cp->kind = CPSock;
\r
9309 *pr = (ProcRef *) cp;
\r
9315 OpenCommPort(char *name, ProcRef *pr)
\r
9320 char fullname[MSG_SIZ];
\r
9322 if (*name != '\\')
\r
9323 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9325 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9327 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9328 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9329 if (h == (HANDLE) -1) {
\r
9330 return GetLastError();
\r
9334 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9336 /* Accumulate characters until a 100ms pause, then parse */
\r
9337 ct.ReadIntervalTimeout = 100;
\r
9338 ct.ReadTotalTimeoutMultiplier = 0;
\r
9339 ct.ReadTotalTimeoutConstant = 0;
\r
9340 ct.WriteTotalTimeoutMultiplier = 0;
\r
9341 ct.WriteTotalTimeoutConstant = 0;
\r
9342 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9344 /* Prepare return value */
\r
9345 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9346 cp->kind = CPComm;
\r
9349 *pr = (ProcRef *) cp;
\r
9355 OpenLoopback(ProcRef *pr)
\r
9357 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9363 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9368 struct sockaddr_in sa, mysa;
\r
9369 struct hostent FAR *hp;
\r
9370 unsigned short uport;
\r
9371 WORD wVersionRequested;
\r
9374 char stderrPortStr[MSG_SIZ];
\r
9376 /* Initialize socket DLL */
\r
9377 wVersionRequested = MAKEWORD(1, 1);
\r
9378 err = WSAStartup(wVersionRequested, &wsaData);
\r
9379 if (err != 0) return err;
\r
9381 /* Resolve remote host name */
\r
9382 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9383 if (!(hp = gethostbyname(host))) {
\r
9384 unsigned int b0, b1, b2, b3;
\r
9386 err = WSAGetLastError();
\r
9388 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9389 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9390 hp->h_addrtype = AF_INET;
\r
9392 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9393 hp->h_addr_list[0] = (char *) malloc(4);
\r
9394 hp->h_addr_list[0][0] = (char) b0;
\r
9395 hp->h_addr_list[0][1] = (char) b1;
\r
9396 hp->h_addr_list[0][2] = (char) b2;
\r
9397 hp->h_addr_list[0][3] = (char) b3;
\r
9403 sa.sin_family = hp->h_addrtype;
\r
9404 uport = (unsigned short) 514;
\r
9405 sa.sin_port = htons(uport);
\r
9406 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9408 /* Bind local socket to unused "privileged" port address
\r
9410 s = INVALID_SOCKET;
\r
9411 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9412 mysa.sin_family = AF_INET;
\r
9413 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9414 for (fromPort = 1023;; fromPort--) {
\r
9415 if (fromPort < 0) {
\r
9417 return WSAEADDRINUSE;
\r
9419 if (s == INVALID_SOCKET) {
\r
9420 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9421 err = WSAGetLastError();
\r
9426 uport = (unsigned short) fromPort;
\r
9427 mysa.sin_port = htons(uport);
\r
9428 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9429 == SOCKET_ERROR) {
\r
9430 err = WSAGetLastError();
\r
9431 if (err == WSAEADDRINUSE) continue;
\r
9435 if (connect(s, (struct sockaddr *) &sa,
\r
9436 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9437 err = WSAGetLastError();
\r
9438 if (err == WSAEADDRINUSE) {
\r
9449 /* Bind stderr local socket to unused "privileged" port address
\r
9451 s2 = INVALID_SOCKET;
\r
9452 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9453 mysa.sin_family = AF_INET;
\r
9454 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9455 for (fromPort = 1023;; fromPort--) {
\r
9456 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9457 if (fromPort < 0) {
\r
9458 (void) closesocket(s);
\r
9460 return WSAEADDRINUSE;
\r
9462 if (s2 == INVALID_SOCKET) {
\r
9463 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9464 err = WSAGetLastError();
\r
9470 uport = (unsigned short) fromPort;
\r
9471 mysa.sin_port = htons(uport);
\r
9472 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9473 == SOCKET_ERROR) {
\r
9474 err = WSAGetLastError();
\r
9475 if (err == WSAEADDRINUSE) continue;
\r
9476 (void) closesocket(s);
\r
9480 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9481 err = WSAGetLastError();
\r
9482 if (err == WSAEADDRINUSE) {
\r
9484 s2 = INVALID_SOCKET;
\r
9487 (void) closesocket(s);
\r
9488 (void) closesocket(s2);
\r
9494 prevStderrPort = fromPort; // remember port used
\r
9495 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9497 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9498 err = WSAGetLastError();
\r
9499 (void) closesocket(s);
\r
9500 (void) closesocket(s2);
\r
9505 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9506 err = WSAGetLastError();
\r
9507 (void) closesocket(s);
\r
9508 (void) closesocket(s2);
\r
9512 if (*user == NULLCHAR) user = UserName();
\r
9513 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9514 err = WSAGetLastError();
\r
9515 (void) closesocket(s);
\r
9516 (void) closesocket(s2);
\r
9520 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9521 err = WSAGetLastError();
\r
9522 (void) closesocket(s);
\r
9523 (void) closesocket(s2);
\r
9528 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9529 err = WSAGetLastError();
\r
9530 (void) closesocket(s);
\r
9531 (void) closesocket(s2);
\r
9535 (void) closesocket(s2); /* Stop listening */
\r
9537 /* Prepare return value */
\r
9538 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9539 cp->kind = CPRcmd;
\r
9542 *pr = (ProcRef *) cp;
\r
9549 AddInputSource(ProcRef pr, int lineByLine,
\r
9550 InputCallback func, VOIDSTAR closure)
\r
9552 InputSource *is, *is2 = NULL;
\r
9553 ChildProc *cp = (ChildProc *) pr;
\r
9555 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9556 is->lineByLine = lineByLine;
\r
9558 is->closure = closure;
\r
9559 is->second = NULL;
\r
9560 is->next = is->buf;
\r
9561 if (pr == NoProc) {
\r
9562 is->kind = CPReal;
\r
9563 consoleInputSource = is;
\r
9565 is->kind = cp->kind;
\r
9567 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9568 we create all threads suspended so that the is->hThread variable can be
\r
9569 safely assigned, then let the threads start with ResumeThread.
\r
9571 switch (cp->kind) {
\r
9573 is->hFile = cp->hFrom;
\r
9574 cp->hFrom = NULL; /* now owned by InputThread */
\r
9576 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9577 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9581 is->hFile = cp->hFrom;
\r
9582 cp->hFrom = NULL; /* now owned by InputThread */
\r
9584 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9585 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9589 is->sock = cp->sock;
\r
9591 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9592 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9596 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9598 is->sock = cp->sock;
\r
9600 is2->sock = cp->sock2;
\r
9601 is2->second = is2;
\r
9603 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9604 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9606 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9607 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9611 if( is->hThread != NULL ) {
\r
9612 ResumeThread( is->hThread );
\r
9615 if( is2 != NULL && is2->hThread != NULL ) {
\r
9616 ResumeThread( is2->hThread );
\r
9620 return (InputSourceRef) is;
\r
9624 RemoveInputSource(InputSourceRef isr)
\r
9628 is = (InputSource *) isr;
\r
9629 is->hThread = NULL; /* tell thread to stop */
\r
9630 CloseHandle(is->hThread);
\r
9631 if (is->second != NULL) {
\r
9632 is->second->hThread = NULL;
\r
9633 CloseHandle(is->second->hThread);
\r
9637 int no_wrap(char *message, int count)
\r
9639 ConsoleOutput(message, count, FALSE);
\r
9644 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9647 int outCount = SOCKET_ERROR;
\r
9648 ChildProc *cp = (ChildProc *) pr;
\r
9649 static OVERLAPPED ovl;
\r
9650 static int line = 0;
\r
9654 if (appData.noJoin || !appData.useInternalWrap)
\r
9655 return no_wrap(message, count);
\r
9658 int width = get_term_width();
\r
9659 int len = wrap(NULL, message, count, width, &line);
\r
9660 char *msg = malloc(len);
\r
9664 return no_wrap(message, count);
\r
9667 dbgchk = wrap(msg, message, count, width, &line);
\r
9668 if (dbgchk != len && appData.debugMode)
\r
9669 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9670 ConsoleOutput(msg, len, FALSE);
\r
9677 if (ovl.hEvent == NULL) {
\r
9678 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9680 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9682 switch (cp->kind) {
\r
9685 outCount = send(cp->sock, message, count, 0);
\r
9686 if (outCount == SOCKET_ERROR) {
\r
9687 *outError = WSAGetLastError();
\r
9689 *outError = NO_ERROR;
\r
9694 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9695 &dOutCount, NULL)) {
\r
9696 *outError = NO_ERROR;
\r
9697 outCount = (int) dOutCount;
\r
9699 *outError = GetLastError();
\r
9704 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9705 &dOutCount, &ovl);
\r
9706 if (*outError == NO_ERROR) {
\r
9707 outCount = (int) dOutCount;
\r
9717 if(n != 0) Sleep(n);
\r
9721 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9724 /* Ignore delay, not implemented for WinBoard */
\r
9725 return OutputToProcess(pr, message, count, outError);
\r
9730 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9731 char *buf, int count, int error)
\r
9733 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9736 /* see wgamelist.c for Game List functions */
\r
9737 /* see wedittags.c for Edit Tags functions */
\r
9744 char buf[MSG_SIZ];
\r
9747 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9748 f = fopen(buf, "r");
\r
9750 ProcessICSInitScript(f);
\r
9758 StartAnalysisClock()
\r
9760 if (analysisTimerEvent) return;
\r
9761 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9762 (UINT) 2000, NULL);
\r
9766 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9768 highlightInfo.sq[0].x = fromX;
\r
9769 highlightInfo.sq[0].y = fromY;
\r
9770 highlightInfo.sq[1].x = toX;
\r
9771 highlightInfo.sq[1].y = toY;
\r
9777 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9778 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9782 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9784 premoveHighlightInfo.sq[0].x = fromX;
\r
9785 premoveHighlightInfo.sq[0].y = fromY;
\r
9786 premoveHighlightInfo.sq[1].x = toX;
\r
9787 premoveHighlightInfo.sq[1].y = toY;
\r
9791 ClearPremoveHighlights()
\r
9793 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9794 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9798 ShutDownFrontEnd()
\r
9800 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9801 DeleteClipboardTempFiles();
\r
9807 if (IsIconic(hwndMain))
\r
9808 ShowWindow(hwndMain, SW_RESTORE);
\r
9810 SetActiveWindow(hwndMain);
\r
9814 * Prototypes for animation support routines
\r
9816 static void ScreenSquare(int column, int row, POINT * pt);
\r
9817 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9818 POINT frames[], int * nFrames);
\r
9824 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9825 { // [HGM] atomic: animate blast wave
\r
9828 explodeInfo.fromX = fromX;
\r
9829 explodeInfo.fromY = fromY;
\r
9830 explodeInfo.toX = toX;
\r
9831 explodeInfo.toY = toY;
\r
9832 for(i=1; i<4*kFactor; i++) {
\r
9833 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9834 DrawPosition(FALSE, board);
\r
9835 Sleep(appData.animSpeed);
\r
9837 explodeInfo.radius = 0;
\r
9838 DrawPosition(TRUE, board);
\r
9842 AnimateMove(board, fromX, fromY, toX, toY)
\r
9849 ChessSquare piece;
\r
9850 POINT start, finish, mid;
\r
9851 POINT frames[kFactor * 2 + 1];
\r
9854 if (!appData.animate) return;
\r
9855 if (doingSizing) return;
\r
9856 if (fromY < 0 || fromX < 0) return;
\r
9857 piece = board[fromY][fromX];
\r
9858 if (piece >= EmptySquare) return;
\r
9860 ScreenSquare(fromX, fromY, &start);
\r
9861 ScreenSquare(toX, toY, &finish);
\r
9863 /* All moves except knight jumps move in straight line */
\r
9864 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
9865 mid.x = start.x + (finish.x - start.x) / 2;
\r
9866 mid.y = start.y + (finish.y - start.y) / 2;
\r
9868 /* Knight: make straight movement then diagonal */
\r
9869 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9870 mid.x = start.x + (finish.x - start.x) / 2;
\r
9874 mid.y = start.y + (finish.y - start.y) / 2;
\r
9878 /* Don't use as many frames for very short moves */
\r
9879 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9880 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9882 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9884 animInfo.from.x = fromX;
\r
9885 animInfo.from.y = fromY;
\r
9886 animInfo.to.x = toX;
\r
9887 animInfo.to.y = toY;
\r
9888 animInfo.lastpos = start;
\r
9889 animInfo.piece = piece;
\r
9890 for (n = 0; n < nFrames; n++) {
\r
9891 animInfo.pos = frames[n];
\r
9892 DrawPosition(FALSE, NULL);
\r
9893 animInfo.lastpos = animInfo.pos;
\r
9894 Sleep(appData.animSpeed);
\r
9896 animInfo.pos = finish;
\r
9897 DrawPosition(FALSE, NULL);
\r
9898 animInfo.piece = EmptySquare;
\r
9899 Explode(board, fromX, fromY, toX, toY);
\r
9902 /* Convert board position to corner of screen rect and color */
\r
9905 ScreenSquare(column, row, pt)
\r
9906 int column; int row; POINT * pt;
\r
9909 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9910 pt->y = lineGap + row * (squareSize + lineGap);
\r
9912 pt->x = lineGap + column * (squareSize + lineGap);
\r
9913 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9917 /* Generate a series of frame coords from start->mid->finish.
\r
9918 The movement rate doubles until the half way point is
\r
9919 reached, then halves back down to the final destination,
\r
9920 which gives a nice slow in/out effect. The algorithmn
\r
9921 may seem to generate too many intermediates for short
\r
9922 moves, but remember that the purpose is to attract the
\r
9923 viewers attention to the piece about to be moved and
\r
9924 then to where it ends up. Too few frames would be less
\r
9928 Tween(start, mid, finish, factor, frames, nFrames)
\r
9929 POINT * start; POINT * mid;
\r
9930 POINT * finish; int factor;
\r
9931 POINT frames[]; int * nFrames;
\r
9933 int n, fraction = 1, count = 0;
\r
9935 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9936 for (n = 0; n < factor; n++)
\r
9938 for (n = 0; n < factor; n++) {
\r
9939 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9940 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9942 fraction = fraction / 2;
\r
9946 frames[count] = *mid;
\r
9949 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9951 for (n = 0; n < factor; n++) {
\r
9952 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9953 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9955 fraction = fraction * 2;
\r
9961 SettingsPopUp(ChessProgramState *cps)
\r
9962 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
9963 EngineOptionsPopup(savedHwnd, cps);
\r
9966 int flock(int fid, int code)
\r
9968 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
9972 ov.OffsetHigh = 0;
\r
9974 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
9975 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
9976 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
9977 default: return -1;
\r