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, border;
\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 char *opponent = "";
\r
1010 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1011 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1012 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1013 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1014 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1015 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1018 if(appData.directory[n] && appData.directory[n][0]) {
\r
1019 SetCurrentDirectory(appData.directory[n]);
\r
1020 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1023 SetCurrentDirectory(dir); /* return to prev directory */
\r
1029 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1030 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1032 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1033 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1034 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1035 liteBackTextureMode = appData.liteBackTextureMode;
\r
1037 if (liteBackTexture == NULL && appData.debugMode) {
\r
1038 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1042 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1043 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1044 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1045 darkBackTextureMode = appData.darkBackTextureMode;
\r
1047 if (darkBackTexture == NULL && appData.debugMode) {
\r
1048 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1054 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1056 HWND hwnd; /* Main window handle. */
\r
1058 WINDOWPLACEMENT wp;
\r
1061 hInst = hInstance; /* Store instance handle in our global variable */
\r
1062 programName = szAppName;
\r
1064 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1065 *filepart = NULLCHAR;
\r
1067 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1069 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1070 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
1071 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1072 /* xboard, and older WinBoards, controlled the move sound with the
\r
1073 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1074 always turn the option on (so that the backend will call us),
\r
1075 then let the user turn the sound off by setting it to silence if
\r
1076 desired. To accommodate old winboard.ini files saved by old
\r
1077 versions of WinBoard, we also turn off the sound if the option
\r
1078 was initially set to false. [HGM] taken out of InitAppData */
\r
1079 if (!appData.ringBellAfterMoves) {
\r
1080 sounds[(int)SoundMove].name = strdup("");
\r
1081 appData.ringBellAfterMoves = TRUE;
\r
1083 if (appData.debugMode) {
\r
1084 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1085 setbuf(debugFP, NULL);
\r
1088 LoadLanguageFile(appData.language);
\r
1092 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1093 // InitEngineUCI( installDir, &second );
\r
1095 /* Create a main window for this application instance. */
\r
1096 hwnd = CreateWindow(szAppName, szTitle,
\r
1097 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1098 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1099 NULL, NULL, hInstance, NULL);
\r
1102 /* If window could not be created, return "failure" */
\r
1107 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1108 LoadLogo(&first, 0, FALSE);
\r
1109 LoadLogo(&second, 1, appData.icsActive);
\r
1113 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1114 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1115 iconCurrent = iconWhite;
\r
1116 InitDrawingColors();
\r
1117 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1118 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1119 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1120 /* Compute window size for each board size, and use the largest
\r
1121 size that fits on this screen as the default. */
\r
1122 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1123 if (boardSize == (BoardSize)-1 &&
\r
1124 winH <= screenHeight
\r
1125 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1126 && winW <= screenWidth) {
\r
1127 boardSize = (BoardSize)ibs;
\r
1131 InitDrawingSizes(boardSize, 0);
\r
1132 RecentEngineMenu(appData.recentEngineList);
\r
1134 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1136 /* [AS] Load textures if specified */
\r
1139 mysrandom( (unsigned) time(NULL) );
\r
1141 /* [AS] Restore layout */
\r
1142 if( wpMoveHistory.visible ) {
\r
1143 MoveHistoryPopUp();
\r
1146 if( wpEvalGraph.visible ) {
\r
1150 if( wpEngineOutput.visible ) {
\r
1151 EngineOutputPopUp();
\r
1154 /* Make the window visible; update its client area; and return "success" */
\r
1155 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1156 wp.length = sizeof(WINDOWPLACEMENT);
\r
1158 wp.showCmd = nCmdShow;
\r
1159 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1160 wp.rcNormalPosition.left = wpMain.x;
\r
1161 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1162 wp.rcNormalPosition.top = wpMain.y;
\r
1163 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1164 SetWindowPlacement(hwndMain, &wp);
\r
1166 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1168 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1169 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1171 if (hwndConsole) {
\r
1173 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1174 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1176 ShowWindow(hwndConsole, nCmdShow);
\r
1177 SetActiveWindow(hwndConsole);
\r
1179 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1180 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1189 HMENU hmenu = GetMenu(hwndMain);
\r
1191 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1192 MF_BYCOMMAND|((appData.icsActive &&
\r
1193 *appData.icsCommPort != NULLCHAR) ?
\r
1194 MF_ENABLED : MF_GRAYED));
\r
1195 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1196 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1197 MF_CHECKED : MF_UNCHECKED));
\r
1200 //---------------------------------------------------------------------------------------------------------
\r
1202 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1203 #define XBOARD FALSE
\r
1205 #define OPTCHAR "/"
\r
1206 #define SEPCHAR "="
\r
1207 #define TOPLEVEL 0
\r
1211 // front-end part of option handling
\r
1214 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1216 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1217 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1220 lf->lfEscapement = 0;
\r
1221 lf->lfOrientation = 0;
\r
1222 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1223 lf->lfItalic = mfp->italic;
\r
1224 lf->lfUnderline = mfp->underline;
\r
1225 lf->lfStrikeOut = mfp->strikeout;
\r
1226 lf->lfCharSet = mfp->charset;
\r
1227 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1228 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1229 lf->lfQuality = DEFAULT_QUALITY;
\r
1230 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1231 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1235 CreateFontInMF(MyFont *mf)
\r
1237 LFfromMFP(&mf->lf, &mf->mfp);
\r
1238 if (mf->hf) DeleteObject(mf->hf);
\r
1239 mf->hf = CreateFontIndirect(&mf->lf);
\r
1242 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1244 colorVariable[] = {
\r
1245 &whitePieceColor,
\r
1246 &blackPieceColor,
\r
1247 &lightSquareColor,
\r
1248 &darkSquareColor,
\r
1249 &highlightSquareColor,
\r
1250 &premoveHighlightColor,
\r
1252 &consoleBackgroundColor,
\r
1253 &appData.fontForeColorWhite,
\r
1254 &appData.fontBackColorWhite,
\r
1255 &appData.fontForeColorBlack,
\r
1256 &appData.fontBackColorBlack,
\r
1257 &appData.evalHistColorWhite,
\r
1258 &appData.evalHistColorBlack,
\r
1259 &appData.highlightArrowColor,
\r
1262 /* Command line font name parser. NULL name means do nothing.
\r
1263 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1264 For backward compatibility, syntax without the colon is also
\r
1265 accepted, but font names with digits in them won't work in that case.
\r
1268 ParseFontName(char *name, MyFontParams *mfp)
\r
1271 if (name == NULL) return;
\r
1273 q = strchr(p, ':');
\r
1275 if (q - p >= sizeof(mfp->faceName))
\r
1276 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1277 memcpy(mfp->faceName, p, q - p);
\r
1278 mfp->faceName[q - p] = NULLCHAR;
\r
1281 q = mfp->faceName;
\r
1282 while (*p && !isdigit(*p)) {
\r
1284 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1285 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1287 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1290 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1291 mfp->pointSize = (float) atof(p);
\r
1292 mfp->bold = (strchr(p, 'b') != NULL);
\r
1293 mfp->italic = (strchr(p, 'i') != NULL);
\r
1294 mfp->underline = (strchr(p, 'u') != NULL);
\r
1295 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1296 mfp->charset = DEFAULT_CHARSET;
\r
1297 q = strchr(p, 'c');
\r
1299 mfp->charset = (BYTE) atoi(q+1);
\r
1303 ParseFont(char *name, int number)
\r
1304 { // wrapper to shield back-end from 'font'
\r
1305 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1310 { // in WB we have a 2D array of fonts; this initializes their description
\r
1312 /* Point font array elements to structures and
\r
1313 parse default font names */
\r
1314 for (i=0; i<NUM_FONTS; i++) {
\r
1315 for (j=0; j<NUM_SIZES; j++) {
\r
1316 font[j][i] = &fontRec[j][i];
\r
1317 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1324 { // here we create the actual fonts from the selected descriptions
\r
1326 for (i=0; i<NUM_FONTS; i++) {
\r
1327 for (j=0; j<NUM_SIZES; j++) {
\r
1328 CreateFontInMF(font[j][i]);
\r
1332 /* Color name parser.
\r
1333 X version accepts X color names, but this one
\r
1334 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1336 ParseColorName(char *name)
\r
1338 int red, green, blue, count;
\r
1339 char buf[MSG_SIZ];
\r
1341 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1343 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1344 &red, &green, &blue);
\r
1347 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1348 DisplayError(buf, 0);
\r
1349 return RGB(0, 0, 0);
\r
1351 return PALETTERGB(red, green, blue);
\r
1355 ParseColor(int n, char *name)
\r
1356 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1357 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1361 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1363 char *e = argValue;
\r
1367 if (*e == 'b') eff |= CFE_BOLD;
\r
1368 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1369 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1370 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1371 else if (*e == '#' || isdigit(*e)) break;
\r
1375 *color = ParseColorName(e);
\r
1379 ParseTextAttribs(ColorClass cc, char *s)
\r
1380 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1381 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1382 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1386 ParseBoardSize(void *addr, char *name)
\r
1387 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1388 BoardSize bs = SizeTiny;
\r
1389 while (sizeInfo[bs].name != NULL) {
\r
1390 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1391 *(BoardSize *)addr = bs;
\r
1396 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1401 { // [HGM] import name from appData first
\r
1404 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1405 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1406 textAttribs[cc].sound.data = NULL;
\r
1407 MyLoadSound(&textAttribs[cc].sound);
\r
1409 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1410 textAttribs[cc].sound.name = strdup("");
\r
1411 textAttribs[cc].sound.data = NULL;
\r
1413 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1414 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1415 sounds[sc].data = NULL;
\r
1416 MyLoadSound(&sounds[sc]);
\r
1421 SetCommPortDefaults()
\r
1423 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1424 dcb.DCBlength = sizeof(DCB);
\r
1425 dcb.BaudRate = 9600;
\r
1426 dcb.fBinary = TRUE;
\r
1427 dcb.fParity = FALSE;
\r
1428 dcb.fOutxCtsFlow = FALSE;
\r
1429 dcb.fOutxDsrFlow = FALSE;
\r
1430 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1431 dcb.fDsrSensitivity = FALSE;
\r
1432 dcb.fTXContinueOnXoff = TRUE;
\r
1433 dcb.fOutX = FALSE;
\r
1435 dcb.fNull = FALSE;
\r
1436 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1437 dcb.fAbortOnError = FALSE;
\r
1439 dcb.Parity = SPACEPARITY;
\r
1440 dcb.StopBits = ONESTOPBIT;
\r
1443 // [HGM] args: these three cases taken out to stay in front-end
\r
1445 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1446 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1447 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1448 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1450 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1451 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1452 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1453 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1454 ad->argName, mfp->faceName, mfp->pointSize,
\r
1455 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1456 mfp->bold ? "b" : "",
\r
1457 mfp->italic ? "i" : "",
\r
1458 mfp->underline ? "u" : "",
\r
1459 mfp->strikeout ? "s" : "",
\r
1460 (int)mfp->charset);
\r
1466 { // [HGM] copy the names from the internal WB variables to appData
\r
1469 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1470 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1471 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1472 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1476 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1477 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1478 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1479 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1480 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1481 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1482 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1483 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1484 (ta->effects) ? " " : "",
\r
1485 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1489 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1490 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1491 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1492 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1493 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1497 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1498 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1499 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1503 ParseCommPortSettings(char *s)
\r
1504 { // wrapper to keep dcb from back-end
\r
1505 ParseCommSettings(s, &dcb);
\r
1510 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1511 GetActualPlacement(hwndMain, &wpMain);
\r
1512 GetActualPlacement(hwndConsole, &wpConsole);
\r
1513 GetActualPlacement(commentDialog, &wpComment);
\r
1514 GetActualPlacement(editTagsDialog, &wpTags);
\r
1515 GetActualPlacement(gameListDialog, &wpGameList);
\r
1516 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1517 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1518 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1522 PrintCommPortSettings(FILE *f, char *name)
\r
1523 { // wrapper to shield back-end from DCB
\r
1524 PrintCommSettings(f, name, &dcb);
\r
1528 MySearchPath(char *installDir, char *name, char *fullname)
\r
1530 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1531 if(name[0]== '%') {
\r
1532 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1533 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1534 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1535 *strchr(buf, '%') = 0;
\r
1536 strcat(fullname, getenv(buf));
\r
1537 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1539 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1540 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1541 return (int) strlen(fullname);
\r
1543 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1547 MyGetFullPathName(char *name, char *fullname)
\r
1550 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1555 { // [HGM] args: allows testing if main window is realized from back-end
\r
1556 return hwndMain != NULL;
\r
1560 PopUpStartupDialog()
\r
1564 LoadLanguageFile(appData.language);
\r
1565 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1566 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1567 FreeProcInstance(lpProc);
\r
1570 /*---------------------------------------------------------------------------*\
\r
1572 * GDI board drawing routines
\r
1574 \*---------------------------------------------------------------------------*/
\r
1576 /* [AS] Draw square using background texture */
\r
1577 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1582 return; /* Should never happen! */
\r
1585 SetGraphicsMode( dst, GM_ADVANCED );
\r
1592 /* X reflection */
\r
1597 x.eDx = (FLOAT) dw + dx - 1;
\r
1600 SetWorldTransform( dst, &x );
\r
1603 /* Y reflection */
\r
1609 x.eDy = (FLOAT) dh + dy - 1;
\r
1611 SetWorldTransform( dst, &x );
\r
1619 x.eDx = (FLOAT) dx;
\r
1620 x.eDy = (FLOAT) dy;
\r
1623 SetWorldTransform( dst, &x );
\r
1627 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1635 SetWorldTransform( dst, &x );
\r
1637 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1640 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1642 PM_WP = (int) WhitePawn,
\r
1643 PM_WN = (int) WhiteKnight,
\r
1644 PM_WB = (int) WhiteBishop,
\r
1645 PM_WR = (int) WhiteRook,
\r
1646 PM_WQ = (int) WhiteQueen,
\r
1647 PM_WF = (int) WhiteFerz,
\r
1648 PM_WW = (int) WhiteWazir,
\r
1649 PM_WE = (int) WhiteAlfil,
\r
1650 PM_WM = (int) WhiteMan,
\r
1651 PM_WO = (int) WhiteCannon,
\r
1652 PM_WU = (int) WhiteUnicorn,
\r
1653 PM_WH = (int) WhiteNightrider,
\r
1654 PM_WA = (int) WhiteAngel,
\r
1655 PM_WC = (int) WhiteMarshall,
\r
1656 PM_WAB = (int) WhiteCardinal,
\r
1657 PM_WD = (int) WhiteDragon,
\r
1658 PM_WL = (int) WhiteLance,
\r
1659 PM_WS = (int) WhiteCobra,
\r
1660 PM_WV = (int) WhiteFalcon,
\r
1661 PM_WSG = (int) WhiteSilver,
\r
1662 PM_WG = (int) WhiteGrasshopper,
\r
1663 PM_WK = (int) WhiteKing,
\r
1664 PM_BP = (int) BlackPawn,
\r
1665 PM_BN = (int) BlackKnight,
\r
1666 PM_BB = (int) BlackBishop,
\r
1667 PM_BR = (int) BlackRook,
\r
1668 PM_BQ = (int) BlackQueen,
\r
1669 PM_BF = (int) BlackFerz,
\r
1670 PM_BW = (int) BlackWazir,
\r
1671 PM_BE = (int) BlackAlfil,
\r
1672 PM_BM = (int) BlackMan,
\r
1673 PM_BO = (int) BlackCannon,
\r
1674 PM_BU = (int) BlackUnicorn,
\r
1675 PM_BH = (int) BlackNightrider,
\r
1676 PM_BA = (int) BlackAngel,
\r
1677 PM_BC = (int) BlackMarshall,
\r
1678 PM_BG = (int) BlackGrasshopper,
\r
1679 PM_BAB = (int) BlackCardinal,
\r
1680 PM_BD = (int) BlackDragon,
\r
1681 PM_BL = (int) BlackLance,
\r
1682 PM_BS = (int) BlackCobra,
\r
1683 PM_BV = (int) BlackFalcon,
\r
1684 PM_BSG = (int) BlackSilver,
\r
1685 PM_BK = (int) BlackKing
\r
1688 static HFONT hPieceFont = NULL;
\r
1689 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1690 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1691 static int fontBitmapSquareSize = 0;
\r
1692 static char pieceToFontChar[(int) EmptySquare] =
\r
1693 { 'p', 'n', 'b', 'r', 'q',
\r
1694 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1695 'k', 'o', 'm', 'v', 't', 'w',
\r
1696 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1699 extern BOOL SetCharTable( char *table, const char * map );
\r
1700 /* [HGM] moved to backend.c */
\r
1702 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1705 BYTE r1 = GetRValue( color );
\r
1706 BYTE g1 = GetGValue( color );
\r
1707 BYTE b1 = GetBValue( color );
\r
1713 /* Create a uniform background first */
\r
1714 hbrush = CreateSolidBrush( color );
\r
1715 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1716 FillRect( hdc, &rc, hbrush );
\r
1717 DeleteObject( hbrush );
\r
1720 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1721 int steps = squareSize / 2;
\r
1724 for( i=0; i<steps; i++ ) {
\r
1725 BYTE r = r1 - (r1-r2) * i / steps;
\r
1726 BYTE g = g1 - (g1-g2) * i / steps;
\r
1727 BYTE b = b1 - (b1-b2) * i / steps;
\r
1729 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1730 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1731 FillRect( hdc, &rc, hbrush );
\r
1732 DeleteObject(hbrush);
\r
1735 else if( mode == 2 ) {
\r
1736 /* Diagonal gradient, good more or less for every piece */
\r
1737 POINT triangle[3];
\r
1738 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1739 HBRUSH hbrush_old;
\r
1740 int steps = squareSize;
\r
1743 triangle[0].x = squareSize - steps;
\r
1744 triangle[0].y = squareSize;
\r
1745 triangle[1].x = squareSize;
\r
1746 triangle[1].y = squareSize;
\r
1747 triangle[2].x = squareSize;
\r
1748 triangle[2].y = squareSize - steps;
\r
1750 for( i=0; i<steps; i++ ) {
\r
1751 BYTE r = r1 - (r1-r2) * i / steps;
\r
1752 BYTE g = g1 - (g1-g2) * i / steps;
\r
1753 BYTE b = b1 - (b1-b2) * i / steps;
\r
1755 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1756 hbrush_old = SelectObject( hdc, hbrush );
\r
1757 Polygon( hdc, triangle, 3 );
\r
1758 SelectObject( hdc, hbrush_old );
\r
1759 DeleteObject(hbrush);
\r
1764 SelectObject( hdc, hpen );
\r
1769 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1770 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1771 piece: follow the steps as explained below.
\r
1773 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1777 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1781 int backColor = whitePieceColor;
\r
1782 int foreColor = blackPieceColor;
\r
1784 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1785 backColor = appData.fontBackColorWhite;
\r
1786 foreColor = appData.fontForeColorWhite;
\r
1788 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1789 backColor = appData.fontBackColorBlack;
\r
1790 foreColor = appData.fontForeColorBlack;
\r
1794 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1796 hbm_old = SelectObject( hdc, hbm );
\r
1800 rc.right = squareSize;
\r
1801 rc.bottom = squareSize;
\r
1803 /* Step 1: background is now black */
\r
1804 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1806 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1808 pt.x = (squareSize - sz.cx) / 2;
\r
1809 pt.y = (squareSize - sz.cy) / 2;
\r
1811 SetBkMode( hdc, TRANSPARENT );
\r
1812 SetTextColor( hdc, chroma );
\r
1813 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1814 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1816 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1817 /* Step 3: the area outside the piece is filled with white */
\r
1818 // FloodFill( hdc, 0, 0, chroma );
\r
1819 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1820 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1821 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1822 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1823 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1825 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1826 but if the start point is not inside the piece we're lost!
\r
1827 There should be a better way to do this... if we could create a region or path
\r
1828 from the fill operation we would be fine for example.
\r
1830 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1831 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1833 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1834 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1835 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1837 SelectObject( dc2, bm2 );
\r
1838 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1839 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1840 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1841 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1842 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1845 DeleteObject( bm2 );
\r
1848 SetTextColor( hdc, 0 );
\r
1850 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1851 draw the piece again in black for safety.
\r
1853 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1855 SelectObject( hdc, hbm_old );
\r
1857 if( hPieceMask[index] != NULL ) {
\r
1858 DeleteObject( hPieceMask[index] );
\r
1861 hPieceMask[index] = hbm;
\r
1864 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1866 SelectObject( hdc, hbm );
\r
1869 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1870 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1871 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1873 SelectObject( dc1, hPieceMask[index] );
\r
1874 SelectObject( dc2, bm2 );
\r
1875 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1876 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1879 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1880 the piece background and deletes (makes transparent) the rest.
\r
1881 Thanks to that mask, we are free to paint the background with the greates
\r
1882 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1883 We use this, to make gradients and give the pieces a "roundish" look.
\r
1885 SetPieceBackground( hdc, backColor, 2 );
\r
1886 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1890 DeleteObject( bm2 );
\r
1893 SetTextColor( hdc, foreColor );
\r
1894 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1896 SelectObject( hdc, hbm_old );
\r
1898 if( hPieceFace[index] != NULL ) {
\r
1899 DeleteObject( hPieceFace[index] );
\r
1902 hPieceFace[index] = hbm;
\r
1905 static int TranslatePieceToFontPiece( int piece )
\r
1935 case BlackMarshall:
\r
1939 case BlackNightrider:
\r
1945 case BlackUnicorn:
\r
1949 case BlackGrasshopper:
\r
1961 case BlackCardinal:
\r
1968 case WhiteMarshall:
\r
1972 case WhiteNightrider:
\r
1978 case WhiteUnicorn:
\r
1982 case WhiteGrasshopper:
\r
1994 case WhiteCardinal:
\r
2003 void CreatePiecesFromFont()
\r
2006 HDC hdc_window = NULL;
\r
2012 if( fontBitmapSquareSize < 0 ) {
\r
2013 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2017 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2018 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2019 fontBitmapSquareSize = -1;
\r
2023 if( fontBitmapSquareSize != squareSize ) {
\r
2024 hdc_window = GetDC( hwndMain );
\r
2025 hdc = CreateCompatibleDC( hdc_window );
\r
2027 if( hPieceFont != NULL ) {
\r
2028 DeleteObject( hPieceFont );
\r
2031 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2032 hPieceMask[i] = NULL;
\r
2033 hPieceFace[i] = NULL;
\r
2039 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2040 fontHeight = appData.fontPieceSize;
\r
2043 fontHeight = (fontHeight * squareSize) / 100;
\r
2045 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2047 lf.lfEscapement = 0;
\r
2048 lf.lfOrientation = 0;
\r
2049 lf.lfWeight = FW_NORMAL;
\r
2051 lf.lfUnderline = 0;
\r
2052 lf.lfStrikeOut = 0;
\r
2053 lf.lfCharSet = DEFAULT_CHARSET;
\r
2054 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2055 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2056 lf.lfQuality = PROOF_QUALITY;
\r
2057 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2058 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2059 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2061 hPieceFont = CreateFontIndirect( &lf );
\r
2063 if( hPieceFont == NULL ) {
\r
2064 fontBitmapSquareSize = -2;
\r
2067 /* Setup font-to-piece character table */
\r
2068 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2069 /* No (or wrong) global settings, try to detect the font */
\r
2070 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2072 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2074 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2075 /* DiagramTT* family */
\r
2076 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2078 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2079 /* Fairy symbols */
\r
2080 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2082 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2083 /* Good Companion (Some characters get warped as literal :-( */
\r
2084 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2085 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2086 SetCharTable(pieceToFontChar, s);
\r
2089 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2090 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2094 /* Create bitmaps */
\r
2095 hfont_old = SelectObject( hdc, hPieceFont );
\r
2096 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2097 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2098 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2100 SelectObject( hdc, hfont_old );
\r
2102 fontBitmapSquareSize = squareSize;
\r
2106 if( hdc != NULL ) {
\r
2110 if( hdc_window != NULL ) {
\r
2111 ReleaseDC( hwndMain, hdc_window );
\r
2116 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2118 char name[128], buf[MSG_SIZ];
\r
2120 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2121 if(appData.pieceDirectory[0]) {
\r
2123 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2124 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2125 if(res) return res;
\r
2127 if (gameInfo.event &&
\r
2128 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2129 strcmp(name, "k80s") == 0) {
\r
2130 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2132 return LoadBitmap(hinst, name);
\r
2136 /* Insert a color into the program's logical palette
\r
2137 structure. This code assumes the given color is
\r
2138 the result of the RGB or PALETTERGB macro, and it
\r
2139 knows how those macros work (which is documented).
\r
2142 InsertInPalette(COLORREF color)
\r
2144 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2146 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2147 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2148 pLogPal->palNumEntries--;
\r
2152 pe->peFlags = (char) 0;
\r
2153 pe->peRed = (char) (0xFF & color);
\r
2154 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2155 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2161 InitDrawingColors()
\r
2163 if (pLogPal == NULL) {
\r
2164 /* Allocate enough memory for a logical palette with
\r
2165 * PALETTESIZE entries and set the size and version fields
\r
2166 * of the logical palette structure.
\r
2168 pLogPal = (NPLOGPALETTE)
\r
2169 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2170 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2171 pLogPal->palVersion = 0x300;
\r
2173 pLogPal->palNumEntries = 0;
\r
2175 InsertInPalette(lightSquareColor);
\r
2176 InsertInPalette(darkSquareColor);
\r
2177 InsertInPalette(whitePieceColor);
\r
2178 InsertInPalette(blackPieceColor);
\r
2179 InsertInPalette(highlightSquareColor);
\r
2180 InsertInPalette(premoveHighlightColor);
\r
2182 /* create a logical color palette according the information
\r
2183 * in the LOGPALETTE structure.
\r
2185 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2187 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2188 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2189 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2190 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2191 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2192 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2193 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2194 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2195 /* [AS] Force rendering of the font-based pieces */
\r
2196 if( fontBitmapSquareSize > 0 ) {
\r
2197 fontBitmapSquareSize = 0;
\r
2203 BoardWidth(int boardSize, int n)
\r
2204 { /* [HGM] argument n added to allow different width and height */
\r
2205 int lineGap = sizeInfo[boardSize].lineGap;
\r
2207 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2208 lineGap = appData.overrideLineGap;
\r
2211 return (n + 1) * lineGap +
\r
2212 n * sizeInfo[boardSize].squareSize;
\r
2215 /* Respond to board resize by dragging edge */
\r
2217 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2219 BoardSize newSize = NUM_SIZES - 1;
\r
2220 static int recurse = 0;
\r
2221 if (IsIconic(hwndMain)) return;
\r
2222 if (recurse > 0) return;
\r
2224 while (newSize > 0) {
\r
2225 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2226 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2227 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2230 boardSize = newSize;
\r
2231 InitDrawingSizes(boardSize, flags);
\r
2236 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2239 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2241 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2242 ChessSquare piece;
\r
2243 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2245 SIZE clockSize, messageSize;
\r
2247 char buf[MSG_SIZ];
\r
2249 HMENU hmenu = GetMenu(hwndMain);
\r
2250 RECT crect, wrect, oldRect;
\r
2252 LOGBRUSH logbrush;
\r
2253 VariantClass v = gameInfo.variant;
\r
2255 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2256 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2258 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2259 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2260 oldBoardSize = boardSize;
\r
2262 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2263 { // correct board size to one where built-in pieces exist
\r
2264 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2265 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2266 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2267 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2268 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {
\r
2269 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2270 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2271 boardSize = SizeMiddling;
\r
2274 if(!appData.useFont && boardSize == SizePetite && (v == VariantShogi || v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2276 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2277 oldRect.top = wpMain.y;
\r
2278 oldRect.right = wpMain.x + wpMain.width;
\r
2279 oldRect.bottom = wpMain.y + wpMain.height;
\r
2281 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2282 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2283 squareSize = sizeInfo[boardSize].squareSize;
\r
2284 lineGap = sizeInfo[boardSize].lineGap;
\r
2285 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2286 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2288 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2289 lineGap = appData.overrideLineGap;
\r
2292 if (tinyLayout != oldTinyLayout) {
\r
2293 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2295 style &= ~WS_SYSMENU;
\r
2296 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2297 "&Minimize\tCtrl+F4");
\r
2299 style |= WS_SYSMENU;
\r
2300 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2302 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2304 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2305 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2306 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2308 DrawMenuBar(hwndMain);
\r
2311 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2312 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2314 /* Get text area sizes */
\r
2315 hdc = GetDC(hwndMain);
\r
2316 if (appData.clockMode) {
\r
2317 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2319 snprintf(buf, MSG_SIZ, _("White"));
\r
2321 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2322 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2323 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2324 str = _("We only care about the height here");
\r
2325 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2326 SelectObject(hdc, oldFont);
\r
2327 ReleaseDC(hwndMain, hdc);
\r
2329 /* Compute where everything goes */
\r
2330 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2331 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2332 logoHeight = 2*clockSize.cy;
\r
2333 leftLogoRect.left = OUTER_MARGIN;
\r
2334 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2335 leftLogoRect.top = OUTER_MARGIN;
\r
2336 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2338 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2339 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2340 rightLogoRect.top = OUTER_MARGIN;
\r
2341 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2344 whiteRect.left = leftLogoRect.right;
\r
2345 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2346 whiteRect.top = OUTER_MARGIN;
\r
2347 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2349 blackRect.right = rightLogoRect.left;
\r
2350 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2351 blackRect.top = whiteRect.top;
\r
2352 blackRect.bottom = whiteRect.bottom;
\r
2354 whiteRect.left = OUTER_MARGIN;
\r
2355 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2356 whiteRect.top = OUTER_MARGIN;
\r
2357 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2359 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2360 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2361 blackRect.top = whiteRect.top;
\r
2362 blackRect.bottom = whiteRect.bottom;
\r
2364 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2367 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2368 if (appData.showButtonBar) {
\r
2369 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2370 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2372 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2374 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2375 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2377 boardRect.left = OUTER_MARGIN;
\r
2378 boardRect.right = boardRect.left + boardWidth;
\r
2379 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2380 boardRect.bottom = boardRect.top + boardHeight;
\r
2382 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2383 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2384 oldTinyLayout = tinyLayout;
\r
2385 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2386 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2387 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2388 winW *= 1 + twoBoards;
\r
2389 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2390 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2391 wpMain.height = winH; // without disturbing window attachments
\r
2392 GetWindowRect(hwndMain, &wrect);
\r
2393 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2394 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2396 // [HGM] placement: let attached windows follow size change.
\r
2397 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2398 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2399 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2400 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2401 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2403 /* compensate if menu bar wrapped */
\r
2404 GetClientRect(hwndMain, &crect);
\r
2405 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2406 wpMain.height += offby;
\r
2408 case WMSZ_TOPLEFT:
\r
2409 SetWindowPos(hwndMain, NULL,
\r
2410 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2411 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2414 case WMSZ_TOPRIGHT:
\r
2416 SetWindowPos(hwndMain, NULL,
\r
2417 wrect.left, wrect.bottom - wpMain.height,
\r
2418 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2421 case WMSZ_BOTTOMLEFT:
\r
2423 SetWindowPos(hwndMain, NULL,
\r
2424 wrect.right - wpMain.width, wrect.top,
\r
2425 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2428 case WMSZ_BOTTOMRIGHT:
\r
2432 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2433 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2438 for (i = 0; i < N_BUTTONS; i++) {
\r
2439 if (buttonDesc[i].hwnd != NULL) {
\r
2440 DestroyWindow(buttonDesc[i].hwnd);
\r
2441 buttonDesc[i].hwnd = NULL;
\r
2443 if (appData.showButtonBar) {
\r
2444 buttonDesc[i].hwnd =
\r
2445 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2446 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2447 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2448 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2449 (HMENU) buttonDesc[i].id,
\r
2450 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2452 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2453 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2454 MAKELPARAM(FALSE, 0));
\r
2456 if (buttonDesc[i].id == IDM_Pause)
\r
2457 hwndPause = buttonDesc[i].hwnd;
\r
2458 buttonDesc[i].wndproc = (WNDPROC)
\r
2459 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2462 if (gridPen != NULL) DeleteObject(gridPen);
\r
2463 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2464 if (premovePen != NULL) DeleteObject(premovePen);
\r
2465 if (lineGap != 0) {
\r
2466 logbrush.lbStyle = BS_SOLID;
\r
2467 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2469 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2470 lineGap, &logbrush, 0, NULL);
\r
2471 logbrush.lbColor = highlightSquareColor;
\r
2473 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2474 lineGap, &logbrush, 0, NULL);
\r
2476 logbrush.lbColor = premoveHighlightColor;
\r
2478 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2479 lineGap, &logbrush, 0, NULL);
\r
2481 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2482 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2483 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2484 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2485 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2486 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2487 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2488 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2490 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2491 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2492 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2493 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2494 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2495 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2496 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2497 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2501 /* [HGM] Licensing requirement */
\r
2503 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2506 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2508 GothicPopUp( "", VariantNormal);
\r
2511 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2513 /* Load piece bitmaps for this board size */
\r
2514 for (i=0; i<=2; i++) {
\r
2515 for (piece = WhitePawn;
\r
2516 (int) piece < (int) BlackPawn;
\r
2517 piece = (ChessSquare) ((int) piece + 1)) {
\r
2518 if (pieceBitmap[i][piece] != NULL)
\r
2519 DeleteObject(pieceBitmap[i][piece]);
\r
2523 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2524 // Orthodox Chess pieces
\r
2525 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2526 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2527 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2528 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2529 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2530 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2531 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2532 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2533 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2534 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2535 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2536 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2537 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2538 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2539 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2540 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2541 // in Shogi, Hijack the unused Queen for Lance
\r
2542 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2543 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2544 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2546 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2547 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2548 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2551 if(squareSize <= 72 && squareSize >= 33) {
\r
2552 /* A & C are available in most sizes now */
\r
2553 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2554 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2555 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2556 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2557 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2558 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2559 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2560 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2561 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2562 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2563 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2564 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2565 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2566 } else { // Smirf-like
\r
2567 if(gameInfo.variant == VariantSChess) {
\r
2568 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2569 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2570 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2572 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2573 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2574 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2577 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2578 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2579 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2580 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2581 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2582 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2583 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2584 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2585 } else { // WinBoard standard
\r
2586 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2587 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2588 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2593 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2594 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2595 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2596 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2597 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2598 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2599 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2600 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2601 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2602 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2603 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2604 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2605 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2606 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2607 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2608 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2609 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2610 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2611 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2612 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2613 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2614 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2615 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2616 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2617 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2618 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2621 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2622 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2623 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2625 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2626 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2627 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2628 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2629 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2630 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2631 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2632 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2633 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2634 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2635 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2636 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2637 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2639 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2640 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2641 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2642 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2645 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2646 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2647 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2648 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2653 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2654 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2655 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2656 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2657 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2658 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2659 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2660 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2661 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2662 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2663 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2664 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2665 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2666 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2667 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2671 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2672 /* special Shogi support in this size */
\r
2673 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2674 for (piece = WhitePawn;
\r
2675 (int) piece < (int) BlackPawn;
\r
2676 piece = (ChessSquare) ((int) piece + 1)) {
\r
2677 if (pieceBitmap[i][piece] != NULL)
\r
2678 DeleteObject(pieceBitmap[i][piece]);
\r
2681 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2682 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2683 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2684 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2685 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2686 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2687 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2688 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2689 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2690 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2691 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2692 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2693 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2694 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2695 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2696 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2697 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2698 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2699 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2700 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2701 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2702 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2703 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2704 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2705 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2706 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2707 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2708 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2709 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2710 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2711 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2712 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2713 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2714 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2715 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2716 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2717 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2718 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2719 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2720 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2721 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2722 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2728 PieceBitmap(ChessSquare p, int kind)
\r
2730 if ((int) p >= (int) BlackPawn)
\r
2731 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2733 return pieceBitmap[kind][(int) p];
\r
2736 /***************************************************************/
\r
2738 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2739 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2741 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2742 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2746 SquareToPos(int row, int column, int * x, int * y)
\r
2749 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2750 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2752 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2753 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2758 DrawCoordsOnDC(HDC hdc)
\r
2760 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2761 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2762 char str[2] = { NULLCHAR, NULLCHAR };
\r
2763 int oldMode, oldAlign, x, y, start, i;
\r
2767 if (!appData.showCoords)
\r
2770 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2772 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2773 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2774 oldAlign = GetTextAlign(hdc);
\r
2775 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2777 y = boardRect.top + lineGap;
\r
2778 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2781 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2782 x += border - lineGap - 4; y += squareSize - 6;
\r
2784 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2785 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2786 str[0] = files[start + i];
\r
2787 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2788 y += squareSize + lineGap;
\r
2791 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2794 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2795 x += -border + 4; y += border - squareSize + 6;
\r
2797 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2798 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2799 str[0] = ranks[start + i];
\r
2800 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2801 x += squareSize + lineGap;
\r
2804 SelectObject(hdc, oldBrush);
\r
2805 SetBkMode(hdc, oldMode);
\r
2806 SetTextAlign(hdc, oldAlign);
\r
2807 SelectObject(hdc, oldFont);
\r
2811 DrawGridOnDC(HDC hdc)
\r
2815 if (lineGap != 0) {
\r
2816 oldPen = SelectObject(hdc, gridPen);
\r
2817 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2818 SelectObject(hdc, oldPen);
\r
2822 #define HIGHLIGHT_PEN 0
\r
2823 #define PREMOVE_PEN 1
\r
2826 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2829 HPEN oldPen, hPen;
\r
2830 if (lineGap == 0) return;
\r
2832 x1 = boardRect.left +
\r
2833 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2834 y1 = boardRect.top +
\r
2835 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2837 x1 = boardRect.left +
\r
2838 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2839 y1 = boardRect.top +
\r
2840 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2842 hPen = pen ? premovePen : highlightPen;
\r
2843 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2844 MoveToEx(hdc, x1, y1, NULL);
\r
2845 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2846 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2847 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2848 LineTo(hdc, x1, y1);
\r
2849 SelectObject(hdc, oldPen);
\r
2853 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2856 for (i=0; i<2; i++) {
\r
2857 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2858 DrawHighlightOnDC(hdc, TRUE,
\r
2859 h->sq[i].x, h->sq[i].y,
\r
2864 /* Note: sqcolor is used only in monoMode */
\r
2865 /* Note that this code is largely duplicated in woptions.c,
\r
2866 function DrawSampleSquare, so that needs to be updated too */
\r
2868 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2870 HBITMAP oldBitmap;
\r
2874 if (appData.blindfold) return;
\r
2876 /* [AS] Use font-based pieces if needed */
\r
2877 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2878 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2879 CreatePiecesFromFont();
\r
2881 if( fontBitmapSquareSize == squareSize ) {
\r
2882 int index = TranslatePieceToFontPiece(piece);
\r
2884 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2886 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2887 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2891 squareSize, squareSize,
\r
2896 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2898 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2899 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2903 squareSize, squareSize,
\r
2912 if (appData.monoMode) {
\r
2913 SelectObject(tmphdc, PieceBitmap(piece,
\r
2914 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2915 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2916 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2918 HBRUSH xBrush = whitePieceBrush;
\r
2919 tmpSize = squareSize;
\r
2920 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2922 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2923 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2924 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2925 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2926 x += (squareSize - minorSize)>>1;
\r
2927 y += squareSize - minorSize - 2;
\r
2928 tmpSize = minorSize;
\r
2930 if (color || appData.allWhite ) {
\r
2931 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2933 oldBrush = SelectObject(hdc, xBrush);
\r
2934 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2935 if(appData.upsideDown && color==flipView)
\r
2936 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2938 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2939 /* Use black for outline of white pieces */
\r
2940 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2941 if(appData.upsideDown && color==flipView)
\r
2942 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2944 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2945 } else if(appData.pieceDirectory[0]) {
\r
2946 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2947 oldBrush = SelectObject(hdc, xBrush);
\r
2948 if(appData.upsideDown && color==flipView)
\r
2949 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2951 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2952 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2953 if(appData.upsideDown && color==flipView)
\r
2954 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2956 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2958 /* Use square color for details of black pieces */
\r
2959 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2960 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2961 if(appData.upsideDown && !flipView)
\r
2962 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2964 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2966 SelectObject(hdc, oldBrush);
\r
2967 SelectObject(tmphdc, oldBitmap);
\r
2971 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2972 int GetBackTextureMode( int algo )
\r
2974 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2978 case BACK_TEXTURE_MODE_PLAIN:
\r
2979 result = 1; /* Always use identity map */
\r
2981 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2982 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2990 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2991 to handle redraws cleanly (as random numbers would always be different).
\r
2993 VOID RebuildTextureSquareInfo()
\r
3003 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3005 if( liteBackTexture != NULL ) {
\r
3006 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3007 lite_w = bi.bmWidth;
\r
3008 lite_h = bi.bmHeight;
\r
3012 if( darkBackTexture != NULL ) {
\r
3013 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3014 dark_w = bi.bmWidth;
\r
3015 dark_h = bi.bmHeight;
\r
3019 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3020 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3021 if( (col + row) & 1 ) {
\r
3023 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3024 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3025 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3027 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3028 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3029 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3031 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3032 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3037 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3038 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3039 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3041 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3042 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3043 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3045 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3046 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3053 /* [AS] Arrow highlighting support */
\r
3055 static double A_WIDTH = 5; /* Width of arrow body */
\r
3057 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3058 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3060 static double Sqr( double x )
\r
3065 static int Round( double x )
\r
3067 return (int) (x + 0.5);
\r
3070 /* Draw an arrow between two points using current settings */
\r
3071 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3074 double dx, dy, j, k, x, y;
\r
3076 if( d_x == s_x ) {
\r
3077 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3079 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3082 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3083 arrow[1].y = d_y - h;
\r
3085 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3086 arrow[2].y = d_y - h;
\r
3091 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3092 arrow[5].y = d_y - h;
\r
3094 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3095 arrow[4].y = d_y - h;
\r
3097 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3100 else if( d_y == s_y ) {
\r
3101 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3104 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3106 arrow[1].x = d_x - w;
\r
3107 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3109 arrow[2].x = d_x - w;
\r
3110 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3115 arrow[5].x = d_x - w;
\r
3116 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3118 arrow[4].x = d_x - w;
\r
3119 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3122 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3125 /* [AS] Needed a lot of paper for this! :-) */
\r
3126 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3127 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3129 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3131 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3136 arrow[0].x = Round(x - j);
\r
3137 arrow[0].y = Round(y + j*dx);
\r
3139 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3140 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3143 x = (double) d_x - k;
\r
3144 y = (double) d_y - k*dy;
\r
3147 x = (double) d_x + k;
\r
3148 y = (double) d_y + k*dy;
\r
3151 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3153 arrow[6].x = Round(x - j);
\r
3154 arrow[6].y = Round(y + j*dx);
\r
3156 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3157 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3159 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3160 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3165 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3166 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3169 Polygon( hdc, arrow, 7 );
\r
3172 /* [AS] Draw an arrow between two squares */
\r
3173 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3175 int s_x, s_y, d_x, d_y;
\r
3182 if( s_col == d_col && s_row == d_row ) {
\r
3186 /* Get source and destination points */
\r
3187 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3188 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3191 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3193 else if( d_y < s_y ) {
\r
3194 d_y += squareSize / 2 + squareSize / 4;
\r
3197 d_y += squareSize / 2;
\r
3201 d_x += squareSize / 2 - squareSize / 4;
\r
3203 else if( d_x < s_x ) {
\r
3204 d_x += squareSize / 2 + squareSize / 4;
\r
3207 d_x += squareSize / 2;
\r
3210 s_x += squareSize / 2;
\r
3211 s_y += squareSize / 2;
\r
3213 /* Adjust width */
\r
3214 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3217 stLB.lbStyle = BS_SOLID;
\r
3218 stLB.lbColor = appData.highlightArrowColor;
\r
3221 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3222 holdpen = SelectObject( hdc, hpen );
\r
3223 hbrush = CreateBrushIndirect( &stLB );
\r
3224 holdbrush = SelectObject( hdc, hbrush );
\r
3226 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3228 SelectObject( hdc, holdpen );
\r
3229 SelectObject( hdc, holdbrush );
\r
3230 DeleteObject( hpen );
\r
3231 DeleteObject( hbrush );
\r
3234 BOOL HasHighlightInfo()
\r
3236 BOOL result = FALSE;
\r
3238 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3239 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3247 BOOL IsDrawArrowEnabled()
\r
3249 BOOL result = FALSE;
\r
3251 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3258 VOID DrawArrowHighlight( HDC hdc )
\r
3260 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3261 DrawArrowBetweenSquares( hdc,
\r
3262 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3263 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3267 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3269 HRGN result = NULL;
\r
3271 if( HasHighlightInfo() ) {
\r
3272 int x1, y1, x2, y2;
\r
3273 int sx, sy, dx, dy;
\r
3275 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3276 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3278 sx = MIN( x1, x2 );
\r
3279 sy = MIN( y1, y2 );
\r
3280 dx = MAX( x1, x2 ) + squareSize;
\r
3281 dy = MAX( y1, y2 ) + squareSize;
\r
3283 result = CreateRectRgn( sx, sy, dx, dy );
\r
3290 Warning: this function modifies the behavior of several other functions.
\r
3292 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3293 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3294 repaint is scattered all over the place, which is not good for features such as
\r
3295 "arrow highlighting" that require a full repaint of the board.
\r
3297 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3298 user interaction, when speed is not so important) but especially to avoid errors
\r
3299 in the displayed graphics.
\r
3301 In such patched places, I always try refer to this function so there is a single
\r
3302 place to maintain knowledge.
\r
3304 To restore the original behavior, just return FALSE unconditionally.
\r
3306 BOOL IsFullRepaintPreferrable()
\r
3308 BOOL result = FALSE;
\r
3310 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3311 /* Arrow may appear on the board */
\r
3319 This function is called by DrawPosition to know whether a full repaint must
\r
3322 Only DrawPosition may directly call this function, which makes use of
\r
3323 some state information. Other function should call DrawPosition specifying
\r
3324 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3326 BOOL DrawPositionNeedsFullRepaint()
\r
3328 BOOL result = FALSE;
\r
3331 Probably a slightly better policy would be to trigger a full repaint
\r
3332 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3333 but animation is fast enough that it's difficult to notice.
\r
3335 if( animInfo.piece == EmptySquare ) {
\r
3336 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3344 static HBITMAP borderBitmap;
\r
3347 DrawBackgroundOnDC(HDC hdc)
\r
3353 static char oldBorder[MSG_SIZ];
\r
3354 int w = 600, h = 600, mode;
\r
3356 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3357 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3358 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3360 if(borderBitmap == NULL) { // loading failed, use white
\r
3361 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3364 tmphdc = CreateCompatibleDC(hdc);
\r
3365 hbm = SelectObject(tmphdc, borderBitmap);
\r
3366 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3370 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3371 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3372 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3373 SetStretchBltMode(hdc, mode);
\r
3374 SelectObject(tmphdc, hbm);
\r
3379 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3381 int row, column, x, y, square_color, piece_color;
\r
3382 ChessSquare piece;
\r
3384 HDC texture_hdc = NULL;
\r
3386 /* [AS] Initialize background textures if needed */
\r
3387 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3388 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3389 if( backTextureSquareSize != squareSize
\r
3390 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3391 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3392 backTextureSquareSize = squareSize;
\r
3393 RebuildTextureSquareInfo();
\r
3396 texture_hdc = CreateCompatibleDC( hdc );
\r
3399 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3400 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3402 SquareToPos(row, column, &x, &y);
\r
3404 piece = board[row][column];
\r
3406 square_color = ((column + row) % 2) == 1;
\r
3407 if( gameInfo.variant == VariantXiangqi ) {
\r
3408 square_color = !InPalace(row, column);
\r
3409 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3410 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3412 piece_color = (int) piece < (int) BlackPawn;
\r
3415 /* [HGM] holdings file: light square or black */
\r
3416 if(column == BOARD_LEFT-2) {
\r
3417 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3420 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3424 if(column == BOARD_RGHT + 1 ) {
\r
3425 if( row < gameInfo.holdingsSize )
\r
3428 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3432 if(column == BOARD_LEFT-1 ) /* left align */
\r
3433 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3434 else if( column == BOARD_RGHT) /* right align */
\r
3435 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3437 if (appData.monoMode) {
\r
3438 if (piece == EmptySquare) {
\r
3439 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3440 square_color ? WHITENESS : BLACKNESS);
\r
3442 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3445 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3446 /* [AS] Draw the square using a texture bitmap */
\r
3447 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3448 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3449 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3452 squareSize, squareSize,
\r
3455 backTextureSquareInfo[r][c].mode,
\r
3456 backTextureSquareInfo[r][c].x,
\r
3457 backTextureSquareInfo[r][c].y );
\r
3459 SelectObject( texture_hdc, hbm );
\r
3461 if (piece != EmptySquare) {
\r
3462 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3466 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3468 oldBrush = SelectObject(hdc, brush );
\r
3469 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3470 SelectObject(hdc, oldBrush);
\r
3471 if (piece != EmptySquare)
\r
3472 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3477 if( texture_hdc != NULL ) {
\r
3478 DeleteDC( texture_hdc );
\r
3482 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3483 void fputDW(FILE *f, int x)
\r
3485 fputc(x & 255, f);
\r
3486 fputc(x>>8 & 255, f);
\r
3487 fputc(x>>16 & 255, f);
\r
3488 fputc(x>>24 & 255, f);
\r
3491 #define MAX_CLIPS 200 /* more than enough */
\r
3494 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3496 // HBITMAP bufferBitmap;
\r
3501 int w = 100, h = 50;
\r
3503 if(logo == NULL) {
\r
3504 if(!logoHeight) return;
\r
3505 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3507 // GetClientRect(hwndMain, &Rect);
\r
3508 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3509 // Rect.bottom-Rect.top+1);
\r
3510 tmphdc = CreateCompatibleDC(hdc);
\r
3511 hbm = SelectObject(tmphdc, logo);
\r
3512 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3516 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3517 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3518 SelectObject(tmphdc, hbm);
\r
3526 HDC hdc = GetDC(hwndMain);
\r
3527 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3528 if(appData.autoLogo) {
\r
3530 switch(gameMode) { // pick logos based on game mode
\r
3531 case IcsObserving:
\r
3532 whiteLogo = second.programLogo; // ICS logo
\r
3533 blackLogo = second.programLogo;
\r
3536 case IcsPlayingWhite:
\r
3537 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3538 blackLogo = second.programLogo; // ICS logo
\r
3540 case IcsPlayingBlack:
\r
3541 whiteLogo = second.programLogo; // ICS logo
\r
3542 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3544 case TwoMachinesPlay:
\r
3545 if(first.twoMachinesColor[0] == 'b') {
\r
3546 whiteLogo = second.programLogo;
\r
3547 blackLogo = first.programLogo;
\r
3550 case MachinePlaysWhite:
\r
3551 blackLogo = userLogo;
\r
3553 case MachinePlaysBlack:
\r
3554 whiteLogo = userLogo;
\r
3555 blackLogo = first.programLogo;
\r
3558 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3559 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3560 ReleaseDC(hwndMain, hdc);
\r
3565 UpdateLogos(int display)
\r
3566 { // called after loading new engine(s), in tourney or from menu
\r
3567 LoadLogo(&first, 0, FALSE);
\r
3568 LoadLogo(&second, 1, appData.icsActive);
\r
3569 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3570 if(display) DisplayLogos();
\r
3573 static HDC hdcSeek;
\r
3575 // [HGM] seekgraph
\r
3576 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3579 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3580 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3581 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3582 SelectObject( hdcSeek, hp );
\r
3585 // front-end wrapper for drawing functions to do rectangles
\r
3586 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3591 if (hdcSeek == NULL) {
\r
3592 hdcSeek = GetDC(hwndMain);
\r
3593 if (!appData.monoMode) {
\r
3594 SelectPalette(hdcSeek, hPal, FALSE);
\r
3595 RealizePalette(hdcSeek);
\r
3598 hp = SelectObject( hdcSeek, gridPen );
\r
3599 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3600 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3601 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3602 SelectObject( hdcSeek, hp );
\r
3605 // front-end wrapper for putting text in graph
\r
3606 void DrawSeekText(char *buf, int x, int y)
\r
3609 SetBkMode( hdcSeek, TRANSPARENT );
\r
3610 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3611 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3614 void DrawSeekDot(int x, int y, int color)
\r
3616 int square = color & 0x80;
\r
3617 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3618 color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);
\r
3621 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3622 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3624 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3625 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3626 SelectObject(hdcSeek, oldBrush);
\r
3629 void DrawSeekOpen()
\r
3633 void DrawSeekClose()
\r
3638 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3640 static Board lastReq[2], lastDrawn[2];
\r
3641 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3642 static int lastDrawnFlipView = 0;
\r
3643 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3644 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3647 HBITMAP bufferBitmap;
\r
3648 HBITMAP oldBitmap;
\r
3650 HRGN clips[MAX_CLIPS];
\r
3651 ChessSquare dragged_piece = EmptySquare;
\r
3652 int nr = twoBoards*partnerUp;
\r
3654 /* I'm undecided on this - this function figures out whether a full
\r
3655 * repaint is necessary on its own, so there's no real reason to have the
\r
3656 * caller tell it that. I think this can safely be set to FALSE - but
\r
3657 * if we trust the callers not to request full repaints unnessesarily, then
\r
3658 * we could skip some clipping work. In other words, only request a full
\r
3659 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3660 * gamestart and similar) --Hawk
\r
3662 Boolean fullrepaint = repaint;
\r
3664 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3666 if( DrawPositionNeedsFullRepaint() ) {
\r
3667 fullrepaint = TRUE;
\r
3670 if (board == NULL) {
\r
3671 if (!lastReqValid[nr]) {
\r
3674 board = lastReq[nr];
\r
3676 CopyBoard(lastReq[nr], board);
\r
3677 lastReqValid[nr] = 1;
\r
3680 if (doingSizing) {
\r
3684 if (IsIconic(hwndMain)) {
\r
3688 if (hdc == NULL) {
\r
3689 hdc = GetDC(hwndMain);
\r
3690 if (!appData.monoMode) {
\r
3691 SelectPalette(hdc, hPal, FALSE);
\r
3692 RealizePalette(hdc);
\r
3696 releaseDC = FALSE;
\r
3699 /* Create some work-DCs */
\r
3700 hdcmem = CreateCompatibleDC(hdc);
\r
3701 tmphdc = CreateCompatibleDC(hdc);
\r
3703 /* If dragging is in progress, we temporarely remove the piece */
\r
3704 /* [HGM] or temporarily decrease count if stacked */
\r
3705 /* !! Moved to before board compare !! */
\r
3706 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3707 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3708 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3709 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3710 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3712 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3713 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3714 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3716 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3719 /* Figure out which squares need updating by comparing the
\r
3720 * newest board with the last drawn board and checking if
\r
3721 * flipping has changed.
\r
3723 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3724 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3725 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3726 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3727 SquareToPos(row, column, &x, &y);
\r
3728 clips[num_clips++] =
\r
3729 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3733 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3734 for (i=0; i<2; i++) {
\r
3735 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3736 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3737 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3738 lastDrawnHighlight.sq[i].y >= 0) {
\r
3739 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3740 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3741 clips[num_clips++] =
\r
3742 CreateRectRgn(x - lineGap, y - lineGap,
\r
3743 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3745 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3746 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3747 clips[num_clips++] =
\r
3748 CreateRectRgn(x - lineGap, y - lineGap,
\r
3749 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3753 for (i=0; i<2; i++) {
\r
3754 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3755 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3756 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3757 lastDrawnPremove.sq[i].y >= 0) {
\r
3758 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3759 lastDrawnPremove.sq[i].x, &x, &y);
\r
3760 clips[num_clips++] =
\r
3761 CreateRectRgn(x - lineGap, y - lineGap,
\r
3762 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3764 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3765 premoveHighlightInfo.sq[i].y >= 0) {
\r
3766 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3767 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3768 clips[num_clips++] =
\r
3769 CreateRectRgn(x - lineGap, y - lineGap,
\r
3770 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3774 } else { // nr == 1
\r
3775 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3776 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3777 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3778 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3779 for (i=0; i<2; i++) {
\r
3780 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3781 partnerHighlightInfo.sq[i].y >= 0) {
\r
3782 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3783 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3784 clips[num_clips++] =
\r
3785 CreateRectRgn(x - lineGap, y - lineGap,
\r
3786 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3788 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3789 oldPartnerHighlight.sq[i].y >= 0) {
\r
3790 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3791 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3792 clips[num_clips++] =
\r
3793 CreateRectRgn(x - lineGap, y - lineGap,
\r
3794 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3799 fullrepaint = TRUE;
\r
3802 /* Create a buffer bitmap - this is the actual bitmap
\r
3803 * being written to. When all the work is done, we can
\r
3804 * copy it to the real DC (the screen). This avoids
\r
3805 * the problems with flickering.
\r
3807 GetClientRect(hwndMain, &Rect);
\r
3808 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3809 Rect.bottom-Rect.top+1);
\r
3810 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3811 if (!appData.monoMode) {
\r
3812 SelectPalette(hdcmem, hPal, FALSE);
\r
3815 /* Create clips for dragging */
\r
3816 if (!fullrepaint) {
\r
3817 if (dragInfo.from.x >= 0) {
\r
3818 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3819 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3821 if (dragInfo.start.x >= 0) {
\r
3822 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3823 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3825 if (dragInfo.pos.x >= 0) {
\r
3826 x = dragInfo.pos.x - squareSize / 2;
\r
3827 y = dragInfo.pos.y - squareSize / 2;
\r
3828 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3830 if (dragInfo.lastpos.x >= 0) {
\r
3831 x = dragInfo.lastpos.x - squareSize / 2;
\r
3832 y = dragInfo.lastpos.y - squareSize / 2;
\r
3833 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3837 /* Are we animating a move?
\r
3839 * - remove the piece from the board (temporarely)
\r
3840 * - calculate the clipping region
\r
3842 if (!fullrepaint) {
\r
3843 if (animInfo.piece != EmptySquare) {
\r
3844 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3845 x = boardRect.left + animInfo.lastpos.x;
\r
3846 y = boardRect.top + animInfo.lastpos.y;
\r
3847 x2 = boardRect.left + animInfo.pos.x;
\r
3848 y2 = boardRect.top + animInfo.pos.y;
\r
3849 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3850 /* Slight kludge. The real problem is that after AnimateMove is
\r
3851 done, the position on the screen does not match lastDrawn.
\r
3852 This currently causes trouble only on e.p. captures in
\r
3853 atomic, where the piece moves to an empty square and then
\r
3854 explodes. The old and new positions both had an empty square
\r
3855 at the destination, but animation has drawn a piece there and
\r
3856 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3857 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3861 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3862 if (num_clips == 0)
\r
3863 fullrepaint = TRUE;
\r
3865 /* Set clipping on the memory DC */
\r
3866 if (!fullrepaint) {
\r
3867 SelectClipRgn(hdcmem, clips[0]);
\r
3868 for (x = 1; x < num_clips; x++) {
\r
3869 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3870 abort(); // this should never ever happen!
\r
3874 /* Do all the drawing to the memory DC */
\r
3875 if(explodeInfo.radius) { // [HGM] atomic
\r
3877 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3878 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3879 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3880 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3881 x += squareSize/2;
\r
3882 y += squareSize/2;
\r
3883 if(!fullrepaint) {
\r
3884 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3885 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3887 DrawGridOnDC(hdcmem);
\r
3888 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3889 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3890 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3891 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3892 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3893 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3894 SelectObject(hdcmem, oldBrush);
\r
3896 if(border) DrawBackgroundOnDC(hdcmem);
\r
3897 DrawGridOnDC(hdcmem);
\r
3898 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3899 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3900 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3902 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3903 oldPartnerHighlight = partnerHighlightInfo;
\r
3905 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3907 if(nr == 0) // [HGM] dual: markers only on left board
\r
3908 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3909 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3910 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3911 HBRUSH oldBrush = SelectObject(hdcmem,
\r
3912 marker[row][column] == 2 ? markerBrush : explodeBrush);
\r
3913 SquareToPos(row, column, &x, &y);
\r
3914 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3915 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3916 SelectObject(hdcmem, oldBrush);
\r
3921 if( appData.highlightMoveWithArrow ) {
\r
3922 DrawArrowHighlight(hdcmem);
\r
3925 DrawCoordsOnDC(hdcmem);
\r
3927 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
3928 /* to make sure lastDrawn contains what is actually drawn */
\r
3930 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3931 if (dragged_piece != EmptySquare) {
\r
3932 /* [HGM] or restack */
\r
3933 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3934 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3936 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3937 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3938 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3939 x = dragInfo.pos.x - squareSize / 2;
\r
3940 y = dragInfo.pos.y - squareSize / 2;
\r
3941 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
3942 ((int) dragInfo.piece < (int) BlackPawn),
\r
3943 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3946 /* Put the animated piece back into place and draw it */
\r
3947 if (animInfo.piece != EmptySquare) {
\r
3948 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3949 x = boardRect.left + animInfo.pos.x;
\r
3950 y = boardRect.top + animInfo.pos.y;
\r
3951 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3952 ((int) animInfo.piece < (int) BlackPawn),
\r
3953 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3956 /* Release the bufferBitmap by selecting in the old bitmap
\r
3957 * and delete the memory DC
\r
3959 SelectObject(hdcmem, oldBitmap);
\r
3962 /* Set clipping on the target DC */
\r
3963 if (!fullrepaint) {
\r
3964 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
3966 GetRgnBox(clips[x], &rect);
\r
3967 DeleteObject(clips[x]);
\r
3968 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
3969 rect.right + wpMain.width/2, rect.bottom);
\r
3971 SelectClipRgn(hdc, clips[0]);
\r
3972 for (x = 1; x < num_clips; x++) {
\r
3973 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3974 abort(); // this should never ever happen!
\r
3978 /* Copy the new bitmap onto the screen in one go.
\r
3979 * This way we avoid any flickering
\r
3981 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3982 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
3983 boardRect.right - boardRect.left,
\r
3984 boardRect.bottom - boardRect.top,
\r
3985 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3986 if(saveDiagFlag) {
\r
3987 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
3988 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
3990 GetObject(bufferBitmap, sizeof(b), &b);
\r
3991 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
3992 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
3993 bih.biWidth = b.bmWidth;
\r
3994 bih.biHeight = b.bmHeight;
\r
3996 bih.biBitCount = b.bmBitsPixel;
\r
3997 bih.biCompression = 0;
\r
3998 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
3999 bih.biXPelsPerMeter = 0;
\r
4000 bih.biYPelsPerMeter = 0;
\r
4001 bih.biClrUsed = 0;
\r
4002 bih.biClrImportant = 0;
\r
4003 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4004 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4005 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4006 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4008 wb = b.bmWidthBytes;
\r
4010 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4011 int k = ((int*) pData)[i];
\r
4012 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4013 if(j >= 16) break;
\r
4015 if(j >= nrColors) nrColors = j+1;
\r
4017 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4019 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4020 for(w=0; w<(wb>>2); w+=2) {
\r
4021 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4022 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4023 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4024 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4025 pData[p++] = m | j<<4;
\r
4027 while(p&3) pData[p++] = 0;
\r
4030 wb = ((wb+31)>>5)<<2;
\r
4032 // write BITMAPFILEHEADER
\r
4033 fprintf(diagFile, "BM");
\r
4034 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4035 fputDW(diagFile, 0);
\r
4036 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4037 // write BITMAPINFOHEADER
\r
4038 fputDW(diagFile, 40);
\r
4039 fputDW(diagFile, b.bmWidth);
\r
4040 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4041 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4042 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4043 fputDW(diagFile, 0);
\r
4044 fputDW(diagFile, 0);
\r
4045 fputDW(diagFile, 0);
\r
4046 fputDW(diagFile, 0);
\r
4047 fputDW(diagFile, 0);
\r
4048 fputDW(diagFile, 0);
\r
4049 // write color table
\r
4051 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4052 // write bitmap data
\r
4053 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4054 fputc(pData[i], diagFile);
\r
4059 SelectObject(tmphdc, oldBitmap);
\r
4061 /* Massive cleanup */
\r
4062 for (x = 0; x < num_clips; x++)
\r
4063 DeleteObject(clips[x]);
\r
4066 DeleteObject(bufferBitmap);
\r
4069 ReleaseDC(hwndMain, hdc);
\r
4071 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4073 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4075 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4078 /* CopyBoard(lastDrawn, board);*/
\r
4079 lastDrawnHighlight = highlightInfo;
\r
4080 lastDrawnPremove = premoveHighlightInfo;
\r
4081 lastDrawnFlipView = flipView;
\r
4082 lastDrawnValid[nr] = 1;
\r
4085 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4090 saveDiagFlag = 1; diagFile = f;
\r
4091 HDCDrawPosition(NULL, TRUE, NULL);
\r
4099 /*---------------------------------------------------------------------------*\
\r
4100 | CLIENT PAINT PROCEDURE
\r
4101 | This is the main event-handler for the WM_PAINT message.
\r
4103 \*---------------------------------------------------------------------------*/
\r
4105 PaintProc(HWND hwnd)
\r
4111 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4112 if (IsIconic(hwnd)) {
\r
4113 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4115 if (!appData.monoMode) {
\r
4116 SelectPalette(hdc, hPal, FALSE);
\r
4117 RealizePalette(hdc);
\r
4119 HDCDrawPosition(hdc, 1, NULL);
\r
4120 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4121 flipView = !flipView; partnerUp = !partnerUp;
\r
4122 HDCDrawPosition(hdc, 1, NULL);
\r
4123 flipView = !flipView; partnerUp = !partnerUp;
\r
4126 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4127 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4128 ETO_CLIPPED|ETO_OPAQUE,
\r
4129 &messageRect, messageText, strlen(messageText), NULL);
\r
4130 SelectObject(hdc, oldFont);
\r
4131 DisplayBothClocks();
\r
4134 EndPaint(hwnd,&ps);
\r
4142 * If the user selects on a border boundary, return -1; if off the board,
\r
4143 * return -2. Otherwise map the event coordinate to the square.
\r
4144 * The offset boardRect.left or boardRect.top must already have been
\r
4145 * subtracted from x.
\r
4147 int EventToSquare(x, limit)
\r
4152 if (x < lineGap + border)
\r
4154 x -= lineGap + border;
\r
4155 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4157 x /= (squareSize + lineGap);
\r
4169 DropEnable dropEnables[] = {
\r
4170 { 'P', DP_Pawn, N_("Pawn") },
\r
4171 { 'N', DP_Knight, N_("Knight") },
\r
4172 { 'B', DP_Bishop, N_("Bishop") },
\r
4173 { 'R', DP_Rook, N_("Rook") },
\r
4174 { 'Q', DP_Queen, N_("Queen") },
\r
4178 SetupDropMenu(HMENU hmenu)
\r
4180 int i, count, enable;
\r
4182 extern char white_holding[], black_holding[];
\r
4183 char item[MSG_SIZ];
\r
4185 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4186 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4187 dropEnables[i].piece);
\r
4189 while (p && *p++ == dropEnables[i].piece) count++;
\r
4190 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4191 enable = count > 0 || !appData.testLegality
\r
4192 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4193 && !appData.icsActive);
\r
4194 ModifyMenu(hmenu, dropEnables[i].command,
\r
4195 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4196 dropEnables[i].command, item);
\r
4200 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4202 dragInfo.lastpos.x = boardRect.left + x;
\r
4203 dragInfo.lastpos.y = boardRect.top + y;
\r
4204 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4205 dragInfo.from.x = fromX;
\r
4206 dragInfo.from.y = fromY;
\r
4207 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4208 dragInfo.start = dragInfo.from;
\r
4209 SetCapture(hwndMain);
\r
4212 void DragPieceEnd(int x, int y)
\r
4215 dragInfo.start.x = dragInfo.start.y = -1;
\r
4216 dragInfo.from = dragInfo.start;
\r
4217 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4220 void ChangeDragPiece(ChessSquare piece)
\r
4222 dragInfo.piece = piece;
\r
4225 /* Event handler for mouse messages */
\r
4227 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4231 static int recursive = 0;
\r
4233 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4236 if (message == WM_MBUTTONUP) {
\r
4237 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4238 to the middle button: we simulate pressing the left button too!
\r
4240 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4241 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4247 pt.x = LOWORD(lParam);
\r
4248 pt.y = HIWORD(lParam);
\r
4249 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4250 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4251 if (!flipView && y >= 0) {
\r
4252 y = BOARD_HEIGHT - 1 - y;
\r
4254 if (flipView && x >= 0) {
\r
4255 x = BOARD_WIDTH - 1 - x;
\r
4258 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4260 switch (message) {
\r
4261 case WM_LBUTTONDOWN:
\r
4262 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4263 ClockClick(flipClock); break;
\r
4264 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4265 ClockClick(!flipClock); break;
\r
4267 dragInfo.start.x = dragInfo.start.y = -1;
\r
4268 dragInfo.from = dragInfo.start;
\r
4269 if(fromX == -1 && frozen) { // not sure where this is for
\r
4270 fromX = fromY = -1;
\r
4271 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4274 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4275 DrawPosition(TRUE, NULL);
\r
4278 case WM_LBUTTONUP:
\r
4279 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4280 DrawPosition(TRUE, NULL);
\r
4283 case WM_MOUSEMOVE:
\r
4284 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4285 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4286 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4287 if ((appData.animateDragging || appData.highlightDragging)
\r
4288 && (wParam & MK_LBUTTON)
\r
4289 && dragInfo.from.x >= 0)
\r
4291 BOOL full_repaint = FALSE;
\r
4293 if (appData.animateDragging) {
\r
4294 dragInfo.pos = pt;
\r
4296 if (appData.highlightDragging) {
\r
4297 SetHighlights(fromX, fromY, x, y);
\r
4298 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4299 full_repaint = TRUE;
\r
4303 DrawPosition( full_repaint, NULL);
\r
4305 dragInfo.lastpos = dragInfo.pos;
\r
4309 case WM_MOUSEWHEEL: // [DM]
\r
4310 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4311 /* Mouse Wheel is being rolled forward
\r
4312 * Play moves forward
\r
4314 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4315 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4316 /* Mouse Wheel is being rolled backward
\r
4317 * Play moves backward
\r
4319 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4320 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4324 case WM_MBUTTONUP:
\r
4325 case WM_RBUTTONUP:
\r
4327 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4330 case WM_MBUTTONDOWN:
\r
4331 case WM_RBUTTONDOWN:
\r
4334 fromX = fromY = -1;
\r
4335 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4336 dragInfo.start.x = dragInfo.start.y = -1;
\r
4337 dragInfo.from = dragInfo.start;
\r
4338 dragInfo.lastpos = dragInfo.pos;
\r
4339 if (appData.highlightDragging) {
\r
4340 ClearHighlights();
\r
4343 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4344 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4345 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4346 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4347 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4351 DrawPosition(TRUE, NULL);
\r
4353 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4356 if (message == WM_MBUTTONDOWN) {
\r
4357 buttonCount = 3; /* even if system didn't think so */
\r
4358 if (wParam & MK_SHIFT)
\r
4359 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4361 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4362 } else { /* message == WM_RBUTTONDOWN */
\r
4363 /* Just have one menu, on the right button. Windows users don't
\r
4364 think to try the middle one, and sometimes other software steals
\r
4365 it, or it doesn't really exist. */
\r
4366 if(gameInfo.variant != VariantShogi)
\r
4367 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4369 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4373 SetCapture(hwndMain);
\r
4376 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4377 SetupDropMenu(hmenu);
\r
4378 MenuPopup(hwnd, pt, hmenu, -1);
\r
4388 /* Preprocess messages for buttons in main window */
\r
4390 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4392 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4395 for (i=0; i<N_BUTTONS; i++) {
\r
4396 if (buttonDesc[i].id == id) break;
\r
4398 if (i == N_BUTTONS) return 0;
\r
4399 switch (message) {
\r
4404 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4405 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4412 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4415 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4416 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4417 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4418 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4420 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4422 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4423 TypeInEvent((char)wParam);
\r
4429 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4432 /* Process messages for Promotion dialog box */
\r
4434 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4438 switch (message) {
\r
4439 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4440 /* Center the dialog over the application window */
\r
4441 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4442 Translate(hDlg, DLG_PromotionKing);
\r
4443 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4444 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4445 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4446 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4447 SW_SHOW : SW_HIDE);
\r
4448 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4449 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4450 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4451 PieceToChar(WhiteAngel) != '~') ||
\r
4452 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4453 PieceToChar(BlackAngel) != '~') ) ?
\r
4454 SW_SHOW : SW_HIDE);
\r
4455 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4456 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4457 PieceToChar(WhiteMarshall) != '~') ||
\r
4458 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4459 PieceToChar(BlackMarshall) != '~') ) ?
\r
4460 SW_SHOW : SW_HIDE);
\r
4461 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4462 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4463 gameInfo.variant != VariantShogi ?
\r
4464 SW_SHOW : SW_HIDE);
\r
4465 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4466 gameInfo.variant != VariantShogi ?
\r
4467 SW_SHOW : SW_HIDE);
\r
4468 if(gameInfo.variant == VariantShogi) {
\r
4469 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4470 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4471 SetWindowText(hDlg, "Promote?");
\r
4473 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4474 gameInfo.variant == VariantSuper ?
\r
4475 SW_SHOW : SW_HIDE);
\r
4478 case WM_COMMAND: /* message: received a command */
\r
4479 switch (LOWORD(wParam)) {
\r
4481 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4482 ClearHighlights();
\r
4483 DrawPosition(FALSE, NULL);
\r
4486 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4489 promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4492 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4493 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4496 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4497 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4499 case PB_Chancellor:
\r
4500 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4502 case PB_Archbishop:
\r
4503 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4506 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);
\r
4511 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4512 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4513 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4514 fromX = fromY = -1;
\r
4515 if (!appData.highlightLastMove) {
\r
4516 ClearHighlights();
\r
4517 DrawPosition(FALSE, NULL);
\r
4524 /* Pop up promotion dialog */
\r
4526 PromotionPopup(HWND hwnd)
\r
4530 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4531 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4532 hwnd, (DLGPROC)lpProc);
\r
4533 FreeProcInstance(lpProc);
\r
4539 DrawPosition(TRUE, NULL);
\r
4540 PromotionPopup(hwndMain);
\r
4544 LoadGameDialog(HWND hwnd, char* title)
\r
4548 char fileTitle[MSG_SIZ];
\r
4549 f = OpenFileDialog(hwnd, "rb", "",
\r
4550 appData.oldSaveStyle ? "gam" : "pgn",
\r
4552 title, &number, fileTitle, NULL);
\r
4554 cmailMsgLoaded = FALSE;
\r
4555 if (number == 0) {
\r
4556 int error = GameListBuild(f);
\r
4558 DisplayError(_("Cannot build game list"), error);
\r
4559 } else if (!ListEmpty(&gameList) &&
\r
4560 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4561 GameListPopUp(f, fileTitle);
\r
4564 GameListDestroy();
\r
4567 LoadGame(f, number, fileTitle, FALSE);
\r
4571 int get_term_width()
\r
4576 HFONT hfont, hold_font;
\r
4581 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4585 // get the text metrics
\r
4586 hdc = GetDC(hText);
\r
4587 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4588 if (consoleCF.dwEffects & CFE_BOLD)
\r
4589 lf.lfWeight = FW_BOLD;
\r
4590 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4591 lf.lfItalic = TRUE;
\r
4592 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4593 lf.lfStrikeOut = TRUE;
\r
4594 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4595 lf.lfUnderline = TRUE;
\r
4596 hfont = CreateFontIndirect(&lf);
\r
4597 hold_font = SelectObject(hdc, hfont);
\r
4598 GetTextMetrics(hdc, &tm);
\r
4599 SelectObject(hdc, hold_font);
\r
4600 DeleteObject(hfont);
\r
4601 ReleaseDC(hText, hdc);
\r
4603 // get the rectangle
\r
4604 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4606 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4609 void UpdateICSWidth(HWND hText)
\r
4611 LONG old_width, new_width;
\r
4613 new_width = get_term_width(hText, FALSE);
\r
4614 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4615 if (new_width != old_width)
\r
4617 ics_update_width(new_width);
\r
4618 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4623 ChangedConsoleFont()
\r
4626 CHARRANGE tmpsel, sel;
\r
4627 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4628 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4629 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4632 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4633 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4634 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4635 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4636 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4637 * size. This was undocumented in the version of MSVC++ that I had
\r
4638 * when I wrote the code, but is apparently documented now.
\r
4640 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4641 cfmt.bCharSet = f->lf.lfCharSet;
\r
4642 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4643 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4644 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4645 /* Why are the following seemingly needed too? */
\r
4646 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4647 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4648 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4650 tmpsel.cpMax = -1; /*999999?*/
\r
4651 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4652 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4653 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4654 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4656 paraf.cbSize = sizeof(paraf);
\r
4657 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4658 paraf.dxStartIndent = 0;
\r
4659 paraf.dxOffset = WRAP_INDENT;
\r
4660 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4661 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4662 UpdateICSWidth(hText);
\r
4665 /*---------------------------------------------------------------------------*\
\r
4667 * Window Proc for main window
\r
4669 \*---------------------------------------------------------------------------*/
\r
4671 /* Process messages for main window, etc. */
\r
4673 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4676 int wmId, wmEvent;
\r
4680 char fileTitle[MSG_SIZ];
\r
4681 char buf[MSG_SIZ];
\r
4682 static SnapData sd;
\r
4683 static int peek=0;
\r
4685 switch (message) {
\r
4687 case WM_PAINT: /* message: repaint portion of window */
\r
4691 case WM_ERASEBKGND:
\r
4692 if (IsIconic(hwnd)) {
\r
4693 /* Cheat; change the message */
\r
4694 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4696 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4700 case WM_LBUTTONDOWN:
\r
4701 case WM_MBUTTONDOWN:
\r
4702 case WM_RBUTTONDOWN:
\r
4703 case WM_LBUTTONUP:
\r
4704 case WM_MBUTTONUP:
\r
4705 case WM_RBUTTONUP:
\r
4706 case WM_MOUSEMOVE:
\r
4707 case WM_MOUSEWHEEL:
\r
4708 MouseEvent(hwnd, message, wParam, lParam);
\r
4712 if((char)wParam == '\b') {
\r
4713 ForwardEvent(); peek = 0;
\r
4716 JAWS_KBUP_NAVIGATION
\r
4721 if((char)wParam == '\b') {
\r
4722 if(!peek) BackwardEvent(), peek = 1;
\r
4725 JAWS_KBDOWN_NAVIGATION
\r
4731 JAWS_ALT_INTERCEPT
\r
4733 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4734 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4735 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4736 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4738 SendMessage(h, message, wParam, lParam);
\r
4739 } else if(lParam != KF_REPEAT) {
\r
4740 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4741 TypeInEvent((char)wParam);
\r
4742 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4743 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4748 case WM_PALETTECHANGED:
\r
4749 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4751 HDC hdc = GetDC(hwndMain);
\r
4752 SelectPalette(hdc, hPal, TRUE);
\r
4753 nnew = RealizePalette(hdc);
\r
4755 paletteChanged = TRUE;
\r
4756 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4758 ReleaseDC(hwnd, hdc);
\r
4762 case WM_QUERYNEWPALETTE:
\r
4763 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4765 HDC hdc = GetDC(hwndMain);
\r
4766 paletteChanged = FALSE;
\r
4767 SelectPalette(hdc, hPal, FALSE);
\r
4768 nnew = RealizePalette(hdc);
\r
4770 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4772 ReleaseDC(hwnd, hdc);
\r
4777 case WM_COMMAND: /* message: command from application menu */
\r
4778 wmId = LOWORD(wParam);
\r
4779 wmEvent = HIWORD(wParam);
\r
4784 SAY("new game enter a move to play against the computer with white");
\r
4787 case IDM_NewGameFRC:
\r
4788 if( NewGameFRC() == 0 ) {
\r
4793 case IDM_NewVariant:
\r
4794 NewVariantPopup(hwnd);
\r
4797 case IDM_LoadGame:
\r
4798 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4801 case IDM_LoadNextGame:
\r
4805 case IDM_LoadPrevGame:
\r
4809 case IDM_ReloadGame:
\r
4813 case IDM_LoadPosition:
\r
4814 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4815 Reset(FALSE, TRUE);
\r
4818 f = OpenFileDialog(hwnd, "rb", "",
\r
4819 appData.oldSaveStyle ? "pos" : "fen",
\r
4821 _("Load Position from File"), &number, fileTitle, NULL);
\r
4823 LoadPosition(f, number, fileTitle);
\r
4827 case IDM_LoadNextPosition:
\r
4828 ReloadPosition(1);
\r
4831 case IDM_LoadPrevPosition:
\r
4832 ReloadPosition(-1);
\r
4835 case IDM_ReloadPosition:
\r
4836 ReloadPosition(0);
\r
4839 case IDM_SaveGame:
\r
4840 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4841 f = OpenFileDialog(hwnd, "a", defName,
\r
4842 appData.oldSaveStyle ? "gam" : "pgn",
\r
4844 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4846 SaveGame(f, 0, "");
\r
4850 case IDM_SavePosition:
\r
4851 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4852 f = OpenFileDialog(hwnd, "a", defName,
\r
4853 appData.oldSaveStyle ? "pos" : "fen",
\r
4855 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4857 SavePosition(f, 0, "");
\r
4861 case IDM_SaveDiagram:
\r
4862 defName = "diagram";
\r
4863 f = OpenFileDialog(hwnd, "wb", defName,
\r
4866 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4872 case IDM_CreateBook:
\r
4873 CreateBookEvent();
\r
4876 case IDM_CopyGame:
\r
4877 CopyGameToClipboard();
\r
4880 case IDM_PasteGame:
\r
4881 PasteGameFromClipboard();
\r
4884 case IDM_CopyGameListToClipboard:
\r
4885 CopyGameListToClipboard();
\r
4888 /* [AS] Autodetect FEN or PGN data */
\r
4889 case IDM_PasteAny:
\r
4890 PasteGameOrFENFromClipboard();
\r
4893 /* [AS] Move history */
\r
4894 case IDM_ShowMoveHistory:
\r
4895 if( MoveHistoryIsUp() ) {
\r
4896 MoveHistoryPopDown();
\r
4899 MoveHistoryPopUp();
\r
4903 /* [AS] Eval graph */
\r
4904 case IDM_ShowEvalGraph:
\r
4905 if( EvalGraphIsUp() ) {
\r
4906 EvalGraphPopDown();
\r
4910 SetFocus(hwndMain);
\r
4914 /* [AS] Engine output */
\r
4915 case IDM_ShowEngineOutput:
\r
4916 if( EngineOutputIsUp() ) {
\r
4917 EngineOutputPopDown();
\r
4920 EngineOutputPopUp();
\r
4924 /* [AS] User adjudication */
\r
4925 case IDM_UserAdjudication_White:
\r
4926 UserAdjudicationEvent( +1 );
\r
4929 case IDM_UserAdjudication_Black:
\r
4930 UserAdjudicationEvent( -1 );
\r
4933 case IDM_UserAdjudication_Draw:
\r
4934 UserAdjudicationEvent( 0 );
\r
4937 /* [AS] Game list options dialog */
\r
4938 case IDM_GameListOptions:
\r
4939 GameListOptions();
\r
4946 case IDM_CopyPosition:
\r
4947 CopyFENToClipboard();
\r
4950 case IDM_PastePosition:
\r
4951 PasteFENFromClipboard();
\r
4954 case IDM_MailMove:
\r
4958 case IDM_ReloadCMailMsg:
\r
4959 Reset(TRUE, TRUE);
\r
4960 ReloadCmailMsgEvent(FALSE);
\r
4963 case IDM_Minimize:
\r
4964 ShowWindow(hwnd, SW_MINIMIZE);
\r
4971 case IDM_MachineWhite:
\r
4972 MachineWhiteEvent();
\r
4974 * refresh the tags dialog only if it's visible
\r
4976 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4978 tags = PGNTags(&gameInfo);
\r
4979 TagsPopUp(tags, CmailMsg());
\r
4982 SAY("computer starts playing white");
\r
4985 case IDM_MachineBlack:
\r
4986 MachineBlackEvent();
\r
4988 * refresh the tags dialog only if it's visible
\r
4990 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4992 tags = PGNTags(&gameInfo);
\r
4993 TagsPopUp(tags, CmailMsg());
\r
4996 SAY("computer starts playing black");
\r
4999 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5000 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5003 case IDM_TwoMachines:
\r
5004 TwoMachinesEvent();
\r
5006 * refresh the tags dialog only if it's visible
\r
5008 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5010 tags = PGNTags(&gameInfo);
\r
5011 TagsPopUp(tags, CmailMsg());
\r
5014 SAY("computer starts playing both sides");
\r
5017 case IDM_AnalysisMode:
\r
5018 if(AnalyzeModeEvent()) {
\r
5019 SAY("analyzing current position");
\r
5023 case IDM_AnalyzeFile:
\r
5024 AnalyzeFileEvent();
\r
5027 case IDM_IcsClient:
\r
5031 case IDM_EditGame:
\r
5032 case IDM_EditGame2:
\r
5037 case IDM_EditPosition:
\r
5038 case IDM_EditPosition2:
\r
5039 EditPositionEvent();
\r
5040 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5043 case IDM_Training:
\r
5047 case IDM_ShowGameList:
\r
5048 ShowGameListProc();
\r
5051 case IDM_EditProgs1:
\r
5052 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5055 case IDM_LoadProg1:
\r
5056 LoadEnginePopUp(hwndMain, 0);
\r
5059 case IDM_LoadProg2:
\r
5060 LoadEnginePopUp(hwndMain, 1);
\r
5063 case IDM_EditServers:
\r
5064 EditTagsPopUp(icsNames, &icsNames);
\r
5067 case IDM_EditTags:
\r
5072 case IDM_EditBook:
\r
5076 case IDM_EditComment:
\r
5078 if (commentUp && editComment) {
\r
5081 EditCommentEvent();
\r
5101 case IDM_CallFlag:
\r
5121 case IDM_StopObserving:
\r
5122 StopObservingEvent();
\r
5125 case IDM_StopExamining:
\r
5126 StopExaminingEvent();
\r
5130 UploadGameEvent();
\r
5133 case IDM_TypeInMove:
\r
5134 TypeInEvent('\000');
\r
5137 case IDM_TypeInName:
\r
5138 PopUpNameDialog('\000');
\r
5141 case IDM_Backward:
\r
5143 SetFocus(hwndMain);
\r
5150 SetFocus(hwndMain);
\r
5155 SetFocus(hwndMain);
\r
5160 SetFocus(hwndMain);
\r
5163 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5164 case OPT_GameListPrev:
\r
5165 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5169 RevertEvent(FALSE);
\r
5172 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5173 RevertEvent(TRUE);
\r
5176 case IDM_TruncateGame:
\r
5177 TruncateGameEvent();
\r
5184 case IDM_RetractMove:
\r
5185 RetractMoveEvent();
\r
5188 case IDM_FlipView:
\r
5189 flipView = !flipView;
\r
5190 DrawPosition(FALSE, NULL);
\r
5193 case IDM_FlipClock:
\r
5194 flipClock = !flipClock;
\r
5195 DisplayBothClocks();
\r
5199 case IDM_MuteSounds:
\r
5200 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5201 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5202 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5205 case IDM_GeneralOptions:
\r
5206 GeneralOptionsPopup(hwnd);
\r
5207 DrawPosition(TRUE, NULL);
\r
5210 case IDM_BoardOptions:
\r
5211 BoardOptionsPopup(hwnd);
\r
5214 case IDM_ThemeOptions:
\r
5215 ThemeOptionsPopup(hwnd);
\r
5218 case IDM_EnginePlayOptions:
\r
5219 EnginePlayOptionsPopup(hwnd);
\r
5222 case IDM_Engine1Options:
\r
5223 EngineOptionsPopup(hwnd, &first);
\r
5226 case IDM_Engine2Options:
\r
5228 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5229 EngineOptionsPopup(hwnd, &second);
\r
5232 case IDM_OptionsUCI:
\r
5233 UciOptionsPopup(hwnd);
\r
5237 TourneyPopup(hwnd);
\r
5240 case IDM_IcsOptions:
\r
5241 IcsOptionsPopup(hwnd);
\r
5245 FontsOptionsPopup(hwnd);
\r
5249 SoundOptionsPopup(hwnd);
\r
5252 case IDM_CommPort:
\r
5253 CommPortOptionsPopup(hwnd);
\r
5256 case IDM_LoadOptions:
\r
5257 LoadOptionsPopup(hwnd);
\r
5260 case IDM_SaveOptions:
\r
5261 SaveOptionsPopup(hwnd);
\r
5264 case IDM_TimeControl:
\r
5265 TimeControlOptionsPopup(hwnd);
\r
5268 case IDM_SaveSettings:
\r
5269 SaveSettings(settingsFileName);
\r
5272 case IDM_SaveSettingsOnExit:
\r
5273 saveSettingsOnExit = !saveSettingsOnExit;
\r
5274 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5275 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5276 MF_CHECKED : MF_UNCHECKED));
\r
5287 case IDM_AboutGame:
\r
5292 appData.debugMode = !appData.debugMode;
\r
5293 if (appData.debugMode) {
\r
5294 char dir[MSG_SIZ];
\r
5295 GetCurrentDirectory(MSG_SIZ, dir);
\r
5296 SetCurrentDirectory(installDir);
\r
5297 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5298 SetCurrentDirectory(dir);
\r
5299 setbuf(debugFP, NULL);
\r
5306 case IDM_HELPCONTENTS:
\r
5307 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5308 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5309 MessageBox (GetFocus(),
\r
5310 _("Unable to activate help"),
\r
5311 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5315 case IDM_HELPSEARCH:
\r
5316 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5317 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5318 MessageBox (GetFocus(),
\r
5319 _("Unable to activate help"),
\r
5320 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5324 case IDM_HELPHELP:
\r
5325 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5326 MessageBox (GetFocus(),
\r
5327 _("Unable to activate help"),
\r
5328 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5333 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5335 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5336 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5337 FreeProcInstance(lpProc);
\r
5340 case IDM_DirectCommand1:
\r
5341 AskQuestionEvent(_("Direct Command"),
\r
5342 _("Send to chess program:"), "", "1");
\r
5344 case IDM_DirectCommand2:
\r
5345 AskQuestionEvent(_("Direct Command"),
\r
5346 _("Send to second chess program:"), "", "2");
\r
5349 case EP_WhitePawn:
\r
5350 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5351 fromX = fromY = -1;
\r
5354 case EP_WhiteKnight:
\r
5355 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5356 fromX = fromY = -1;
\r
5359 case EP_WhiteBishop:
\r
5360 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5361 fromX = fromY = -1;
\r
5364 case EP_WhiteRook:
\r
5365 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5366 fromX = fromY = -1;
\r
5369 case EP_WhiteQueen:
\r
5370 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5371 fromX = fromY = -1;
\r
5374 case EP_WhiteFerz:
\r
5375 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5376 fromX = fromY = -1;
\r
5379 case EP_WhiteWazir:
\r
5380 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5381 fromX = fromY = -1;
\r
5384 case EP_WhiteAlfil:
\r
5385 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5386 fromX = fromY = -1;
\r
5389 case EP_WhiteCannon:
\r
5390 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5391 fromX = fromY = -1;
\r
5394 case EP_WhiteCardinal:
\r
5395 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5396 fromX = fromY = -1;
\r
5399 case EP_WhiteMarshall:
\r
5400 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5401 fromX = fromY = -1;
\r
5404 case EP_WhiteKing:
\r
5405 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5406 fromX = fromY = -1;
\r
5409 case EP_BlackPawn:
\r
5410 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5411 fromX = fromY = -1;
\r
5414 case EP_BlackKnight:
\r
5415 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5416 fromX = fromY = -1;
\r
5419 case EP_BlackBishop:
\r
5420 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5421 fromX = fromY = -1;
\r
5424 case EP_BlackRook:
\r
5425 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5426 fromX = fromY = -1;
\r
5429 case EP_BlackQueen:
\r
5430 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5431 fromX = fromY = -1;
\r
5434 case EP_BlackFerz:
\r
5435 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5436 fromX = fromY = -1;
\r
5439 case EP_BlackWazir:
\r
5440 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5441 fromX = fromY = -1;
\r
5444 case EP_BlackAlfil:
\r
5445 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5446 fromX = fromY = -1;
\r
5449 case EP_BlackCannon:
\r
5450 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5451 fromX = fromY = -1;
\r
5454 case EP_BlackCardinal:
\r
5455 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5456 fromX = fromY = -1;
\r
5459 case EP_BlackMarshall:
\r
5460 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5461 fromX = fromY = -1;
\r
5464 case EP_BlackKing:
\r
5465 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5466 fromX = fromY = -1;
\r
5469 case EP_EmptySquare:
\r
5470 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5471 fromX = fromY = -1;
\r
5474 case EP_ClearBoard:
\r
5475 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5476 fromX = fromY = -1;
\r
5480 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5481 fromX = fromY = -1;
\r
5485 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5486 fromX = fromY = -1;
\r
5490 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5491 fromX = fromY = -1;
\r
5495 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5496 fromX = fromY = -1;
\r
5500 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5501 fromX = fromY = -1;
\r
5505 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5506 fromX = fromY = -1;
\r
5510 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5511 fromX = fromY = -1;
\r
5515 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5516 fromX = fromY = -1;
\r
5520 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5521 fromX = fromY = -1;
\r
5525 barbaric = 0; appData.language = "";
\r
5526 TranslateMenus(0);
\r
5527 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5528 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5529 lastChecked = wmId;
\r
5533 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5534 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5536 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5537 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5538 TranslateMenus(0);
\r
5539 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5540 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5541 lastChecked = wmId;
\r
5544 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5550 case CLOCK_TIMER_ID:
\r
5551 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5552 clockTimerEvent = 0;
\r
5553 DecrementClocks(); /* call into back end */
\r
5555 case LOAD_GAME_TIMER_ID:
\r
5556 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5557 loadGameTimerEvent = 0;
\r
5558 AutoPlayGameLoop(); /* call into back end */
\r
5560 case ANALYSIS_TIMER_ID:
\r
5561 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5562 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5563 AnalysisPeriodicEvent(0);
\r
5565 KillTimer(hwnd, analysisTimerEvent);
\r
5566 analysisTimerEvent = 0;
\r
5569 case DELAYED_TIMER_ID:
\r
5570 KillTimer(hwnd, delayedTimerEvent);
\r
5571 delayedTimerEvent = 0;
\r
5572 delayedTimerCallback();
\r
5577 case WM_USER_Input:
\r
5578 InputEvent(hwnd, message, wParam, lParam);
\r
5581 /* [AS] Also move "attached" child windows */
\r
5582 case WM_WINDOWPOSCHANGING:
\r
5584 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5585 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5587 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5588 /* Window is moving */
\r
5591 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5592 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5593 rcMain.right = wpMain.x + wpMain.width;
\r
5594 rcMain.top = wpMain.y;
\r
5595 rcMain.bottom = wpMain.y + wpMain.height;
\r
5597 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5598 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5599 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5600 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5601 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5602 wpMain.x = lpwp->x;
\r
5603 wpMain.y = lpwp->y;
\r
5608 /* [AS] Snapping */
\r
5609 case WM_ENTERSIZEMOVE:
\r
5610 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5611 if (hwnd == hwndMain) {
\r
5612 doingSizing = TRUE;
\r
5615 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5619 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5620 if (hwnd == hwndMain) {
\r
5621 lastSizing = wParam;
\r
5626 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5627 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5629 case WM_EXITSIZEMOVE:
\r
5630 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5631 if (hwnd == hwndMain) {
\r
5633 doingSizing = FALSE;
\r
5634 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5635 GetClientRect(hwnd, &client);
\r
5636 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5638 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5640 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5643 case WM_DESTROY: /* message: window being destroyed */
\r
5644 PostQuitMessage(0);
\r
5648 if (hwnd == hwndMain) {
\r
5653 default: /* Passes it on if unprocessed */
\r
5654 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5659 /*---------------------------------------------------------------------------*\
\r
5661 * Misc utility routines
\r
5663 \*---------------------------------------------------------------------------*/
\r
5666 * Decent random number generator, at least not as bad as Windows
\r
5667 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5669 unsigned int randstate;
\r
5674 randstate = randstate * 1664525 + 1013904223;
\r
5675 return (int) randstate & 0x7fffffff;
\r
5679 mysrandom(unsigned int seed)
\r
5686 * returns TRUE if user selects a different color, FALSE otherwise
\r
5690 ChangeColor(HWND hwnd, COLORREF *which)
\r
5692 static BOOL firstTime = TRUE;
\r
5693 static DWORD customColors[16];
\r
5695 COLORREF newcolor;
\r
5700 /* Make initial colors in use available as custom colors */
\r
5701 /* Should we put the compiled-in defaults here instead? */
\r
5703 customColors[i++] = lightSquareColor & 0xffffff;
\r
5704 customColors[i++] = darkSquareColor & 0xffffff;
\r
5705 customColors[i++] = whitePieceColor & 0xffffff;
\r
5706 customColors[i++] = blackPieceColor & 0xffffff;
\r
5707 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5708 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5710 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5711 customColors[i++] = textAttribs[ccl].color;
\r
5713 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5714 firstTime = FALSE;
\r
5717 cc.lStructSize = sizeof(cc);
\r
5718 cc.hwndOwner = hwnd;
\r
5719 cc.hInstance = NULL;
\r
5720 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5721 cc.lpCustColors = (LPDWORD) customColors;
\r
5722 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5724 if (!ChooseColor(&cc)) return FALSE;
\r
5726 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5727 if (newcolor == *which) return FALSE;
\r
5728 *which = newcolor;
\r
5732 InitDrawingColors();
\r
5733 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5738 MyLoadSound(MySound *ms)
\r
5744 if (ms->data && ms->flag) free(ms->data);
\r
5747 switch (ms->name[0]) {
\r
5753 /* System sound from Control Panel. Don't preload here. */
\r
5757 if (ms->name[1] == NULLCHAR) {
\r
5758 /* "!" alone = silence */
\r
5761 /* Builtin wave resource. Error if not found. */
\r
5762 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5763 if (h == NULL) break;
\r
5764 ms->data = (void *)LoadResource(hInst, h);
\r
5765 ms->flag = 0; // not maloced, so cannot be freed!
\r
5766 if (h == NULL) break;
\r
5771 /* .wav file. Error if not found. */
\r
5772 f = fopen(ms->name, "rb");
\r
5773 if (f == NULL) break;
\r
5774 if (fstat(fileno(f), &st) < 0) break;
\r
5775 ms->data = malloc(st.st_size);
\r
5777 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5783 char buf[MSG_SIZ];
\r
5784 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5785 DisplayError(buf, GetLastError());
\r
5791 MyPlaySound(MySound *ms)
\r
5793 BOOLEAN ok = FALSE;
\r
5795 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5796 switch (ms->name[0]) {
\r
5798 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5803 /* System sound from Control Panel (deprecated feature).
\r
5804 "$" alone or an unset sound name gets default beep (still in use). */
\r
5805 if (ms->name[1]) {
\r
5806 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5808 if (!ok) ok = MessageBeep(MB_OK);
\r
5811 /* Builtin wave resource, or "!" alone for silence */
\r
5812 if (ms->name[1]) {
\r
5813 if (ms->data == NULL) return FALSE;
\r
5814 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5820 /* .wav file. Error if not found. */
\r
5821 if (ms->data == NULL) return FALSE;
\r
5822 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5825 /* Don't print an error: this can happen innocently if the sound driver
\r
5826 is busy; for instance, if another instance of WinBoard is playing
\r
5827 a sound at about the same time. */
\r
5833 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5836 OPENFILENAME *ofn;
\r
5837 static UINT *number; /* gross that this is static */
\r
5839 switch (message) {
\r
5840 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5841 /* Center the dialog over the application window */
\r
5842 ofn = (OPENFILENAME *) lParam;
\r
5843 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5844 number = (UINT *) ofn->lCustData;
\r
5845 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5849 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5850 Translate(hDlg, 1536);
\r
5851 return FALSE; /* Allow for further processing */
\r
5854 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5855 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5857 return FALSE; /* Allow for further processing */
\r
5863 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5865 static UINT *number;
\r
5866 OPENFILENAME *ofname;
\r
5869 case WM_INITDIALOG:
\r
5870 Translate(hdlg, DLG_IndexNumber);
\r
5871 ofname = (OPENFILENAME *)lParam;
\r
5872 number = (UINT *)(ofname->lCustData);
\r
5875 ofnot = (OFNOTIFY *)lParam;
\r
5876 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5877 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5886 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5887 char *nameFilt, char *dlgTitle, UINT *number,
\r
5888 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5890 OPENFILENAME openFileName;
\r
5891 char buf1[MSG_SIZ];
\r
5894 if (fileName == NULL) fileName = buf1;
\r
5895 if (defName == NULL) {
\r
5896 safeStrCpy(fileName, "*.", 3 );
\r
5897 strcat(fileName, defExt);
\r
5899 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5901 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5902 if (number) *number = 0;
\r
5904 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5905 openFileName.hwndOwner = hwnd;
\r
5906 openFileName.hInstance = (HANDLE) hInst;
\r
5907 openFileName.lpstrFilter = nameFilt;
\r
5908 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5909 openFileName.nMaxCustFilter = 0L;
\r
5910 openFileName.nFilterIndex = 1L;
\r
5911 openFileName.lpstrFile = fileName;
\r
5912 openFileName.nMaxFile = MSG_SIZ;
\r
5913 openFileName.lpstrFileTitle = fileTitle;
\r
5914 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5915 openFileName.lpstrInitialDir = NULL;
\r
5916 openFileName.lpstrTitle = dlgTitle;
\r
5917 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5918 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5919 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5920 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5921 openFileName.nFileOffset = 0;
\r
5922 openFileName.nFileExtension = 0;
\r
5923 openFileName.lpstrDefExt = defExt;
\r
5924 openFileName.lCustData = (LONG) number;
\r
5925 openFileName.lpfnHook = oldDialog ?
\r
5926 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5927 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5929 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5930 GetOpenFileName(&openFileName)) {
\r
5931 /* open the file */
\r
5932 f = fopen(openFileName.lpstrFile, write);
\r
5934 MessageBox(hwnd, _("File open failed"), NULL,
\r
5935 MB_OK|MB_ICONEXCLAMATION);
\r
5939 int err = CommDlgExtendedError();
\r
5940 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
5949 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5951 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5954 * Get the first pop-up menu in the menu template. This is the
\r
5955 * menu that TrackPopupMenu displays.
\r
5957 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5958 TranslateOneMenu(10, hmenuTrackPopup);
\r
5960 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5963 * TrackPopup uses screen coordinates, so convert the
\r
5964 * coordinates of the mouse click to screen coordinates.
\r
5966 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5968 /* Draw and track the floating pop-up menu. */
\r
5969 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5970 pt.x, pt.y, 0, hwnd, NULL);
\r
5972 /* Destroy the menu.*/
\r
5973 DestroyMenu(hmenu);
\r
5978 int sizeX, sizeY, newSizeX, newSizeY;
\r
5980 } ResizeEditPlusButtonsClosure;
\r
5983 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5985 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5989 if (hChild == cl->hText) return TRUE;
\r
5990 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5991 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5992 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5993 ScreenToClient(cl->hDlg, &pt);
\r
5994 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5995 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5999 /* Resize a dialog that has a (rich) edit field filling most of
\r
6000 the top, with a row of buttons below */
\r
6002 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6005 int newTextHeight, newTextWidth;
\r
6006 ResizeEditPlusButtonsClosure cl;
\r
6008 /*if (IsIconic(hDlg)) return;*/
\r
6009 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6011 cl.hdwp = BeginDeferWindowPos(8);
\r
6013 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6014 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6015 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6016 if (newTextHeight < 0) {
\r
6017 newSizeY += -newTextHeight;
\r
6018 newTextHeight = 0;
\r
6020 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6021 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6027 cl.newSizeX = newSizeX;
\r
6028 cl.newSizeY = newSizeY;
\r
6029 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6031 EndDeferWindowPos(cl.hdwp);
\r
6034 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6036 RECT rChild, rParent;
\r
6037 int wChild, hChild, wParent, hParent;
\r
6038 int wScreen, hScreen, xNew, yNew;
\r
6041 /* Get the Height and Width of the child window */
\r
6042 GetWindowRect (hwndChild, &rChild);
\r
6043 wChild = rChild.right - rChild.left;
\r
6044 hChild = rChild.bottom - rChild.top;
\r
6046 /* Get the Height and Width of the parent window */
\r
6047 GetWindowRect (hwndParent, &rParent);
\r
6048 wParent = rParent.right - rParent.left;
\r
6049 hParent = rParent.bottom - rParent.top;
\r
6051 /* Get the display limits */
\r
6052 hdc = GetDC (hwndChild);
\r
6053 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6054 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6055 ReleaseDC(hwndChild, hdc);
\r
6057 /* Calculate new X position, then adjust for screen */
\r
6058 xNew = rParent.left + ((wParent - wChild) /2);
\r
6061 } else if ((xNew+wChild) > wScreen) {
\r
6062 xNew = wScreen - wChild;
\r
6065 /* Calculate new Y position, then adjust for screen */
\r
6067 yNew = rParent.top + ((hParent - hChild) /2);
\r
6070 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6075 } else if ((yNew+hChild) > hScreen) {
\r
6076 yNew = hScreen - hChild;
\r
6079 /* Set it, and return */
\r
6080 return SetWindowPos (hwndChild, NULL,
\r
6081 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6084 /* Center one window over another */
\r
6085 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6087 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6090 /*---------------------------------------------------------------------------*\
\r
6092 * Startup Dialog functions
\r
6094 \*---------------------------------------------------------------------------*/
\r
6096 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6098 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6100 while (*cd != NULL) {
\r
6101 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6107 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6109 char buf1[MAX_ARG_LEN];
\r
6112 if (str[0] == '@') {
\r
6113 FILE* f = fopen(str + 1, "r");
\r
6115 DisplayFatalError(str + 1, errno, 2);
\r
6118 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6120 buf1[len] = NULLCHAR;
\r
6124 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6127 char buf[MSG_SIZ];
\r
6128 char *end = strchr(str, '\n');
\r
6129 if (end == NULL) return;
\r
6130 memcpy(buf, str, end - str);
\r
6131 buf[end - str] = NULLCHAR;
\r
6132 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6138 SetStartupDialogEnables(HWND hDlg)
\r
6140 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6141 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6142 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6143 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6144 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6145 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6146 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6147 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6148 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6149 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6150 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6151 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6152 IsDlgButtonChecked(hDlg, OPT_View));
\r
6156 QuoteForFilename(char *filename)
\r
6158 int dquote, space;
\r
6159 dquote = strchr(filename, '"') != NULL;
\r
6160 space = strchr(filename, ' ') != NULL;
\r
6161 if (dquote || space) {
\r
6173 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6175 char buf[MSG_SIZ];
\r
6178 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6179 q = QuoteForFilename(nthcp);
\r
6180 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6181 if (*nthdir != NULLCHAR) {
\r
6182 q = QuoteForFilename(nthdir);
\r
6183 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6185 if (*nthcp == NULLCHAR) {
\r
6186 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6187 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6188 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6189 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6194 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6196 char buf[MSG_SIZ];
\r
6200 switch (message) {
\r
6201 case WM_INITDIALOG:
\r
6202 /* Center the dialog */
\r
6203 CenterWindow (hDlg, GetDesktopWindow());
\r
6204 Translate(hDlg, DLG_Startup);
\r
6205 /* Initialize the dialog items */
\r
6206 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6207 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6208 firstChessProgramNames);
\r
6209 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6210 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6211 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6212 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6213 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6214 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6215 if (*appData.icsHelper != NULLCHAR) {
\r
6216 char *q = QuoteForFilename(appData.icsHelper);
\r
6217 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6219 if (*appData.icsHost == NULLCHAR) {
\r
6220 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6221 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6222 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6223 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6224 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6227 if (appData.icsActive) {
\r
6228 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6230 else if (appData.noChessProgram) {
\r
6231 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6234 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6237 SetStartupDialogEnables(hDlg);
\r
6241 switch (LOWORD(wParam)) {
\r
6243 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6244 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6245 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6247 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6248 ParseArgs(StringGet, &p);
\r
6249 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6250 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6252 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6253 ParseArgs(StringGet, &p);
\r
6254 SwapEngines(singleList); // ... and then make it 'second'
\r
6255 appData.noChessProgram = FALSE;
\r
6256 appData.icsActive = FALSE;
\r
6257 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6258 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6259 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6261 ParseArgs(StringGet, &p);
\r
6262 if (appData.zippyPlay) {
\r
6263 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6264 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6266 ParseArgs(StringGet, &p);
\r
6268 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6269 appData.noChessProgram = TRUE;
\r
6270 appData.icsActive = FALSE;
\r
6272 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6273 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6276 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6277 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6279 ParseArgs(StringGet, &p);
\r
6281 EndDialog(hDlg, TRUE);
\r
6288 case IDM_HELPCONTENTS:
\r
6289 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6290 MessageBox (GetFocus(),
\r
6291 _("Unable to activate help"),
\r
6292 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6297 SetStartupDialogEnables(hDlg);
\r
6305 /*---------------------------------------------------------------------------*\
\r
6307 * About box dialog functions
\r
6309 \*---------------------------------------------------------------------------*/
\r
6311 /* Process messages for "About" dialog box */
\r
6313 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6315 switch (message) {
\r
6316 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6317 /* Center the dialog over the application window */
\r
6318 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6319 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6320 Translate(hDlg, ABOUTBOX);
\r
6324 case WM_COMMAND: /* message: received a command */
\r
6325 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6326 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6327 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6335 /*---------------------------------------------------------------------------*\
\r
6337 * Comment Dialog functions
\r
6339 \*---------------------------------------------------------------------------*/
\r
6342 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6344 static HANDLE hwndText = NULL;
\r
6345 int len, newSizeX, newSizeY, flags;
\r
6346 static int sizeX, sizeY;
\r
6351 switch (message) {
\r
6352 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6353 /* Initialize the dialog items */
\r
6354 Translate(hDlg, DLG_EditComment);
\r
6355 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6356 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6357 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6358 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6359 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6360 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6361 SetWindowText(hDlg, commentTitle);
\r
6362 if (editComment) {
\r
6363 SetFocus(hwndText);
\r
6365 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6367 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6368 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6369 MAKELPARAM(FALSE, 0));
\r
6370 /* Size and position the dialog */
\r
6371 if (!commentDialog) {
\r
6372 commentDialog = hDlg;
\r
6373 flags = SWP_NOZORDER;
\r
6374 GetClientRect(hDlg, &rect);
\r
6375 sizeX = rect.right;
\r
6376 sizeY = rect.bottom;
\r
6377 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6378 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6379 WINDOWPLACEMENT wp;
\r
6380 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6381 wp.length = sizeof(WINDOWPLACEMENT);
\r
6383 wp.showCmd = SW_SHOW;
\r
6384 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6385 wp.rcNormalPosition.left = wpComment.x;
\r
6386 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6387 wp.rcNormalPosition.top = wpComment.y;
\r
6388 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6389 SetWindowPlacement(hDlg, &wp);
\r
6391 GetClientRect(hDlg, &rect);
\r
6392 newSizeX = rect.right;
\r
6393 newSizeY = rect.bottom;
\r
6394 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6395 newSizeX, newSizeY);
\r
6400 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6403 case WM_COMMAND: /* message: received a command */
\r
6404 switch (LOWORD(wParam)) {
\r
6406 if (editComment) {
\r
6408 /* Read changed options from the dialog box */
\r
6409 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6410 len = GetWindowTextLength(hwndText);
\r
6411 str = (char *) malloc(len + 1);
\r
6412 GetWindowText(hwndText, str, len + 1);
\r
6421 ReplaceComment(commentIndex, str);
\r
6428 case OPT_CancelComment:
\r
6432 case OPT_ClearComment:
\r
6433 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6436 case OPT_EditComment:
\r
6437 EditCommentEvent();
\r
6445 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6446 if( wParam == OPT_CommentText ) {
\r
6447 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6449 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6450 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6454 pt.x = LOWORD( lpMF->lParam );
\r
6455 pt.y = HIWORD( lpMF->lParam );
\r
6457 if(lpMF->msg == WM_CHAR) {
\r
6459 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6460 index = sel.cpMin;
\r
6462 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6464 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6465 len = GetWindowTextLength(hwndText);
\r
6466 str = (char *) malloc(len + 1);
\r
6467 GetWindowText(hwndText, str, len + 1);
\r
6468 ReplaceComment(commentIndex, str);
\r
6469 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6470 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6473 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6474 lpMF->msg = WM_USER;
\r
6482 newSizeX = LOWORD(lParam);
\r
6483 newSizeY = HIWORD(lParam);
\r
6484 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6489 case WM_GETMINMAXINFO:
\r
6490 /* Prevent resizing window too small */
\r
6491 mmi = (MINMAXINFO *) lParam;
\r
6492 mmi->ptMinTrackSize.x = 100;
\r
6493 mmi->ptMinTrackSize.y = 100;
\r
6500 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6505 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6507 if (str == NULL) str = "";
\r
6508 p = (char *) malloc(2 * strlen(str) + 2);
\r
6511 if (*str == '\n') *q++ = '\r';
\r
6515 if (commentText != NULL) free(commentText);
\r
6517 commentIndex = index;
\r
6518 commentTitle = title;
\r
6520 editComment = edit;
\r
6522 if (commentDialog) {
\r
6523 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6524 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6526 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6527 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6528 hwndMain, (DLGPROC)lpProc);
\r
6529 FreeProcInstance(lpProc);
\r
6535 /*---------------------------------------------------------------------------*\
\r
6537 * Type-in move dialog functions
\r
6539 \*---------------------------------------------------------------------------*/
\r
6542 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6544 char move[MSG_SIZ];
\r
6547 switch (message) {
\r
6548 case WM_INITDIALOG:
\r
6549 move[0] = (char) lParam;
\r
6550 move[1] = NULLCHAR;
\r
6551 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6552 Translate(hDlg, DLG_TypeInMove);
\r
6553 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6554 SetWindowText(hInput, move);
\r
6556 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6560 switch (LOWORD(wParam)) {
\r
6563 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6564 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6565 TypeInDoneEvent(move);
\r
6566 EndDialog(hDlg, TRUE);
\r
6569 EndDialog(hDlg, FALSE);
\r
6580 PopUpMoveDialog(char firstchar)
\r
6584 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6585 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6586 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6587 FreeProcInstance(lpProc);
\r
6590 /*---------------------------------------------------------------------------*\
\r
6592 * Type-in name dialog functions
\r
6594 \*---------------------------------------------------------------------------*/
\r
6597 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6599 char move[MSG_SIZ];
\r
6602 switch (message) {
\r
6603 case WM_INITDIALOG:
\r
6604 move[0] = (char) lParam;
\r
6605 move[1] = NULLCHAR;
\r
6606 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6607 Translate(hDlg, DLG_TypeInName);
\r
6608 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6609 SetWindowText(hInput, move);
\r
6611 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6615 switch (LOWORD(wParam)) {
\r
6617 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6618 appData.userName = strdup(move);
\r
6621 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6622 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6623 DisplayTitle(move);
\r
6627 EndDialog(hDlg, TRUE);
\r
6630 EndDialog(hDlg, FALSE);
\r
6641 PopUpNameDialog(char firstchar)
\r
6645 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6646 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6647 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6648 FreeProcInstance(lpProc);
\r
6651 /*---------------------------------------------------------------------------*\
\r
6655 \*---------------------------------------------------------------------------*/
\r
6657 /* Nonmodal error box */
\r
6658 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6659 WPARAM wParam, LPARAM lParam);
\r
6662 ErrorPopUp(char *title, char *content)
\r
6666 BOOLEAN modal = hwndMain == NULL;
\r
6684 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6685 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6688 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6690 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6691 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6692 hwndMain, (DLGPROC)lpProc);
\r
6693 FreeProcInstance(lpProc);
\r
6700 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6701 if (errorDialog == NULL) return;
\r
6702 DestroyWindow(errorDialog);
\r
6703 errorDialog = NULL;
\r
6704 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6708 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6713 switch (message) {
\r
6714 case WM_INITDIALOG:
\r
6715 GetWindowRect(hDlg, &rChild);
\r
6718 SetWindowPos(hDlg, NULL, rChild.left,
\r
6719 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6720 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6724 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6725 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6726 and it doesn't work when you resize the dialog.
\r
6727 For now, just give it a default position.
\r
6729 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6730 Translate(hDlg, DLG_Error);
\r
6732 errorDialog = hDlg;
\r
6733 SetWindowText(hDlg, errorTitle);
\r
6734 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6735 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6739 switch (LOWORD(wParam)) {
\r
6742 if (errorDialog == hDlg) errorDialog = NULL;
\r
6743 DestroyWindow(hDlg);
\r
6755 HWND gothicDialog = NULL;
\r
6758 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6762 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6764 switch (message) {
\r
6765 case WM_INITDIALOG:
\r
6766 GetWindowRect(hDlg, &rChild);
\r
6768 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6772 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6773 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6774 and it doesn't work when you resize the dialog.
\r
6775 For now, just give it a default position.
\r
6777 gothicDialog = hDlg;
\r
6778 SetWindowText(hDlg, errorTitle);
\r
6779 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6780 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6784 switch (LOWORD(wParam)) {
\r
6787 if (errorDialog == hDlg) errorDialog = NULL;
\r
6788 DestroyWindow(hDlg);
\r
6800 GothicPopUp(char *title, VariantClass variant)
\r
6803 static char *lastTitle;
\r
6805 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6806 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6808 if(lastTitle != title && gothicDialog != NULL) {
\r
6809 DestroyWindow(gothicDialog);
\r
6810 gothicDialog = NULL;
\r
6812 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6813 title = lastTitle;
\r
6814 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6815 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6816 hwndMain, (DLGPROC)lpProc);
\r
6817 FreeProcInstance(lpProc);
\r
6822 /*---------------------------------------------------------------------------*\
\r
6824 * Ics Interaction console functions
\r
6826 \*---------------------------------------------------------------------------*/
\r
6828 #define HISTORY_SIZE 64
\r
6829 static char *history[HISTORY_SIZE];
\r
6830 int histIn = 0, histP = 0;
\r
6833 SaveInHistory(char *cmd)
\r
6835 if (history[histIn] != NULL) {
\r
6836 free(history[histIn]);
\r
6837 history[histIn] = NULL;
\r
6839 if (*cmd == NULLCHAR) return;
\r
6840 history[histIn] = StrSave(cmd);
\r
6841 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6842 if (history[histIn] != NULL) {
\r
6843 free(history[histIn]);
\r
6844 history[histIn] = NULL;
\r
6850 PrevInHistory(char *cmd)
\r
6853 if (histP == histIn) {
\r
6854 if (history[histIn] != NULL) free(history[histIn]);
\r
6855 history[histIn] = StrSave(cmd);
\r
6857 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6858 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6860 return history[histP];
\r
6866 if (histP == histIn) return NULL;
\r
6867 histP = (histP + 1) % HISTORY_SIZE;
\r
6868 return history[histP];
\r
6872 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6876 hmenu = LoadMenu(hInst, "TextMenu");
\r
6877 h = GetSubMenu(hmenu, 0);
\r
6879 if (strcmp(e->item, "-") == 0) {
\r
6880 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6881 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6882 int flags = MF_STRING, j = 0;
\r
6883 if (e->item[0] == '|') {
\r
6884 flags |= MF_MENUBARBREAK;
\r
6887 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6888 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6896 WNDPROC consoleTextWindowProc;
\r
6899 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6901 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6902 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6906 SetWindowText(hInput, command);
\r
6908 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6910 sel.cpMin = 999999;
\r
6911 sel.cpMax = 999999;
\r
6912 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6917 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6918 if (sel.cpMin == sel.cpMax) {
\r
6919 /* Expand to surrounding word */
\r
6922 tr.chrg.cpMax = sel.cpMin;
\r
6923 tr.chrg.cpMin = --sel.cpMin;
\r
6924 if (sel.cpMin < 0) break;
\r
6925 tr.lpstrText = name;
\r
6926 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6927 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6931 tr.chrg.cpMin = sel.cpMax;
\r
6932 tr.chrg.cpMax = ++sel.cpMax;
\r
6933 tr.lpstrText = name;
\r
6934 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6935 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6938 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6939 MessageBeep(MB_ICONEXCLAMATION);
\r
6943 tr.lpstrText = name;
\r
6944 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6946 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6947 MessageBeep(MB_ICONEXCLAMATION);
\r
6950 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6953 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
6954 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
6955 SetWindowText(hInput, buf);
\r
6956 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6958 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
6959 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
6960 SetWindowText(hInput, buf);
\r
6961 sel.cpMin = 999999;
\r
6962 sel.cpMax = 999999;
\r
6963 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6969 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6974 switch (message) {
\r
6976 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6977 if(wParam=='R') return 0;
\r
6980 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6983 sel.cpMin = 999999;
\r
6984 sel.cpMax = 999999;
\r
6985 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6986 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6991 if(wParam != '\022') {
\r
6992 if (wParam == '\t') {
\r
6993 if (GetKeyState(VK_SHIFT) < 0) {
\r
6995 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6996 if (buttonDesc[0].hwnd) {
\r
6997 SetFocus(buttonDesc[0].hwnd);
\r
6999 SetFocus(hwndMain);
\r
7003 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7006 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7007 JAWS_DELETE( SetFocus(hInput); )
\r
7008 SendMessage(hInput, message, wParam, lParam);
\r
7011 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7013 case WM_RBUTTONDOWN:
\r
7014 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7015 /* Move selection here if it was empty */
\r
7017 pt.x = LOWORD(lParam);
\r
7018 pt.y = HIWORD(lParam);
\r
7019 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7020 if (sel.cpMin == sel.cpMax) {
\r
7021 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7022 sel.cpMax = sel.cpMin;
\r
7023 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7025 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7026 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7028 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7029 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7030 if (sel.cpMin == sel.cpMax) {
\r
7031 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7032 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7034 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7035 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7037 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7038 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7039 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7040 MenuPopup(hwnd, pt, hmenu, -1);
\r
7044 case WM_RBUTTONUP:
\r
7045 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7046 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7047 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7051 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7053 return SendMessage(hInput, message, wParam, lParam);
\r
7054 case WM_MBUTTONDOWN:
\r
7055 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7057 switch (LOWORD(wParam)) {
\r
7058 case IDM_QuickPaste:
\r
7060 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7061 if (sel.cpMin == sel.cpMax) {
\r
7062 MessageBeep(MB_ICONEXCLAMATION);
\r
7065 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7066 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7067 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7072 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7075 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7078 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7082 int i = LOWORD(wParam) - IDM_CommandX;
\r
7083 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7084 icsTextMenuEntry[i].command != NULL) {
\r
7085 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7086 icsTextMenuEntry[i].getname,
\r
7087 icsTextMenuEntry[i].immediate);
\r
7095 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7098 WNDPROC consoleInputWindowProc;
\r
7101 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7103 char buf[MSG_SIZ];
\r
7105 static BOOL sendNextChar = FALSE;
\r
7106 static BOOL quoteNextChar = FALSE;
\r
7107 InputSource *is = consoleInputSource;
\r
7111 switch (message) {
\r
7113 if (!appData.localLineEditing || sendNextChar) {
\r
7114 is->buf[0] = (CHAR) wParam;
\r
7116 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7117 sendNextChar = FALSE;
\r
7120 if (quoteNextChar) {
\r
7121 buf[0] = (char) wParam;
\r
7122 buf[1] = NULLCHAR;
\r
7123 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7124 quoteNextChar = FALSE;
\r
7128 case '\r': /* Enter key */
\r
7129 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7130 if (consoleEcho) SaveInHistory(is->buf);
\r
7131 is->buf[is->count++] = '\n';
\r
7132 is->buf[is->count] = NULLCHAR;
\r
7133 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7134 if (consoleEcho) {
\r
7135 ConsoleOutput(is->buf, is->count, TRUE);
\r
7136 } else if (appData.localLineEditing) {
\r
7137 ConsoleOutput("\n", 1, TRUE);
\r
7140 case '\033': /* Escape key */
\r
7141 SetWindowText(hwnd, "");
\r
7142 cf.cbSize = sizeof(CHARFORMAT);
\r
7143 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7144 if (consoleEcho) {
\r
7145 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7147 cf.crTextColor = COLOR_ECHOOFF;
\r
7149 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7150 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7152 case '\t': /* Tab key */
\r
7153 if (GetKeyState(VK_SHIFT) < 0) {
\r
7155 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7158 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7159 if (buttonDesc[0].hwnd) {
\r
7160 SetFocus(buttonDesc[0].hwnd);
\r
7162 SetFocus(hwndMain);
\r
7166 case '\023': /* Ctrl+S */
\r
7167 sendNextChar = TRUE;
\r
7169 case '\021': /* Ctrl+Q */
\r
7170 quoteNextChar = TRUE;
\r
7180 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7181 p = PrevInHistory(buf);
\r
7183 SetWindowText(hwnd, p);
\r
7184 sel.cpMin = 999999;
\r
7185 sel.cpMax = 999999;
\r
7186 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7191 p = NextInHistory();
\r
7193 SetWindowText(hwnd, p);
\r
7194 sel.cpMin = 999999;
\r
7195 sel.cpMax = 999999;
\r
7196 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7202 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7206 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7210 case WM_MBUTTONDOWN:
\r
7211 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7212 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7214 case WM_RBUTTONUP:
\r
7215 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7216 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7217 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7221 hmenu = LoadMenu(hInst, "InputMenu");
\r
7222 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7223 if (sel.cpMin == sel.cpMax) {
\r
7224 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7225 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7227 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7228 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7230 pt.x = LOWORD(lParam);
\r
7231 pt.y = HIWORD(lParam);
\r
7232 MenuPopup(hwnd, pt, hmenu, -1);
\r
7236 switch (LOWORD(wParam)) {
\r
7238 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7240 case IDM_SelectAll:
\r
7242 sel.cpMax = -1; /*999999?*/
\r
7243 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7246 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7249 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7252 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7257 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7260 #define CO_MAX 100000
\r
7261 #define CO_TRIM 1000
\r
7264 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7266 static SnapData sd;
\r
7267 HWND hText, hInput;
\r
7269 static int sizeX, sizeY;
\r
7270 int newSizeX, newSizeY;
\r
7274 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7275 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7277 switch (message) {
\r
7279 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7281 ENLINK *pLink = (ENLINK*)lParam;
\r
7282 if (pLink->msg == WM_LBUTTONUP)
\r
7286 tr.chrg = pLink->chrg;
\r
7287 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7288 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7289 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7290 free(tr.lpstrText);
\r
7294 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7295 hwndConsole = hDlg;
\r
7297 consoleTextWindowProc = (WNDPROC)
\r
7298 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7299 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7300 consoleInputWindowProc = (WNDPROC)
\r
7301 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7302 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7303 Colorize(ColorNormal, TRUE);
\r
7304 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7305 ChangedConsoleFont();
\r
7306 GetClientRect(hDlg, &rect);
\r
7307 sizeX = rect.right;
\r
7308 sizeY = rect.bottom;
\r
7309 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7310 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7311 WINDOWPLACEMENT wp;
\r
7312 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7313 wp.length = sizeof(WINDOWPLACEMENT);
\r
7315 wp.showCmd = SW_SHOW;
\r
7316 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7317 wp.rcNormalPosition.left = wpConsole.x;
\r
7318 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7319 wp.rcNormalPosition.top = wpConsole.y;
\r
7320 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7321 SetWindowPlacement(hDlg, &wp);
\r
7324 // [HGM] Chessknight's change 2004-07-13
\r
7325 else { /* Determine Defaults */
\r
7326 WINDOWPLACEMENT wp;
\r
7327 wpConsole.x = wpMain.width + 1;
\r
7328 wpConsole.y = wpMain.y;
\r
7329 wpConsole.width = screenWidth - wpMain.width;
\r
7330 wpConsole.height = wpMain.height;
\r
7331 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7332 wp.length = sizeof(WINDOWPLACEMENT);
\r
7334 wp.showCmd = SW_SHOW;
\r
7335 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7336 wp.rcNormalPosition.left = wpConsole.x;
\r
7337 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7338 wp.rcNormalPosition.top = wpConsole.y;
\r
7339 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7340 SetWindowPlacement(hDlg, &wp);
\r
7343 // Allow hText to highlight URLs and send notifications on them
\r
7344 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7345 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7346 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7347 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7361 if (IsIconic(hDlg)) break;
\r
7362 newSizeX = LOWORD(lParam);
\r
7363 newSizeY = HIWORD(lParam);
\r
7364 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7365 RECT rectText, rectInput;
\r
7367 int newTextHeight, newTextWidth;
\r
7368 GetWindowRect(hText, &rectText);
\r
7369 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7370 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7371 if (newTextHeight < 0) {
\r
7372 newSizeY += -newTextHeight;
\r
7373 newTextHeight = 0;
\r
7375 SetWindowPos(hText, NULL, 0, 0,
\r
7376 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7377 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7378 pt.x = rectInput.left;
\r
7379 pt.y = rectInput.top + newSizeY - sizeY;
\r
7380 ScreenToClient(hDlg, &pt);
\r
7381 SetWindowPos(hInput, NULL,
\r
7382 pt.x, pt.y, /* needs client coords */
\r
7383 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7384 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7390 case WM_GETMINMAXINFO:
\r
7391 /* Prevent resizing window too small */
\r
7392 mmi = (MINMAXINFO *) lParam;
\r
7393 mmi->ptMinTrackSize.x = 100;
\r
7394 mmi->ptMinTrackSize.y = 100;
\r
7397 /* [AS] Snapping */
\r
7398 case WM_ENTERSIZEMOVE:
\r
7399 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7402 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7405 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7407 case WM_EXITSIZEMOVE:
\r
7408 UpdateICSWidth(hText);
\r
7409 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7412 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7420 if (hwndConsole) return;
\r
7421 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7422 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7427 ConsoleOutput(char* data, int length, int forceVisible)
\r
7432 char buf[CO_MAX+1];
\r
7435 static int delayLF = 0;
\r
7436 CHARRANGE savesel, sel;
\r
7438 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7446 while (length--) {
\r
7454 } else if (*p == '\007') {
\r
7455 MyPlaySound(&sounds[(int)SoundBell]);
\r
7462 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7463 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7464 /* Save current selection */
\r
7465 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7466 exlen = GetWindowTextLength(hText);
\r
7467 /* Find out whether current end of text is visible */
\r
7468 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7469 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7470 /* Trim existing text if it's too long */
\r
7471 if (exlen + (q - buf) > CO_MAX) {
\r
7472 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7475 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7476 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7478 savesel.cpMin -= trim;
\r
7479 savesel.cpMax -= trim;
\r
7480 if (exlen < 0) exlen = 0;
\r
7481 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7482 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7484 /* Append the new text */
\r
7485 sel.cpMin = exlen;
\r
7486 sel.cpMax = exlen;
\r
7487 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7488 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7489 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7490 if (forceVisible || exlen == 0 ||
\r
7491 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7492 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7493 /* Scroll to make new end of text visible if old end of text
\r
7494 was visible or new text is an echo of user typein */
\r
7495 sel.cpMin = 9999999;
\r
7496 sel.cpMax = 9999999;
\r
7497 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7498 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7499 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7500 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7502 if (savesel.cpMax == exlen || forceVisible) {
\r
7503 /* Move insert point to new end of text if it was at the old
\r
7504 end of text or if the new text is an echo of user typein */
\r
7505 sel.cpMin = 9999999;
\r
7506 sel.cpMax = 9999999;
\r
7507 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7509 /* Restore previous selection */
\r
7510 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7512 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7519 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7523 COLORREF oldFg, oldBg;
\r
7527 if(copyNumber > 1)
\r
7528 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7530 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7531 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7532 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7535 rect.right = x + squareSize;
\r
7537 rect.bottom = y + squareSize;
\r
7540 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7541 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7542 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7543 &rect, str, strlen(str), NULL);
\r
7545 (void) SetTextColor(hdc, oldFg);
\r
7546 (void) SetBkColor(hdc, oldBg);
\r
7547 (void) SelectObject(hdc, oldFont);
\r
7551 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7552 RECT *rect, char *color, char *flagFell)
\r
7556 COLORREF oldFg, oldBg;
\r
7559 if (twoBoards && partnerUp) return;
\r
7560 if (appData.clockMode) {
\r
7562 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7564 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7571 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7572 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7574 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7575 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7577 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7581 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7582 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7583 rect, str, strlen(str), NULL);
\r
7584 if(logoHeight > 0 && appData.clockMode) {
\r
7586 str += strlen(color)+2;
\r
7587 r.top = rect->top + logoHeight/2;
\r
7588 r.left = rect->left;
\r
7589 r.right = rect->right;
\r
7590 r.bottom = rect->bottom;
\r
7591 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7592 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7593 &r, str, strlen(str), NULL);
\r
7595 (void) SetTextColor(hdc, oldFg);
\r
7596 (void) SetBkColor(hdc, oldBg);
\r
7597 (void) SelectObject(hdc, oldFont);
\r
7602 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7608 if( count <= 0 ) {
\r
7609 if (appData.debugMode) {
\r
7610 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7613 return ERROR_INVALID_USER_BUFFER;
\r
7616 ResetEvent(ovl->hEvent);
\r
7617 ovl->Offset = ovl->OffsetHigh = 0;
\r
7618 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7622 err = GetLastError();
\r
7623 if (err == ERROR_IO_PENDING) {
\r
7624 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7628 err = GetLastError();
\r
7635 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7640 ResetEvent(ovl->hEvent);
\r
7641 ovl->Offset = ovl->OffsetHigh = 0;
\r
7642 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7646 err = GetLastError();
\r
7647 if (err == ERROR_IO_PENDING) {
\r
7648 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7652 err = GetLastError();
\r
7658 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7659 void CheckForInputBufferFull( InputSource * is )
\r
7661 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7662 /* Look for end of line */
\r
7663 char * p = is->buf;
\r
7665 while( p < is->next && *p != '\n' ) {
\r
7669 if( p >= is->next ) {
\r
7670 if (appData.debugMode) {
\r
7671 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7674 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7675 is->count = (DWORD) -1;
\r
7676 is->next = is->buf;
\r
7682 InputThread(LPVOID arg)
\r
7687 is = (InputSource *) arg;
\r
7688 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7689 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7690 while (is->hThread != NULL) {
\r
7691 is->error = DoReadFile(is->hFile, is->next,
\r
7692 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7693 &is->count, &ovl);
\r
7694 if (is->error == NO_ERROR) {
\r
7695 is->next += is->count;
\r
7697 if (is->error == ERROR_BROKEN_PIPE) {
\r
7698 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7701 is->count = (DWORD) -1;
\r
7702 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7707 CheckForInputBufferFull( is );
\r
7709 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7711 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7713 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7716 CloseHandle(ovl.hEvent);
\r
7717 CloseHandle(is->hFile);
\r
7719 if (appData.debugMode) {
\r
7720 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7727 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7729 NonOvlInputThread(LPVOID arg)
\r
7736 is = (InputSource *) arg;
\r
7737 while (is->hThread != NULL) {
\r
7738 is->error = ReadFile(is->hFile, is->next,
\r
7739 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7740 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7741 if (is->error == NO_ERROR) {
\r
7742 /* Change CRLF to LF */
\r
7743 if (is->next > is->buf) {
\r
7745 i = is->count + 1;
\r
7753 if (prev == '\r' && *p == '\n') {
\r
7765 if (is->error == ERROR_BROKEN_PIPE) {
\r
7766 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7769 is->count = (DWORD) -1;
\r
7773 CheckForInputBufferFull( is );
\r
7775 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7777 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7779 if (is->count < 0) break; /* Quit on error */
\r
7781 CloseHandle(is->hFile);
\r
7786 SocketInputThread(LPVOID arg)
\r
7790 is = (InputSource *) arg;
\r
7791 while (is->hThread != NULL) {
\r
7792 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7793 if ((int)is->count == SOCKET_ERROR) {
\r
7794 is->count = (DWORD) -1;
\r
7795 is->error = WSAGetLastError();
\r
7797 is->error = NO_ERROR;
\r
7798 is->next += is->count;
\r
7799 if (is->count == 0 && is->second == is) {
\r
7800 /* End of file on stderr; quit with no message */
\r
7804 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7806 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7808 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7814 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7818 is = (InputSource *) lParam;
\r
7819 if (is->lineByLine) {
\r
7820 /* Feed in lines one by one */
\r
7821 char *p = is->buf;
\r
7823 while (q < is->next) {
\r
7824 if (*q++ == '\n') {
\r
7825 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7830 /* Move any partial line to the start of the buffer */
\r
7832 while (p < is->next) {
\r
7837 if (is->error != NO_ERROR || is->count == 0) {
\r
7838 /* Notify backend of the error. Note: If there was a partial
\r
7839 line at the end, it is not flushed through. */
\r
7840 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7843 /* Feed in the whole chunk of input at once */
\r
7844 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7845 is->next = is->buf;
\r
7849 /*---------------------------------------------------------------------------*\
\r
7851 * Menu enables. Used when setting various modes.
\r
7853 \*---------------------------------------------------------------------------*/
\r
7861 GreyRevert(Boolean grey)
\r
7862 { // [HGM] vari: for retracting variations in local mode
\r
7863 HMENU hmenu = GetMenu(hwndMain);
\r
7864 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7865 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7869 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7871 while (enab->item > 0) {
\r
7872 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7877 Enables gnuEnables[] = {
\r
7878 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7879 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7880 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7881 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7882 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7883 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7884 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7885 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7886 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7887 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7888 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7889 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7890 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7892 // Needed to switch from ncp to GNU mode on Engine Load
\r
7893 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7894 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7895 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7896 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7897 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7898 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7899 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7900 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7901 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7902 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7903 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7904 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7905 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7906 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7910 Enables icsEnables[] = {
\r
7911 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7912 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7913 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7914 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7915 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7916 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7917 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7918 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7919 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7920 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7921 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7922 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7923 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7924 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
7925 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
7926 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7927 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7928 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7929 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7930 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
7935 Enables zippyEnables[] = {
\r
7936 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7937 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7938 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7939 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7944 Enables ncpEnables[] = {
\r
7945 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7946 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7947 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7948 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7949 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7950 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7951 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7952 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7953 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7954 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7955 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7956 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7957 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7958 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7959 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7960 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7961 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7962 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7963 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7964 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7965 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7966 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
7970 Enables trainingOnEnables[] = {
\r
7971 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7972 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7983 Enables trainingOffEnables[] = {
\r
7984 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7985 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
7986 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7987 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7990 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7991 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7992 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7996 /* These modify either ncpEnables or gnuEnables */
\r
7997 Enables cmailEnables[] = {
\r
7998 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7999 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8000 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8001 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8002 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8003 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8004 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8008 Enables machineThinkingEnables[] = {
\r
8009 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8019 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8020 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8021 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8022 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8023 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8024 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8028 Enables userThinkingEnables[] = {
\r
8029 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8030 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8031 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8032 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8033 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8034 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8035 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8036 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8037 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8038 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8039 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8040 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8041 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8042 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8043 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8044 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8048 /*---------------------------------------------------------------------------*\
\r
8050 * Front-end interface functions exported by XBoard.
\r
8051 * Functions appear in same order as prototypes in frontend.h.
\r
8053 \*---------------------------------------------------------------------------*/
\r
8055 CheckMark(UINT item, int state)
\r
8057 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8063 static UINT prevChecked = 0;
\r
8064 static int prevPausing = 0;
\r
8067 if (pausing != prevPausing) {
\r
8068 prevPausing = pausing;
\r
8069 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8070 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8071 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8074 switch (gameMode) {
\r
8075 case BeginningOfGame:
\r
8076 if (appData.icsActive)
\r
8077 nowChecked = IDM_IcsClient;
\r
8078 else if (appData.noChessProgram)
\r
8079 nowChecked = IDM_EditGame;
\r
8081 nowChecked = IDM_MachineBlack;
\r
8083 case MachinePlaysBlack:
\r
8084 nowChecked = IDM_MachineBlack;
\r
8086 case MachinePlaysWhite:
\r
8087 nowChecked = IDM_MachineWhite;
\r
8089 case TwoMachinesPlay:
\r
8090 nowChecked = IDM_TwoMachines;
\r
8093 nowChecked = IDM_AnalysisMode;
\r
8096 nowChecked = IDM_AnalyzeFile;
\r
8099 nowChecked = IDM_EditGame;
\r
8101 case PlayFromGameFile:
\r
8102 nowChecked = IDM_LoadGame;
\r
8104 case EditPosition:
\r
8105 nowChecked = IDM_EditPosition;
\r
8108 nowChecked = IDM_Training;
\r
8110 case IcsPlayingWhite:
\r
8111 case IcsPlayingBlack:
\r
8112 case IcsObserving:
\r
8114 nowChecked = IDM_IcsClient;
\r
8121 CheckMark(prevChecked, MF_UNCHECKED);
\r
8122 CheckMark(nowChecked, MF_CHECKED);
\r
8123 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8125 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8126 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8127 MF_BYCOMMAND|MF_ENABLED);
\r
8129 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8130 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8133 prevChecked = nowChecked;
\r
8135 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8136 if (appData.icsActive) {
\r
8137 if (appData.icsEngineAnalyze) {
\r
8138 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8140 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8143 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8149 HMENU hmenu = GetMenu(hwndMain);
\r
8150 SetMenuEnables(hmenu, icsEnables);
\r
8151 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8152 MF_BYCOMMAND|MF_ENABLED);
\r
8154 if (appData.zippyPlay) {
\r
8155 SetMenuEnables(hmenu, zippyEnables);
\r
8156 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8157 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8158 MF_BYCOMMAND|MF_ENABLED);
\r
8166 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8172 HMENU hmenu = GetMenu(hwndMain);
\r
8173 SetMenuEnables(hmenu, ncpEnables);
\r
8174 DrawMenuBar(hwndMain);
\r
8180 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8184 SetTrainingModeOn()
\r
8187 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8188 for (i = 0; i < N_BUTTONS; i++) {
\r
8189 if (buttonDesc[i].hwnd != NULL)
\r
8190 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8195 VOID SetTrainingModeOff()
\r
8198 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8199 for (i = 0; i < N_BUTTONS; i++) {
\r
8200 if (buttonDesc[i].hwnd != NULL)
\r
8201 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8207 SetUserThinkingEnables()
\r
8209 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8213 SetMachineThinkingEnables()
\r
8215 HMENU hMenu = GetMenu(hwndMain);
\r
8216 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8218 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8220 if (gameMode == MachinePlaysBlack) {
\r
8221 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8222 } else if (gameMode == MachinePlaysWhite) {
\r
8223 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8224 } else if (gameMode == TwoMachinesPlay) {
\r
8225 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8231 DisplayTitle(char *str)
\r
8233 char title[MSG_SIZ], *host;
\r
8234 if (str[0] != NULLCHAR) {
\r
8235 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8236 } else if (appData.icsActive) {
\r
8237 if (appData.icsCommPort[0] != NULLCHAR)
\r
8240 host = appData.icsHost;
\r
8241 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8242 } else if (appData.noChessProgram) {
\r
8243 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8245 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8246 strcat(title, ": ");
\r
8247 strcat(title, first.tidy);
\r
8249 SetWindowText(hwndMain, title);
\r
8254 DisplayMessage(char *str1, char *str2)
\r
8258 int remain = MESSAGE_TEXT_MAX - 1;
\r
8261 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8262 messageText[0] = NULLCHAR;
\r
8264 len = strlen(str1);
\r
8265 if (len > remain) len = remain;
\r
8266 strncpy(messageText, str1, len);
\r
8267 messageText[len] = NULLCHAR;
\r
8270 if (*str2 && remain >= 2) {
\r
8272 strcat(messageText, " ");
\r
8275 len = strlen(str2);
\r
8276 if (len > remain) len = remain;
\r
8277 strncat(messageText, str2, len);
\r
8279 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8280 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8282 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8286 hdc = GetDC(hwndMain);
\r
8287 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8288 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8289 &messageRect, messageText, strlen(messageText), NULL);
\r
8290 (void) SelectObject(hdc, oldFont);
\r
8291 (void) ReleaseDC(hwndMain, hdc);
\r
8295 DisplayError(char *str, int error)
\r
8297 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8301 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8303 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8304 NULL, error, LANG_NEUTRAL,
\r
8305 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8307 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8309 ErrorMap *em = errmap;
\r
8310 while (em->err != 0 && em->err != error) em++;
\r
8311 if (em->err != 0) {
\r
8312 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8314 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8319 ErrorPopUp(_("Error"), buf);
\r
8324 DisplayMoveError(char *str)
\r
8326 fromX = fromY = -1;
\r
8327 ClearHighlights();
\r
8328 DrawPosition(FALSE, NULL);
\r
8329 if (appData.popupMoveErrors) {
\r
8330 ErrorPopUp(_("Error"), str);
\r
8332 DisplayMessage(str, "");
\r
8333 moveErrorMessageUp = TRUE;
\r
8338 DisplayFatalError(char *str, int error, int exitStatus)
\r
8340 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8342 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8345 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8346 NULL, error, LANG_NEUTRAL,
\r
8347 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8349 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8351 ErrorMap *em = errmap;
\r
8352 while (em->err != 0 && em->err != error) em++;
\r
8353 if (em->err != 0) {
\r
8354 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8356 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8361 if (appData.debugMode) {
\r
8362 fprintf(debugFP, "%s: %s\n", label, str);
\r
8364 if (appData.popupExitMessage) {
\r
8365 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8366 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8368 ExitEvent(exitStatus);
\r
8373 DisplayInformation(char *str)
\r
8375 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8380 DisplayNote(char *str)
\r
8382 ErrorPopUp(_("Note"), str);
\r
8387 char *title, *question, *replyPrefix;
\r
8392 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8394 static QuestionParams *qp;
\r
8395 char reply[MSG_SIZ];
\r
8398 switch (message) {
\r
8399 case WM_INITDIALOG:
\r
8400 qp = (QuestionParams *) lParam;
\r
8401 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8402 Translate(hDlg, DLG_Question);
\r
8403 SetWindowText(hDlg, qp->title);
\r
8404 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8405 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8409 switch (LOWORD(wParam)) {
\r
8411 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8412 if (*reply) strcat(reply, " ");
\r
8413 len = strlen(reply);
\r
8414 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8415 strcat(reply, "\n");
\r
8416 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8417 EndDialog(hDlg, TRUE);
\r
8418 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8421 EndDialog(hDlg, FALSE);
\r
8432 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8434 QuestionParams qp;
\r
8438 qp.question = question;
\r
8439 qp.replyPrefix = replyPrefix;
\r
8441 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8442 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8443 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8444 FreeProcInstance(lpProc);
\r
8447 /* [AS] Pick FRC position */
\r
8448 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8450 static int * lpIndexFRC;
\r
8456 case WM_INITDIALOG:
\r
8457 lpIndexFRC = (int *) lParam;
\r
8459 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8460 Translate(hDlg, DLG_NewGameFRC);
\r
8462 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8463 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8464 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8465 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8470 switch( LOWORD(wParam) ) {
\r
8472 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8473 EndDialog( hDlg, 0 );
\r
8474 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8477 EndDialog( hDlg, 1 );
\r
8479 case IDC_NFG_Edit:
\r
8480 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8481 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8483 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8486 case IDC_NFG_Random:
\r
8487 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8488 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8501 int index = appData.defaultFrcPosition;
\r
8502 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8504 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8506 if( result == 0 ) {
\r
8507 appData.defaultFrcPosition = index;
\r
8513 /* [AS] Game list options. Refactored by HGM */
\r
8515 HWND gameListOptionsDialog;
\r
8517 // low-level front-end: clear text edit / list widget
\r
8521 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8524 // low-level front-end: clear text edit / list widget
\r
8526 GLT_DeSelectList()
\r
8528 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8531 // low-level front-end: append line to text edit / list widget
\r
8533 GLT_AddToList( char *name )
\r
8536 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8540 // low-level front-end: get line from text edit / list widget
\r
8542 GLT_GetFromList( int index, char *name )
\r
8545 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8551 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8553 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8554 int idx2 = idx1 + delta;
\r
8555 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8557 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8560 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8561 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8562 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8563 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8567 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8571 case WM_INITDIALOG:
\r
8572 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8574 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8575 Translate(hDlg, DLG_GameListOptions);
\r
8577 /* Initialize list */
\r
8578 GLT_TagsToList( lpUserGLT );
\r
8580 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8585 switch( LOWORD(wParam) ) {
\r
8588 EndDialog( hDlg, 0 );
\r
8591 EndDialog( hDlg, 1 );
\r
8594 case IDC_GLT_Default:
\r
8595 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8598 case IDC_GLT_Restore:
\r
8599 GLT_TagsToList( appData.gameListTags );
\r
8603 GLT_MoveSelection( hDlg, -1 );
\r
8606 case IDC_GLT_Down:
\r
8607 GLT_MoveSelection( hDlg, +1 );
\r
8617 int GameListOptions()
\r
8620 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8622 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8624 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8626 if( result == 0 ) {
\r
8627 /* [AS] Memory leak here! */
\r
8628 appData.gameListTags = strdup( lpUserGLT );
\r
8635 DisplayIcsInteractionTitle(char *str)
\r
8637 char consoleTitle[MSG_SIZ];
\r
8639 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8640 SetWindowText(hwndConsole, consoleTitle);
\r
8642 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8643 char buf[MSG_SIZ], *p = buf, *q;
\r
8644 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8646 q = strchr(p, ';');
\r
8648 if(*p) ChatPopUp(p);
\r
8652 SetActiveWindow(hwndMain);
\r
8656 DrawPosition(int fullRedraw, Board board)
\r
8658 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8661 void NotifyFrontendLogin()
\r
8664 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8670 fromX = fromY = -1;
\r
8671 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8672 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8673 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8674 dragInfo.lastpos = dragInfo.pos;
\r
8675 dragInfo.start.x = dragInfo.start.y = -1;
\r
8676 dragInfo.from = dragInfo.start;
\r
8678 DrawPosition(TRUE, NULL);
\r
8685 CommentPopUp(char *title, char *str)
\r
8687 HWND hwnd = GetActiveWindow();
\r
8688 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8690 SetActiveWindow(hwnd);
\r
8694 CommentPopDown(void)
\r
8696 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8697 if (commentDialog) {
\r
8698 ShowWindow(commentDialog, SW_HIDE);
\r
8700 commentUp = FALSE;
\r
8704 EditCommentPopUp(int index, char *title, char *str)
\r
8706 EitherCommentPopUp(index, title, str, TRUE);
\r
8713 MyPlaySound(&sounds[(int)SoundMove]);
\r
8716 VOID PlayIcsWinSound()
\r
8718 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8721 VOID PlayIcsLossSound()
\r
8723 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8726 VOID PlayIcsDrawSound()
\r
8728 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8731 VOID PlayIcsUnfinishedSound()
\r
8733 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8739 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8745 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8753 consoleEcho = TRUE;
\r
8754 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8755 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8756 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8765 consoleEcho = FALSE;
\r
8766 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8767 /* This works OK: set text and background both to the same color */
\r
8769 cf.crTextColor = COLOR_ECHOOFF;
\r
8770 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8771 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8774 /* No Raw()...? */
\r
8776 void Colorize(ColorClass cc, int continuation)
\r
8778 currentColorClass = cc;
\r
8779 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8780 consoleCF.crTextColor = textAttribs[cc].color;
\r
8781 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8782 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8788 static char buf[MSG_SIZ];
\r
8789 DWORD bufsiz = MSG_SIZ;
\r
8791 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8792 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8794 if (!GetUserName(buf, &bufsiz)) {
\r
8795 /*DisplayError("Error getting user name", GetLastError());*/
\r
8796 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8804 static char buf[MSG_SIZ];
\r
8805 DWORD bufsiz = MSG_SIZ;
\r
8807 if (!GetComputerName(buf, &bufsiz)) {
\r
8808 /*DisplayError("Error getting host name", GetLastError());*/
\r
8809 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8816 ClockTimerRunning()
\r
8818 return clockTimerEvent != 0;
\r
8824 if (clockTimerEvent == 0) return FALSE;
\r
8825 KillTimer(hwndMain, clockTimerEvent);
\r
8826 clockTimerEvent = 0;
\r
8831 StartClockTimer(long millisec)
\r
8833 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8834 (UINT) millisec, NULL);
\r
8838 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8841 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8843 if(appData.noGUI) return;
\r
8844 hdc = GetDC(hwndMain);
\r
8845 if (!IsIconic(hwndMain)) {
\r
8846 DisplayAClock(hdc, timeRemaining, highlight,
\r
8847 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8849 if (highlight && iconCurrent == iconBlack) {
\r
8850 iconCurrent = iconWhite;
\r
8851 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8852 if (IsIconic(hwndMain)) {
\r
8853 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8856 (void) ReleaseDC(hwndMain, hdc);
\r
8858 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8862 DisplayBlackClock(long timeRemaining, int highlight)
\r
8865 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8867 if(appData.noGUI) return;
\r
8868 hdc = GetDC(hwndMain);
\r
8869 if (!IsIconic(hwndMain)) {
\r
8870 DisplayAClock(hdc, timeRemaining, highlight,
\r
8871 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8873 if (highlight && iconCurrent == iconWhite) {
\r
8874 iconCurrent = iconBlack;
\r
8875 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8876 if (IsIconic(hwndMain)) {
\r
8877 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8880 (void) ReleaseDC(hwndMain, hdc);
\r
8882 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8887 LoadGameTimerRunning()
\r
8889 return loadGameTimerEvent != 0;
\r
8893 StopLoadGameTimer()
\r
8895 if (loadGameTimerEvent == 0) return FALSE;
\r
8896 KillTimer(hwndMain, loadGameTimerEvent);
\r
8897 loadGameTimerEvent = 0;
\r
8902 StartLoadGameTimer(long millisec)
\r
8904 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8905 (UINT) millisec, NULL);
\r
8913 char fileTitle[MSG_SIZ];
\r
8915 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8916 f = OpenFileDialog(hwndMain, "a", defName,
\r
8917 appData.oldSaveStyle ? "gam" : "pgn",
\r
8919 _("Save Game to File"), NULL, fileTitle, NULL);
\r
8921 SaveGame(f, 0, "");
\r
8928 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8930 if (delayedTimerEvent != 0) {
\r
8931 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8932 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8934 KillTimer(hwndMain, delayedTimerEvent);
\r
8935 delayedTimerEvent = 0;
\r
8936 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8937 delayedTimerCallback();
\r
8939 delayedTimerCallback = cb;
\r
8940 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8941 (UINT) millisec, NULL);
\r
8944 DelayedEventCallback
\r
8947 if (delayedTimerEvent) {
\r
8948 return delayedTimerCallback;
\r
8955 CancelDelayedEvent()
\r
8957 if (delayedTimerEvent) {
\r
8958 KillTimer(hwndMain, delayedTimerEvent);
\r
8959 delayedTimerEvent = 0;
\r
8963 DWORD GetWin32Priority(int nice)
\r
8964 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8966 REALTIME_PRIORITY_CLASS 0x00000100
\r
8967 HIGH_PRIORITY_CLASS 0x00000080
\r
8968 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8969 NORMAL_PRIORITY_CLASS 0x00000020
\r
8970 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8971 IDLE_PRIORITY_CLASS 0x00000040
\r
8973 if (nice < -15) return 0x00000080;
\r
8974 if (nice < 0) return 0x00008000;
\r
8975 if (nice == 0) return 0x00000020;
\r
8976 if (nice < 15) return 0x00004000;
\r
8977 return 0x00000040;
\r
8980 void RunCommand(char *cmdLine)
\r
8982 /* Now create the child process. */
\r
8983 STARTUPINFO siStartInfo;
\r
8984 PROCESS_INFORMATION piProcInfo;
\r
8986 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8987 siStartInfo.lpReserved = NULL;
\r
8988 siStartInfo.lpDesktop = NULL;
\r
8989 siStartInfo.lpTitle = NULL;
\r
8990 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8991 siStartInfo.cbReserved2 = 0;
\r
8992 siStartInfo.lpReserved2 = NULL;
\r
8993 siStartInfo.hStdInput = NULL;
\r
8994 siStartInfo.hStdOutput = NULL;
\r
8995 siStartInfo.hStdError = NULL;
\r
8997 CreateProcess(NULL,
\r
8998 cmdLine, /* command line */
\r
8999 NULL, /* process security attributes */
\r
9000 NULL, /* primary thread security attrs */
\r
9001 TRUE, /* handles are inherited */
\r
9002 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9003 NULL, /* use parent's environment */
\r
9005 &siStartInfo, /* STARTUPINFO pointer */
\r
9006 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9008 CloseHandle(piProcInfo.hThread);
\r
9011 /* Start a child process running the given program.
\r
9012 The process's standard output can be read from "from", and its
\r
9013 standard input can be written to "to".
\r
9014 Exit with fatal error if anything goes wrong.
\r
9015 Returns an opaque pointer that can be used to destroy the process
\r
9019 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9021 #define BUFSIZE 4096
\r
9023 HANDLE hChildStdinRd, hChildStdinWr,
\r
9024 hChildStdoutRd, hChildStdoutWr;
\r
9025 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9026 SECURITY_ATTRIBUTES saAttr;
\r
9028 PROCESS_INFORMATION piProcInfo;
\r
9029 STARTUPINFO siStartInfo;
\r
9031 char buf[MSG_SIZ];
\r
9034 if (appData.debugMode) {
\r
9035 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9040 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9041 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9042 saAttr.bInheritHandle = TRUE;
\r
9043 saAttr.lpSecurityDescriptor = NULL;
\r
9046 * The steps for redirecting child's STDOUT:
\r
9047 * 1. Create anonymous pipe to be STDOUT for child.
\r
9048 * 2. Create a noninheritable duplicate of read handle,
\r
9049 * and close the inheritable read handle.
\r
9052 /* Create a pipe for the child's STDOUT. */
\r
9053 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9054 return GetLastError();
\r
9057 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9058 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9059 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9060 FALSE, /* not inherited */
\r
9061 DUPLICATE_SAME_ACCESS);
\r
9063 return GetLastError();
\r
9065 CloseHandle(hChildStdoutRd);
\r
9068 * The steps for redirecting child's STDIN:
\r
9069 * 1. Create anonymous pipe to be STDIN for child.
\r
9070 * 2. Create a noninheritable duplicate of write handle,
\r
9071 * and close the inheritable write handle.
\r
9074 /* Create a pipe for the child's STDIN. */
\r
9075 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9076 return GetLastError();
\r
9079 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9080 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9081 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9082 FALSE, /* not inherited */
\r
9083 DUPLICATE_SAME_ACCESS);
\r
9085 return GetLastError();
\r
9087 CloseHandle(hChildStdinWr);
\r
9089 /* Arrange to (1) look in dir for the child .exe file, and
\r
9090 * (2) have dir be the child's working directory. Interpret
\r
9091 * dir relative to the directory WinBoard loaded from. */
\r
9092 GetCurrentDirectory(MSG_SIZ, buf);
\r
9093 SetCurrentDirectory(installDir);
\r
9094 SetCurrentDirectory(dir);
\r
9096 /* Now create the child process. */
\r
9098 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9099 siStartInfo.lpReserved = NULL;
\r
9100 siStartInfo.lpDesktop = NULL;
\r
9101 siStartInfo.lpTitle = NULL;
\r
9102 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9103 siStartInfo.cbReserved2 = 0;
\r
9104 siStartInfo.lpReserved2 = NULL;
\r
9105 siStartInfo.hStdInput = hChildStdinRd;
\r
9106 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9107 siStartInfo.hStdError = hChildStdoutWr;
\r
9109 fSuccess = CreateProcess(NULL,
\r
9110 cmdLine, /* command line */
\r
9111 NULL, /* process security attributes */
\r
9112 NULL, /* primary thread security attrs */
\r
9113 TRUE, /* handles are inherited */
\r
9114 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9115 NULL, /* use parent's environment */
\r
9117 &siStartInfo, /* STARTUPINFO pointer */
\r
9118 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9120 err = GetLastError();
\r
9121 SetCurrentDirectory(buf); /* return to prev directory */
\r
9126 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9127 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9128 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9131 /* Close the handles we don't need in the parent */
\r
9132 CloseHandle(piProcInfo.hThread);
\r
9133 CloseHandle(hChildStdinRd);
\r
9134 CloseHandle(hChildStdoutWr);
\r
9136 /* Prepare return value */
\r
9137 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9138 cp->kind = CPReal;
\r
9139 cp->hProcess = piProcInfo.hProcess;
\r
9140 cp->pid = piProcInfo.dwProcessId;
\r
9141 cp->hFrom = hChildStdoutRdDup;
\r
9142 cp->hTo = hChildStdinWrDup;
\r
9144 *pr = (void *) cp;
\r
9146 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9147 2000 where engines sometimes don't see the initial command(s)
\r
9148 from WinBoard and hang. I don't understand how that can happen,
\r
9149 but the Sleep is harmless, so I've put it in. Others have also
\r
9150 reported what may be the same problem, so hopefully this will fix
\r
9151 it for them too. */
\r
9159 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9161 ChildProc *cp; int result;
\r
9163 cp = (ChildProc *) pr;
\r
9164 if (cp == NULL) return;
\r
9166 switch (cp->kind) {
\r
9168 /* TerminateProcess is considered harmful, so... */
\r
9169 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9170 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9171 /* The following doesn't work because the chess program
\r
9172 doesn't "have the same console" as WinBoard. Maybe
\r
9173 we could arrange for this even though neither WinBoard
\r
9174 nor the chess program uses a console for stdio? */
\r
9175 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9177 /* [AS] Special termination modes for misbehaving programs... */
\r
9178 if( signal == 9 ) {
\r
9179 result = TerminateProcess( cp->hProcess, 0 );
\r
9181 if ( appData.debugMode) {
\r
9182 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9185 else if( signal == 10 ) {
\r
9186 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9188 if( dw != WAIT_OBJECT_0 ) {
\r
9189 result = TerminateProcess( cp->hProcess, 0 );
\r
9191 if ( appData.debugMode) {
\r
9192 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9198 CloseHandle(cp->hProcess);
\r
9202 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9206 closesocket(cp->sock);
\r
9211 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9212 closesocket(cp->sock);
\r
9213 closesocket(cp->sock2);
\r
9221 InterruptChildProcess(ProcRef pr)
\r
9225 cp = (ChildProc *) pr;
\r
9226 if (cp == NULL) return;
\r
9227 switch (cp->kind) {
\r
9229 /* The following doesn't work because the chess program
\r
9230 doesn't "have the same console" as WinBoard. Maybe
\r
9231 we could arrange for this even though neither WinBoard
\r
9232 nor the chess program uses a console for stdio */
\r
9233 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9238 /* Can't interrupt */
\r
9242 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9249 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9251 char cmdLine[MSG_SIZ];
\r
9253 if (port[0] == NULLCHAR) {
\r
9254 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9256 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9258 return StartChildProcess(cmdLine, "", pr);
\r
9262 /* Code to open TCP sockets */
\r
9265 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9271 struct sockaddr_in sa, mysa;
\r
9272 struct hostent FAR *hp;
\r
9273 unsigned short uport;
\r
9274 WORD wVersionRequested;
\r
9277 /* Initialize socket DLL */
\r
9278 wVersionRequested = MAKEWORD(1, 1);
\r
9279 err = WSAStartup(wVersionRequested, &wsaData);
\r
9280 if (err != 0) return err;
\r
9283 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9284 err = WSAGetLastError();
\r
9289 /* Bind local address using (mostly) don't-care values.
\r
9291 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9292 mysa.sin_family = AF_INET;
\r
9293 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9294 uport = (unsigned short) 0;
\r
9295 mysa.sin_port = htons(uport);
\r
9296 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9297 == SOCKET_ERROR) {
\r
9298 err = WSAGetLastError();
\r
9303 /* Resolve remote host name */
\r
9304 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9305 if (!(hp = gethostbyname(host))) {
\r
9306 unsigned int b0, b1, b2, b3;
\r
9308 err = WSAGetLastError();
\r
9310 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9311 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9312 hp->h_addrtype = AF_INET;
\r
9314 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9315 hp->h_addr_list[0] = (char *) malloc(4);
\r
9316 hp->h_addr_list[0][0] = (char) b0;
\r
9317 hp->h_addr_list[0][1] = (char) b1;
\r
9318 hp->h_addr_list[0][2] = (char) b2;
\r
9319 hp->h_addr_list[0][3] = (char) b3;
\r
9325 sa.sin_family = hp->h_addrtype;
\r
9326 uport = (unsigned short) atoi(port);
\r
9327 sa.sin_port = htons(uport);
\r
9328 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9330 /* Make connection */
\r
9331 if (connect(s, (struct sockaddr *) &sa,
\r
9332 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9333 err = WSAGetLastError();
\r
9338 /* Prepare return value */
\r
9339 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9340 cp->kind = CPSock;
\r
9342 *pr = (ProcRef *) cp;
\r
9348 OpenCommPort(char *name, ProcRef *pr)
\r
9353 char fullname[MSG_SIZ];
\r
9355 if (*name != '\\')
\r
9356 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9358 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9360 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9361 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9362 if (h == (HANDLE) -1) {
\r
9363 return GetLastError();
\r
9367 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9369 /* Accumulate characters until a 100ms pause, then parse */
\r
9370 ct.ReadIntervalTimeout = 100;
\r
9371 ct.ReadTotalTimeoutMultiplier = 0;
\r
9372 ct.ReadTotalTimeoutConstant = 0;
\r
9373 ct.WriteTotalTimeoutMultiplier = 0;
\r
9374 ct.WriteTotalTimeoutConstant = 0;
\r
9375 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9377 /* Prepare return value */
\r
9378 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9379 cp->kind = CPComm;
\r
9382 *pr = (ProcRef *) cp;
\r
9388 OpenLoopback(ProcRef *pr)
\r
9390 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9396 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9401 struct sockaddr_in sa, mysa;
\r
9402 struct hostent FAR *hp;
\r
9403 unsigned short uport;
\r
9404 WORD wVersionRequested;
\r
9407 char stderrPortStr[MSG_SIZ];
\r
9409 /* Initialize socket DLL */
\r
9410 wVersionRequested = MAKEWORD(1, 1);
\r
9411 err = WSAStartup(wVersionRequested, &wsaData);
\r
9412 if (err != 0) return err;
\r
9414 /* Resolve remote host name */
\r
9415 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9416 if (!(hp = gethostbyname(host))) {
\r
9417 unsigned int b0, b1, b2, b3;
\r
9419 err = WSAGetLastError();
\r
9421 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9422 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9423 hp->h_addrtype = AF_INET;
\r
9425 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9426 hp->h_addr_list[0] = (char *) malloc(4);
\r
9427 hp->h_addr_list[0][0] = (char) b0;
\r
9428 hp->h_addr_list[0][1] = (char) b1;
\r
9429 hp->h_addr_list[0][2] = (char) b2;
\r
9430 hp->h_addr_list[0][3] = (char) b3;
\r
9436 sa.sin_family = hp->h_addrtype;
\r
9437 uport = (unsigned short) 514;
\r
9438 sa.sin_port = htons(uport);
\r
9439 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9441 /* Bind local socket to unused "privileged" port address
\r
9443 s = INVALID_SOCKET;
\r
9444 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9445 mysa.sin_family = AF_INET;
\r
9446 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9447 for (fromPort = 1023;; fromPort--) {
\r
9448 if (fromPort < 0) {
\r
9450 return WSAEADDRINUSE;
\r
9452 if (s == INVALID_SOCKET) {
\r
9453 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9454 err = WSAGetLastError();
\r
9459 uport = (unsigned short) fromPort;
\r
9460 mysa.sin_port = htons(uport);
\r
9461 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9462 == SOCKET_ERROR) {
\r
9463 err = WSAGetLastError();
\r
9464 if (err == WSAEADDRINUSE) continue;
\r
9468 if (connect(s, (struct sockaddr *) &sa,
\r
9469 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9470 err = WSAGetLastError();
\r
9471 if (err == WSAEADDRINUSE) {
\r
9482 /* Bind stderr local socket to unused "privileged" port address
\r
9484 s2 = INVALID_SOCKET;
\r
9485 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9486 mysa.sin_family = AF_INET;
\r
9487 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9488 for (fromPort = 1023;; fromPort--) {
\r
9489 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9490 if (fromPort < 0) {
\r
9491 (void) closesocket(s);
\r
9493 return WSAEADDRINUSE;
\r
9495 if (s2 == INVALID_SOCKET) {
\r
9496 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9497 err = WSAGetLastError();
\r
9503 uport = (unsigned short) fromPort;
\r
9504 mysa.sin_port = htons(uport);
\r
9505 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9506 == SOCKET_ERROR) {
\r
9507 err = WSAGetLastError();
\r
9508 if (err == WSAEADDRINUSE) continue;
\r
9509 (void) closesocket(s);
\r
9513 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9514 err = WSAGetLastError();
\r
9515 if (err == WSAEADDRINUSE) {
\r
9517 s2 = INVALID_SOCKET;
\r
9520 (void) closesocket(s);
\r
9521 (void) closesocket(s2);
\r
9527 prevStderrPort = fromPort; // remember port used
\r
9528 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9530 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9531 err = WSAGetLastError();
\r
9532 (void) closesocket(s);
\r
9533 (void) closesocket(s2);
\r
9538 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9539 err = WSAGetLastError();
\r
9540 (void) closesocket(s);
\r
9541 (void) closesocket(s2);
\r
9545 if (*user == NULLCHAR) user = UserName();
\r
9546 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9547 err = WSAGetLastError();
\r
9548 (void) closesocket(s);
\r
9549 (void) closesocket(s2);
\r
9553 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9554 err = WSAGetLastError();
\r
9555 (void) closesocket(s);
\r
9556 (void) closesocket(s2);
\r
9561 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9562 err = WSAGetLastError();
\r
9563 (void) closesocket(s);
\r
9564 (void) closesocket(s2);
\r
9568 (void) closesocket(s2); /* Stop listening */
\r
9570 /* Prepare return value */
\r
9571 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9572 cp->kind = CPRcmd;
\r
9575 *pr = (ProcRef *) cp;
\r
9582 AddInputSource(ProcRef pr, int lineByLine,
\r
9583 InputCallback func, VOIDSTAR closure)
\r
9585 InputSource *is, *is2 = NULL;
\r
9586 ChildProc *cp = (ChildProc *) pr;
\r
9588 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9589 is->lineByLine = lineByLine;
\r
9591 is->closure = closure;
\r
9592 is->second = NULL;
\r
9593 is->next = is->buf;
\r
9594 if (pr == NoProc) {
\r
9595 is->kind = CPReal;
\r
9596 consoleInputSource = is;
\r
9598 is->kind = cp->kind;
\r
9600 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9601 we create all threads suspended so that the is->hThread variable can be
\r
9602 safely assigned, then let the threads start with ResumeThread.
\r
9604 switch (cp->kind) {
\r
9606 is->hFile = cp->hFrom;
\r
9607 cp->hFrom = NULL; /* now owned by InputThread */
\r
9609 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9610 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9614 is->hFile = cp->hFrom;
\r
9615 cp->hFrom = NULL; /* now owned by InputThread */
\r
9617 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9618 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9622 is->sock = cp->sock;
\r
9624 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9625 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9629 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9631 is->sock = cp->sock;
\r
9633 is2->sock = cp->sock2;
\r
9634 is2->second = is2;
\r
9636 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9637 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9639 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9640 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9644 if( is->hThread != NULL ) {
\r
9645 ResumeThread( is->hThread );
\r
9648 if( is2 != NULL && is2->hThread != NULL ) {
\r
9649 ResumeThread( is2->hThread );
\r
9653 return (InputSourceRef) is;
\r
9657 RemoveInputSource(InputSourceRef isr)
\r
9661 is = (InputSource *) isr;
\r
9662 is->hThread = NULL; /* tell thread to stop */
\r
9663 CloseHandle(is->hThread);
\r
9664 if (is->second != NULL) {
\r
9665 is->second->hThread = NULL;
\r
9666 CloseHandle(is->second->hThread);
\r
9670 int no_wrap(char *message, int count)
\r
9672 ConsoleOutput(message, count, FALSE);
\r
9677 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9680 int outCount = SOCKET_ERROR;
\r
9681 ChildProc *cp = (ChildProc *) pr;
\r
9682 static OVERLAPPED ovl;
\r
9683 static int line = 0;
\r
9687 if (appData.noJoin || !appData.useInternalWrap)
\r
9688 return no_wrap(message, count);
\r
9691 int width = get_term_width();
\r
9692 int len = wrap(NULL, message, count, width, &line);
\r
9693 char *msg = malloc(len);
\r
9697 return no_wrap(message, count);
\r
9700 dbgchk = wrap(msg, message, count, width, &line);
\r
9701 if (dbgchk != len && appData.debugMode)
\r
9702 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9703 ConsoleOutput(msg, len, FALSE);
\r
9710 if (ovl.hEvent == NULL) {
\r
9711 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9713 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9715 switch (cp->kind) {
\r
9718 outCount = send(cp->sock, message, count, 0);
\r
9719 if (outCount == SOCKET_ERROR) {
\r
9720 *outError = WSAGetLastError();
\r
9722 *outError = NO_ERROR;
\r
9727 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9728 &dOutCount, NULL)) {
\r
9729 *outError = NO_ERROR;
\r
9730 outCount = (int) dOutCount;
\r
9732 *outError = GetLastError();
\r
9737 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9738 &dOutCount, &ovl);
\r
9739 if (*outError == NO_ERROR) {
\r
9740 outCount = (int) dOutCount;
\r
9750 if(n != 0) Sleep(n);
\r
9754 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9757 /* Ignore delay, not implemented for WinBoard */
\r
9758 return OutputToProcess(pr, message, count, outError);
\r
9763 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9764 char *buf, int count, int error)
\r
9766 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9769 /* see wgamelist.c for Game List functions */
\r
9770 /* see wedittags.c for Edit Tags functions */
\r
9777 char buf[MSG_SIZ];
\r
9780 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9781 f = fopen(buf, "r");
\r
9783 ProcessICSInitScript(f);
\r
9793 StartAnalysisClock()
\r
9795 if (analysisTimerEvent) return;
\r
9796 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9797 (UINT) 2000, NULL);
\r
9801 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9803 highlightInfo.sq[0].x = fromX;
\r
9804 highlightInfo.sq[0].y = fromY;
\r
9805 highlightInfo.sq[1].x = toX;
\r
9806 highlightInfo.sq[1].y = toY;
\r
9812 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9813 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9817 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9819 premoveHighlightInfo.sq[0].x = fromX;
\r
9820 premoveHighlightInfo.sq[0].y = fromY;
\r
9821 premoveHighlightInfo.sq[1].x = toX;
\r
9822 premoveHighlightInfo.sq[1].y = toY;
\r
9826 ClearPremoveHighlights()
\r
9828 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9829 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9833 ShutDownFrontEnd()
\r
9835 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9836 DeleteClipboardTempFiles();
\r
9842 if (IsIconic(hwndMain))
\r
9843 ShowWindow(hwndMain, SW_RESTORE);
\r
9845 SetActiveWindow(hwndMain);
\r
9849 * Prototypes for animation support routines
\r
9851 static void ScreenSquare(int column, int row, POINT * pt);
\r
9852 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9853 POINT frames[], int * nFrames);
\r
9859 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9860 { // [HGM] atomic: animate blast wave
\r
9863 explodeInfo.fromX = fromX;
\r
9864 explodeInfo.fromY = fromY;
\r
9865 explodeInfo.toX = toX;
\r
9866 explodeInfo.toY = toY;
\r
9867 for(i=1; i<4*kFactor; i++) {
\r
9868 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9869 DrawPosition(FALSE, board);
\r
9870 Sleep(appData.animSpeed);
\r
9872 explodeInfo.radius = 0;
\r
9873 DrawPosition(TRUE, board);
\r
9877 AnimateMove(board, fromX, fromY, toX, toY)
\r
9884 ChessSquare piece;
\r
9885 POINT start, finish, mid;
\r
9886 POINT frames[kFactor * 2 + 1];
\r
9889 if (!appData.animate) return;
\r
9890 if (doingSizing) return;
\r
9891 if (fromY < 0 || fromX < 0) return;
\r
9892 piece = board[fromY][fromX];
\r
9893 if (piece >= EmptySquare) return;
\r
9895 ScreenSquare(fromX, fromY, &start);
\r
9896 ScreenSquare(toX, toY, &finish);
\r
9898 /* All moves except knight jumps move in straight line */
\r
9899 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
9900 mid.x = start.x + (finish.x - start.x) / 2;
\r
9901 mid.y = start.y + (finish.y - start.y) / 2;
\r
9903 /* Knight: make straight movement then diagonal */
\r
9904 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9905 mid.x = start.x + (finish.x - start.x) / 2;
\r
9909 mid.y = start.y + (finish.y - start.y) / 2;
\r
9913 /* Don't use as many frames for very short moves */
\r
9914 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9915 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9917 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9919 animInfo.from.x = fromX;
\r
9920 animInfo.from.y = fromY;
\r
9921 animInfo.to.x = toX;
\r
9922 animInfo.to.y = toY;
\r
9923 animInfo.lastpos = start;
\r
9924 animInfo.piece = piece;
\r
9925 for (n = 0; n < nFrames; n++) {
\r
9926 animInfo.pos = frames[n];
\r
9927 DrawPosition(FALSE, NULL);
\r
9928 animInfo.lastpos = animInfo.pos;
\r
9929 Sleep(appData.animSpeed);
\r
9931 animInfo.pos = finish;
\r
9932 DrawPosition(FALSE, NULL);
\r
9933 animInfo.piece = EmptySquare;
\r
9934 Explode(board, fromX, fromY, toX, toY);
\r
9937 /* Convert board position to corner of screen rect and color */
\r
9940 ScreenSquare(column, row, pt)
\r
9941 int column; int row; POINT * pt;
\r
9944 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
9945 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
9947 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
9948 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
9952 /* Generate a series of frame coords from start->mid->finish.
\r
9953 The movement rate doubles until the half way point is
\r
9954 reached, then halves back down to the final destination,
\r
9955 which gives a nice slow in/out effect. The algorithmn
\r
9956 may seem to generate too many intermediates for short
\r
9957 moves, but remember that the purpose is to attract the
\r
9958 viewers attention to the piece about to be moved and
\r
9959 then to where it ends up. Too few frames would be less
\r
9963 Tween(start, mid, finish, factor, frames, nFrames)
\r
9964 POINT * start; POINT * mid;
\r
9965 POINT * finish; int factor;
\r
9966 POINT frames[]; int * nFrames;
\r
9968 int n, fraction = 1, count = 0;
\r
9970 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9971 for (n = 0; n < factor; n++)
\r
9973 for (n = 0; n < factor; n++) {
\r
9974 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9975 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9977 fraction = fraction / 2;
\r
9981 frames[count] = *mid;
\r
9984 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9986 for (n = 0; n < factor; n++) {
\r
9987 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9988 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9990 fraction = fraction * 2;
\r
9996 SettingsPopUp(ChessProgramState *cps)
\r
9997 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
9998 EngineOptionsPopup(savedHwnd, cps);
\r
10001 int flock(int fid, int code)
\r
10003 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10005 ov.hEvent = NULL;
\r
10007 ov.OffsetHigh = 0;
\r
10009 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10010 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10011 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10012 default: return -1;
\r
10021 static char col[8][20];
\r
10022 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10024 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10029 ActivateTheme (int new)
\r
10030 { // Redo initialization of features depending on options that can occur in themes
\r
10032 if(new) InitDrawingColors();
\r
10033 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10034 InitDrawingSizes(-2, 0);
\r
10035 InvalidateRect(hwndMain, NULL, TRUE);
\r