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;
\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 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3371 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3372 SelectObject(tmphdc, hbm);
\r
3377 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3379 int row, column, x, y, square_color, piece_color;
\r
3380 ChessSquare piece;
\r
3382 HDC texture_hdc = NULL;
\r
3384 /* [AS] Initialize background textures if needed */
\r
3385 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3386 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3387 if( backTextureSquareSize != squareSize
\r
3388 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3389 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3390 backTextureSquareSize = squareSize;
\r
3391 RebuildTextureSquareInfo();
\r
3394 texture_hdc = CreateCompatibleDC( hdc );
\r
3397 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3398 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3400 SquareToPos(row, column, &x, &y);
\r
3402 piece = board[row][column];
\r
3404 square_color = ((column + row) % 2) == 1;
\r
3405 if( gameInfo.variant == VariantXiangqi ) {
\r
3406 square_color = !InPalace(row, column);
\r
3407 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3408 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3410 piece_color = (int) piece < (int) BlackPawn;
\r
3413 /* [HGM] holdings file: light square or black */
\r
3414 if(column == BOARD_LEFT-2) {
\r
3415 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3418 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3422 if(column == BOARD_RGHT + 1 ) {
\r
3423 if( row < gameInfo.holdingsSize )
\r
3426 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3430 if(column == BOARD_LEFT-1 ) /* left align */
\r
3431 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3432 else if( column == BOARD_RGHT) /* right align */
\r
3433 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3435 if (appData.monoMode) {
\r
3436 if (piece == EmptySquare) {
\r
3437 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3438 square_color ? WHITENESS : BLACKNESS);
\r
3440 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3443 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3444 /* [AS] Draw the square using a texture bitmap */
\r
3445 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3446 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3447 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3450 squareSize, squareSize,
\r
3453 backTextureSquareInfo[r][c].mode,
\r
3454 backTextureSquareInfo[r][c].x,
\r
3455 backTextureSquareInfo[r][c].y );
\r
3457 SelectObject( texture_hdc, hbm );
\r
3459 if (piece != EmptySquare) {
\r
3460 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3464 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3466 oldBrush = SelectObject(hdc, brush );
\r
3467 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3468 SelectObject(hdc, oldBrush);
\r
3469 if (piece != EmptySquare)
\r
3470 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3475 if( texture_hdc != NULL ) {
\r
3476 DeleteDC( texture_hdc );
\r
3480 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3481 void fputDW(FILE *f, int x)
\r
3483 fputc(x & 255, f);
\r
3484 fputc(x>>8 & 255, f);
\r
3485 fputc(x>>16 & 255, f);
\r
3486 fputc(x>>24 & 255, f);
\r
3489 #define MAX_CLIPS 200 /* more than enough */
\r
3492 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3494 // HBITMAP bufferBitmap;
\r
3499 int w = 100, h = 50;
\r
3501 if(logo == NULL) {
\r
3502 if(!logoHeight) return;
\r
3503 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3505 // GetClientRect(hwndMain, &Rect);
\r
3506 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3507 // Rect.bottom-Rect.top+1);
\r
3508 tmphdc = CreateCompatibleDC(hdc);
\r
3509 hbm = SelectObject(tmphdc, logo);
\r
3510 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3514 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3515 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3516 SelectObject(tmphdc, hbm);
\r
3524 HDC hdc = GetDC(hwndMain);
\r
3525 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3526 if(appData.autoLogo) {
\r
3528 switch(gameMode) { // pick logos based on game mode
\r
3529 case IcsObserving:
\r
3530 whiteLogo = second.programLogo; // ICS logo
\r
3531 blackLogo = second.programLogo;
\r
3534 case IcsPlayingWhite:
\r
3535 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3536 blackLogo = second.programLogo; // ICS logo
\r
3538 case IcsPlayingBlack:
\r
3539 whiteLogo = second.programLogo; // ICS logo
\r
3540 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3542 case TwoMachinesPlay:
\r
3543 if(first.twoMachinesColor[0] == 'b') {
\r
3544 whiteLogo = second.programLogo;
\r
3545 blackLogo = first.programLogo;
\r
3548 case MachinePlaysWhite:
\r
3549 blackLogo = userLogo;
\r
3551 case MachinePlaysBlack:
\r
3552 whiteLogo = userLogo;
\r
3553 blackLogo = first.programLogo;
\r
3556 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3557 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3558 ReleaseDC(hwndMain, hdc);
\r
3563 UpdateLogos(int display)
\r
3564 { // called after loading new engine(s), in tourney or from menu
\r
3565 LoadLogo(&first, 0, FALSE);
\r
3566 LoadLogo(&second, 1, appData.icsActive);
\r
3567 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3568 if(display) DisplayLogos();
\r
3571 static HDC hdcSeek;
\r
3573 // [HGM] seekgraph
\r
3574 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3577 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3578 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3579 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3580 SelectObject( hdcSeek, hp );
\r
3583 // front-end wrapper for drawing functions to do rectangles
\r
3584 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3589 if (hdcSeek == NULL) {
\r
3590 hdcSeek = GetDC(hwndMain);
\r
3591 if (!appData.monoMode) {
\r
3592 SelectPalette(hdcSeek, hPal, FALSE);
\r
3593 RealizePalette(hdcSeek);
\r
3596 hp = SelectObject( hdcSeek, gridPen );
\r
3597 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3598 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3599 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3600 SelectObject( hdcSeek, hp );
\r
3603 // front-end wrapper for putting text in graph
\r
3604 void DrawSeekText(char *buf, int x, int y)
\r
3607 SetBkMode( hdcSeek, TRANSPARENT );
\r
3608 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3609 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3612 void DrawSeekDot(int x, int y, int color)
\r
3614 int square = color & 0x80;
\r
3615 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3616 color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);
\r
3619 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3620 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3622 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3623 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3624 SelectObject(hdcSeek, oldBrush);
\r
3627 void DrawSeekOpen()
\r
3631 void DrawSeekClose()
\r
3636 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3638 static Board lastReq[2], lastDrawn[2];
\r
3639 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3640 static int lastDrawnFlipView = 0;
\r
3641 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3642 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3645 HBITMAP bufferBitmap;
\r
3646 HBITMAP oldBitmap;
\r
3648 HRGN clips[MAX_CLIPS];
\r
3649 ChessSquare dragged_piece = EmptySquare;
\r
3650 int nr = twoBoards*partnerUp;
\r
3652 /* I'm undecided on this - this function figures out whether a full
\r
3653 * repaint is necessary on its own, so there's no real reason to have the
\r
3654 * caller tell it that. I think this can safely be set to FALSE - but
\r
3655 * if we trust the callers not to request full repaints unnessesarily, then
\r
3656 * we could skip some clipping work. In other words, only request a full
\r
3657 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3658 * gamestart and similar) --Hawk
\r
3660 Boolean fullrepaint = repaint;
\r
3662 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3664 if( DrawPositionNeedsFullRepaint() ) {
\r
3665 fullrepaint = TRUE;
\r
3668 if (board == NULL) {
\r
3669 if (!lastReqValid[nr]) {
\r
3672 board = lastReq[nr];
\r
3674 CopyBoard(lastReq[nr], board);
\r
3675 lastReqValid[nr] = 1;
\r
3678 if (doingSizing) {
\r
3682 if (IsIconic(hwndMain)) {
\r
3686 if (hdc == NULL) {
\r
3687 hdc = GetDC(hwndMain);
\r
3688 if (!appData.monoMode) {
\r
3689 SelectPalette(hdc, hPal, FALSE);
\r
3690 RealizePalette(hdc);
\r
3694 releaseDC = FALSE;
\r
3697 /* Create some work-DCs */
\r
3698 hdcmem = CreateCompatibleDC(hdc);
\r
3699 tmphdc = CreateCompatibleDC(hdc);
\r
3701 /* If dragging is in progress, we temporarely remove the piece */
\r
3702 /* [HGM] or temporarily decrease count if stacked */
\r
3703 /* !! Moved to before board compare !! */
\r
3704 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3705 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3706 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3707 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3708 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3710 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3711 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3712 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3714 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3717 /* Figure out which squares need updating by comparing the
\r
3718 * newest board with the last drawn board and checking if
\r
3719 * flipping has changed.
\r
3721 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3722 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3723 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3724 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3725 SquareToPos(row, column, &x, &y);
\r
3726 clips[num_clips++] =
\r
3727 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3731 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3732 for (i=0; i<2; i++) {
\r
3733 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3734 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3735 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3736 lastDrawnHighlight.sq[i].y >= 0) {
\r
3737 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3738 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3739 clips[num_clips++] =
\r
3740 CreateRectRgn(x - lineGap, y - lineGap,
\r
3741 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3743 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3744 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3745 clips[num_clips++] =
\r
3746 CreateRectRgn(x - lineGap, y - lineGap,
\r
3747 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3751 for (i=0; i<2; i++) {
\r
3752 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3753 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3754 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3755 lastDrawnPremove.sq[i].y >= 0) {
\r
3756 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3757 lastDrawnPremove.sq[i].x, &x, &y);
\r
3758 clips[num_clips++] =
\r
3759 CreateRectRgn(x - lineGap, y - lineGap,
\r
3760 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3762 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3763 premoveHighlightInfo.sq[i].y >= 0) {
\r
3764 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3765 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3766 clips[num_clips++] =
\r
3767 CreateRectRgn(x - lineGap, y - lineGap,
\r
3768 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3772 } else { // nr == 1
\r
3773 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3774 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3775 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3776 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3777 for (i=0; i<2; i++) {
\r
3778 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3779 partnerHighlightInfo.sq[i].y >= 0) {
\r
3780 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3781 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3782 clips[num_clips++] =
\r
3783 CreateRectRgn(x - lineGap, y - lineGap,
\r
3784 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3786 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3787 oldPartnerHighlight.sq[i].y >= 0) {
\r
3788 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3789 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3790 clips[num_clips++] =
\r
3791 CreateRectRgn(x - lineGap, y - lineGap,
\r
3792 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3797 fullrepaint = TRUE;
\r
3800 /* Create a buffer bitmap - this is the actual bitmap
\r
3801 * being written to. When all the work is done, we can
\r
3802 * copy it to the real DC (the screen). This avoids
\r
3803 * the problems with flickering.
\r
3805 GetClientRect(hwndMain, &Rect);
\r
3806 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3807 Rect.bottom-Rect.top+1);
\r
3808 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3809 if (!appData.monoMode) {
\r
3810 SelectPalette(hdcmem, hPal, FALSE);
\r
3813 /* Create clips for dragging */
\r
3814 if (!fullrepaint) {
\r
3815 if (dragInfo.from.x >= 0) {
\r
3816 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3817 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3819 if (dragInfo.start.x >= 0) {
\r
3820 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3821 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3823 if (dragInfo.pos.x >= 0) {
\r
3824 x = dragInfo.pos.x - squareSize / 2;
\r
3825 y = dragInfo.pos.y - squareSize / 2;
\r
3826 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3828 if (dragInfo.lastpos.x >= 0) {
\r
3829 x = dragInfo.lastpos.x - squareSize / 2;
\r
3830 y = dragInfo.lastpos.y - squareSize / 2;
\r
3831 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3835 /* Are we animating a move?
\r
3837 * - remove the piece from the board (temporarely)
\r
3838 * - calculate the clipping region
\r
3840 if (!fullrepaint) {
\r
3841 if (animInfo.piece != EmptySquare) {
\r
3842 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3843 x = boardRect.left + animInfo.lastpos.x;
\r
3844 y = boardRect.top + animInfo.lastpos.y;
\r
3845 x2 = boardRect.left + animInfo.pos.x;
\r
3846 y2 = boardRect.top + animInfo.pos.y;
\r
3847 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3848 /* Slight kludge. The real problem is that after AnimateMove is
\r
3849 done, the position on the screen does not match lastDrawn.
\r
3850 This currently causes trouble only on e.p. captures in
\r
3851 atomic, where the piece moves to an empty square and then
\r
3852 explodes. The old and new positions both had an empty square
\r
3853 at the destination, but animation has drawn a piece there and
\r
3854 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3855 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3859 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3860 if (num_clips == 0)
\r
3861 fullrepaint = TRUE;
\r
3863 /* Set clipping on the memory DC */
\r
3864 if (!fullrepaint) {
\r
3865 SelectClipRgn(hdcmem, clips[0]);
\r
3866 for (x = 1; x < num_clips; x++) {
\r
3867 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3868 abort(); // this should never ever happen!
\r
3872 /* Do all the drawing to the memory DC */
\r
3873 if(explodeInfo.radius) { // [HGM] atomic
\r
3875 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3876 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3877 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3878 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3879 x += squareSize/2;
\r
3880 y += squareSize/2;
\r
3881 if(!fullrepaint) {
\r
3882 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3883 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3885 DrawGridOnDC(hdcmem);
\r
3886 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3887 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3888 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3889 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3890 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3891 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3892 SelectObject(hdcmem, oldBrush);
\r
3894 if(border) DrawBackgroundOnDC(hdcmem);
\r
3895 DrawGridOnDC(hdcmem);
\r
3896 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3897 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3898 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3900 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3901 oldPartnerHighlight = partnerHighlightInfo;
\r
3903 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3905 if(nr == 0) // [HGM] dual: markers only on left board
\r
3906 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3907 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3908 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3909 HBRUSH oldBrush = SelectObject(hdcmem,
\r
3910 marker[row][column] == 2 ? markerBrush : explodeBrush);
\r
3911 SquareToPos(row, column, &x, &y);
\r
3912 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3913 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3914 SelectObject(hdcmem, oldBrush);
\r
3919 if( appData.highlightMoveWithArrow ) {
\r
3920 DrawArrowHighlight(hdcmem);
\r
3923 DrawCoordsOnDC(hdcmem);
\r
3925 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
3926 /* to make sure lastDrawn contains what is actually drawn */
\r
3928 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3929 if (dragged_piece != EmptySquare) {
\r
3930 /* [HGM] or restack */
\r
3931 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3932 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3934 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3935 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3936 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3937 x = dragInfo.pos.x - squareSize / 2;
\r
3938 y = dragInfo.pos.y - squareSize / 2;
\r
3939 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
3940 ((int) dragInfo.piece < (int) BlackPawn),
\r
3941 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3944 /* Put the animated piece back into place and draw it */
\r
3945 if (animInfo.piece != EmptySquare) {
\r
3946 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3947 x = boardRect.left + animInfo.pos.x;
\r
3948 y = boardRect.top + animInfo.pos.y;
\r
3949 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3950 ((int) animInfo.piece < (int) BlackPawn),
\r
3951 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3954 /* Release the bufferBitmap by selecting in the old bitmap
\r
3955 * and delete the memory DC
\r
3957 SelectObject(hdcmem, oldBitmap);
\r
3960 /* Set clipping on the target DC */
\r
3961 if (!fullrepaint) {
\r
3962 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
3964 GetRgnBox(clips[x], &rect);
\r
3965 DeleteObject(clips[x]);
\r
3966 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
3967 rect.right + wpMain.width/2, rect.bottom);
\r
3969 SelectClipRgn(hdc, clips[0]);
\r
3970 for (x = 1; x < num_clips; x++) {
\r
3971 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3972 abort(); // this should never ever happen!
\r
3976 /* Copy the new bitmap onto the screen in one go.
\r
3977 * This way we avoid any flickering
\r
3979 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3980 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
3981 boardRect.right - boardRect.left,
\r
3982 boardRect.bottom - boardRect.top,
\r
3983 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3984 if(saveDiagFlag) {
\r
3985 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
3986 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
3988 GetObject(bufferBitmap, sizeof(b), &b);
\r
3989 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
3990 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
3991 bih.biWidth = b.bmWidth;
\r
3992 bih.biHeight = b.bmHeight;
\r
3994 bih.biBitCount = b.bmBitsPixel;
\r
3995 bih.biCompression = 0;
\r
3996 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
3997 bih.biXPelsPerMeter = 0;
\r
3998 bih.biYPelsPerMeter = 0;
\r
3999 bih.biClrUsed = 0;
\r
4000 bih.biClrImportant = 0;
\r
4001 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4002 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4003 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4004 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4006 wb = b.bmWidthBytes;
\r
4008 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4009 int k = ((int*) pData)[i];
\r
4010 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4011 if(j >= 16) break;
\r
4013 if(j >= nrColors) nrColors = j+1;
\r
4015 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4017 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4018 for(w=0; w<(wb>>2); w+=2) {
\r
4019 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4020 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4021 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4022 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4023 pData[p++] = m | j<<4;
\r
4025 while(p&3) pData[p++] = 0;
\r
4028 wb = ((wb+31)>>5)<<2;
\r
4030 // write BITMAPFILEHEADER
\r
4031 fprintf(diagFile, "BM");
\r
4032 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4033 fputDW(diagFile, 0);
\r
4034 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4035 // write BITMAPINFOHEADER
\r
4036 fputDW(diagFile, 40);
\r
4037 fputDW(diagFile, b.bmWidth);
\r
4038 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4039 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4040 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4041 fputDW(diagFile, 0);
\r
4042 fputDW(diagFile, 0);
\r
4043 fputDW(diagFile, 0);
\r
4044 fputDW(diagFile, 0);
\r
4045 fputDW(diagFile, 0);
\r
4046 fputDW(diagFile, 0);
\r
4047 // write color table
\r
4049 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4050 // write bitmap data
\r
4051 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4052 fputc(pData[i], diagFile);
\r
4057 SelectObject(tmphdc, oldBitmap);
\r
4059 /* Massive cleanup */
\r
4060 for (x = 0; x < num_clips; x++)
\r
4061 DeleteObject(clips[x]);
\r
4064 DeleteObject(bufferBitmap);
\r
4067 ReleaseDC(hwndMain, hdc);
\r
4069 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4071 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4073 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4076 /* CopyBoard(lastDrawn, board);*/
\r
4077 lastDrawnHighlight = highlightInfo;
\r
4078 lastDrawnPremove = premoveHighlightInfo;
\r
4079 lastDrawnFlipView = flipView;
\r
4080 lastDrawnValid[nr] = 1;
\r
4083 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4088 saveDiagFlag = 1; diagFile = f;
\r
4089 HDCDrawPosition(NULL, TRUE, NULL);
\r
4097 /*---------------------------------------------------------------------------*\
\r
4098 | CLIENT PAINT PROCEDURE
\r
4099 | This is the main event-handler for the WM_PAINT message.
\r
4101 \*---------------------------------------------------------------------------*/
\r
4103 PaintProc(HWND hwnd)
\r
4109 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4110 if (IsIconic(hwnd)) {
\r
4111 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4113 if (!appData.monoMode) {
\r
4114 SelectPalette(hdc, hPal, FALSE);
\r
4115 RealizePalette(hdc);
\r
4117 HDCDrawPosition(hdc, 1, NULL);
\r
4118 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4119 flipView = !flipView; partnerUp = !partnerUp;
\r
4120 HDCDrawPosition(hdc, 1, NULL);
\r
4121 flipView = !flipView; partnerUp = !partnerUp;
\r
4124 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4125 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4126 ETO_CLIPPED|ETO_OPAQUE,
\r
4127 &messageRect, messageText, strlen(messageText), NULL);
\r
4128 SelectObject(hdc, oldFont);
\r
4129 DisplayBothClocks();
\r
4132 EndPaint(hwnd,&ps);
\r
4140 * If the user selects on a border boundary, return -1; if off the board,
\r
4141 * return -2. Otherwise map the event coordinate to the square.
\r
4142 * The offset boardRect.left or boardRect.top must already have been
\r
4143 * subtracted from x.
\r
4145 int EventToSquare(x, limit)
\r
4150 if (x < lineGap + border)
\r
4152 x -= lineGap + border;
\r
4153 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4155 x /= (squareSize + lineGap);
\r
4167 DropEnable dropEnables[] = {
\r
4168 { 'P', DP_Pawn, N_("Pawn") },
\r
4169 { 'N', DP_Knight, N_("Knight") },
\r
4170 { 'B', DP_Bishop, N_("Bishop") },
\r
4171 { 'R', DP_Rook, N_("Rook") },
\r
4172 { 'Q', DP_Queen, N_("Queen") },
\r
4176 SetupDropMenu(HMENU hmenu)
\r
4178 int i, count, enable;
\r
4180 extern char white_holding[], black_holding[];
\r
4181 char item[MSG_SIZ];
\r
4183 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4184 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4185 dropEnables[i].piece);
\r
4187 while (p && *p++ == dropEnables[i].piece) count++;
\r
4188 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4189 enable = count > 0 || !appData.testLegality
\r
4190 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4191 && !appData.icsActive);
\r
4192 ModifyMenu(hmenu, dropEnables[i].command,
\r
4193 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4194 dropEnables[i].command, item);
\r
4198 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4200 dragInfo.lastpos.x = boardRect.left + x;
\r
4201 dragInfo.lastpos.y = boardRect.top + y;
\r
4202 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4203 dragInfo.from.x = fromX;
\r
4204 dragInfo.from.y = fromY;
\r
4205 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4206 dragInfo.start = dragInfo.from;
\r
4207 SetCapture(hwndMain);
\r
4210 void DragPieceEnd(int x, int y)
\r
4213 dragInfo.start.x = dragInfo.start.y = -1;
\r
4214 dragInfo.from = dragInfo.start;
\r
4215 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4218 void ChangeDragPiece(ChessSquare piece)
\r
4220 dragInfo.piece = piece;
\r
4223 /* Event handler for mouse messages */
\r
4225 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4229 static int recursive = 0;
\r
4231 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4234 if (message == WM_MBUTTONUP) {
\r
4235 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4236 to the middle button: we simulate pressing the left button too!
\r
4238 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4239 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4245 pt.x = LOWORD(lParam);
\r
4246 pt.y = HIWORD(lParam);
\r
4247 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4248 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4249 if (!flipView && y >= 0) {
\r
4250 y = BOARD_HEIGHT - 1 - y;
\r
4252 if (flipView && x >= 0) {
\r
4253 x = BOARD_WIDTH - 1 - x;
\r
4256 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4258 switch (message) {
\r
4259 case WM_LBUTTONDOWN:
\r
4260 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4261 ClockClick(flipClock); break;
\r
4262 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4263 ClockClick(!flipClock); break;
\r
4265 dragInfo.start.x = dragInfo.start.y = -1;
\r
4266 dragInfo.from = dragInfo.start;
\r
4267 if(fromX == -1 && frozen) { // not sure where this is for
\r
4268 fromX = fromY = -1;
\r
4269 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4272 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4273 DrawPosition(TRUE, NULL);
\r
4276 case WM_LBUTTONUP:
\r
4277 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4278 DrawPosition(TRUE, NULL);
\r
4281 case WM_MOUSEMOVE:
\r
4282 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4283 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4284 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4285 if ((appData.animateDragging || appData.highlightDragging)
\r
4286 && (wParam & MK_LBUTTON)
\r
4287 && dragInfo.from.x >= 0)
\r
4289 BOOL full_repaint = FALSE;
\r
4291 if (appData.animateDragging) {
\r
4292 dragInfo.pos = pt;
\r
4294 if (appData.highlightDragging) {
\r
4295 SetHighlights(fromX, fromY, x, y);
\r
4296 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4297 full_repaint = TRUE;
\r
4301 DrawPosition( full_repaint, NULL);
\r
4303 dragInfo.lastpos = dragInfo.pos;
\r
4307 case WM_MOUSEWHEEL: // [DM]
\r
4308 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4309 /* Mouse Wheel is being rolled forward
\r
4310 * Play moves forward
\r
4312 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4313 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4314 /* Mouse Wheel is being rolled backward
\r
4315 * Play moves backward
\r
4317 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4318 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4322 case WM_MBUTTONUP:
\r
4323 case WM_RBUTTONUP:
\r
4325 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4328 case WM_MBUTTONDOWN:
\r
4329 case WM_RBUTTONDOWN:
\r
4332 fromX = fromY = -1;
\r
4333 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4334 dragInfo.start.x = dragInfo.start.y = -1;
\r
4335 dragInfo.from = dragInfo.start;
\r
4336 dragInfo.lastpos = dragInfo.pos;
\r
4337 if (appData.highlightDragging) {
\r
4338 ClearHighlights();
\r
4341 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4342 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4343 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4344 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4345 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4349 DrawPosition(TRUE, NULL);
\r
4351 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4354 if (message == WM_MBUTTONDOWN) {
\r
4355 buttonCount = 3; /* even if system didn't think so */
\r
4356 if (wParam & MK_SHIFT)
\r
4357 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4359 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4360 } else { /* message == WM_RBUTTONDOWN */
\r
4361 /* Just have one menu, on the right button. Windows users don't
\r
4362 think to try the middle one, and sometimes other software steals
\r
4363 it, or it doesn't really exist. */
\r
4364 if(gameInfo.variant != VariantShogi)
\r
4365 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4367 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4371 SetCapture(hwndMain);
\r
4374 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4375 SetupDropMenu(hmenu);
\r
4376 MenuPopup(hwnd, pt, hmenu, -1);
\r
4386 /* Preprocess messages for buttons in main window */
\r
4388 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4390 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4393 for (i=0; i<N_BUTTONS; i++) {
\r
4394 if (buttonDesc[i].id == id) break;
\r
4396 if (i == N_BUTTONS) return 0;
\r
4397 switch (message) {
\r
4402 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4403 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4410 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4413 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4414 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4415 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4416 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4418 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4420 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4421 TypeInEvent((char)wParam);
\r
4427 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4430 /* Process messages for Promotion dialog box */
\r
4432 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4436 switch (message) {
\r
4437 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4438 /* Center the dialog over the application window */
\r
4439 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4440 Translate(hDlg, DLG_PromotionKing);
\r
4441 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4442 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4443 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4444 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4445 SW_SHOW : SW_HIDE);
\r
4446 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4447 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4448 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4449 PieceToChar(WhiteAngel) != '~') ||
\r
4450 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4451 PieceToChar(BlackAngel) != '~') ) ?
\r
4452 SW_SHOW : SW_HIDE);
\r
4453 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4454 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4455 PieceToChar(WhiteMarshall) != '~') ||
\r
4456 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4457 PieceToChar(BlackMarshall) != '~') ) ?
\r
4458 SW_SHOW : SW_HIDE);
\r
4459 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4460 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4461 gameInfo.variant != VariantShogi ?
\r
4462 SW_SHOW : SW_HIDE);
\r
4463 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4464 gameInfo.variant != VariantShogi ?
\r
4465 SW_SHOW : SW_HIDE);
\r
4466 if(gameInfo.variant == VariantShogi) {
\r
4467 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4468 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4469 SetWindowText(hDlg, "Promote?");
\r
4471 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4472 gameInfo.variant == VariantSuper ?
\r
4473 SW_SHOW : SW_HIDE);
\r
4476 case WM_COMMAND: /* message: received a command */
\r
4477 switch (LOWORD(wParam)) {
\r
4479 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4480 ClearHighlights();
\r
4481 DrawPosition(FALSE, NULL);
\r
4484 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4487 promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4490 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4491 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4494 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4495 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4497 case PB_Chancellor:
\r
4498 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4500 case PB_Archbishop:
\r
4501 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4504 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);
\r
4509 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4510 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4511 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4512 fromX = fromY = -1;
\r
4513 if (!appData.highlightLastMove) {
\r
4514 ClearHighlights();
\r
4515 DrawPosition(FALSE, NULL);
\r
4522 /* Pop up promotion dialog */
\r
4524 PromotionPopup(HWND hwnd)
\r
4528 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4529 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4530 hwnd, (DLGPROC)lpProc);
\r
4531 FreeProcInstance(lpProc);
\r
4537 DrawPosition(TRUE, NULL);
\r
4538 PromotionPopup(hwndMain);
\r
4542 LoadGameDialog(HWND hwnd, char* title)
\r
4546 char fileTitle[MSG_SIZ];
\r
4547 f = OpenFileDialog(hwnd, "rb", "",
\r
4548 appData.oldSaveStyle ? "gam" : "pgn",
\r
4550 title, &number, fileTitle, NULL);
\r
4552 cmailMsgLoaded = FALSE;
\r
4553 if (number == 0) {
\r
4554 int error = GameListBuild(f);
\r
4556 DisplayError(_("Cannot build game list"), error);
\r
4557 } else if (!ListEmpty(&gameList) &&
\r
4558 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4559 GameListPopUp(f, fileTitle);
\r
4562 GameListDestroy();
\r
4565 LoadGame(f, number, fileTitle, FALSE);
\r
4569 int get_term_width()
\r
4574 HFONT hfont, hold_font;
\r
4579 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4583 // get the text metrics
\r
4584 hdc = GetDC(hText);
\r
4585 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4586 if (consoleCF.dwEffects & CFE_BOLD)
\r
4587 lf.lfWeight = FW_BOLD;
\r
4588 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4589 lf.lfItalic = TRUE;
\r
4590 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4591 lf.lfStrikeOut = TRUE;
\r
4592 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4593 lf.lfUnderline = TRUE;
\r
4594 hfont = CreateFontIndirect(&lf);
\r
4595 hold_font = SelectObject(hdc, hfont);
\r
4596 GetTextMetrics(hdc, &tm);
\r
4597 SelectObject(hdc, hold_font);
\r
4598 DeleteObject(hfont);
\r
4599 ReleaseDC(hText, hdc);
\r
4601 // get the rectangle
\r
4602 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4604 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4607 void UpdateICSWidth(HWND hText)
\r
4609 LONG old_width, new_width;
\r
4611 new_width = get_term_width(hText, FALSE);
\r
4612 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4613 if (new_width != old_width)
\r
4615 ics_update_width(new_width);
\r
4616 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4621 ChangedConsoleFont()
\r
4624 CHARRANGE tmpsel, sel;
\r
4625 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4626 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4627 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4630 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4631 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4632 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4633 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4634 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4635 * size. This was undocumented in the version of MSVC++ that I had
\r
4636 * when I wrote the code, but is apparently documented now.
\r
4638 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4639 cfmt.bCharSet = f->lf.lfCharSet;
\r
4640 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4641 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4642 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4643 /* Why are the following seemingly needed too? */
\r
4644 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4645 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4646 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4648 tmpsel.cpMax = -1; /*999999?*/
\r
4649 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4650 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4651 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4652 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4654 paraf.cbSize = sizeof(paraf);
\r
4655 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4656 paraf.dxStartIndent = 0;
\r
4657 paraf.dxOffset = WRAP_INDENT;
\r
4658 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4659 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4660 UpdateICSWidth(hText);
\r
4663 /*---------------------------------------------------------------------------*\
\r
4665 * Window Proc for main window
\r
4667 \*---------------------------------------------------------------------------*/
\r
4669 /* Process messages for main window, etc. */
\r
4671 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4674 int wmId, wmEvent;
\r
4678 char fileTitle[MSG_SIZ];
\r
4679 char buf[MSG_SIZ];
\r
4680 static SnapData sd;
\r
4681 static int peek=0;
\r
4683 switch (message) {
\r
4685 case WM_PAINT: /* message: repaint portion of window */
\r
4689 case WM_ERASEBKGND:
\r
4690 if (IsIconic(hwnd)) {
\r
4691 /* Cheat; change the message */
\r
4692 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4694 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4698 case WM_LBUTTONDOWN:
\r
4699 case WM_MBUTTONDOWN:
\r
4700 case WM_RBUTTONDOWN:
\r
4701 case WM_LBUTTONUP:
\r
4702 case WM_MBUTTONUP:
\r
4703 case WM_RBUTTONUP:
\r
4704 case WM_MOUSEMOVE:
\r
4705 case WM_MOUSEWHEEL:
\r
4706 MouseEvent(hwnd, message, wParam, lParam);
\r
4710 if((char)wParam == '\b') {
\r
4711 ForwardEvent(); peek = 0;
\r
4714 JAWS_KBUP_NAVIGATION
\r
4719 if((char)wParam == '\b') {
\r
4720 if(!peek) BackwardEvent(), peek = 1;
\r
4723 JAWS_KBDOWN_NAVIGATION
\r
4729 JAWS_ALT_INTERCEPT
\r
4731 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4732 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4733 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4734 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4736 SendMessage(h, message, wParam, lParam);
\r
4737 } else if(lParam != KF_REPEAT) {
\r
4738 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4739 TypeInEvent((char)wParam);
\r
4740 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4741 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4746 case WM_PALETTECHANGED:
\r
4747 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4749 HDC hdc = GetDC(hwndMain);
\r
4750 SelectPalette(hdc, hPal, TRUE);
\r
4751 nnew = RealizePalette(hdc);
\r
4753 paletteChanged = TRUE;
\r
4754 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4756 ReleaseDC(hwnd, hdc);
\r
4760 case WM_QUERYNEWPALETTE:
\r
4761 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4763 HDC hdc = GetDC(hwndMain);
\r
4764 paletteChanged = FALSE;
\r
4765 SelectPalette(hdc, hPal, FALSE);
\r
4766 nnew = RealizePalette(hdc);
\r
4768 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4770 ReleaseDC(hwnd, hdc);
\r
4775 case WM_COMMAND: /* message: command from application menu */
\r
4776 wmId = LOWORD(wParam);
\r
4777 wmEvent = HIWORD(wParam);
\r
4782 SAY("new game enter a move to play against the computer with white");
\r
4785 case IDM_NewGameFRC:
\r
4786 if( NewGameFRC() == 0 ) {
\r
4791 case IDM_NewVariant:
\r
4792 NewVariantPopup(hwnd);
\r
4795 case IDM_LoadGame:
\r
4796 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4799 case IDM_LoadNextGame:
\r
4803 case IDM_LoadPrevGame:
\r
4807 case IDM_ReloadGame:
\r
4811 case IDM_LoadPosition:
\r
4812 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4813 Reset(FALSE, TRUE);
\r
4816 f = OpenFileDialog(hwnd, "rb", "",
\r
4817 appData.oldSaveStyle ? "pos" : "fen",
\r
4819 _("Load Position from File"), &number, fileTitle, NULL);
\r
4821 LoadPosition(f, number, fileTitle);
\r
4825 case IDM_LoadNextPosition:
\r
4826 ReloadPosition(1);
\r
4829 case IDM_LoadPrevPosition:
\r
4830 ReloadPosition(-1);
\r
4833 case IDM_ReloadPosition:
\r
4834 ReloadPosition(0);
\r
4837 case IDM_SaveGame:
\r
4838 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4839 f = OpenFileDialog(hwnd, "a", defName,
\r
4840 appData.oldSaveStyle ? "gam" : "pgn",
\r
4842 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4844 SaveGame(f, 0, "");
\r
4848 case IDM_SavePosition:
\r
4849 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4850 f = OpenFileDialog(hwnd, "a", defName,
\r
4851 appData.oldSaveStyle ? "pos" : "fen",
\r
4853 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4855 SavePosition(f, 0, "");
\r
4859 case IDM_SaveDiagram:
\r
4860 defName = "diagram";
\r
4861 f = OpenFileDialog(hwnd, "wb", defName,
\r
4864 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4870 case IDM_CreateBook:
\r
4871 CreateBookEvent();
\r
4874 case IDM_CopyGame:
\r
4875 CopyGameToClipboard();
\r
4878 case IDM_PasteGame:
\r
4879 PasteGameFromClipboard();
\r
4882 case IDM_CopyGameListToClipboard:
\r
4883 CopyGameListToClipboard();
\r
4886 /* [AS] Autodetect FEN or PGN data */
\r
4887 case IDM_PasteAny:
\r
4888 PasteGameOrFENFromClipboard();
\r
4891 /* [AS] Move history */
\r
4892 case IDM_ShowMoveHistory:
\r
4893 if( MoveHistoryIsUp() ) {
\r
4894 MoveHistoryPopDown();
\r
4897 MoveHistoryPopUp();
\r
4901 /* [AS] Eval graph */
\r
4902 case IDM_ShowEvalGraph:
\r
4903 if( EvalGraphIsUp() ) {
\r
4904 EvalGraphPopDown();
\r
4908 SetFocus(hwndMain);
\r
4912 /* [AS] Engine output */
\r
4913 case IDM_ShowEngineOutput:
\r
4914 if( EngineOutputIsUp() ) {
\r
4915 EngineOutputPopDown();
\r
4918 EngineOutputPopUp();
\r
4922 /* [AS] User adjudication */
\r
4923 case IDM_UserAdjudication_White:
\r
4924 UserAdjudicationEvent( +1 );
\r
4927 case IDM_UserAdjudication_Black:
\r
4928 UserAdjudicationEvent( -1 );
\r
4931 case IDM_UserAdjudication_Draw:
\r
4932 UserAdjudicationEvent( 0 );
\r
4935 /* [AS] Game list options dialog */
\r
4936 case IDM_GameListOptions:
\r
4937 GameListOptions();
\r
4944 case IDM_CopyPosition:
\r
4945 CopyFENToClipboard();
\r
4948 case IDM_PastePosition:
\r
4949 PasteFENFromClipboard();
\r
4952 case IDM_MailMove:
\r
4956 case IDM_ReloadCMailMsg:
\r
4957 Reset(TRUE, TRUE);
\r
4958 ReloadCmailMsgEvent(FALSE);
\r
4961 case IDM_Minimize:
\r
4962 ShowWindow(hwnd, SW_MINIMIZE);
\r
4969 case IDM_MachineWhite:
\r
4970 MachineWhiteEvent();
\r
4972 * refresh the tags dialog only if it's visible
\r
4974 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4976 tags = PGNTags(&gameInfo);
\r
4977 TagsPopUp(tags, CmailMsg());
\r
4980 SAY("computer starts playing white");
\r
4983 case IDM_MachineBlack:
\r
4984 MachineBlackEvent();
\r
4986 * refresh the tags dialog only if it's visible
\r
4988 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4990 tags = PGNTags(&gameInfo);
\r
4991 TagsPopUp(tags, CmailMsg());
\r
4994 SAY("computer starts playing black");
\r
4997 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
4998 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5001 case IDM_TwoMachines:
\r
5002 TwoMachinesEvent();
\r
5004 * refresh the tags dialog only if it's visible
\r
5006 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5008 tags = PGNTags(&gameInfo);
\r
5009 TagsPopUp(tags, CmailMsg());
\r
5012 SAY("computer starts playing both sides");
\r
5015 case IDM_AnalysisMode:
\r
5016 if(AnalyzeModeEvent()) {
\r
5017 SAY("analyzing current position");
\r
5021 case IDM_AnalyzeFile:
\r
5022 AnalyzeFileEvent();
\r
5025 case IDM_IcsClient:
\r
5029 case IDM_EditGame:
\r
5030 case IDM_EditGame2:
\r
5035 case IDM_EditPosition:
\r
5036 case IDM_EditPosition2:
\r
5037 EditPositionEvent();
\r
5038 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5041 case IDM_Training:
\r
5045 case IDM_ShowGameList:
\r
5046 ShowGameListProc();
\r
5049 case IDM_EditProgs1:
\r
5050 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5053 case IDM_LoadProg1:
\r
5054 LoadEnginePopUp(hwndMain, 0);
\r
5057 case IDM_LoadProg2:
\r
5058 LoadEnginePopUp(hwndMain, 1);
\r
5061 case IDM_EditServers:
\r
5062 EditTagsPopUp(icsNames, &icsNames);
\r
5065 case IDM_EditTags:
\r
5070 case IDM_EditBook:
\r
5074 case IDM_EditComment:
\r
5076 if (commentUp && editComment) {
\r
5079 EditCommentEvent();
\r
5099 case IDM_CallFlag:
\r
5119 case IDM_StopObserving:
\r
5120 StopObservingEvent();
\r
5123 case IDM_StopExamining:
\r
5124 StopExaminingEvent();
\r
5128 UploadGameEvent();
\r
5131 case IDM_TypeInMove:
\r
5132 TypeInEvent('\000');
\r
5135 case IDM_TypeInName:
\r
5136 PopUpNameDialog('\000');
\r
5139 case IDM_Backward:
\r
5141 SetFocus(hwndMain);
\r
5148 SetFocus(hwndMain);
\r
5153 SetFocus(hwndMain);
\r
5158 SetFocus(hwndMain);
\r
5161 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5162 case OPT_GameListPrev:
\r
5163 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5167 RevertEvent(FALSE);
\r
5170 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5171 RevertEvent(TRUE);
\r
5174 case IDM_TruncateGame:
\r
5175 TruncateGameEvent();
\r
5182 case IDM_RetractMove:
\r
5183 RetractMoveEvent();
\r
5186 case IDM_FlipView:
\r
5187 flipView = !flipView;
\r
5188 DrawPosition(FALSE, NULL);
\r
5191 case IDM_FlipClock:
\r
5192 flipClock = !flipClock;
\r
5193 DisplayBothClocks();
\r
5197 case IDM_MuteSounds:
\r
5198 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5199 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5200 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5203 case IDM_GeneralOptions:
\r
5204 GeneralOptionsPopup(hwnd);
\r
5205 DrawPosition(TRUE, NULL);
\r
5208 case IDM_BoardOptions:
\r
5209 BoardOptionsPopup(hwnd);
\r
5212 case IDM_ThemeOptions:
\r
5213 ThemeOptionsPopup(hwnd);
\r
5216 case IDM_EnginePlayOptions:
\r
5217 EnginePlayOptionsPopup(hwnd);
\r
5220 case IDM_Engine1Options:
\r
5221 EngineOptionsPopup(hwnd, &first);
\r
5224 case IDM_Engine2Options:
\r
5226 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5227 EngineOptionsPopup(hwnd, &second);
\r
5230 case IDM_OptionsUCI:
\r
5231 UciOptionsPopup(hwnd);
\r
5235 TourneyPopup(hwnd);
\r
5238 case IDM_IcsOptions:
\r
5239 IcsOptionsPopup(hwnd);
\r
5243 FontsOptionsPopup(hwnd);
\r
5247 SoundOptionsPopup(hwnd);
\r
5250 case IDM_CommPort:
\r
5251 CommPortOptionsPopup(hwnd);
\r
5254 case IDM_LoadOptions:
\r
5255 LoadOptionsPopup(hwnd);
\r
5258 case IDM_SaveOptions:
\r
5259 SaveOptionsPopup(hwnd);
\r
5262 case IDM_TimeControl:
\r
5263 TimeControlOptionsPopup(hwnd);
\r
5266 case IDM_SaveSettings:
\r
5267 SaveSettings(settingsFileName);
\r
5270 case IDM_SaveSettingsOnExit:
\r
5271 saveSettingsOnExit = !saveSettingsOnExit;
\r
5272 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5273 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5274 MF_CHECKED : MF_UNCHECKED));
\r
5285 case IDM_AboutGame:
\r
5290 appData.debugMode = !appData.debugMode;
\r
5291 if (appData.debugMode) {
\r
5292 char dir[MSG_SIZ];
\r
5293 GetCurrentDirectory(MSG_SIZ, dir);
\r
5294 SetCurrentDirectory(installDir);
\r
5295 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5296 SetCurrentDirectory(dir);
\r
5297 setbuf(debugFP, NULL);
\r
5304 case IDM_HELPCONTENTS:
\r
5305 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5306 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5307 MessageBox (GetFocus(),
\r
5308 _("Unable to activate help"),
\r
5309 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5313 case IDM_HELPSEARCH:
\r
5314 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5315 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5316 MessageBox (GetFocus(),
\r
5317 _("Unable to activate help"),
\r
5318 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5322 case IDM_HELPHELP:
\r
5323 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5324 MessageBox (GetFocus(),
\r
5325 _("Unable to activate help"),
\r
5326 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5331 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5333 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5334 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5335 FreeProcInstance(lpProc);
\r
5338 case IDM_DirectCommand1:
\r
5339 AskQuestionEvent(_("Direct Command"),
\r
5340 _("Send to chess program:"), "", "1");
\r
5342 case IDM_DirectCommand2:
\r
5343 AskQuestionEvent(_("Direct Command"),
\r
5344 _("Send to second chess program:"), "", "2");
\r
5347 case EP_WhitePawn:
\r
5348 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5349 fromX = fromY = -1;
\r
5352 case EP_WhiteKnight:
\r
5353 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5354 fromX = fromY = -1;
\r
5357 case EP_WhiteBishop:
\r
5358 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5359 fromX = fromY = -1;
\r
5362 case EP_WhiteRook:
\r
5363 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5364 fromX = fromY = -1;
\r
5367 case EP_WhiteQueen:
\r
5368 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5369 fromX = fromY = -1;
\r
5372 case EP_WhiteFerz:
\r
5373 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5374 fromX = fromY = -1;
\r
5377 case EP_WhiteWazir:
\r
5378 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5379 fromX = fromY = -1;
\r
5382 case EP_WhiteAlfil:
\r
5383 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5384 fromX = fromY = -1;
\r
5387 case EP_WhiteCannon:
\r
5388 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5389 fromX = fromY = -1;
\r
5392 case EP_WhiteCardinal:
\r
5393 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5394 fromX = fromY = -1;
\r
5397 case EP_WhiteMarshall:
\r
5398 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5399 fromX = fromY = -1;
\r
5402 case EP_WhiteKing:
\r
5403 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5404 fromX = fromY = -1;
\r
5407 case EP_BlackPawn:
\r
5408 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5409 fromX = fromY = -1;
\r
5412 case EP_BlackKnight:
\r
5413 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5414 fromX = fromY = -1;
\r
5417 case EP_BlackBishop:
\r
5418 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5419 fromX = fromY = -1;
\r
5422 case EP_BlackRook:
\r
5423 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5424 fromX = fromY = -1;
\r
5427 case EP_BlackQueen:
\r
5428 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5429 fromX = fromY = -1;
\r
5432 case EP_BlackFerz:
\r
5433 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5434 fromX = fromY = -1;
\r
5437 case EP_BlackWazir:
\r
5438 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5439 fromX = fromY = -1;
\r
5442 case EP_BlackAlfil:
\r
5443 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5444 fromX = fromY = -1;
\r
5447 case EP_BlackCannon:
\r
5448 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5449 fromX = fromY = -1;
\r
5452 case EP_BlackCardinal:
\r
5453 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5454 fromX = fromY = -1;
\r
5457 case EP_BlackMarshall:
\r
5458 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5459 fromX = fromY = -1;
\r
5462 case EP_BlackKing:
\r
5463 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5464 fromX = fromY = -1;
\r
5467 case EP_EmptySquare:
\r
5468 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5469 fromX = fromY = -1;
\r
5472 case EP_ClearBoard:
\r
5473 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5474 fromX = fromY = -1;
\r
5478 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5479 fromX = fromY = -1;
\r
5483 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5484 fromX = fromY = -1;
\r
5488 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5489 fromX = fromY = -1;
\r
5493 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5494 fromX = fromY = -1;
\r
5498 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5499 fromX = fromY = -1;
\r
5503 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5504 fromX = fromY = -1;
\r
5508 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5509 fromX = fromY = -1;
\r
5513 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5514 fromX = fromY = -1;
\r
5518 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5519 fromX = fromY = -1;
\r
5523 barbaric = 0; appData.language = "";
\r
5524 TranslateMenus(0);
\r
5525 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5526 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5527 lastChecked = wmId;
\r
5531 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5532 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5534 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5535 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5536 TranslateMenus(0);
\r
5537 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5538 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5539 lastChecked = wmId;
\r
5542 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5548 case CLOCK_TIMER_ID:
\r
5549 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5550 clockTimerEvent = 0;
\r
5551 DecrementClocks(); /* call into back end */
\r
5553 case LOAD_GAME_TIMER_ID:
\r
5554 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5555 loadGameTimerEvent = 0;
\r
5556 AutoPlayGameLoop(); /* call into back end */
\r
5558 case ANALYSIS_TIMER_ID:
\r
5559 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5560 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5561 AnalysisPeriodicEvent(0);
\r
5563 KillTimer(hwnd, analysisTimerEvent);
\r
5564 analysisTimerEvent = 0;
\r
5567 case DELAYED_TIMER_ID:
\r
5568 KillTimer(hwnd, delayedTimerEvent);
\r
5569 delayedTimerEvent = 0;
\r
5570 delayedTimerCallback();
\r
5575 case WM_USER_Input:
\r
5576 InputEvent(hwnd, message, wParam, lParam);
\r
5579 /* [AS] Also move "attached" child windows */
\r
5580 case WM_WINDOWPOSCHANGING:
\r
5582 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5583 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5585 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5586 /* Window is moving */
\r
5589 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5590 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5591 rcMain.right = wpMain.x + wpMain.width;
\r
5592 rcMain.top = wpMain.y;
\r
5593 rcMain.bottom = wpMain.y + wpMain.height;
\r
5595 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5596 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5597 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5598 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5599 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5600 wpMain.x = lpwp->x;
\r
5601 wpMain.y = lpwp->y;
\r
5606 /* [AS] Snapping */
\r
5607 case WM_ENTERSIZEMOVE:
\r
5608 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5609 if (hwnd == hwndMain) {
\r
5610 doingSizing = TRUE;
\r
5613 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5617 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5618 if (hwnd == hwndMain) {
\r
5619 lastSizing = wParam;
\r
5624 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5625 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5627 case WM_EXITSIZEMOVE:
\r
5628 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5629 if (hwnd == hwndMain) {
\r
5631 doingSizing = FALSE;
\r
5632 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5633 GetClientRect(hwnd, &client);
\r
5634 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5636 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5638 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5641 case WM_DESTROY: /* message: window being destroyed */
\r
5642 PostQuitMessage(0);
\r
5646 if (hwnd == hwndMain) {
\r
5651 default: /* Passes it on if unprocessed */
\r
5652 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5657 /*---------------------------------------------------------------------------*\
\r
5659 * Misc utility routines
\r
5661 \*---------------------------------------------------------------------------*/
\r
5664 * Decent random number generator, at least not as bad as Windows
\r
5665 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5667 unsigned int randstate;
\r
5672 randstate = randstate * 1664525 + 1013904223;
\r
5673 return (int) randstate & 0x7fffffff;
\r
5677 mysrandom(unsigned int seed)
\r
5684 * returns TRUE if user selects a different color, FALSE otherwise
\r
5688 ChangeColor(HWND hwnd, COLORREF *which)
\r
5690 static BOOL firstTime = TRUE;
\r
5691 static DWORD customColors[16];
\r
5693 COLORREF newcolor;
\r
5698 /* Make initial colors in use available as custom colors */
\r
5699 /* Should we put the compiled-in defaults here instead? */
\r
5701 customColors[i++] = lightSquareColor & 0xffffff;
\r
5702 customColors[i++] = darkSquareColor & 0xffffff;
\r
5703 customColors[i++] = whitePieceColor & 0xffffff;
\r
5704 customColors[i++] = blackPieceColor & 0xffffff;
\r
5705 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5706 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5708 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5709 customColors[i++] = textAttribs[ccl].color;
\r
5711 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5712 firstTime = FALSE;
\r
5715 cc.lStructSize = sizeof(cc);
\r
5716 cc.hwndOwner = hwnd;
\r
5717 cc.hInstance = NULL;
\r
5718 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5719 cc.lpCustColors = (LPDWORD) customColors;
\r
5720 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5722 if (!ChooseColor(&cc)) return FALSE;
\r
5724 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5725 if (newcolor == *which) return FALSE;
\r
5726 *which = newcolor;
\r
5730 InitDrawingColors();
\r
5731 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5736 MyLoadSound(MySound *ms)
\r
5742 if (ms->data && ms->flag) free(ms->data);
\r
5745 switch (ms->name[0]) {
\r
5751 /* System sound from Control Panel. Don't preload here. */
\r
5755 if (ms->name[1] == NULLCHAR) {
\r
5756 /* "!" alone = silence */
\r
5759 /* Builtin wave resource. Error if not found. */
\r
5760 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5761 if (h == NULL) break;
\r
5762 ms->data = (void *)LoadResource(hInst, h);
\r
5763 ms->flag = 0; // not maloced, so cannot be freed!
\r
5764 if (h == NULL) break;
\r
5769 /* .wav file. Error if not found. */
\r
5770 f = fopen(ms->name, "rb");
\r
5771 if (f == NULL) break;
\r
5772 if (fstat(fileno(f), &st) < 0) break;
\r
5773 ms->data = malloc(st.st_size);
\r
5775 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5781 char buf[MSG_SIZ];
\r
5782 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5783 DisplayError(buf, GetLastError());
\r
5789 MyPlaySound(MySound *ms)
\r
5791 BOOLEAN ok = FALSE;
\r
5793 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5794 switch (ms->name[0]) {
\r
5796 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5801 /* System sound from Control Panel (deprecated feature).
\r
5802 "$" alone or an unset sound name gets default beep (still in use). */
\r
5803 if (ms->name[1]) {
\r
5804 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5806 if (!ok) ok = MessageBeep(MB_OK);
\r
5809 /* Builtin wave resource, or "!" alone for silence */
\r
5810 if (ms->name[1]) {
\r
5811 if (ms->data == NULL) return FALSE;
\r
5812 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5818 /* .wav file. Error if not found. */
\r
5819 if (ms->data == NULL) return FALSE;
\r
5820 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5823 /* Don't print an error: this can happen innocently if the sound driver
\r
5824 is busy; for instance, if another instance of WinBoard is playing
\r
5825 a sound at about the same time. */
\r
5831 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5834 OPENFILENAME *ofn;
\r
5835 static UINT *number; /* gross that this is static */
\r
5837 switch (message) {
\r
5838 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5839 /* Center the dialog over the application window */
\r
5840 ofn = (OPENFILENAME *) lParam;
\r
5841 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5842 number = (UINT *) ofn->lCustData;
\r
5843 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5847 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5848 Translate(hDlg, 1536);
\r
5849 return FALSE; /* Allow for further processing */
\r
5852 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5853 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5855 return FALSE; /* Allow for further processing */
\r
5861 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5863 static UINT *number;
\r
5864 OPENFILENAME *ofname;
\r
5867 case WM_INITDIALOG:
\r
5868 Translate(hdlg, DLG_IndexNumber);
\r
5869 ofname = (OPENFILENAME *)lParam;
\r
5870 number = (UINT *)(ofname->lCustData);
\r
5873 ofnot = (OFNOTIFY *)lParam;
\r
5874 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5875 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5884 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5885 char *nameFilt, char *dlgTitle, UINT *number,
\r
5886 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5888 OPENFILENAME openFileName;
\r
5889 char buf1[MSG_SIZ];
\r
5892 if (fileName == NULL) fileName = buf1;
\r
5893 if (defName == NULL) {
\r
5894 safeStrCpy(fileName, "*.", 3 );
\r
5895 strcat(fileName, defExt);
\r
5897 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5899 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5900 if (number) *number = 0;
\r
5902 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5903 openFileName.hwndOwner = hwnd;
\r
5904 openFileName.hInstance = (HANDLE) hInst;
\r
5905 openFileName.lpstrFilter = nameFilt;
\r
5906 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5907 openFileName.nMaxCustFilter = 0L;
\r
5908 openFileName.nFilterIndex = 1L;
\r
5909 openFileName.lpstrFile = fileName;
\r
5910 openFileName.nMaxFile = MSG_SIZ;
\r
5911 openFileName.lpstrFileTitle = fileTitle;
\r
5912 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5913 openFileName.lpstrInitialDir = NULL;
\r
5914 openFileName.lpstrTitle = dlgTitle;
\r
5915 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5916 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5917 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5918 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5919 openFileName.nFileOffset = 0;
\r
5920 openFileName.nFileExtension = 0;
\r
5921 openFileName.lpstrDefExt = defExt;
\r
5922 openFileName.lCustData = (LONG) number;
\r
5923 openFileName.lpfnHook = oldDialog ?
\r
5924 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5925 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5927 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5928 GetOpenFileName(&openFileName)) {
\r
5929 /* open the file */
\r
5930 f = fopen(openFileName.lpstrFile, write);
\r
5932 MessageBox(hwnd, _("File open failed"), NULL,
\r
5933 MB_OK|MB_ICONEXCLAMATION);
\r
5937 int err = CommDlgExtendedError();
\r
5938 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
5947 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5949 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5952 * Get the first pop-up menu in the menu template. This is the
\r
5953 * menu that TrackPopupMenu displays.
\r
5955 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5956 TranslateOneMenu(10, hmenuTrackPopup);
\r
5958 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5961 * TrackPopup uses screen coordinates, so convert the
\r
5962 * coordinates of the mouse click to screen coordinates.
\r
5964 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5966 /* Draw and track the floating pop-up menu. */
\r
5967 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5968 pt.x, pt.y, 0, hwnd, NULL);
\r
5970 /* Destroy the menu.*/
\r
5971 DestroyMenu(hmenu);
\r
5976 int sizeX, sizeY, newSizeX, newSizeY;
\r
5978 } ResizeEditPlusButtonsClosure;
\r
5981 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5983 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5987 if (hChild == cl->hText) return TRUE;
\r
5988 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5989 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5990 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5991 ScreenToClient(cl->hDlg, &pt);
\r
5992 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5993 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5997 /* Resize a dialog that has a (rich) edit field filling most of
\r
5998 the top, with a row of buttons below */
\r
6000 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6003 int newTextHeight, newTextWidth;
\r
6004 ResizeEditPlusButtonsClosure cl;
\r
6006 /*if (IsIconic(hDlg)) return;*/
\r
6007 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6009 cl.hdwp = BeginDeferWindowPos(8);
\r
6011 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6012 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6013 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6014 if (newTextHeight < 0) {
\r
6015 newSizeY += -newTextHeight;
\r
6016 newTextHeight = 0;
\r
6018 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6019 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6025 cl.newSizeX = newSizeX;
\r
6026 cl.newSizeY = newSizeY;
\r
6027 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6029 EndDeferWindowPos(cl.hdwp);
\r
6032 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6034 RECT rChild, rParent;
\r
6035 int wChild, hChild, wParent, hParent;
\r
6036 int wScreen, hScreen, xNew, yNew;
\r
6039 /* Get the Height and Width of the child window */
\r
6040 GetWindowRect (hwndChild, &rChild);
\r
6041 wChild = rChild.right - rChild.left;
\r
6042 hChild = rChild.bottom - rChild.top;
\r
6044 /* Get the Height and Width of the parent window */
\r
6045 GetWindowRect (hwndParent, &rParent);
\r
6046 wParent = rParent.right - rParent.left;
\r
6047 hParent = rParent.bottom - rParent.top;
\r
6049 /* Get the display limits */
\r
6050 hdc = GetDC (hwndChild);
\r
6051 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6052 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6053 ReleaseDC(hwndChild, hdc);
\r
6055 /* Calculate new X position, then adjust for screen */
\r
6056 xNew = rParent.left + ((wParent - wChild) /2);
\r
6059 } else if ((xNew+wChild) > wScreen) {
\r
6060 xNew = wScreen - wChild;
\r
6063 /* Calculate new Y position, then adjust for screen */
\r
6065 yNew = rParent.top + ((hParent - hChild) /2);
\r
6068 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6073 } else if ((yNew+hChild) > hScreen) {
\r
6074 yNew = hScreen - hChild;
\r
6077 /* Set it, and return */
\r
6078 return SetWindowPos (hwndChild, NULL,
\r
6079 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6082 /* Center one window over another */
\r
6083 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6085 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6088 /*---------------------------------------------------------------------------*\
\r
6090 * Startup Dialog functions
\r
6092 \*---------------------------------------------------------------------------*/
\r
6094 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6096 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6098 while (*cd != NULL) {
\r
6099 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6105 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6107 char buf1[MAX_ARG_LEN];
\r
6110 if (str[0] == '@') {
\r
6111 FILE* f = fopen(str + 1, "r");
\r
6113 DisplayFatalError(str + 1, errno, 2);
\r
6116 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6118 buf1[len] = NULLCHAR;
\r
6122 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6125 char buf[MSG_SIZ];
\r
6126 char *end = strchr(str, '\n');
\r
6127 if (end == NULL) return;
\r
6128 memcpy(buf, str, end - str);
\r
6129 buf[end - str] = NULLCHAR;
\r
6130 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6136 SetStartupDialogEnables(HWND hDlg)
\r
6138 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6139 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6140 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6141 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6142 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6143 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6144 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6145 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6146 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6147 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6148 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6149 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6150 IsDlgButtonChecked(hDlg, OPT_View));
\r
6154 QuoteForFilename(char *filename)
\r
6156 int dquote, space;
\r
6157 dquote = strchr(filename, '"') != NULL;
\r
6158 space = strchr(filename, ' ') != NULL;
\r
6159 if (dquote || space) {
\r
6171 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6173 char buf[MSG_SIZ];
\r
6176 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6177 q = QuoteForFilename(nthcp);
\r
6178 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6179 if (*nthdir != NULLCHAR) {
\r
6180 q = QuoteForFilename(nthdir);
\r
6181 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6183 if (*nthcp == NULLCHAR) {
\r
6184 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6185 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6186 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6187 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6192 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6194 char buf[MSG_SIZ];
\r
6198 switch (message) {
\r
6199 case WM_INITDIALOG:
\r
6200 /* Center the dialog */
\r
6201 CenterWindow (hDlg, GetDesktopWindow());
\r
6202 Translate(hDlg, DLG_Startup);
\r
6203 /* Initialize the dialog items */
\r
6204 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6205 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6206 firstChessProgramNames);
\r
6207 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6208 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6209 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6210 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6211 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6212 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6213 if (*appData.icsHelper != NULLCHAR) {
\r
6214 char *q = QuoteForFilename(appData.icsHelper);
\r
6215 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6217 if (*appData.icsHost == NULLCHAR) {
\r
6218 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6219 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6220 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6221 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6222 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6225 if (appData.icsActive) {
\r
6226 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6228 else if (appData.noChessProgram) {
\r
6229 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6232 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6235 SetStartupDialogEnables(hDlg);
\r
6239 switch (LOWORD(wParam)) {
\r
6241 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6242 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6243 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6245 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6246 ParseArgs(StringGet, &p);
\r
6247 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6248 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6250 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6251 ParseArgs(StringGet, &p);
\r
6252 SwapEngines(singleList); // ... and then make it 'second'
\r
6253 appData.noChessProgram = FALSE;
\r
6254 appData.icsActive = FALSE;
\r
6255 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6256 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6257 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6259 ParseArgs(StringGet, &p);
\r
6260 if (appData.zippyPlay) {
\r
6261 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6262 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6264 ParseArgs(StringGet, &p);
\r
6266 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6267 appData.noChessProgram = TRUE;
\r
6268 appData.icsActive = FALSE;
\r
6270 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6271 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6274 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6275 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6277 ParseArgs(StringGet, &p);
\r
6279 EndDialog(hDlg, TRUE);
\r
6286 case IDM_HELPCONTENTS:
\r
6287 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6288 MessageBox (GetFocus(),
\r
6289 _("Unable to activate help"),
\r
6290 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6295 SetStartupDialogEnables(hDlg);
\r
6303 /*---------------------------------------------------------------------------*\
\r
6305 * About box dialog functions
\r
6307 \*---------------------------------------------------------------------------*/
\r
6309 /* Process messages for "About" dialog box */
\r
6311 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6313 switch (message) {
\r
6314 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6315 /* Center the dialog over the application window */
\r
6316 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6317 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6318 Translate(hDlg, ABOUTBOX);
\r
6322 case WM_COMMAND: /* message: received a command */
\r
6323 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6324 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6325 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6333 /*---------------------------------------------------------------------------*\
\r
6335 * Comment Dialog functions
\r
6337 \*---------------------------------------------------------------------------*/
\r
6340 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6342 static HANDLE hwndText = NULL;
\r
6343 int len, newSizeX, newSizeY, flags;
\r
6344 static int sizeX, sizeY;
\r
6349 switch (message) {
\r
6350 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6351 /* Initialize the dialog items */
\r
6352 Translate(hDlg, DLG_EditComment);
\r
6353 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6354 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6355 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6356 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6357 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6358 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6359 SetWindowText(hDlg, commentTitle);
\r
6360 if (editComment) {
\r
6361 SetFocus(hwndText);
\r
6363 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6365 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6366 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6367 MAKELPARAM(FALSE, 0));
\r
6368 /* Size and position the dialog */
\r
6369 if (!commentDialog) {
\r
6370 commentDialog = hDlg;
\r
6371 flags = SWP_NOZORDER;
\r
6372 GetClientRect(hDlg, &rect);
\r
6373 sizeX = rect.right;
\r
6374 sizeY = rect.bottom;
\r
6375 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6376 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6377 WINDOWPLACEMENT wp;
\r
6378 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6379 wp.length = sizeof(WINDOWPLACEMENT);
\r
6381 wp.showCmd = SW_SHOW;
\r
6382 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6383 wp.rcNormalPosition.left = wpComment.x;
\r
6384 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6385 wp.rcNormalPosition.top = wpComment.y;
\r
6386 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6387 SetWindowPlacement(hDlg, &wp);
\r
6389 GetClientRect(hDlg, &rect);
\r
6390 newSizeX = rect.right;
\r
6391 newSizeY = rect.bottom;
\r
6392 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6393 newSizeX, newSizeY);
\r
6398 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6401 case WM_COMMAND: /* message: received a command */
\r
6402 switch (LOWORD(wParam)) {
\r
6404 if (editComment) {
\r
6406 /* Read changed options from the dialog box */
\r
6407 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6408 len = GetWindowTextLength(hwndText);
\r
6409 str = (char *) malloc(len + 1);
\r
6410 GetWindowText(hwndText, str, len + 1);
\r
6419 ReplaceComment(commentIndex, str);
\r
6426 case OPT_CancelComment:
\r
6430 case OPT_ClearComment:
\r
6431 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6434 case OPT_EditComment:
\r
6435 EditCommentEvent();
\r
6443 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6444 if( wParam == OPT_CommentText ) {
\r
6445 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6447 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6448 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6452 pt.x = LOWORD( lpMF->lParam );
\r
6453 pt.y = HIWORD( lpMF->lParam );
\r
6455 if(lpMF->msg == WM_CHAR) {
\r
6457 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6458 index = sel.cpMin;
\r
6460 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6462 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6463 len = GetWindowTextLength(hwndText);
\r
6464 str = (char *) malloc(len + 1);
\r
6465 GetWindowText(hwndText, str, len + 1);
\r
6466 ReplaceComment(commentIndex, str);
\r
6467 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6468 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6471 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6472 lpMF->msg = WM_USER;
\r
6480 newSizeX = LOWORD(lParam);
\r
6481 newSizeY = HIWORD(lParam);
\r
6482 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6487 case WM_GETMINMAXINFO:
\r
6488 /* Prevent resizing window too small */
\r
6489 mmi = (MINMAXINFO *) lParam;
\r
6490 mmi->ptMinTrackSize.x = 100;
\r
6491 mmi->ptMinTrackSize.y = 100;
\r
6498 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6503 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6505 if (str == NULL) str = "";
\r
6506 p = (char *) malloc(2 * strlen(str) + 2);
\r
6509 if (*str == '\n') *q++ = '\r';
\r
6513 if (commentText != NULL) free(commentText);
\r
6515 commentIndex = index;
\r
6516 commentTitle = title;
\r
6518 editComment = edit;
\r
6520 if (commentDialog) {
\r
6521 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6522 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6524 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6525 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6526 hwndMain, (DLGPROC)lpProc);
\r
6527 FreeProcInstance(lpProc);
\r
6533 /*---------------------------------------------------------------------------*\
\r
6535 * Type-in move dialog functions
\r
6537 \*---------------------------------------------------------------------------*/
\r
6540 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6542 char move[MSG_SIZ];
\r
6545 switch (message) {
\r
6546 case WM_INITDIALOG:
\r
6547 move[0] = (char) lParam;
\r
6548 move[1] = NULLCHAR;
\r
6549 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6550 Translate(hDlg, DLG_TypeInMove);
\r
6551 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6552 SetWindowText(hInput, move);
\r
6554 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6558 switch (LOWORD(wParam)) {
\r
6561 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6562 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6563 TypeInDoneEvent(move);
\r
6564 EndDialog(hDlg, TRUE);
\r
6567 EndDialog(hDlg, FALSE);
\r
6578 PopUpMoveDialog(char firstchar)
\r
6582 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6583 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6584 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6585 FreeProcInstance(lpProc);
\r
6588 /*---------------------------------------------------------------------------*\
\r
6590 * Type-in name dialog functions
\r
6592 \*---------------------------------------------------------------------------*/
\r
6595 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6597 char move[MSG_SIZ];
\r
6600 switch (message) {
\r
6601 case WM_INITDIALOG:
\r
6602 move[0] = (char) lParam;
\r
6603 move[1] = NULLCHAR;
\r
6604 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6605 Translate(hDlg, DLG_TypeInName);
\r
6606 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6607 SetWindowText(hInput, move);
\r
6609 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6613 switch (LOWORD(wParam)) {
\r
6615 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6616 appData.userName = strdup(move);
\r
6619 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6620 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6621 DisplayTitle(move);
\r
6625 EndDialog(hDlg, TRUE);
\r
6628 EndDialog(hDlg, FALSE);
\r
6639 PopUpNameDialog(char firstchar)
\r
6643 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6644 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6645 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6646 FreeProcInstance(lpProc);
\r
6649 /*---------------------------------------------------------------------------*\
\r
6653 \*---------------------------------------------------------------------------*/
\r
6655 /* Nonmodal error box */
\r
6656 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6657 WPARAM wParam, LPARAM lParam);
\r
6660 ErrorPopUp(char *title, char *content)
\r
6664 BOOLEAN modal = hwndMain == NULL;
\r
6682 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6683 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6686 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6688 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6689 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6690 hwndMain, (DLGPROC)lpProc);
\r
6691 FreeProcInstance(lpProc);
\r
6698 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6699 if (errorDialog == NULL) return;
\r
6700 DestroyWindow(errorDialog);
\r
6701 errorDialog = NULL;
\r
6702 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6706 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6711 switch (message) {
\r
6712 case WM_INITDIALOG:
\r
6713 GetWindowRect(hDlg, &rChild);
\r
6716 SetWindowPos(hDlg, NULL, rChild.left,
\r
6717 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6718 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6722 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6723 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6724 and it doesn't work when you resize the dialog.
\r
6725 For now, just give it a default position.
\r
6727 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6728 Translate(hDlg, DLG_Error);
\r
6730 errorDialog = hDlg;
\r
6731 SetWindowText(hDlg, errorTitle);
\r
6732 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6733 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6737 switch (LOWORD(wParam)) {
\r
6740 if (errorDialog == hDlg) errorDialog = NULL;
\r
6741 DestroyWindow(hDlg);
\r
6753 HWND gothicDialog = NULL;
\r
6756 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6760 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6762 switch (message) {
\r
6763 case WM_INITDIALOG:
\r
6764 GetWindowRect(hDlg, &rChild);
\r
6766 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6770 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6771 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6772 and it doesn't work when you resize the dialog.
\r
6773 For now, just give it a default position.
\r
6775 gothicDialog = hDlg;
\r
6776 SetWindowText(hDlg, errorTitle);
\r
6777 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6778 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6782 switch (LOWORD(wParam)) {
\r
6785 if (errorDialog == hDlg) errorDialog = NULL;
\r
6786 DestroyWindow(hDlg);
\r
6798 GothicPopUp(char *title, VariantClass variant)
\r
6801 static char *lastTitle;
\r
6803 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6804 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6806 if(lastTitle != title && gothicDialog != NULL) {
\r
6807 DestroyWindow(gothicDialog);
\r
6808 gothicDialog = NULL;
\r
6810 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6811 title = lastTitle;
\r
6812 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6813 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6814 hwndMain, (DLGPROC)lpProc);
\r
6815 FreeProcInstance(lpProc);
\r
6820 /*---------------------------------------------------------------------------*\
\r
6822 * Ics Interaction console functions
\r
6824 \*---------------------------------------------------------------------------*/
\r
6826 #define HISTORY_SIZE 64
\r
6827 static char *history[HISTORY_SIZE];
\r
6828 int histIn = 0, histP = 0;
\r
6831 SaveInHistory(char *cmd)
\r
6833 if (history[histIn] != NULL) {
\r
6834 free(history[histIn]);
\r
6835 history[histIn] = NULL;
\r
6837 if (*cmd == NULLCHAR) return;
\r
6838 history[histIn] = StrSave(cmd);
\r
6839 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6840 if (history[histIn] != NULL) {
\r
6841 free(history[histIn]);
\r
6842 history[histIn] = NULL;
\r
6848 PrevInHistory(char *cmd)
\r
6851 if (histP == histIn) {
\r
6852 if (history[histIn] != NULL) free(history[histIn]);
\r
6853 history[histIn] = StrSave(cmd);
\r
6855 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6856 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6858 return history[histP];
\r
6864 if (histP == histIn) return NULL;
\r
6865 histP = (histP + 1) % HISTORY_SIZE;
\r
6866 return history[histP];
\r
6870 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6874 hmenu = LoadMenu(hInst, "TextMenu");
\r
6875 h = GetSubMenu(hmenu, 0);
\r
6877 if (strcmp(e->item, "-") == 0) {
\r
6878 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6879 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6880 int flags = MF_STRING, j = 0;
\r
6881 if (e->item[0] == '|') {
\r
6882 flags |= MF_MENUBARBREAK;
\r
6885 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6886 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6894 WNDPROC consoleTextWindowProc;
\r
6897 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6899 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6900 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6904 SetWindowText(hInput, command);
\r
6906 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6908 sel.cpMin = 999999;
\r
6909 sel.cpMax = 999999;
\r
6910 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6915 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6916 if (sel.cpMin == sel.cpMax) {
\r
6917 /* Expand to surrounding word */
\r
6920 tr.chrg.cpMax = sel.cpMin;
\r
6921 tr.chrg.cpMin = --sel.cpMin;
\r
6922 if (sel.cpMin < 0) break;
\r
6923 tr.lpstrText = name;
\r
6924 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6925 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6929 tr.chrg.cpMin = sel.cpMax;
\r
6930 tr.chrg.cpMax = ++sel.cpMax;
\r
6931 tr.lpstrText = name;
\r
6932 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6933 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6936 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6937 MessageBeep(MB_ICONEXCLAMATION);
\r
6941 tr.lpstrText = name;
\r
6942 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6944 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6945 MessageBeep(MB_ICONEXCLAMATION);
\r
6948 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6951 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
6952 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
6953 SetWindowText(hInput, buf);
\r
6954 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6956 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
6957 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
6958 SetWindowText(hInput, buf);
\r
6959 sel.cpMin = 999999;
\r
6960 sel.cpMax = 999999;
\r
6961 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6967 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6972 switch (message) {
\r
6974 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6975 if(wParam=='R') return 0;
\r
6978 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6981 sel.cpMin = 999999;
\r
6982 sel.cpMax = 999999;
\r
6983 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6984 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6989 if(wParam != '\022') {
\r
6990 if (wParam == '\t') {
\r
6991 if (GetKeyState(VK_SHIFT) < 0) {
\r
6993 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6994 if (buttonDesc[0].hwnd) {
\r
6995 SetFocus(buttonDesc[0].hwnd);
\r
6997 SetFocus(hwndMain);
\r
7001 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7004 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7005 JAWS_DELETE( SetFocus(hInput); )
\r
7006 SendMessage(hInput, message, wParam, lParam);
\r
7009 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7011 case WM_RBUTTONDOWN:
\r
7012 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7013 /* Move selection here if it was empty */
\r
7015 pt.x = LOWORD(lParam);
\r
7016 pt.y = HIWORD(lParam);
\r
7017 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7018 if (sel.cpMin == sel.cpMax) {
\r
7019 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7020 sel.cpMax = sel.cpMin;
\r
7021 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7023 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7024 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7026 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7027 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7028 if (sel.cpMin == sel.cpMax) {
\r
7029 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7030 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7032 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7033 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7035 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7036 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7037 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7038 MenuPopup(hwnd, pt, hmenu, -1);
\r
7042 case WM_RBUTTONUP:
\r
7043 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7044 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7045 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7049 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7051 return SendMessage(hInput, message, wParam, lParam);
\r
7052 case WM_MBUTTONDOWN:
\r
7053 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7055 switch (LOWORD(wParam)) {
\r
7056 case IDM_QuickPaste:
\r
7058 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7059 if (sel.cpMin == sel.cpMax) {
\r
7060 MessageBeep(MB_ICONEXCLAMATION);
\r
7063 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7064 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7065 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7070 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7073 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7076 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7080 int i = LOWORD(wParam) - IDM_CommandX;
\r
7081 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7082 icsTextMenuEntry[i].command != NULL) {
\r
7083 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7084 icsTextMenuEntry[i].getname,
\r
7085 icsTextMenuEntry[i].immediate);
\r
7093 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7096 WNDPROC consoleInputWindowProc;
\r
7099 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7101 char buf[MSG_SIZ];
\r
7103 static BOOL sendNextChar = FALSE;
\r
7104 static BOOL quoteNextChar = FALSE;
\r
7105 InputSource *is = consoleInputSource;
\r
7109 switch (message) {
\r
7111 if (!appData.localLineEditing || sendNextChar) {
\r
7112 is->buf[0] = (CHAR) wParam;
\r
7114 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7115 sendNextChar = FALSE;
\r
7118 if (quoteNextChar) {
\r
7119 buf[0] = (char) wParam;
\r
7120 buf[1] = NULLCHAR;
\r
7121 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7122 quoteNextChar = FALSE;
\r
7126 case '\r': /* Enter key */
\r
7127 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7128 if (consoleEcho) SaveInHistory(is->buf);
\r
7129 is->buf[is->count++] = '\n';
\r
7130 is->buf[is->count] = NULLCHAR;
\r
7131 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7132 if (consoleEcho) {
\r
7133 ConsoleOutput(is->buf, is->count, TRUE);
\r
7134 } else if (appData.localLineEditing) {
\r
7135 ConsoleOutput("\n", 1, TRUE);
\r
7138 case '\033': /* Escape key */
\r
7139 SetWindowText(hwnd, "");
\r
7140 cf.cbSize = sizeof(CHARFORMAT);
\r
7141 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7142 if (consoleEcho) {
\r
7143 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7145 cf.crTextColor = COLOR_ECHOOFF;
\r
7147 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7148 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7150 case '\t': /* Tab key */
\r
7151 if (GetKeyState(VK_SHIFT) < 0) {
\r
7153 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7156 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7157 if (buttonDesc[0].hwnd) {
\r
7158 SetFocus(buttonDesc[0].hwnd);
\r
7160 SetFocus(hwndMain);
\r
7164 case '\023': /* Ctrl+S */
\r
7165 sendNextChar = TRUE;
\r
7167 case '\021': /* Ctrl+Q */
\r
7168 quoteNextChar = TRUE;
\r
7178 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7179 p = PrevInHistory(buf);
\r
7181 SetWindowText(hwnd, p);
\r
7182 sel.cpMin = 999999;
\r
7183 sel.cpMax = 999999;
\r
7184 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7189 p = NextInHistory();
\r
7191 SetWindowText(hwnd, p);
\r
7192 sel.cpMin = 999999;
\r
7193 sel.cpMax = 999999;
\r
7194 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7200 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7204 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7208 case WM_MBUTTONDOWN:
\r
7209 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7210 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7212 case WM_RBUTTONUP:
\r
7213 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7214 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7215 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7219 hmenu = LoadMenu(hInst, "InputMenu");
\r
7220 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7221 if (sel.cpMin == sel.cpMax) {
\r
7222 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7223 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7225 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7226 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7228 pt.x = LOWORD(lParam);
\r
7229 pt.y = HIWORD(lParam);
\r
7230 MenuPopup(hwnd, pt, hmenu, -1);
\r
7234 switch (LOWORD(wParam)) {
\r
7236 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7238 case IDM_SelectAll:
\r
7240 sel.cpMax = -1; /*999999?*/
\r
7241 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7244 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7247 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7250 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7255 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7258 #define CO_MAX 100000
\r
7259 #define CO_TRIM 1000
\r
7262 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7264 static SnapData sd;
\r
7265 HWND hText, hInput;
\r
7267 static int sizeX, sizeY;
\r
7268 int newSizeX, newSizeY;
\r
7272 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7273 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7275 switch (message) {
\r
7277 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7279 ENLINK *pLink = (ENLINK*)lParam;
\r
7280 if (pLink->msg == WM_LBUTTONUP)
\r
7284 tr.chrg = pLink->chrg;
\r
7285 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7286 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7287 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7288 free(tr.lpstrText);
\r
7292 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7293 hwndConsole = hDlg;
\r
7295 consoleTextWindowProc = (WNDPROC)
\r
7296 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7297 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7298 consoleInputWindowProc = (WNDPROC)
\r
7299 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7300 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7301 Colorize(ColorNormal, TRUE);
\r
7302 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7303 ChangedConsoleFont();
\r
7304 GetClientRect(hDlg, &rect);
\r
7305 sizeX = rect.right;
\r
7306 sizeY = rect.bottom;
\r
7307 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7308 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7309 WINDOWPLACEMENT wp;
\r
7310 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7311 wp.length = sizeof(WINDOWPLACEMENT);
\r
7313 wp.showCmd = SW_SHOW;
\r
7314 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7315 wp.rcNormalPosition.left = wpConsole.x;
\r
7316 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7317 wp.rcNormalPosition.top = wpConsole.y;
\r
7318 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7319 SetWindowPlacement(hDlg, &wp);
\r
7322 // [HGM] Chessknight's change 2004-07-13
\r
7323 else { /* Determine Defaults */
\r
7324 WINDOWPLACEMENT wp;
\r
7325 wpConsole.x = wpMain.width + 1;
\r
7326 wpConsole.y = wpMain.y;
\r
7327 wpConsole.width = screenWidth - wpMain.width;
\r
7328 wpConsole.height = wpMain.height;
\r
7329 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7330 wp.length = sizeof(WINDOWPLACEMENT);
\r
7332 wp.showCmd = SW_SHOW;
\r
7333 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7334 wp.rcNormalPosition.left = wpConsole.x;
\r
7335 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7336 wp.rcNormalPosition.top = wpConsole.y;
\r
7337 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7338 SetWindowPlacement(hDlg, &wp);
\r
7341 // Allow hText to highlight URLs and send notifications on them
\r
7342 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7343 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7344 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7345 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7359 if (IsIconic(hDlg)) break;
\r
7360 newSizeX = LOWORD(lParam);
\r
7361 newSizeY = HIWORD(lParam);
\r
7362 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7363 RECT rectText, rectInput;
\r
7365 int newTextHeight, newTextWidth;
\r
7366 GetWindowRect(hText, &rectText);
\r
7367 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7368 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7369 if (newTextHeight < 0) {
\r
7370 newSizeY += -newTextHeight;
\r
7371 newTextHeight = 0;
\r
7373 SetWindowPos(hText, NULL, 0, 0,
\r
7374 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7375 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7376 pt.x = rectInput.left;
\r
7377 pt.y = rectInput.top + newSizeY - sizeY;
\r
7378 ScreenToClient(hDlg, &pt);
\r
7379 SetWindowPos(hInput, NULL,
\r
7380 pt.x, pt.y, /* needs client coords */
\r
7381 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7382 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7388 case WM_GETMINMAXINFO:
\r
7389 /* Prevent resizing window too small */
\r
7390 mmi = (MINMAXINFO *) lParam;
\r
7391 mmi->ptMinTrackSize.x = 100;
\r
7392 mmi->ptMinTrackSize.y = 100;
\r
7395 /* [AS] Snapping */
\r
7396 case WM_ENTERSIZEMOVE:
\r
7397 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7400 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7403 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7405 case WM_EXITSIZEMOVE:
\r
7406 UpdateICSWidth(hText);
\r
7407 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7410 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7418 if (hwndConsole) return;
\r
7419 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7420 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7425 ConsoleOutput(char* data, int length, int forceVisible)
\r
7430 char buf[CO_MAX+1];
\r
7433 static int delayLF = 0;
\r
7434 CHARRANGE savesel, sel;
\r
7436 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7444 while (length--) {
\r
7452 } else if (*p == '\007') {
\r
7453 MyPlaySound(&sounds[(int)SoundBell]);
\r
7460 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7461 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7462 /* Save current selection */
\r
7463 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7464 exlen = GetWindowTextLength(hText);
\r
7465 /* Find out whether current end of text is visible */
\r
7466 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7467 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7468 /* Trim existing text if it's too long */
\r
7469 if (exlen + (q - buf) > CO_MAX) {
\r
7470 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7473 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7474 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7476 savesel.cpMin -= trim;
\r
7477 savesel.cpMax -= trim;
\r
7478 if (exlen < 0) exlen = 0;
\r
7479 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7480 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7482 /* Append the new text */
\r
7483 sel.cpMin = exlen;
\r
7484 sel.cpMax = exlen;
\r
7485 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7486 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7487 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7488 if (forceVisible || exlen == 0 ||
\r
7489 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7490 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7491 /* Scroll to make new end of text visible if old end of text
\r
7492 was visible or new text is an echo of user typein */
\r
7493 sel.cpMin = 9999999;
\r
7494 sel.cpMax = 9999999;
\r
7495 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7496 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7497 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7498 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7500 if (savesel.cpMax == exlen || forceVisible) {
\r
7501 /* Move insert point to new end of text if it was at the old
\r
7502 end of text or if the new text is an echo of user typein */
\r
7503 sel.cpMin = 9999999;
\r
7504 sel.cpMax = 9999999;
\r
7505 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7507 /* Restore previous selection */
\r
7508 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7510 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7517 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7521 COLORREF oldFg, oldBg;
\r
7525 if(copyNumber > 1)
\r
7526 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7528 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7529 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7530 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7533 rect.right = x + squareSize;
\r
7535 rect.bottom = y + squareSize;
\r
7538 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7539 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7540 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7541 &rect, str, strlen(str), NULL);
\r
7543 (void) SetTextColor(hdc, oldFg);
\r
7544 (void) SetBkColor(hdc, oldBg);
\r
7545 (void) SelectObject(hdc, oldFont);
\r
7549 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7550 RECT *rect, char *color, char *flagFell)
\r
7554 COLORREF oldFg, oldBg;
\r
7557 if (twoBoards && partnerUp) return;
\r
7558 if (appData.clockMode) {
\r
7560 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7562 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7569 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7570 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7572 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7573 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7575 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7579 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7580 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7581 rect, str, strlen(str), NULL);
\r
7582 if(logoHeight > 0 && appData.clockMode) {
\r
7584 str += strlen(color)+2;
\r
7585 r.top = rect->top + logoHeight/2;
\r
7586 r.left = rect->left;
\r
7587 r.right = rect->right;
\r
7588 r.bottom = rect->bottom;
\r
7589 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7590 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7591 &r, str, strlen(str), NULL);
\r
7593 (void) SetTextColor(hdc, oldFg);
\r
7594 (void) SetBkColor(hdc, oldBg);
\r
7595 (void) SelectObject(hdc, oldFont);
\r
7600 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7606 if( count <= 0 ) {
\r
7607 if (appData.debugMode) {
\r
7608 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7611 return ERROR_INVALID_USER_BUFFER;
\r
7614 ResetEvent(ovl->hEvent);
\r
7615 ovl->Offset = ovl->OffsetHigh = 0;
\r
7616 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7620 err = GetLastError();
\r
7621 if (err == ERROR_IO_PENDING) {
\r
7622 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7626 err = GetLastError();
\r
7633 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7638 ResetEvent(ovl->hEvent);
\r
7639 ovl->Offset = ovl->OffsetHigh = 0;
\r
7640 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7644 err = GetLastError();
\r
7645 if (err == ERROR_IO_PENDING) {
\r
7646 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7650 err = GetLastError();
\r
7656 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7657 void CheckForInputBufferFull( InputSource * is )
\r
7659 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7660 /* Look for end of line */
\r
7661 char * p = is->buf;
\r
7663 while( p < is->next && *p != '\n' ) {
\r
7667 if( p >= is->next ) {
\r
7668 if (appData.debugMode) {
\r
7669 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7672 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7673 is->count = (DWORD) -1;
\r
7674 is->next = is->buf;
\r
7680 InputThread(LPVOID arg)
\r
7685 is = (InputSource *) arg;
\r
7686 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7687 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7688 while (is->hThread != NULL) {
\r
7689 is->error = DoReadFile(is->hFile, is->next,
\r
7690 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7691 &is->count, &ovl);
\r
7692 if (is->error == NO_ERROR) {
\r
7693 is->next += is->count;
\r
7695 if (is->error == ERROR_BROKEN_PIPE) {
\r
7696 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7699 is->count = (DWORD) -1;
\r
7700 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7705 CheckForInputBufferFull( is );
\r
7707 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7709 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7711 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7714 CloseHandle(ovl.hEvent);
\r
7715 CloseHandle(is->hFile);
\r
7717 if (appData.debugMode) {
\r
7718 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7725 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7727 NonOvlInputThread(LPVOID arg)
\r
7734 is = (InputSource *) arg;
\r
7735 while (is->hThread != NULL) {
\r
7736 is->error = ReadFile(is->hFile, is->next,
\r
7737 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7738 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7739 if (is->error == NO_ERROR) {
\r
7740 /* Change CRLF to LF */
\r
7741 if (is->next > is->buf) {
\r
7743 i = is->count + 1;
\r
7751 if (prev == '\r' && *p == '\n') {
\r
7763 if (is->error == ERROR_BROKEN_PIPE) {
\r
7764 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7767 is->count = (DWORD) -1;
\r
7771 CheckForInputBufferFull( is );
\r
7773 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7775 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7777 if (is->count < 0) break; /* Quit on error */
\r
7779 CloseHandle(is->hFile);
\r
7784 SocketInputThread(LPVOID arg)
\r
7788 is = (InputSource *) arg;
\r
7789 while (is->hThread != NULL) {
\r
7790 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7791 if ((int)is->count == SOCKET_ERROR) {
\r
7792 is->count = (DWORD) -1;
\r
7793 is->error = WSAGetLastError();
\r
7795 is->error = NO_ERROR;
\r
7796 is->next += is->count;
\r
7797 if (is->count == 0 && is->second == is) {
\r
7798 /* End of file on stderr; quit with no message */
\r
7802 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7804 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7806 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7812 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7816 is = (InputSource *) lParam;
\r
7817 if (is->lineByLine) {
\r
7818 /* Feed in lines one by one */
\r
7819 char *p = is->buf;
\r
7821 while (q < is->next) {
\r
7822 if (*q++ == '\n') {
\r
7823 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7828 /* Move any partial line to the start of the buffer */
\r
7830 while (p < is->next) {
\r
7835 if (is->error != NO_ERROR || is->count == 0) {
\r
7836 /* Notify backend of the error. Note: If there was a partial
\r
7837 line at the end, it is not flushed through. */
\r
7838 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7841 /* Feed in the whole chunk of input at once */
\r
7842 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7843 is->next = is->buf;
\r
7847 /*---------------------------------------------------------------------------*\
\r
7849 * Menu enables. Used when setting various modes.
\r
7851 \*---------------------------------------------------------------------------*/
\r
7859 GreyRevert(Boolean grey)
\r
7860 { // [HGM] vari: for retracting variations in local mode
\r
7861 HMENU hmenu = GetMenu(hwndMain);
\r
7862 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7863 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7867 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7869 while (enab->item > 0) {
\r
7870 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7875 Enables gnuEnables[] = {
\r
7876 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7877 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7878 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7879 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7880 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7881 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7882 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7883 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7884 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7885 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7886 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7887 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7888 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7890 // Needed to switch from ncp to GNU mode on Engine Load
\r
7891 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7892 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7893 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7894 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7895 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7896 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7897 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7898 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7899 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7900 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7901 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7902 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7903 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7904 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7908 Enables icsEnables[] = {
\r
7909 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7910 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7911 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7912 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7913 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7914 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7915 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7916 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7917 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7918 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7919 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7920 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7921 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7922 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
7923 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
7924 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7925 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7926 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7927 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7928 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
7933 Enables zippyEnables[] = {
\r
7934 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7935 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7936 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7937 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7942 Enables ncpEnables[] = {
\r
7943 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7944 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7945 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7946 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7947 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7948 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7949 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7950 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7951 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7952 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7953 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7954 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7955 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7956 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7957 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7958 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7959 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7960 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7961 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7962 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7963 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7964 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
7968 Enables trainingOnEnables[] = {
\r
7969 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7970 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
7971 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7972 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7981 Enables trainingOffEnables[] = {
\r
7982 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7983 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
7984 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7985 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7986 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7987 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7990 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7994 /* These modify either ncpEnables or gnuEnables */
\r
7995 Enables cmailEnables[] = {
\r
7996 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7997 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7998 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7999 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8000 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8001 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8002 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8006 Enables machineThinkingEnables[] = {
\r
8007 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8008 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8019 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8020 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8021 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8022 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8026 Enables userThinkingEnables[] = {
\r
8027 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8028 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8029 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8030 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8031 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8032 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8033 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8034 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8035 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8036 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8037 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8038 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8039 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8040 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8041 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8042 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8046 /*---------------------------------------------------------------------------*\
\r
8048 * Front-end interface functions exported by XBoard.
\r
8049 * Functions appear in same order as prototypes in frontend.h.
\r
8051 \*---------------------------------------------------------------------------*/
\r
8053 CheckMark(UINT item, int state)
\r
8055 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8061 static UINT prevChecked = 0;
\r
8062 static int prevPausing = 0;
\r
8065 if (pausing != prevPausing) {
\r
8066 prevPausing = pausing;
\r
8067 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8068 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8069 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8072 switch (gameMode) {
\r
8073 case BeginningOfGame:
\r
8074 if (appData.icsActive)
\r
8075 nowChecked = IDM_IcsClient;
\r
8076 else if (appData.noChessProgram)
\r
8077 nowChecked = IDM_EditGame;
\r
8079 nowChecked = IDM_MachineBlack;
\r
8081 case MachinePlaysBlack:
\r
8082 nowChecked = IDM_MachineBlack;
\r
8084 case MachinePlaysWhite:
\r
8085 nowChecked = IDM_MachineWhite;
\r
8087 case TwoMachinesPlay:
\r
8088 nowChecked = IDM_TwoMachines;
\r
8091 nowChecked = IDM_AnalysisMode;
\r
8094 nowChecked = IDM_AnalyzeFile;
\r
8097 nowChecked = IDM_EditGame;
\r
8099 case PlayFromGameFile:
\r
8100 nowChecked = IDM_LoadGame;
\r
8102 case EditPosition:
\r
8103 nowChecked = IDM_EditPosition;
\r
8106 nowChecked = IDM_Training;
\r
8108 case IcsPlayingWhite:
\r
8109 case IcsPlayingBlack:
\r
8110 case IcsObserving:
\r
8112 nowChecked = IDM_IcsClient;
\r
8119 CheckMark(prevChecked, MF_UNCHECKED);
\r
8120 CheckMark(nowChecked, MF_CHECKED);
\r
8121 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8123 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8124 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8125 MF_BYCOMMAND|MF_ENABLED);
\r
8127 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8128 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8131 prevChecked = nowChecked;
\r
8133 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8134 if (appData.icsActive) {
\r
8135 if (appData.icsEngineAnalyze) {
\r
8136 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8138 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8141 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8147 HMENU hmenu = GetMenu(hwndMain);
\r
8148 SetMenuEnables(hmenu, icsEnables);
\r
8149 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8150 MF_BYCOMMAND|MF_ENABLED);
\r
8152 if (appData.zippyPlay) {
\r
8153 SetMenuEnables(hmenu, zippyEnables);
\r
8154 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8155 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8156 MF_BYCOMMAND|MF_ENABLED);
\r
8164 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8170 HMENU hmenu = GetMenu(hwndMain);
\r
8171 SetMenuEnables(hmenu, ncpEnables);
\r
8172 DrawMenuBar(hwndMain);
\r
8178 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8182 SetTrainingModeOn()
\r
8185 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8186 for (i = 0; i < N_BUTTONS; i++) {
\r
8187 if (buttonDesc[i].hwnd != NULL)
\r
8188 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8193 VOID SetTrainingModeOff()
\r
8196 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8197 for (i = 0; i < N_BUTTONS; i++) {
\r
8198 if (buttonDesc[i].hwnd != NULL)
\r
8199 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8205 SetUserThinkingEnables()
\r
8207 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8211 SetMachineThinkingEnables()
\r
8213 HMENU hMenu = GetMenu(hwndMain);
\r
8214 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8216 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8218 if (gameMode == MachinePlaysBlack) {
\r
8219 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8220 } else if (gameMode == MachinePlaysWhite) {
\r
8221 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8222 } else if (gameMode == TwoMachinesPlay) {
\r
8223 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8229 DisplayTitle(char *str)
\r
8231 char title[MSG_SIZ], *host;
\r
8232 if (str[0] != NULLCHAR) {
\r
8233 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8234 } else if (appData.icsActive) {
\r
8235 if (appData.icsCommPort[0] != NULLCHAR)
\r
8238 host = appData.icsHost;
\r
8239 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8240 } else if (appData.noChessProgram) {
\r
8241 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8243 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8244 strcat(title, ": ");
\r
8245 strcat(title, first.tidy);
\r
8247 SetWindowText(hwndMain, title);
\r
8252 DisplayMessage(char *str1, char *str2)
\r
8256 int remain = MESSAGE_TEXT_MAX - 1;
\r
8259 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8260 messageText[0] = NULLCHAR;
\r
8262 len = strlen(str1);
\r
8263 if (len > remain) len = remain;
\r
8264 strncpy(messageText, str1, len);
\r
8265 messageText[len] = NULLCHAR;
\r
8268 if (*str2 && remain >= 2) {
\r
8270 strcat(messageText, " ");
\r
8273 len = strlen(str2);
\r
8274 if (len > remain) len = remain;
\r
8275 strncat(messageText, str2, len);
\r
8277 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8278 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8280 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8284 hdc = GetDC(hwndMain);
\r
8285 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8286 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8287 &messageRect, messageText, strlen(messageText), NULL);
\r
8288 (void) SelectObject(hdc, oldFont);
\r
8289 (void) ReleaseDC(hwndMain, hdc);
\r
8293 DisplayError(char *str, int error)
\r
8295 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8299 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8301 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8302 NULL, error, LANG_NEUTRAL,
\r
8303 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8305 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8307 ErrorMap *em = errmap;
\r
8308 while (em->err != 0 && em->err != error) em++;
\r
8309 if (em->err != 0) {
\r
8310 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8312 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8317 ErrorPopUp(_("Error"), buf);
\r
8322 DisplayMoveError(char *str)
\r
8324 fromX = fromY = -1;
\r
8325 ClearHighlights();
\r
8326 DrawPosition(FALSE, NULL);
\r
8327 if (appData.popupMoveErrors) {
\r
8328 ErrorPopUp(_("Error"), str);
\r
8330 DisplayMessage(str, "");
\r
8331 moveErrorMessageUp = TRUE;
\r
8336 DisplayFatalError(char *str, int error, int exitStatus)
\r
8338 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8340 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8343 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8344 NULL, error, LANG_NEUTRAL,
\r
8345 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8347 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8349 ErrorMap *em = errmap;
\r
8350 while (em->err != 0 && em->err != error) em++;
\r
8351 if (em->err != 0) {
\r
8352 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8354 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8359 if (appData.debugMode) {
\r
8360 fprintf(debugFP, "%s: %s\n", label, str);
\r
8362 if (appData.popupExitMessage) {
\r
8363 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8364 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8366 ExitEvent(exitStatus);
\r
8371 DisplayInformation(char *str)
\r
8373 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8378 DisplayNote(char *str)
\r
8380 ErrorPopUp(_("Note"), str);
\r
8385 char *title, *question, *replyPrefix;
\r
8390 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8392 static QuestionParams *qp;
\r
8393 char reply[MSG_SIZ];
\r
8396 switch (message) {
\r
8397 case WM_INITDIALOG:
\r
8398 qp = (QuestionParams *) lParam;
\r
8399 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8400 Translate(hDlg, DLG_Question);
\r
8401 SetWindowText(hDlg, qp->title);
\r
8402 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8403 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8407 switch (LOWORD(wParam)) {
\r
8409 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8410 if (*reply) strcat(reply, " ");
\r
8411 len = strlen(reply);
\r
8412 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8413 strcat(reply, "\n");
\r
8414 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8415 EndDialog(hDlg, TRUE);
\r
8416 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8419 EndDialog(hDlg, FALSE);
\r
8430 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8432 QuestionParams qp;
\r
8436 qp.question = question;
\r
8437 qp.replyPrefix = replyPrefix;
\r
8439 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8440 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8441 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8442 FreeProcInstance(lpProc);
\r
8445 /* [AS] Pick FRC position */
\r
8446 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8448 static int * lpIndexFRC;
\r
8454 case WM_INITDIALOG:
\r
8455 lpIndexFRC = (int *) lParam;
\r
8457 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8458 Translate(hDlg, DLG_NewGameFRC);
\r
8460 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8461 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8462 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8463 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8468 switch( LOWORD(wParam) ) {
\r
8470 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8471 EndDialog( hDlg, 0 );
\r
8472 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8475 EndDialog( hDlg, 1 );
\r
8477 case IDC_NFG_Edit:
\r
8478 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8479 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8481 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8484 case IDC_NFG_Random:
\r
8485 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8486 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8499 int index = appData.defaultFrcPosition;
\r
8500 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8502 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8504 if( result == 0 ) {
\r
8505 appData.defaultFrcPosition = index;
\r
8511 /* [AS] Game list options. Refactored by HGM */
\r
8513 HWND gameListOptionsDialog;
\r
8515 // low-level front-end: clear text edit / list widget
\r
8519 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8522 // low-level front-end: clear text edit / list widget
\r
8524 GLT_DeSelectList()
\r
8526 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8529 // low-level front-end: append line to text edit / list widget
\r
8531 GLT_AddToList( char *name )
\r
8534 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8538 // low-level front-end: get line from text edit / list widget
\r
8540 GLT_GetFromList( int index, char *name )
\r
8543 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8549 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8551 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8552 int idx2 = idx1 + delta;
\r
8553 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8555 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8558 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8559 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8560 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8561 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8565 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8569 case WM_INITDIALOG:
\r
8570 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8572 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8573 Translate(hDlg, DLG_GameListOptions);
\r
8575 /* Initialize list */
\r
8576 GLT_TagsToList( lpUserGLT );
\r
8578 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8583 switch( LOWORD(wParam) ) {
\r
8586 EndDialog( hDlg, 0 );
\r
8589 EndDialog( hDlg, 1 );
\r
8592 case IDC_GLT_Default:
\r
8593 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8596 case IDC_GLT_Restore:
\r
8597 GLT_TagsToList( appData.gameListTags );
\r
8601 GLT_MoveSelection( hDlg, -1 );
\r
8604 case IDC_GLT_Down:
\r
8605 GLT_MoveSelection( hDlg, +1 );
\r
8615 int GameListOptions()
\r
8618 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8620 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8622 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8624 if( result == 0 ) {
\r
8625 /* [AS] Memory leak here! */
\r
8626 appData.gameListTags = strdup( lpUserGLT );
\r
8633 DisplayIcsInteractionTitle(char *str)
\r
8635 char consoleTitle[MSG_SIZ];
\r
8637 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8638 SetWindowText(hwndConsole, consoleTitle);
\r
8640 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8641 char buf[MSG_SIZ], *p = buf, *q;
\r
8642 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8644 q = strchr(p, ';');
\r
8646 if(*p) ChatPopUp(p);
\r
8650 SetActiveWindow(hwndMain);
\r
8654 DrawPosition(int fullRedraw, Board board)
\r
8656 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8659 void NotifyFrontendLogin()
\r
8662 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8668 fromX = fromY = -1;
\r
8669 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8670 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8671 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8672 dragInfo.lastpos = dragInfo.pos;
\r
8673 dragInfo.start.x = dragInfo.start.y = -1;
\r
8674 dragInfo.from = dragInfo.start;
\r
8676 DrawPosition(TRUE, NULL);
\r
8683 CommentPopUp(char *title, char *str)
\r
8685 HWND hwnd = GetActiveWindow();
\r
8686 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8688 SetActiveWindow(hwnd);
\r
8692 CommentPopDown(void)
\r
8694 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8695 if (commentDialog) {
\r
8696 ShowWindow(commentDialog, SW_HIDE);
\r
8698 commentUp = FALSE;
\r
8702 EditCommentPopUp(int index, char *title, char *str)
\r
8704 EitherCommentPopUp(index, title, str, TRUE);
\r
8711 MyPlaySound(&sounds[(int)SoundMove]);
\r
8714 VOID PlayIcsWinSound()
\r
8716 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8719 VOID PlayIcsLossSound()
\r
8721 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8724 VOID PlayIcsDrawSound()
\r
8726 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8729 VOID PlayIcsUnfinishedSound()
\r
8731 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8737 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8743 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8751 consoleEcho = TRUE;
\r
8752 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8753 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8754 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8763 consoleEcho = FALSE;
\r
8764 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8765 /* This works OK: set text and background both to the same color */
\r
8767 cf.crTextColor = COLOR_ECHOOFF;
\r
8768 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8769 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8772 /* No Raw()...? */
\r
8774 void Colorize(ColorClass cc, int continuation)
\r
8776 currentColorClass = cc;
\r
8777 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8778 consoleCF.crTextColor = textAttribs[cc].color;
\r
8779 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8780 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8786 static char buf[MSG_SIZ];
\r
8787 DWORD bufsiz = MSG_SIZ;
\r
8789 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8790 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8792 if (!GetUserName(buf, &bufsiz)) {
\r
8793 /*DisplayError("Error getting user name", GetLastError());*/
\r
8794 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8802 static char buf[MSG_SIZ];
\r
8803 DWORD bufsiz = MSG_SIZ;
\r
8805 if (!GetComputerName(buf, &bufsiz)) {
\r
8806 /*DisplayError("Error getting host name", GetLastError());*/
\r
8807 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8814 ClockTimerRunning()
\r
8816 return clockTimerEvent != 0;
\r
8822 if (clockTimerEvent == 0) return FALSE;
\r
8823 KillTimer(hwndMain, clockTimerEvent);
\r
8824 clockTimerEvent = 0;
\r
8829 StartClockTimer(long millisec)
\r
8831 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8832 (UINT) millisec, NULL);
\r
8836 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8839 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8841 if(appData.noGUI) return;
\r
8842 hdc = GetDC(hwndMain);
\r
8843 if (!IsIconic(hwndMain)) {
\r
8844 DisplayAClock(hdc, timeRemaining, highlight,
\r
8845 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8847 if (highlight && iconCurrent == iconBlack) {
\r
8848 iconCurrent = iconWhite;
\r
8849 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8850 if (IsIconic(hwndMain)) {
\r
8851 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8854 (void) ReleaseDC(hwndMain, hdc);
\r
8856 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8860 DisplayBlackClock(long timeRemaining, int highlight)
\r
8863 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8865 if(appData.noGUI) return;
\r
8866 hdc = GetDC(hwndMain);
\r
8867 if (!IsIconic(hwndMain)) {
\r
8868 DisplayAClock(hdc, timeRemaining, highlight,
\r
8869 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8871 if (highlight && iconCurrent == iconWhite) {
\r
8872 iconCurrent = iconBlack;
\r
8873 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8874 if (IsIconic(hwndMain)) {
\r
8875 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8878 (void) ReleaseDC(hwndMain, hdc);
\r
8880 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8885 LoadGameTimerRunning()
\r
8887 return loadGameTimerEvent != 0;
\r
8891 StopLoadGameTimer()
\r
8893 if (loadGameTimerEvent == 0) return FALSE;
\r
8894 KillTimer(hwndMain, loadGameTimerEvent);
\r
8895 loadGameTimerEvent = 0;
\r
8900 StartLoadGameTimer(long millisec)
\r
8902 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8903 (UINT) millisec, NULL);
\r
8911 char fileTitle[MSG_SIZ];
\r
8913 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8914 f = OpenFileDialog(hwndMain, "a", defName,
\r
8915 appData.oldSaveStyle ? "gam" : "pgn",
\r
8917 _("Save Game to File"), NULL, fileTitle, NULL);
\r
8919 SaveGame(f, 0, "");
\r
8926 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8928 if (delayedTimerEvent != 0) {
\r
8929 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8930 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8932 KillTimer(hwndMain, delayedTimerEvent);
\r
8933 delayedTimerEvent = 0;
\r
8934 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8935 delayedTimerCallback();
\r
8937 delayedTimerCallback = cb;
\r
8938 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8939 (UINT) millisec, NULL);
\r
8942 DelayedEventCallback
\r
8945 if (delayedTimerEvent) {
\r
8946 return delayedTimerCallback;
\r
8953 CancelDelayedEvent()
\r
8955 if (delayedTimerEvent) {
\r
8956 KillTimer(hwndMain, delayedTimerEvent);
\r
8957 delayedTimerEvent = 0;
\r
8961 DWORD GetWin32Priority(int nice)
\r
8962 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8964 REALTIME_PRIORITY_CLASS 0x00000100
\r
8965 HIGH_PRIORITY_CLASS 0x00000080
\r
8966 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8967 NORMAL_PRIORITY_CLASS 0x00000020
\r
8968 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8969 IDLE_PRIORITY_CLASS 0x00000040
\r
8971 if (nice < -15) return 0x00000080;
\r
8972 if (nice < 0) return 0x00008000;
\r
8973 if (nice == 0) return 0x00000020;
\r
8974 if (nice < 15) return 0x00004000;
\r
8975 return 0x00000040;
\r
8978 void RunCommand(char *cmdLine)
\r
8980 /* Now create the child process. */
\r
8981 STARTUPINFO siStartInfo;
\r
8982 PROCESS_INFORMATION piProcInfo;
\r
8984 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8985 siStartInfo.lpReserved = NULL;
\r
8986 siStartInfo.lpDesktop = NULL;
\r
8987 siStartInfo.lpTitle = NULL;
\r
8988 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8989 siStartInfo.cbReserved2 = 0;
\r
8990 siStartInfo.lpReserved2 = NULL;
\r
8991 siStartInfo.hStdInput = NULL;
\r
8992 siStartInfo.hStdOutput = NULL;
\r
8993 siStartInfo.hStdError = NULL;
\r
8995 CreateProcess(NULL,
\r
8996 cmdLine, /* command line */
\r
8997 NULL, /* process security attributes */
\r
8998 NULL, /* primary thread security attrs */
\r
8999 TRUE, /* handles are inherited */
\r
9000 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9001 NULL, /* use parent's environment */
\r
9003 &siStartInfo, /* STARTUPINFO pointer */
\r
9004 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9006 CloseHandle(piProcInfo.hThread);
\r
9009 /* Start a child process running the given program.
\r
9010 The process's standard output can be read from "from", and its
\r
9011 standard input can be written to "to".
\r
9012 Exit with fatal error if anything goes wrong.
\r
9013 Returns an opaque pointer that can be used to destroy the process
\r
9017 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9019 #define BUFSIZE 4096
\r
9021 HANDLE hChildStdinRd, hChildStdinWr,
\r
9022 hChildStdoutRd, hChildStdoutWr;
\r
9023 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9024 SECURITY_ATTRIBUTES saAttr;
\r
9026 PROCESS_INFORMATION piProcInfo;
\r
9027 STARTUPINFO siStartInfo;
\r
9029 char buf[MSG_SIZ];
\r
9032 if (appData.debugMode) {
\r
9033 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9038 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9039 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9040 saAttr.bInheritHandle = TRUE;
\r
9041 saAttr.lpSecurityDescriptor = NULL;
\r
9044 * The steps for redirecting child's STDOUT:
\r
9045 * 1. Create anonymous pipe to be STDOUT for child.
\r
9046 * 2. Create a noninheritable duplicate of read handle,
\r
9047 * and close the inheritable read handle.
\r
9050 /* Create a pipe for the child's STDOUT. */
\r
9051 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9052 return GetLastError();
\r
9055 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9056 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9057 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9058 FALSE, /* not inherited */
\r
9059 DUPLICATE_SAME_ACCESS);
\r
9061 return GetLastError();
\r
9063 CloseHandle(hChildStdoutRd);
\r
9066 * The steps for redirecting child's STDIN:
\r
9067 * 1. Create anonymous pipe to be STDIN for child.
\r
9068 * 2. Create a noninheritable duplicate of write handle,
\r
9069 * and close the inheritable write handle.
\r
9072 /* Create a pipe for the child's STDIN. */
\r
9073 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9074 return GetLastError();
\r
9077 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9078 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9079 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9080 FALSE, /* not inherited */
\r
9081 DUPLICATE_SAME_ACCESS);
\r
9083 return GetLastError();
\r
9085 CloseHandle(hChildStdinWr);
\r
9087 /* Arrange to (1) look in dir for the child .exe file, and
\r
9088 * (2) have dir be the child's working directory. Interpret
\r
9089 * dir relative to the directory WinBoard loaded from. */
\r
9090 GetCurrentDirectory(MSG_SIZ, buf);
\r
9091 SetCurrentDirectory(installDir);
\r
9092 SetCurrentDirectory(dir);
\r
9094 /* Now create the child process. */
\r
9096 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9097 siStartInfo.lpReserved = NULL;
\r
9098 siStartInfo.lpDesktop = NULL;
\r
9099 siStartInfo.lpTitle = NULL;
\r
9100 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9101 siStartInfo.cbReserved2 = 0;
\r
9102 siStartInfo.lpReserved2 = NULL;
\r
9103 siStartInfo.hStdInput = hChildStdinRd;
\r
9104 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9105 siStartInfo.hStdError = hChildStdoutWr;
\r
9107 fSuccess = CreateProcess(NULL,
\r
9108 cmdLine, /* command line */
\r
9109 NULL, /* process security attributes */
\r
9110 NULL, /* primary thread security attrs */
\r
9111 TRUE, /* handles are inherited */
\r
9112 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9113 NULL, /* use parent's environment */
\r
9115 &siStartInfo, /* STARTUPINFO pointer */
\r
9116 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9118 err = GetLastError();
\r
9119 SetCurrentDirectory(buf); /* return to prev directory */
\r
9124 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9125 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9126 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9129 /* Close the handles we don't need in the parent */
\r
9130 CloseHandle(piProcInfo.hThread);
\r
9131 CloseHandle(hChildStdinRd);
\r
9132 CloseHandle(hChildStdoutWr);
\r
9134 /* Prepare return value */
\r
9135 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9136 cp->kind = CPReal;
\r
9137 cp->hProcess = piProcInfo.hProcess;
\r
9138 cp->pid = piProcInfo.dwProcessId;
\r
9139 cp->hFrom = hChildStdoutRdDup;
\r
9140 cp->hTo = hChildStdinWrDup;
\r
9142 *pr = (void *) cp;
\r
9144 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9145 2000 where engines sometimes don't see the initial command(s)
\r
9146 from WinBoard and hang. I don't understand how that can happen,
\r
9147 but the Sleep is harmless, so I've put it in. Others have also
\r
9148 reported what may be the same problem, so hopefully this will fix
\r
9149 it for them too. */
\r
9157 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9159 ChildProc *cp; int result;
\r
9161 cp = (ChildProc *) pr;
\r
9162 if (cp == NULL) return;
\r
9164 switch (cp->kind) {
\r
9166 /* TerminateProcess is considered harmful, so... */
\r
9167 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9168 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9169 /* The following doesn't work because the chess program
\r
9170 doesn't "have the same console" as WinBoard. Maybe
\r
9171 we could arrange for this even though neither WinBoard
\r
9172 nor the chess program uses a console for stdio? */
\r
9173 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9175 /* [AS] Special termination modes for misbehaving programs... */
\r
9176 if( signal == 9 ) {
\r
9177 result = TerminateProcess( cp->hProcess, 0 );
\r
9179 if ( appData.debugMode) {
\r
9180 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9183 else if( signal == 10 ) {
\r
9184 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9186 if( dw != WAIT_OBJECT_0 ) {
\r
9187 result = TerminateProcess( cp->hProcess, 0 );
\r
9189 if ( appData.debugMode) {
\r
9190 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9196 CloseHandle(cp->hProcess);
\r
9200 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9204 closesocket(cp->sock);
\r
9209 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9210 closesocket(cp->sock);
\r
9211 closesocket(cp->sock2);
\r
9219 InterruptChildProcess(ProcRef pr)
\r
9223 cp = (ChildProc *) pr;
\r
9224 if (cp == NULL) return;
\r
9225 switch (cp->kind) {
\r
9227 /* The following doesn't work because the chess program
\r
9228 doesn't "have the same console" as WinBoard. Maybe
\r
9229 we could arrange for this even though neither WinBoard
\r
9230 nor the chess program uses a console for stdio */
\r
9231 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9236 /* Can't interrupt */
\r
9240 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9247 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9249 char cmdLine[MSG_SIZ];
\r
9251 if (port[0] == NULLCHAR) {
\r
9252 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9254 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9256 return StartChildProcess(cmdLine, "", pr);
\r
9260 /* Code to open TCP sockets */
\r
9263 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9269 struct sockaddr_in sa, mysa;
\r
9270 struct hostent FAR *hp;
\r
9271 unsigned short uport;
\r
9272 WORD wVersionRequested;
\r
9275 /* Initialize socket DLL */
\r
9276 wVersionRequested = MAKEWORD(1, 1);
\r
9277 err = WSAStartup(wVersionRequested, &wsaData);
\r
9278 if (err != 0) return err;
\r
9281 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9282 err = WSAGetLastError();
\r
9287 /* Bind local address using (mostly) don't-care values.
\r
9289 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9290 mysa.sin_family = AF_INET;
\r
9291 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9292 uport = (unsigned short) 0;
\r
9293 mysa.sin_port = htons(uport);
\r
9294 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9295 == SOCKET_ERROR) {
\r
9296 err = WSAGetLastError();
\r
9301 /* Resolve remote host name */
\r
9302 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9303 if (!(hp = gethostbyname(host))) {
\r
9304 unsigned int b0, b1, b2, b3;
\r
9306 err = WSAGetLastError();
\r
9308 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9309 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9310 hp->h_addrtype = AF_INET;
\r
9312 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9313 hp->h_addr_list[0] = (char *) malloc(4);
\r
9314 hp->h_addr_list[0][0] = (char) b0;
\r
9315 hp->h_addr_list[0][1] = (char) b1;
\r
9316 hp->h_addr_list[0][2] = (char) b2;
\r
9317 hp->h_addr_list[0][3] = (char) b3;
\r
9323 sa.sin_family = hp->h_addrtype;
\r
9324 uport = (unsigned short) atoi(port);
\r
9325 sa.sin_port = htons(uport);
\r
9326 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9328 /* Make connection */
\r
9329 if (connect(s, (struct sockaddr *) &sa,
\r
9330 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9331 err = WSAGetLastError();
\r
9336 /* Prepare return value */
\r
9337 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9338 cp->kind = CPSock;
\r
9340 *pr = (ProcRef *) cp;
\r
9346 OpenCommPort(char *name, ProcRef *pr)
\r
9351 char fullname[MSG_SIZ];
\r
9353 if (*name != '\\')
\r
9354 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9356 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9358 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9359 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9360 if (h == (HANDLE) -1) {
\r
9361 return GetLastError();
\r
9365 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9367 /* Accumulate characters until a 100ms pause, then parse */
\r
9368 ct.ReadIntervalTimeout = 100;
\r
9369 ct.ReadTotalTimeoutMultiplier = 0;
\r
9370 ct.ReadTotalTimeoutConstant = 0;
\r
9371 ct.WriteTotalTimeoutMultiplier = 0;
\r
9372 ct.WriteTotalTimeoutConstant = 0;
\r
9373 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9375 /* Prepare return value */
\r
9376 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9377 cp->kind = CPComm;
\r
9380 *pr = (ProcRef *) cp;
\r
9386 OpenLoopback(ProcRef *pr)
\r
9388 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9394 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9399 struct sockaddr_in sa, mysa;
\r
9400 struct hostent FAR *hp;
\r
9401 unsigned short uport;
\r
9402 WORD wVersionRequested;
\r
9405 char stderrPortStr[MSG_SIZ];
\r
9407 /* Initialize socket DLL */
\r
9408 wVersionRequested = MAKEWORD(1, 1);
\r
9409 err = WSAStartup(wVersionRequested, &wsaData);
\r
9410 if (err != 0) return err;
\r
9412 /* Resolve remote host name */
\r
9413 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9414 if (!(hp = gethostbyname(host))) {
\r
9415 unsigned int b0, b1, b2, b3;
\r
9417 err = WSAGetLastError();
\r
9419 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9420 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9421 hp->h_addrtype = AF_INET;
\r
9423 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9424 hp->h_addr_list[0] = (char *) malloc(4);
\r
9425 hp->h_addr_list[0][0] = (char) b0;
\r
9426 hp->h_addr_list[0][1] = (char) b1;
\r
9427 hp->h_addr_list[0][2] = (char) b2;
\r
9428 hp->h_addr_list[0][3] = (char) b3;
\r
9434 sa.sin_family = hp->h_addrtype;
\r
9435 uport = (unsigned short) 514;
\r
9436 sa.sin_port = htons(uport);
\r
9437 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9439 /* Bind local socket to unused "privileged" port address
\r
9441 s = INVALID_SOCKET;
\r
9442 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9443 mysa.sin_family = AF_INET;
\r
9444 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9445 for (fromPort = 1023;; fromPort--) {
\r
9446 if (fromPort < 0) {
\r
9448 return WSAEADDRINUSE;
\r
9450 if (s == INVALID_SOCKET) {
\r
9451 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9452 err = WSAGetLastError();
\r
9457 uport = (unsigned short) fromPort;
\r
9458 mysa.sin_port = htons(uport);
\r
9459 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9460 == SOCKET_ERROR) {
\r
9461 err = WSAGetLastError();
\r
9462 if (err == WSAEADDRINUSE) continue;
\r
9466 if (connect(s, (struct sockaddr *) &sa,
\r
9467 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9468 err = WSAGetLastError();
\r
9469 if (err == WSAEADDRINUSE) {
\r
9480 /* Bind stderr local socket to unused "privileged" port address
\r
9482 s2 = INVALID_SOCKET;
\r
9483 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9484 mysa.sin_family = AF_INET;
\r
9485 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9486 for (fromPort = 1023;; fromPort--) {
\r
9487 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9488 if (fromPort < 0) {
\r
9489 (void) closesocket(s);
\r
9491 return WSAEADDRINUSE;
\r
9493 if (s2 == INVALID_SOCKET) {
\r
9494 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9495 err = WSAGetLastError();
\r
9501 uport = (unsigned short) fromPort;
\r
9502 mysa.sin_port = htons(uport);
\r
9503 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9504 == SOCKET_ERROR) {
\r
9505 err = WSAGetLastError();
\r
9506 if (err == WSAEADDRINUSE) continue;
\r
9507 (void) closesocket(s);
\r
9511 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9512 err = WSAGetLastError();
\r
9513 if (err == WSAEADDRINUSE) {
\r
9515 s2 = INVALID_SOCKET;
\r
9518 (void) closesocket(s);
\r
9519 (void) closesocket(s2);
\r
9525 prevStderrPort = fromPort; // remember port used
\r
9526 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9528 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9529 err = WSAGetLastError();
\r
9530 (void) closesocket(s);
\r
9531 (void) closesocket(s2);
\r
9536 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9537 err = WSAGetLastError();
\r
9538 (void) closesocket(s);
\r
9539 (void) closesocket(s2);
\r
9543 if (*user == NULLCHAR) user = UserName();
\r
9544 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9545 err = WSAGetLastError();
\r
9546 (void) closesocket(s);
\r
9547 (void) closesocket(s2);
\r
9551 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9552 err = WSAGetLastError();
\r
9553 (void) closesocket(s);
\r
9554 (void) closesocket(s2);
\r
9559 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9560 err = WSAGetLastError();
\r
9561 (void) closesocket(s);
\r
9562 (void) closesocket(s2);
\r
9566 (void) closesocket(s2); /* Stop listening */
\r
9568 /* Prepare return value */
\r
9569 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9570 cp->kind = CPRcmd;
\r
9573 *pr = (ProcRef *) cp;
\r
9580 AddInputSource(ProcRef pr, int lineByLine,
\r
9581 InputCallback func, VOIDSTAR closure)
\r
9583 InputSource *is, *is2 = NULL;
\r
9584 ChildProc *cp = (ChildProc *) pr;
\r
9586 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9587 is->lineByLine = lineByLine;
\r
9589 is->closure = closure;
\r
9590 is->second = NULL;
\r
9591 is->next = is->buf;
\r
9592 if (pr == NoProc) {
\r
9593 is->kind = CPReal;
\r
9594 consoleInputSource = is;
\r
9596 is->kind = cp->kind;
\r
9598 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9599 we create all threads suspended so that the is->hThread variable can be
\r
9600 safely assigned, then let the threads start with ResumeThread.
\r
9602 switch (cp->kind) {
\r
9604 is->hFile = cp->hFrom;
\r
9605 cp->hFrom = NULL; /* now owned by InputThread */
\r
9607 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9608 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9612 is->hFile = cp->hFrom;
\r
9613 cp->hFrom = NULL; /* now owned by InputThread */
\r
9615 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9616 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9620 is->sock = cp->sock;
\r
9622 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9623 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9627 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9629 is->sock = cp->sock;
\r
9631 is2->sock = cp->sock2;
\r
9632 is2->second = is2;
\r
9634 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9635 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9637 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9638 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9642 if( is->hThread != NULL ) {
\r
9643 ResumeThread( is->hThread );
\r
9646 if( is2 != NULL && is2->hThread != NULL ) {
\r
9647 ResumeThread( is2->hThread );
\r
9651 return (InputSourceRef) is;
\r
9655 RemoveInputSource(InputSourceRef isr)
\r
9659 is = (InputSource *) isr;
\r
9660 is->hThread = NULL; /* tell thread to stop */
\r
9661 CloseHandle(is->hThread);
\r
9662 if (is->second != NULL) {
\r
9663 is->second->hThread = NULL;
\r
9664 CloseHandle(is->second->hThread);
\r
9668 int no_wrap(char *message, int count)
\r
9670 ConsoleOutput(message, count, FALSE);
\r
9675 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9678 int outCount = SOCKET_ERROR;
\r
9679 ChildProc *cp = (ChildProc *) pr;
\r
9680 static OVERLAPPED ovl;
\r
9681 static int line = 0;
\r
9685 if (appData.noJoin || !appData.useInternalWrap)
\r
9686 return no_wrap(message, count);
\r
9689 int width = get_term_width();
\r
9690 int len = wrap(NULL, message, count, width, &line);
\r
9691 char *msg = malloc(len);
\r
9695 return no_wrap(message, count);
\r
9698 dbgchk = wrap(msg, message, count, width, &line);
\r
9699 if (dbgchk != len && appData.debugMode)
\r
9700 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9701 ConsoleOutput(msg, len, FALSE);
\r
9708 if (ovl.hEvent == NULL) {
\r
9709 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9711 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9713 switch (cp->kind) {
\r
9716 outCount = send(cp->sock, message, count, 0);
\r
9717 if (outCount == SOCKET_ERROR) {
\r
9718 *outError = WSAGetLastError();
\r
9720 *outError = NO_ERROR;
\r
9725 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9726 &dOutCount, NULL)) {
\r
9727 *outError = NO_ERROR;
\r
9728 outCount = (int) dOutCount;
\r
9730 *outError = GetLastError();
\r
9735 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9736 &dOutCount, &ovl);
\r
9737 if (*outError == NO_ERROR) {
\r
9738 outCount = (int) dOutCount;
\r
9748 if(n != 0) Sleep(n);
\r
9752 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9755 /* Ignore delay, not implemented for WinBoard */
\r
9756 return OutputToProcess(pr, message, count, outError);
\r
9761 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9762 char *buf, int count, int error)
\r
9764 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9767 /* see wgamelist.c for Game List functions */
\r
9768 /* see wedittags.c for Edit Tags functions */
\r
9775 char buf[MSG_SIZ];
\r
9778 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9779 f = fopen(buf, "r");
\r
9781 ProcessICSInitScript(f);
\r
9791 StartAnalysisClock()
\r
9793 if (analysisTimerEvent) return;
\r
9794 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9795 (UINT) 2000, NULL);
\r
9799 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9801 highlightInfo.sq[0].x = fromX;
\r
9802 highlightInfo.sq[0].y = fromY;
\r
9803 highlightInfo.sq[1].x = toX;
\r
9804 highlightInfo.sq[1].y = toY;
\r
9810 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9811 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9815 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9817 premoveHighlightInfo.sq[0].x = fromX;
\r
9818 premoveHighlightInfo.sq[0].y = fromY;
\r
9819 premoveHighlightInfo.sq[1].x = toX;
\r
9820 premoveHighlightInfo.sq[1].y = toY;
\r
9824 ClearPremoveHighlights()
\r
9826 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9827 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9831 ShutDownFrontEnd()
\r
9833 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9834 DeleteClipboardTempFiles();
\r
9840 if (IsIconic(hwndMain))
\r
9841 ShowWindow(hwndMain, SW_RESTORE);
\r
9843 SetActiveWindow(hwndMain);
\r
9847 * Prototypes for animation support routines
\r
9849 static void ScreenSquare(int column, int row, POINT * pt);
\r
9850 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9851 POINT frames[], int * nFrames);
\r
9857 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9858 { // [HGM] atomic: animate blast wave
\r
9861 explodeInfo.fromX = fromX;
\r
9862 explodeInfo.fromY = fromY;
\r
9863 explodeInfo.toX = toX;
\r
9864 explodeInfo.toY = toY;
\r
9865 for(i=1; i<4*kFactor; i++) {
\r
9866 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9867 DrawPosition(FALSE, board);
\r
9868 Sleep(appData.animSpeed);
\r
9870 explodeInfo.radius = 0;
\r
9871 DrawPosition(TRUE, board);
\r
9875 AnimateMove(board, fromX, fromY, toX, toY)
\r
9882 ChessSquare piece;
\r
9883 POINT start, finish, mid;
\r
9884 POINT frames[kFactor * 2 + 1];
\r
9887 if (!appData.animate) return;
\r
9888 if (doingSizing) return;
\r
9889 if (fromY < 0 || fromX < 0) return;
\r
9890 piece = board[fromY][fromX];
\r
9891 if (piece >= EmptySquare) return;
\r
9893 ScreenSquare(fromX, fromY, &start);
\r
9894 ScreenSquare(toX, toY, &finish);
\r
9896 /* All moves except knight jumps move in straight line */
\r
9897 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
9898 mid.x = start.x + (finish.x - start.x) / 2;
\r
9899 mid.y = start.y + (finish.y - start.y) / 2;
\r
9901 /* Knight: make straight movement then diagonal */
\r
9902 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9903 mid.x = start.x + (finish.x - start.x) / 2;
\r
9907 mid.y = start.y + (finish.y - start.y) / 2;
\r
9911 /* Don't use as many frames for very short moves */
\r
9912 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9913 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9915 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9917 animInfo.from.x = fromX;
\r
9918 animInfo.from.y = fromY;
\r
9919 animInfo.to.x = toX;
\r
9920 animInfo.to.y = toY;
\r
9921 animInfo.lastpos = start;
\r
9922 animInfo.piece = piece;
\r
9923 for (n = 0; n < nFrames; n++) {
\r
9924 animInfo.pos = frames[n];
\r
9925 DrawPosition(FALSE, NULL);
\r
9926 animInfo.lastpos = animInfo.pos;
\r
9927 Sleep(appData.animSpeed);
\r
9929 animInfo.pos = finish;
\r
9930 DrawPosition(FALSE, NULL);
\r
9931 animInfo.piece = EmptySquare;
\r
9932 Explode(board, fromX, fromY, toX, toY);
\r
9935 /* Convert board position to corner of screen rect and color */
\r
9938 ScreenSquare(column, row, pt)
\r
9939 int column; int row; POINT * pt;
\r
9942 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
9943 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
9945 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
9946 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
9950 /* Generate a series of frame coords from start->mid->finish.
\r
9951 The movement rate doubles until the half way point is
\r
9952 reached, then halves back down to the final destination,
\r
9953 which gives a nice slow in/out effect. The algorithmn
\r
9954 may seem to generate too many intermediates for short
\r
9955 moves, but remember that the purpose is to attract the
\r
9956 viewers attention to the piece about to be moved and
\r
9957 then to where it ends up. Too few frames would be less
\r
9961 Tween(start, mid, finish, factor, frames, nFrames)
\r
9962 POINT * start; POINT * mid;
\r
9963 POINT * finish; int factor;
\r
9964 POINT frames[]; int * nFrames;
\r
9966 int n, fraction = 1, count = 0;
\r
9968 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9969 for (n = 0; n < factor; n++)
\r
9971 for (n = 0; n < factor; n++) {
\r
9972 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9973 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9975 fraction = fraction / 2;
\r
9979 frames[count] = *mid;
\r
9982 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9984 for (n = 0; n < factor; n++) {
\r
9985 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9986 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9988 fraction = fraction * 2;
\r
9994 SettingsPopUp(ChessProgramState *cps)
\r
9995 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
9996 EngineOptionsPopup(savedHwnd, cps);
\r
9999 int flock(int fid, int code)
\r
10001 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10003 ov.hEvent = NULL;
\r
10005 ov.OffsetHigh = 0;
\r
10007 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10008 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10009 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10010 default: return -1;
\r
10019 static char col[8][20];
\r
10020 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10022 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10027 ActivateTheme (int new)
\r
10028 { // Redo initialization of features depending on options that can occur in themes
\r
10030 if(new) InitDrawingColors();
\r
10031 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10032 InitDrawingSizes(-2, 0);
\r
10033 InvalidateRect(hwndMain, NULL, TRUE);
\r