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 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
83 #include "frontend.h"
\r
84 #include "backend.h"
\r
85 #include "winboard.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
101 extern HANDLE chatHandle[];
\r
102 extern int ics_type;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
111 void ChatPopUp P((char *s));
\r
113 ChessSquare piece;
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
117 POINT to; /* board coordinates of the piece's new pos */
\r
120 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT start; /* window coordinates of start pos */
\r
124 POINT pos; /* window coordinates of current pos */
\r
125 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
126 POINT from; /* board coordinates of the piece's orig pos */
\r
129 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
132 POINT sq[2]; /* board coordinates of from, to squares */
\r
135 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
136 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
137 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 Boolean saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
158 int errorExitStatus;
\r
160 BoardSize boardSize;
\r
161 Boolean chessProgram;
\r
162 //static int boardX, boardY;
\r
163 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
164 int squareSize, lineGap, minorSize;
\r
165 static int winW, winH;
\r
166 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
167 static int logoHeight = 0;
\r
168 static char messageText[MESSAGE_TEXT_MAX];
\r
169 static int clockTimerEvent = 0;
\r
170 static int loadGameTimerEvent = 0;
\r
171 static int analysisTimerEvent = 0;
\r
172 static DelayedEventCallback delayedTimerCallback;
\r
173 static int delayedTimerEvent = 0;
\r
174 static int buttonCount = 2;
\r
175 char *icsTextMenuString;
\r
177 char *firstChessProgramNames;
\r
178 char *secondChessProgramNames;
\r
180 #define PALETTESIZE 256
\r
182 HINSTANCE hInst; /* current instance */
\r
183 Boolean alwaysOnTop = FALSE;
\r
185 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
186 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
188 ColorClass currentColorClass;
\r
190 HWND hCommPort = NULL; /* currently open comm port */
\r
191 static HWND hwndPause; /* pause button */
\r
192 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
193 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
194 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
195 explodeBrush, /* [HGM] atomic */
\r
196 markerBrush, /* [HGM] markers */
\r
197 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
198 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
199 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
200 static HPEN gridPen = NULL;
\r
201 static HPEN highlightPen = NULL;
\r
202 static HPEN premovePen = NULL;
\r
203 static NPLOGPALETTE pLogPal;
\r
204 static BOOL paletteChanged = FALSE;
\r
205 static HICON iconWhite, iconBlack, iconCurrent;
\r
206 static int doingSizing = FALSE;
\r
207 static int lastSizing = 0;
\r
208 static int prevStderrPort;
\r
209 static HBITMAP userLogo;
\r
211 static HBITMAP liteBackTexture = NULL;
\r
212 static HBITMAP darkBackTexture = NULL;
\r
213 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
214 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
215 static int backTextureSquareSize = 0;
\r
216 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
218 #if __GNUC__ && !defined(_winmajor)
\r
219 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
221 #if defined(_winmajor)
\r
222 #define oldDialog (_winmajor < 4)
\r
224 #define oldDialog 0
\r
228 #define INTERNATIONAL
\r
230 #ifdef INTERNATIONAL
\r
231 # define _(s) T_(s)
\r
237 # define Translate(x, y)
\r
238 # define LoadLanguageFile(s)
\r
241 #ifdef INTERNATIONAL
\r
243 Boolean barbaric; // flag indicating if translation is needed
\r
245 // list of item numbers used in each dialog (used to alter language at run time)
\r
247 #define ABOUTBOX -1 /* not sure why these are needed */
\r
248 #define ABOUTBOX2 -1
\r
250 int dialogItems[][40] = {
\r
251 { ABOUTBOX, IDOK, 400 },
\r
252 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
253 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
254 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, IDOK, IDCANCEL },
\r
255 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
256 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
257 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
258 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
259 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
260 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
261 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
262 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
263 { ABOUTBOX2, IDC_ChessBoard },
\r
264 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
265 OPT_GameListClose, IDC_GameListDoFilter },
\r
266 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
267 { DLG_Error, IDOK },
\r
268 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
269 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
270 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
271 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
272 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
273 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
274 { DLG_IndexNumber, IDC_Index },
\r
275 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
276 { DLG_TypeInName, IDOK, IDCANCEL },
\r
277 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
278 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
279 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
280 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove, OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
281 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
282 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
283 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
284 OPT_HighlightMoveArrow, OPT_AutoLogo },
\r
285 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
286 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
287 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
288 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
289 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
290 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
291 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
292 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
293 GPB_General, GPB_Alarm },
\r
294 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
295 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
296 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
297 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
298 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
299 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
300 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
301 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size },
\r
302 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
303 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
304 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
305 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
306 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
307 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
308 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat,
\r
309 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
310 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
311 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
312 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
313 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont,
\r
314 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
315 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
316 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
317 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
318 { DLG_MoveHistory },
\r
319 { DLG_EvalGraph },
\r
320 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
321 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
322 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
323 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
324 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
325 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
326 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
327 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
328 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
332 char languageBuf[40000], *foreign[1000], *english[1000];
\r
335 LoadLanguageFile(char *name)
\r
336 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
338 int i=0, j=0, n=0, k;
\r
339 static char oldLanguage[MSG_SIZ];
\r
340 if(!strcmp(name, oldLanguage)) return;
\r
341 if(!name || name[0] == NULLCHAR) return;
\r
342 if((f = fopen(name, "r")) == NULL) return;
\r
343 while((k = fgetc(f)) != EOF) {
\r
344 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
345 languageBuf[i] = k;
\r
347 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
349 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
350 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
351 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
352 english[j] = languageBuf + n + 1; *p = 0;
\r
353 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
354 if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
359 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
361 case 'n': k = '\n'; break;
\r
362 case 'r': k = '\r'; break;
\r
363 case 't': k = '\t'; break;
\r
365 languageBuf[--i] = k;
\r
370 barbaric = (j != 0);
\r
371 if(barbaric) strcpy(oldLanguage, name); else oldLanguage[0] = NULLCHAR;
\r
376 { // return the translation of the given string
\r
377 // efficiency can be improved a lot...
\r
379 if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
380 if(!barbaric) return s;
\r
381 if(!s) return ""; // sanity
\r
382 while(english[i]) {
\r
383 if(!strcmp(s, english[i])) return foreign[i];
\r
390 Translate(HANDLE hDlg, int dialogID)
\r
391 { // translate all text items in the given dialog
\r
393 char buf[MSG_SIZ], *s;
\r
394 //if(appData.debugMode) fprintf(debugFP, "Translate(%d)\n", dialogID);
\r
395 if(!barbaric) return;
\r
396 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
397 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
398 GetWindowText( hDlg, buf, MSG_SIZ );
\r
400 if(appData.debugMode) fprintf(debugFP, "WindowText '%s' -> '%s'\n", buf, s);
\r
401 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
402 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
403 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
404 if(strlen(buf) == 0) continue;
\r
406 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
415 HMENU mainMenu = GetMenu(hwndMain);
\r
416 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
417 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
418 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
420 UINT k = GetMenuItemID(subMenu, j);
\r
421 GetMenuString(subMenu, j, buf, MSG_SIZ, MF_BYPOSITION);
\r
422 if(buf[0] == NULLCHAR) continue;
\r
423 //fprintf(debugFP, "menu(%d,%d) = %s (%08x, %08x) %d\n", i, j, buf, mainMenu, subMenu, k);
\r
424 ModifyMenu(subMenu, j, MF_STRING|MF_BYPOSITION,
\r
440 int cliWidth, cliHeight;
\r
443 SizeInfo sizeInfo[] =
\r
445 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
446 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
447 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
448 { "petite", 33, 1, 1, 1, 0, 0 },
\r
449 { "slim", 37, 2, 1, 0, 0, 0 },
\r
450 { "small", 40, 2, 1, 0, 0, 0 },
\r
451 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
452 { "middling", 49, 2, 0, 0, 0, 0 },
\r
453 { "average", 54, 2, 0, 0, 0, 0 },
\r
454 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
455 { "medium", 64, 3, 0, 0, 0, 0 },
\r
456 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
457 { "large", 80, 3, 0, 0, 0, 0 },
\r
458 { "big", 87, 3, 0, 0, 0, 0 },
\r
459 { "huge", 95, 3, 0, 0, 0, 0 },
\r
460 { "giant", 108, 3, 0, 0, 0, 0 },
\r
461 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
462 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
463 { NULL, 0, 0, 0, 0, 0, 0 }
\r
466 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
467 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
469 { 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) },
\r
470 { 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) },
\r
471 { 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) },
\r
472 { 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) },
\r
473 { 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) },
\r
474 { 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) },
\r
475 { 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) },
\r
476 { 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) },
\r
477 { 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) },
\r
478 { 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) },
\r
479 { 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) },
\r
480 { 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) },
\r
481 { 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) },
\r
482 { 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) },
\r
483 { 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) },
\r
484 { 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) },
\r
485 { 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) },
\r
486 { 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) },
\r
489 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
498 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
499 #define N_BUTTONS 5
\r
501 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
503 {"<<", IDM_ToStart, NULL, NULL},
\r
504 {"<", IDM_Backward, NULL, NULL},
\r
505 {"P", IDM_Pause, NULL, NULL},
\r
506 {">", IDM_Forward, NULL, NULL},
\r
507 {">>", IDM_ToEnd, NULL, NULL},
\r
510 int tinyLayout = 0, smallLayout = 0;
\r
511 #define MENU_BAR_ITEMS 7
\r
512 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
513 { N_("&File"), N_("&Mode"), N_("&Action"), N_("&Step"), N_("&Options"), N_("&Help"), NULL },
\r
514 { N_("&F"), N_("&M"), N_("&A"), N_("&S"), N_("&O"), N_("&H"), NULL },
\r
518 MySound sounds[(int)NSoundClasses];
\r
519 MyTextAttribs textAttribs[(int)NColorClasses];
\r
521 MyColorizeAttribs colorizeAttribs[] = {
\r
522 { (COLORREF)0, 0, N_("Shout Text") },
\r
523 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
524 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
525 { (COLORREF)0, 0, N_("Channel Text") },
\r
526 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
527 { (COLORREF)0, 0, N_("Tell Text") },
\r
528 { (COLORREF)0, 0, N_("Challenge Text") },
\r
529 { (COLORREF)0, 0, N_("Request Text") },
\r
530 { (COLORREF)0, 0, N_("Seek Text") },
\r
531 { (COLORREF)0, 0, N_("Normal Text") },
\r
532 { (COLORREF)0, 0, N_("None") }
\r
537 static char *commentTitle;
\r
538 static char *commentText;
\r
539 static int commentIndex;
\r
540 static Boolean editComment = FALSE;
\r
543 char errorTitle[MSG_SIZ];
\r
544 char errorMessage[2*MSG_SIZ];
\r
545 HWND errorDialog = NULL;
\r
546 BOOLEAN moveErrorMessageUp = FALSE;
\r
547 BOOLEAN consoleEcho = TRUE;
\r
548 CHARFORMAT consoleCF;
\r
549 COLORREF consoleBackgroundColor;
\r
551 char *programVersion;
\r
557 typedef int CPKind;
\r
566 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
569 #define INPUT_SOURCE_BUF_SIZE 4096
\r
571 typedef struct _InputSource {
\r
578 char buf[INPUT_SOURCE_BUF_SIZE];
\r
582 InputCallback func;
\r
583 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
587 InputSource *consoleInputSource;
\r
592 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
593 VOID ConsoleCreate();
\r
595 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
596 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
597 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
598 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
600 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
601 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
602 void ParseIcsTextMenu(char *icsTextMenuString);
\r
603 VOID PopUpMoveDialog(char firstchar);
\r
604 VOID PopUpNameDialog(char firstchar);
\r
605 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
609 int GameListOptions();
\r
611 int dummy; // [HGM] for obsolete args
\r
613 HWND hwndMain = NULL; /* root window*/
\r
614 HWND hwndConsole = NULL;
\r
615 HWND commentDialog = NULL;
\r
616 HWND moveHistoryDialog = NULL;
\r
617 HWND evalGraphDialog = NULL;
\r
618 HWND engineOutputDialog = NULL;
\r
619 HWND gameListDialog = NULL;
\r
620 HWND editTagsDialog = NULL;
\r
622 int commentUp = FALSE;
\r
624 WindowPlacement wpMain;
\r
625 WindowPlacement wpConsole;
\r
626 WindowPlacement wpComment;
\r
627 WindowPlacement wpMoveHistory;
\r
628 WindowPlacement wpEvalGraph;
\r
629 WindowPlacement wpEngineOutput;
\r
630 WindowPlacement wpGameList;
\r
631 WindowPlacement wpTags;
\r
633 VOID EngineOptionsPopup(); // [HGM] settings
\r
635 VOID GothicPopUp(char *title, VariantClass variant);
\r
637 * Setting "frozen" should disable all user input other than deleting
\r
638 * the window. We do this while engines are initializing themselves.
\r
640 static int frozen = 0;
\r
641 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
647 if (frozen) return;
\r
649 hmenu = GetMenu(hwndMain);
\r
650 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
651 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
653 DrawMenuBar(hwndMain);
\r
656 /* Undo a FreezeUI */
\r
662 if (!frozen) return;
\r
664 hmenu = GetMenu(hwndMain);
\r
665 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
666 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
668 DrawMenuBar(hwndMain);
\r
671 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
673 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
679 #define JAWS_ALT_INTERCEPT
\r
680 #define JAWS_KB_NAVIGATION
\r
681 #define JAWS_MENU_ITEMS
\r
682 #define JAWS_SILENCE
\r
683 #define JAWS_REPLAY
\r
685 #define JAWS_COPYRIGHT
\r
686 #define JAWS_DELETE(X) X
\r
687 #define SAYMACHINEMOVE()
\r
691 /*---------------------------------------------------------------------------*\
\r
695 \*---------------------------------------------------------------------------*/
\r
698 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
699 LPSTR lpCmdLine, int nCmdShow)
\r
702 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
703 // INITCOMMONCONTROLSEX ex;
\r
707 LoadLibrary("RICHED32.DLL");
\r
708 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
710 if (!InitApplication(hInstance)) {
\r
713 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
719 // InitCommonControlsEx(&ex);
\r
720 InitCommonControls();
\r
722 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
723 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
724 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
726 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
728 while (GetMessage(&msg, /* message structure */
\r
729 NULL, /* handle of window receiving the message */
\r
730 0, /* lowest message to examine */
\r
731 0)) /* highest message to examine */
\r
734 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
735 // [HGM] navigate: switch between all windows with tab
\r
736 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
737 int i, currentElement = 0;
\r
739 // first determine what element of the chain we come from (if any)
\r
740 if(appData.icsActive) {
\r
741 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
742 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
744 if(engineOutputDialog && EngineOutputIsUp()) {
\r
745 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
746 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
748 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
749 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
751 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
752 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
753 if(msg.hwnd == e1) currentElement = 2; else
\r
754 if(msg.hwnd == e2) currentElement = 3; else
\r
755 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
756 if(msg.hwnd == mh) currentElement = 4; else
\r
757 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
758 if(msg.hwnd == hText) currentElement = 5; else
\r
759 if(msg.hwnd == hInput) currentElement = 6; else
\r
760 for (i = 0; i < N_BUTTONS; i++) {
\r
761 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
764 // determine where to go to
\r
765 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
767 currentElement = (currentElement + direction) % 7;
\r
768 switch(currentElement) {
\r
770 h = hwndMain; break; // passing this case always makes the loop exit
\r
772 h = buttonDesc[0].hwnd; break; // could be NULL
\r
774 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
777 if(!EngineOutputIsUp()) continue;
\r
780 if(!MoveHistoryIsUp()) continue;
\r
782 // case 6: // input to eval graph does not seem to get here!
\r
783 // if(!EvalGraphIsUp()) continue;
\r
784 // h = evalGraphDialog; break;
\r
786 if(!appData.icsActive) continue;
\r
790 if(!appData.icsActive) continue;
\r
796 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
797 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
800 continue; // this message now has been processed
\r
804 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
805 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
806 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
807 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
808 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
809 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
810 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
811 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
812 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
813 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
814 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
815 for(i=0; i<MAX_CHAT; i++)
\r
816 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
819 if(done) continue; // [HGM] chat: end patch
\r
820 TranslateMessage(&msg); /* Translates virtual key codes */
\r
821 DispatchMessage(&msg); /* Dispatches message to window */
\r
826 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
829 /*---------------------------------------------------------------------------*\
\r
831 * Initialization functions
\r
833 \*---------------------------------------------------------------------------*/
\r
837 { // update user logo if necessary
\r
838 static char oldUserName[MSG_SIZ], *curName;
\r
840 if(appData.autoLogo) {
\r
841 curName = UserName();
\r
842 if(strcmp(curName, oldUserName)) {
\r
843 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
844 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
845 strcpy(oldUserName, curName);
\r
851 InitApplication(HINSTANCE hInstance)
\r
855 /* Fill in window class structure with parameters that describe the */
\r
858 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
859 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
860 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
861 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
862 wc.hInstance = hInstance; /* Owner of this class */
\r
863 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
864 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
865 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
866 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
867 wc.lpszClassName = szAppName; /* Name to register as */
\r
869 /* Register the window class and return success/failure code. */
\r
870 if (!RegisterClass(&wc)) return FALSE;
\r
872 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
873 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
875 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
876 wc.hInstance = hInstance;
\r
877 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
878 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
879 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
880 wc.lpszMenuName = NULL;
\r
881 wc.lpszClassName = szConsoleName;
\r
883 if (!RegisterClass(&wc)) return FALSE;
\r
888 /* Set by InitInstance, used by EnsureOnScreen */
\r
889 int screenHeight, screenWidth;
\r
892 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
894 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
895 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
896 if (*x > screenWidth - 32) *x = 0;
\r
897 if (*y > screenHeight - 32) *y = 0;
\r
898 if (*x < minX) *x = minX;
\r
899 if (*y < minY) *y = minY;
\r
903 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
905 HWND hwnd; /* Main window handle. */
\r
907 WINDOWPLACEMENT wp;
\r
910 hInst = hInstance; /* Store instance handle in our global variable */
\r
911 programName = szAppName;
\r
913 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
914 *filepart = NULLCHAR;
\r
916 GetCurrentDirectory(MSG_SIZ, installDir);
\r
918 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
919 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
920 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
921 /* xboard, and older WinBoards, controlled the move sound with the
\r
922 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
923 always turn the option on (so that the backend will call us),
\r
924 then let the user turn the sound off by setting it to silence if
\r
925 desired. To accommodate old winboard.ini files saved by old
\r
926 versions of WinBoard, we also turn off the sound if the option
\r
927 was initially set to false. [HGM] taken out of InitAppData */
\r
928 if (!appData.ringBellAfterMoves) {
\r
929 sounds[(int)SoundMove].name = strdup("");
\r
930 appData.ringBellAfterMoves = TRUE;
\r
932 if (appData.debugMode) {
\r
933 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
934 setbuf(debugFP, NULL);
\r
937 LoadLanguageFile(appData.language);
\r
941 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
942 // InitEngineUCI( installDir, &second );
\r
944 /* Create a main window for this application instance. */
\r
945 hwnd = CreateWindow(szAppName, szTitle,
\r
946 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
947 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
948 NULL, NULL, hInstance, NULL);
\r
951 /* If window could not be created, return "failure" */
\r
956 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
957 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
958 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
960 if (first.programLogo == NULL && appData.debugMode) {
\r
961 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
963 } else if(appData.autoLogo) {
\r
964 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
966 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
967 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
971 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
972 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
974 if (second.programLogo == NULL && appData.debugMode) {
\r
975 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
977 } else if(appData.autoLogo) {
\r
979 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
980 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
981 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
983 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
984 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
985 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
991 iconWhite = LoadIcon(hInstance, "icon_white");
\r
992 iconBlack = LoadIcon(hInstance, "icon_black");
\r
993 iconCurrent = iconWhite;
\r
994 InitDrawingColors();
\r
995 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
996 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
997 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
998 /* Compute window size for each board size, and use the largest
\r
999 size that fits on this screen as the default. */
\r
1000 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1001 if (boardSize == (BoardSize)-1 &&
\r
1002 winH <= screenHeight
\r
1003 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1004 && winW <= screenWidth) {
\r
1005 boardSize = (BoardSize)ibs;
\r
1009 InitDrawingSizes(boardSize, 0);
\r
1012 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1014 /* [AS] Load textures if specified */
\r
1015 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1017 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1018 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1019 liteBackTextureMode = appData.liteBackTextureMode;
\r
1021 if (liteBackTexture == NULL && appData.debugMode) {
\r
1022 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1026 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1027 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1028 darkBackTextureMode = appData.darkBackTextureMode;
\r
1030 if (darkBackTexture == NULL && appData.debugMode) {
\r
1031 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1035 mysrandom( (unsigned) time(NULL) );
\r
1037 /* [AS] Restore layout */
\r
1038 if( wpMoveHistory.visible ) {
\r
1039 MoveHistoryPopUp();
\r
1042 if( wpEvalGraph.visible ) {
\r
1046 if( wpEngineOutput.visible ) {
\r
1047 EngineOutputPopUp();
\r
1050 /* Make the window visible; update its client area; and return "success" */
\r
1051 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1052 wp.length = sizeof(WINDOWPLACEMENT);
\r
1054 wp.showCmd = nCmdShow;
\r
1055 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1056 wp.rcNormalPosition.left = wpMain.x;
\r
1057 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1058 wp.rcNormalPosition.top = wpMain.y;
\r
1059 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1060 SetWindowPlacement(hwndMain, &wp);
\r
1062 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1064 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1065 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1067 if (hwndConsole) {
\r
1069 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1070 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1072 ShowWindow(hwndConsole, nCmdShow);
\r
1073 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
1074 char buf[MSG_SIZ], *p = buf, *q;
\r
1075 strcpy(buf, appData.chatBoxes);
\r
1077 q = strchr(p, ';');
\r
1079 if(*p) ChatPopUp(p);
\r
1082 SetActiveWindow(hwndConsole);
\r
1084 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1085 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1094 HMENU hmenu = GetMenu(hwndMain);
\r
1096 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1097 MF_BYCOMMAND|((appData.icsActive &&
\r
1098 *appData.icsCommPort != NULLCHAR) ?
\r
1099 MF_ENABLED : MF_GRAYED));
\r
1100 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1101 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1102 MF_CHECKED : MF_UNCHECKED));
\r
1105 //---------------------------------------------------------------------------------------------------------
\r
1107 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1108 #define XBOARD FALSE
\r
1110 #define OPTCHAR "/"
\r
1111 #define SEPCHAR "="
\r
1115 // front-end part of option handling
\r
1118 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1120 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1121 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1124 lf->lfEscapement = 0;
\r
1125 lf->lfOrientation = 0;
\r
1126 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1127 lf->lfItalic = mfp->italic;
\r
1128 lf->lfUnderline = mfp->underline;
\r
1129 lf->lfStrikeOut = mfp->strikeout;
\r
1130 lf->lfCharSet = mfp->charset;
\r
1131 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1132 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1133 lf->lfQuality = DEFAULT_QUALITY;
\r
1134 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1135 strcpy(lf->lfFaceName, mfp->faceName);
\r
1139 CreateFontInMF(MyFont *mf)
\r
1141 LFfromMFP(&mf->lf, &mf->mfp);
\r
1142 if (mf->hf) DeleteObject(mf->hf);
\r
1143 mf->hf = CreateFontIndirect(&mf->lf);
\r
1146 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1148 colorVariable[] = {
\r
1149 &whitePieceColor,
\r
1150 &blackPieceColor,
\r
1151 &lightSquareColor,
\r
1152 &darkSquareColor,
\r
1153 &highlightSquareColor,
\r
1154 &premoveHighlightColor,
\r
1156 &consoleBackgroundColor,
\r
1157 &appData.fontForeColorWhite,
\r
1158 &appData.fontBackColorWhite,
\r
1159 &appData.fontForeColorBlack,
\r
1160 &appData.fontBackColorBlack,
\r
1161 &appData.evalHistColorWhite,
\r
1162 &appData.evalHistColorBlack,
\r
1163 &appData.highlightArrowColor,
\r
1166 /* Command line font name parser. NULL name means do nothing.
\r
1167 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1168 For backward compatibility, syntax without the colon is also
\r
1169 accepted, but font names with digits in them won't work in that case.
\r
1172 ParseFontName(char *name, MyFontParams *mfp)
\r
1175 if (name == NULL) return;
\r
1177 q = strchr(p, ':');
\r
1179 if (q - p >= sizeof(mfp->faceName))
\r
1180 ExitArgError(_("Font name too long:"), name);
\r
1181 memcpy(mfp->faceName, p, q - p);
\r
1182 mfp->faceName[q - p] = NULLCHAR;
\r
1185 q = mfp->faceName;
\r
1186 while (*p && !isdigit(*p)) {
\r
1188 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1189 ExitArgError(_("Font name too long:"), name);
\r
1191 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1194 if (!*p) ExitArgError(_("Font point size missing:"), name);
\r
1195 mfp->pointSize = (float) atof(p);
\r
1196 mfp->bold = (strchr(p, 'b') != NULL);
\r
1197 mfp->italic = (strchr(p, 'i') != NULL);
\r
1198 mfp->underline = (strchr(p, 'u') != NULL);
\r
1199 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1200 mfp->charset = DEFAULT_CHARSET;
\r
1201 q = strchr(p, 'c');
\r
1203 mfp->charset = (BYTE) atoi(q+1);
\r
1207 ParseFont(char *name, int number)
\r
1208 { // wrapper to shield back-end from 'font'
\r
1209 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1214 { // in WB we have a 2D array of fonts; this initializes their description
\r
1216 /* Point font array elements to structures and
\r
1217 parse default font names */
\r
1218 for (i=0; i<NUM_FONTS; i++) {
\r
1219 for (j=0; j<NUM_SIZES; j++) {
\r
1220 font[j][i] = &fontRec[j][i];
\r
1221 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1228 { // here we create the actual fonts from the selected descriptions
\r
1230 for (i=0; i<NUM_FONTS; i++) {
\r
1231 for (j=0; j<NUM_SIZES; j++) {
\r
1232 CreateFontInMF(font[j][i]);
\r
1236 /* Color name parser.
\r
1237 X version accepts X color names, but this one
\r
1238 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1240 ParseColorName(char *name)
\r
1242 int red, green, blue, count;
\r
1243 char buf[MSG_SIZ];
\r
1245 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1247 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1248 &red, &green, &blue);
\r
1251 sprintf(buf, _("Can't parse color name %s"), name);
\r
1252 DisplayError(buf, 0);
\r
1253 return RGB(0, 0, 0);
\r
1255 return PALETTERGB(red, green, blue);
\r
1259 ParseColor(int n, char *name)
\r
1260 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1261 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1265 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1267 char *e = argValue;
\r
1271 if (*e == 'b') eff |= CFE_BOLD;
\r
1272 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1273 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1274 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1275 else if (*e == '#' || isdigit(*e)) break;
\r
1279 *color = ParseColorName(e);
\r
1283 ParseTextAttribs(ColorClass cc, char *s)
\r
1284 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1285 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1286 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1290 ParseBoardSize(void *addr, char *name)
\r
1291 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1292 BoardSize bs = SizeTiny;
\r
1293 while (sizeInfo[bs].name != NULL) {
\r
1294 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1295 *(BoardSize *)addr = bs;
\r
1300 ExitArgError(_("Unrecognized board size value"), name);
\r
1305 { // [HGM] import name from appData first
\r
1308 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1309 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1310 textAttribs[cc].sound.data = NULL;
\r
1311 MyLoadSound(&textAttribs[cc].sound);
\r
1313 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1314 textAttribs[cc].sound.name = strdup("");
\r
1315 textAttribs[cc].sound.data = NULL;
\r
1317 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1318 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1319 sounds[sc].data = NULL;
\r
1320 MyLoadSound(&sounds[sc]);
\r
1325 SetCommPortDefaults()
\r
1327 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1328 dcb.DCBlength = sizeof(DCB);
\r
1329 dcb.BaudRate = 9600;
\r
1330 dcb.fBinary = TRUE;
\r
1331 dcb.fParity = FALSE;
\r
1332 dcb.fOutxCtsFlow = FALSE;
\r
1333 dcb.fOutxDsrFlow = FALSE;
\r
1334 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1335 dcb.fDsrSensitivity = FALSE;
\r
1336 dcb.fTXContinueOnXoff = TRUE;
\r
1337 dcb.fOutX = FALSE;
\r
1339 dcb.fNull = FALSE;
\r
1340 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1341 dcb.fAbortOnError = FALSE;
\r
1343 dcb.Parity = SPACEPARITY;
\r
1344 dcb.StopBits = ONESTOPBIT;
\r
1347 // [HGM] args: these three cases taken out to stay in front-end
\r
1349 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1350 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1351 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1352 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1354 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1355 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1356 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1357 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1358 ad->argName, mfp->faceName, mfp->pointSize,
\r
1359 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1360 mfp->bold ? "b" : "",
\r
1361 mfp->italic ? "i" : "",
\r
1362 mfp->underline ? "u" : "",
\r
1363 mfp->strikeout ? "s" : "",
\r
1364 (int)mfp->charset);
\r
1370 { // [HGM] copy the names from the internal WB variables to appData
\r
1373 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1374 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1375 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1376 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1380 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1381 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1382 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1383 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1384 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1385 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1386 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1387 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1388 (ta->effects) ? " " : "",
\r
1389 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1393 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1394 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1395 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1396 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1397 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1401 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1402 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1403 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1407 ParseCommPortSettings(char *s)
\r
1408 { // wrapper to keep dcb from back-end
\r
1409 ParseCommSettings(s, &dcb);
\r
1414 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1415 GetActualPlacement(hwndMain, &wpMain);
\r
1416 GetActualPlacement(hwndConsole, &wpConsole);
\r
1417 GetActualPlacement(commentDialog, &wpComment);
\r
1418 GetActualPlacement(editTagsDialog, &wpTags);
\r
1419 GetActualPlacement(gameListDialog, &wpGameList);
\r
1420 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1421 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1422 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1426 PrintCommPortSettings(FILE *f, char *name)
\r
1427 { // wrapper to shield back-end from DCB
\r
1428 PrintCommSettings(f, name, &dcb);
\r
1432 MySearchPath(char *installDir, char *name, char *fullname)
\r
1434 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1435 if(name[0]== '%') {
\r
1436 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1437 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1439 *strchr(buf, '%') = 0;
\r
1440 strcat(fullname, getenv(buf));
\r
1441 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1443 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1444 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1445 return (int) strlen(fullname);
\r
1447 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1451 MyGetFullPathName(char *name, char *fullname)
\r
1454 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1459 { // [HGM] args: allows testing if main window is realized from back-end
\r
1460 return hwndMain != NULL;
\r
1464 PopUpStartupDialog()
\r
1468 LoadLanguageFile(appData.language);
\r
1469 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1470 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1471 FreeProcInstance(lpProc);
\r
1474 /*---------------------------------------------------------------------------*\
\r
1476 * GDI board drawing routines
\r
1478 \*---------------------------------------------------------------------------*/
\r
1480 /* [AS] Draw square using background texture */
\r
1481 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1486 return; /* Should never happen! */
\r
1489 SetGraphicsMode( dst, GM_ADVANCED );
\r
1496 /* X reflection */
\r
1501 x.eDx = (FLOAT) dw + dx - 1;
\r
1504 SetWorldTransform( dst, &x );
\r
1507 /* Y reflection */
\r
1513 x.eDy = (FLOAT) dh + dy - 1;
\r
1515 SetWorldTransform( dst, &x );
\r
1523 x.eDx = (FLOAT) dx;
\r
1524 x.eDy = (FLOAT) dy;
\r
1527 SetWorldTransform( dst, &x );
\r
1531 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1539 SetWorldTransform( dst, &x );
\r
1541 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1544 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1546 PM_WP = (int) WhitePawn,
\r
1547 PM_WN = (int) WhiteKnight,
\r
1548 PM_WB = (int) WhiteBishop,
\r
1549 PM_WR = (int) WhiteRook,
\r
1550 PM_WQ = (int) WhiteQueen,
\r
1551 PM_WF = (int) WhiteFerz,
\r
1552 PM_WW = (int) WhiteWazir,
\r
1553 PM_WE = (int) WhiteAlfil,
\r
1554 PM_WM = (int) WhiteMan,
\r
1555 PM_WO = (int) WhiteCannon,
\r
1556 PM_WU = (int) WhiteUnicorn,
\r
1557 PM_WH = (int) WhiteNightrider,
\r
1558 PM_WA = (int) WhiteAngel,
\r
1559 PM_WC = (int) WhiteMarshall,
\r
1560 PM_WAB = (int) WhiteCardinal,
\r
1561 PM_WD = (int) WhiteDragon,
\r
1562 PM_WL = (int) WhiteLance,
\r
1563 PM_WS = (int) WhiteCobra,
\r
1564 PM_WV = (int) WhiteFalcon,
\r
1565 PM_WSG = (int) WhiteSilver,
\r
1566 PM_WG = (int) WhiteGrasshopper,
\r
1567 PM_WK = (int) WhiteKing,
\r
1568 PM_BP = (int) BlackPawn,
\r
1569 PM_BN = (int) BlackKnight,
\r
1570 PM_BB = (int) BlackBishop,
\r
1571 PM_BR = (int) BlackRook,
\r
1572 PM_BQ = (int) BlackQueen,
\r
1573 PM_BF = (int) BlackFerz,
\r
1574 PM_BW = (int) BlackWazir,
\r
1575 PM_BE = (int) BlackAlfil,
\r
1576 PM_BM = (int) BlackMan,
\r
1577 PM_BO = (int) BlackCannon,
\r
1578 PM_BU = (int) BlackUnicorn,
\r
1579 PM_BH = (int) BlackNightrider,
\r
1580 PM_BA = (int) BlackAngel,
\r
1581 PM_BC = (int) BlackMarshall,
\r
1582 PM_BG = (int) BlackGrasshopper,
\r
1583 PM_BAB = (int) BlackCardinal,
\r
1584 PM_BD = (int) BlackDragon,
\r
1585 PM_BL = (int) BlackLance,
\r
1586 PM_BS = (int) BlackCobra,
\r
1587 PM_BV = (int) BlackFalcon,
\r
1588 PM_BSG = (int) BlackSilver,
\r
1589 PM_BK = (int) BlackKing
\r
1592 static HFONT hPieceFont = NULL;
\r
1593 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1594 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1595 static int fontBitmapSquareSize = 0;
\r
1596 static char pieceToFontChar[(int) EmptySquare] =
\r
1597 { 'p', 'n', 'b', 'r', 'q',
\r
1598 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1599 'k', 'o', 'm', 'v', 't', 'w',
\r
1600 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1603 extern BOOL SetCharTable( char *table, const char * map );
\r
1604 /* [HGM] moved to backend.c */
\r
1606 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1609 BYTE r1 = GetRValue( color );
\r
1610 BYTE g1 = GetGValue( color );
\r
1611 BYTE b1 = GetBValue( color );
\r
1617 /* Create a uniform background first */
\r
1618 hbrush = CreateSolidBrush( color );
\r
1619 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1620 FillRect( hdc, &rc, hbrush );
\r
1621 DeleteObject( hbrush );
\r
1624 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1625 int steps = squareSize / 2;
\r
1628 for( i=0; i<steps; i++ ) {
\r
1629 BYTE r = r1 - (r1-r2) * i / steps;
\r
1630 BYTE g = g1 - (g1-g2) * i / steps;
\r
1631 BYTE b = b1 - (b1-b2) * i / steps;
\r
1633 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1634 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1635 FillRect( hdc, &rc, hbrush );
\r
1636 DeleteObject(hbrush);
\r
1639 else if( mode == 2 ) {
\r
1640 /* Diagonal gradient, good more or less for every piece */
\r
1641 POINT triangle[3];
\r
1642 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1643 HBRUSH hbrush_old;
\r
1644 int steps = squareSize;
\r
1647 triangle[0].x = squareSize - steps;
\r
1648 triangle[0].y = squareSize;
\r
1649 triangle[1].x = squareSize;
\r
1650 triangle[1].y = squareSize;
\r
1651 triangle[2].x = squareSize;
\r
1652 triangle[2].y = squareSize - steps;
\r
1654 for( i=0; i<steps; i++ ) {
\r
1655 BYTE r = r1 - (r1-r2) * i / steps;
\r
1656 BYTE g = g1 - (g1-g2) * i / steps;
\r
1657 BYTE b = b1 - (b1-b2) * i / steps;
\r
1659 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1660 hbrush_old = SelectObject( hdc, hbrush );
\r
1661 Polygon( hdc, triangle, 3 );
\r
1662 SelectObject( hdc, hbrush_old );
\r
1663 DeleteObject(hbrush);
\r
1668 SelectObject( hdc, hpen );
\r
1673 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1674 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1675 piece: follow the steps as explained below.
\r
1677 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1681 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1685 int backColor = whitePieceColor;
\r
1686 int foreColor = blackPieceColor;
\r
1688 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1689 backColor = appData.fontBackColorWhite;
\r
1690 foreColor = appData.fontForeColorWhite;
\r
1692 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1693 backColor = appData.fontBackColorBlack;
\r
1694 foreColor = appData.fontForeColorBlack;
\r
1698 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1700 hbm_old = SelectObject( hdc, hbm );
\r
1704 rc.right = squareSize;
\r
1705 rc.bottom = squareSize;
\r
1707 /* Step 1: background is now black */
\r
1708 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1710 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1712 pt.x = (squareSize - sz.cx) / 2;
\r
1713 pt.y = (squareSize - sz.cy) / 2;
\r
1715 SetBkMode( hdc, TRANSPARENT );
\r
1716 SetTextColor( hdc, chroma );
\r
1717 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1718 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1720 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1721 /* Step 3: the area outside the piece is filled with white */
\r
1722 // FloodFill( hdc, 0, 0, chroma );
\r
1723 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1724 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1725 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1726 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1727 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1729 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1730 but if the start point is not inside the piece we're lost!
\r
1731 There should be a better way to do this... if we could create a region or path
\r
1732 from the fill operation we would be fine for example.
\r
1734 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1735 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1737 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1738 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1739 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1741 SelectObject( dc2, bm2 );
\r
1742 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1743 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1744 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1745 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1746 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1749 DeleteObject( bm2 );
\r
1752 SetTextColor( hdc, 0 );
\r
1754 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1755 draw the piece again in black for safety.
\r
1757 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1759 SelectObject( hdc, hbm_old );
\r
1761 if( hPieceMask[index] != NULL ) {
\r
1762 DeleteObject( hPieceMask[index] );
\r
1765 hPieceMask[index] = hbm;
\r
1768 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1770 SelectObject( hdc, hbm );
\r
1773 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1774 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1775 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1777 SelectObject( dc1, hPieceMask[index] );
\r
1778 SelectObject( dc2, bm2 );
\r
1779 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1780 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1783 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1784 the piece background and deletes (makes transparent) the rest.
\r
1785 Thanks to that mask, we are free to paint the background with the greates
\r
1786 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1787 We use this, to make gradients and give the pieces a "roundish" look.
\r
1789 SetPieceBackground( hdc, backColor, 2 );
\r
1790 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1794 DeleteObject( bm2 );
\r
1797 SetTextColor( hdc, foreColor );
\r
1798 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1800 SelectObject( hdc, hbm_old );
\r
1802 if( hPieceFace[index] != NULL ) {
\r
1803 DeleteObject( hPieceFace[index] );
\r
1806 hPieceFace[index] = hbm;
\r
1809 static int TranslatePieceToFontPiece( int piece )
\r
1839 case BlackMarshall:
\r
1843 case BlackNightrider:
\r
1849 case BlackUnicorn:
\r
1853 case BlackGrasshopper:
\r
1865 case BlackCardinal:
\r
1872 case WhiteMarshall:
\r
1876 case WhiteNightrider:
\r
1882 case WhiteUnicorn:
\r
1886 case WhiteGrasshopper:
\r
1898 case WhiteCardinal:
\r
1907 void CreatePiecesFromFont()
\r
1910 HDC hdc_window = NULL;
\r
1916 if( fontBitmapSquareSize < 0 ) {
\r
1917 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
1921 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
1922 fontBitmapSquareSize = -1;
\r
1926 if( fontBitmapSquareSize != squareSize ) {
\r
1927 hdc_window = GetDC( hwndMain );
\r
1928 hdc = CreateCompatibleDC( hdc_window );
\r
1930 if( hPieceFont != NULL ) {
\r
1931 DeleteObject( hPieceFont );
\r
1934 for( i=0; i<=(int)BlackKing; i++ ) {
\r
1935 hPieceMask[i] = NULL;
\r
1936 hPieceFace[i] = NULL;
\r
1942 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
1943 fontHeight = appData.fontPieceSize;
\r
1946 fontHeight = (fontHeight * squareSize) / 100;
\r
1948 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
1950 lf.lfEscapement = 0;
\r
1951 lf.lfOrientation = 0;
\r
1952 lf.lfWeight = FW_NORMAL;
\r
1954 lf.lfUnderline = 0;
\r
1955 lf.lfStrikeOut = 0;
\r
1956 lf.lfCharSet = DEFAULT_CHARSET;
\r
1957 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1958 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1959 lf.lfQuality = PROOF_QUALITY;
\r
1960 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
1961 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
1962 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
1964 hPieceFont = CreateFontIndirect( &lf );
\r
1966 if( hPieceFont == NULL ) {
\r
1967 fontBitmapSquareSize = -2;
\r
1970 /* Setup font-to-piece character table */
\r
1971 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
1972 /* No (or wrong) global settings, try to detect the font */
\r
1973 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
1975 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
1977 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
1978 /* DiagramTT* family */
\r
1979 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
1981 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
1982 /* Fairy symbols */
\r
1983 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
1985 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
1986 /* Good Companion (Some characters get warped as literal :-( */
\r
1987 char s[] = "1cmWG0??S??oYI23wgQU";
\r
1988 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
1989 SetCharTable(pieceToFontChar, s);
\r
1992 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
1993 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
1997 /* Create bitmaps */
\r
1998 hfont_old = SelectObject( hdc, hPieceFont );
\r
1999 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2000 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2001 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2003 SelectObject( hdc, hfont_old );
\r
2005 fontBitmapSquareSize = squareSize;
\r
2009 if( hdc != NULL ) {
\r
2013 if( hdc_window != NULL ) {
\r
2014 ReleaseDC( hwndMain, hdc_window );
\r
2019 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2023 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2024 if (gameInfo.event &&
\r
2025 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2026 strcmp(name, "k80s") == 0) {
\r
2027 strcpy(name, "tim");
\r
2029 return LoadBitmap(hinst, name);
\r
2033 /* Insert a color into the program's logical palette
\r
2034 structure. This code assumes the given color is
\r
2035 the result of the RGB or PALETTERGB macro, and it
\r
2036 knows how those macros work (which is documented).
\r
2039 InsertInPalette(COLORREF color)
\r
2041 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2043 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2044 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2045 pLogPal->palNumEntries--;
\r
2049 pe->peFlags = (char) 0;
\r
2050 pe->peRed = (char) (0xFF & color);
\r
2051 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2052 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2058 InitDrawingColors()
\r
2060 if (pLogPal == NULL) {
\r
2061 /* Allocate enough memory for a logical palette with
\r
2062 * PALETTESIZE entries and set the size and version fields
\r
2063 * of the logical palette structure.
\r
2065 pLogPal = (NPLOGPALETTE)
\r
2066 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2067 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2068 pLogPal->palVersion = 0x300;
\r
2070 pLogPal->palNumEntries = 0;
\r
2072 InsertInPalette(lightSquareColor);
\r
2073 InsertInPalette(darkSquareColor);
\r
2074 InsertInPalette(whitePieceColor);
\r
2075 InsertInPalette(blackPieceColor);
\r
2076 InsertInPalette(highlightSquareColor);
\r
2077 InsertInPalette(premoveHighlightColor);
\r
2079 /* create a logical color palette according the information
\r
2080 * in the LOGPALETTE structure.
\r
2082 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2084 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2085 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2086 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2087 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2088 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2089 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2090 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2091 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
2092 /* [AS] Force rendering of the font-based pieces */
\r
2093 if( fontBitmapSquareSize > 0 ) {
\r
2094 fontBitmapSquareSize = 0;
\r
2100 BoardWidth(int boardSize, int n)
\r
2101 { /* [HGM] argument n added to allow different width and height */
\r
2102 int lineGap = sizeInfo[boardSize].lineGap;
\r
2104 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2105 lineGap = appData.overrideLineGap;
\r
2108 return (n + 1) * lineGap +
\r
2109 n * sizeInfo[boardSize].squareSize;
\r
2112 /* Respond to board resize by dragging edge */
\r
2114 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2116 BoardSize newSize = NUM_SIZES - 1;
\r
2117 static int recurse = 0;
\r
2118 if (IsIconic(hwndMain)) return;
\r
2119 if (recurse > 0) return;
\r
2121 while (newSize > 0) {
\r
2122 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2123 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2124 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2127 boardSize = newSize;
\r
2128 InitDrawingSizes(boardSize, flags);
\r
2133 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2136 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2138 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2139 ChessSquare piece;
\r
2140 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2142 SIZE clockSize, messageSize;
\r
2144 char buf[MSG_SIZ];
\r
2146 HMENU hmenu = GetMenu(hwndMain);
\r
2147 RECT crect, wrect, oldRect;
\r
2149 LOGBRUSH logbrush;
\r
2151 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2152 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2154 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2155 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2157 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2158 oldRect.top = wpMain.y;
\r
2159 oldRect.right = wpMain.x + wpMain.width;
\r
2160 oldRect.bottom = wpMain.y + wpMain.height;
\r
2162 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2163 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2164 squareSize = sizeInfo[boardSize].squareSize;
\r
2165 lineGap = sizeInfo[boardSize].lineGap;
\r
2166 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2168 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2169 lineGap = appData.overrideLineGap;
\r
2172 if (tinyLayout != oldTinyLayout) {
\r
2173 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2175 style &= ~WS_SYSMENU;
\r
2176 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2177 "&Minimize\tCtrl+F4");
\r
2179 style |= WS_SYSMENU;
\r
2180 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2182 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2184 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2185 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2186 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2188 DrawMenuBar(hwndMain);
\r
2191 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2192 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2194 /* Get text area sizes */
\r
2195 hdc = GetDC(hwndMain);
\r
2196 if (appData.clockMode) {
\r
2197 sprintf(buf, _("White: %s"), TimeString(23*60*60*1000L));
\r
2199 sprintf(buf, _("White"));
\r
2201 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2202 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2203 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2204 str = _("We only care about the height here");
\r
2205 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2206 SelectObject(hdc, oldFont);
\r
2207 ReleaseDC(hwndMain, hdc);
\r
2209 /* Compute where everything goes */
\r
2210 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2211 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2212 logoHeight = 2*clockSize.cy;
\r
2213 leftLogoRect.left = OUTER_MARGIN;
\r
2214 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2215 leftLogoRect.top = OUTER_MARGIN;
\r
2216 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2218 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2219 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2220 rightLogoRect.top = OUTER_MARGIN;
\r
2221 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2224 whiteRect.left = leftLogoRect.right;
\r
2225 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2226 whiteRect.top = OUTER_MARGIN;
\r
2227 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2229 blackRect.right = rightLogoRect.left;
\r
2230 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2231 blackRect.top = whiteRect.top;
\r
2232 blackRect.bottom = whiteRect.bottom;
\r
2234 whiteRect.left = OUTER_MARGIN;
\r
2235 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2236 whiteRect.top = OUTER_MARGIN;
\r
2237 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2239 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2240 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2241 blackRect.top = whiteRect.top;
\r
2242 blackRect.bottom = whiteRect.bottom;
\r
2244 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2247 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2248 if (appData.showButtonBar) {
\r
2249 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2250 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2252 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2254 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2255 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2257 boardRect.left = OUTER_MARGIN;
\r
2258 boardRect.right = boardRect.left + boardWidth;
\r
2259 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2260 boardRect.bottom = boardRect.top + boardHeight;
\r
2262 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2263 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2264 oldBoardSize = boardSize;
\r
2265 oldTinyLayout = tinyLayout;
\r
2266 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2267 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2268 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2269 winW *= 1 + twoBoards;
\r
2270 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2271 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2272 wpMain.height = winH; // without disturbing window attachments
\r
2273 GetWindowRect(hwndMain, &wrect);
\r
2274 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2275 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2277 // [HGM] placement: let attached windows follow size change.
\r
2278 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2279 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2280 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2281 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2282 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2284 /* compensate if menu bar wrapped */
\r
2285 GetClientRect(hwndMain, &crect);
\r
2286 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2287 wpMain.height += offby;
\r
2289 case WMSZ_TOPLEFT:
\r
2290 SetWindowPos(hwndMain, NULL,
\r
2291 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2292 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2295 case WMSZ_TOPRIGHT:
\r
2297 SetWindowPos(hwndMain, NULL,
\r
2298 wrect.left, wrect.bottom - wpMain.height,
\r
2299 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2302 case WMSZ_BOTTOMLEFT:
\r
2304 SetWindowPos(hwndMain, NULL,
\r
2305 wrect.right - wpMain.width, wrect.top,
\r
2306 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2309 case WMSZ_BOTTOMRIGHT:
\r
2313 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2314 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2319 for (i = 0; i < N_BUTTONS; i++) {
\r
2320 if (buttonDesc[i].hwnd != NULL) {
\r
2321 DestroyWindow(buttonDesc[i].hwnd);
\r
2322 buttonDesc[i].hwnd = NULL;
\r
2324 if (appData.showButtonBar) {
\r
2325 buttonDesc[i].hwnd =
\r
2326 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2327 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2328 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2329 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2330 (HMENU) buttonDesc[i].id,
\r
2331 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2333 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2334 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2335 MAKELPARAM(FALSE, 0));
\r
2337 if (buttonDesc[i].id == IDM_Pause)
\r
2338 hwndPause = buttonDesc[i].hwnd;
\r
2339 buttonDesc[i].wndproc = (WNDPROC)
\r
2340 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2343 if (gridPen != NULL) DeleteObject(gridPen);
\r
2344 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2345 if (premovePen != NULL) DeleteObject(premovePen);
\r
2346 if (lineGap != 0) {
\r
2347 logbrush.lbStyle = BS_SOLID;
\r
2348 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2350 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2351 lineGap, &logbrush, 0, NULL);
\r
2352 logbrush.lbColor = highlightSquareColor;
\r
2354 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2355 lineGap, &logbrush, 0, NULL);
\r
2357 logbrush.lbColor = premoveHighlightColor;
\r
2359 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2360 lineGap, &logbrush, 0, NULL);
\r
2362 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2363 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2364 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2365 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2366 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2367 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2368 BOARD_WIDTH * (squareSize + lineGap);
\r
2369 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2371 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2372 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2373 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2374 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2375 lineGap / 2 + (i * (squareSize + lineGap));
\r
2376 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2377 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2378 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2382 /* [HGM] Licensing requirement */
\r
2384 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2387 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2389 GothicPopUp( "", VariantNormal);
\r
2392 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2394 /* Load piece bitmaps for this board size */
\r
2395 for (i=0; i<=2; i++) {
\r
2396 for (piece = WhitePawn;
\r
2397 (int) piece < (int) BlackPawn;
\r
2398 piece = (ChessSquare) ((int) piece + 1)) {
\r
2399 if (pieceBitmap[i][piece] != NULL)
\r
2400 DeleteObject(pieceBitmap[i][piece]);
\r
2404 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2405 // Orthodox Chess pieces
\r
2406 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2407 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2408 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2409 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2410 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2411 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2412 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2413 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2414 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2415 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2416 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2417 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2418 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2419 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2420 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2421 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
2422 // in Shogi, Hijack the unused Queen for Lance
\r
2423 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2424 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2425 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2427 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2428 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2429 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2432 if(squareSize <= 72 && squareSize >= 33) {
\r
2433 /* A & C are available in most sizes now */
\r
2434 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2435 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2436 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2437 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2438 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2439 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2440 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2441 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2442 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2443 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2444 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2445 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2446 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2447 } else { // Smirf-like
\r
2448 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2449 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2450 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2452 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2453 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2454 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2455 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2456 } else { // WinBoard standard
\r
2457 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2458 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2459 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2464 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2465 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2466 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2467 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2468 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2469 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2470 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2471 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2472 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2473 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2474 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2475 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2476 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2477 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2478 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2479 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2480 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2481 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2482 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2483 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2484 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2485 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2486 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2487 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2488 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2489 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2490 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2491 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2492 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2493 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2494 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2496 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2497 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2498 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2499 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2500 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2501 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2502 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2503 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2504 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2505 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2506 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2507 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2508 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2510 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2511 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2512 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2513 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2514 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2515 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2516 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2517 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2518 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2519 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2520 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2521 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2524 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2525 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2526 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2527 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2528 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2529 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2530 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2531 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2532 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2533 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2534 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2535 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2536 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2537 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2538 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2542 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2543 /* special Shogi support in this size */
\r
2544 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2545 for (piece = WhitePawn;
\r
2546 (int) piece < (int) BlackPawn;
\r
2547 piece = (ChessSquare) ((int) piece + 1)) {
\r
2548 if (pieceBitmap[i][piece] != NULL)
\r
2549 DeleteObject(pieceBitmap[i][piece]);
\r
2552 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2553 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2554 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2555 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2556 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2557 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2558 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2559 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2560 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2561 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2562 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2563 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2564 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2565 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2566 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2567 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2568 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2569 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2570 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2571 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2572 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2573 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2574 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2575 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2576 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2577 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2578 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2579 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2580 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2581 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2582 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2583 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2584 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2585 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2586 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2587 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2588 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2589 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2590 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2591 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2592 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2593 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2599 PieceBitmap(ChessSquare p, int kind)
\r
2601 if ((int) p >= (int) BlackPawn)
\r
2602 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2604 return pieceBitmap[kind][(int) p];
\r
2607 /***************************************************************/
\r
2609 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2610 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2612 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2613 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2617 SquareToPos(int row, int column, int * x, int * y)
\r
2620 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2621 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2623 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2624 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2629 DrawCoordsOnDC(HDC hdc)
\r
2631 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
2632 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
2633 char str[2] = { NULLCHAR, NULLCHAR };
\r
2634 int oldMode, oldAlign, x, y, start, i;
\r
2638 if (!appData.showCoords)
\r
2641 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
2643 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2644 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2645 oldAlign = GetTextAlign(hdc);
\r
2646 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2648 y = boardRect.top + lineGap;
\r
2649 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2651 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2652 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2653 str[0] = files[start + i];
\r
2654 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2655 y += squareSize + lineGap;
\r
2658 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
2660 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2661 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2662 str[0] = ranks[start + i];
\r
2663 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2664 x += squareSize + lineGap;
\r
2667 SelectObject(hdc, oldBrush);
\r
2668 SetBkMode(hdc, oldMode);
\r
2669 SetTextAlign(hdc, oldAlign);
\r
2670 SelectObject(hdc, oldFont);
\r
2674 DrawGridOnDC(HDC hdc)
\r
2678 if (lineGap != 0) {
\r
2679 oldPen = SelectObject(hdc, gridPen);
\r
2680 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2681 SelectObject(hdc, oldPen);
\r
2685 #define HIGHLIGHT_PEN 0
\r
2686 #define PREMOVE_PEN 1
\r
2689 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2692 HPEN oldPen, hPen;
\r
2693 if (lineGap == 0) return;
\r
2695 x1 = boardRect.left +
\r
2696 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2697 y1 = boardRect.top +
\r
2698 lineGap/2 + y * (squareSize + lineGap);
\r
2700 x1 = boardRect.left +
\r
2701 lineGap/2 + x * (squareSize + lineGap);
\r
2702 y1 = boardRect.top +
\r
2703 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2705 hPen = pen ? premovePen : highlightPen;
\r
2706 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2707 MoveToEx(hdc, x1, y1, NULL);
\r
2708 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2709 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2710 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2711 LineTo(hdc, x1, y1);
\r
2712 SelectObject(hdc, oldPen);
\r
2716 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2719 for (i=0; i<2; i++) {
\r
2720 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2721 DrawHighlightOnDC(hdc, TRUE,
\r
2722 h->sq[i].x, h->sq[i].y,
\r
2727 /* Note: sqcolor is used only in monoMode */
\r
2728 /* Note that this code is largely duplicated in woptions.c,
\r
2729 function DrawSampleSquare, so that needs to be updated too */
\r
2731 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2733 HBITMAP oldBitmap;
\r
2737 if (appData.blindfold) return;
\r
2739 /* [AS] Use font-based pieces if needed */
\r
2740 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2741 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2742 CreatePiecesFromFont();
\r
2744 if( fontBitmapSquareSize == squareSize ) {
\r
2745 int index = TranslatePieceToFontPiece(piece);
\r
2747 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2749 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2750 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2754 squareSize, squareSize,
\r
2759 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2761 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2762 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2766 squareSize, squareSize,
\r
2775 if (appData.monoMode) {
\r
2776 SelectObject(tmphdc, PieceBitmap(piece,
\r
2777 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2778 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2779 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2781 tmpSize = squareSize;
\r
2783 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2784 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2785 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2786 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2787 x += (squareSize - minorSize)>>1;
\r
2788 y += squareSize - minorSize - 2;
\r
2789 tmpSize = minorSize;
\r
2791 if (color || appData.allWhite ) {
\r
2792 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2794 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2795 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2796 if(appData.upsideDown && color==flipView)
\r
2797 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2799 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2800 /* Use black for outline of white pieces */
\r
2801 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2802 if(appData.upsideDown && color==flipView)
\r
2803 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2805 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2807 /* Use square color for details of black pieces */
\r
2808 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2809 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2810 if(appData.upsideDown && !flipView)
\r
2811 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2813 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2815 SelectObject(hdc, oldBrush);
\r
2816 SelectObject(tmphdc, oldBitmap);
\r
2820 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2821 int GetBackTextureMode( int algo )
\r
2823 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2827 case BACK_TEXTURE_MODE_PLAIN:
\r
2828 result = 1; /* Always use identity map */
\r
2830 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2831 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2839 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2840 to handle redraws cleanly (as random numbers would always be different).
\r
2842 VOID RebuildTextureSquareInfo()
\r
2852 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2854 if( liteBackTexture != NULL ) {
\r
2855 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2856 lite_w = bi.bmWidth;
\r
2857 lite_h = bi.bmHeight;
\r
2861 if( darkBackTexture != NULL ) {
\r
2862 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2863 dark_w = bi.bmWidth;
\r
2864 dark_h = bi.bmHeight;
\r
2868 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2869 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2870 if( (col + row) & 1 ) {
\r
2872 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2873 if( lite_w >= squareSize*BOARD_WIDTH )
\r
2874 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
2876 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2877 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
2878 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
2880 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2881 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2886 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2887 if( dark_w >= squareSize*BOARD_WIDTH )
\r
2888 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
2890 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2891 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
2892 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
2894 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2895 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
2902 /* [AS] Arrow highlighting support */
\r
2904 static int A_WIDTH = 5; /* Width of arrow body */
\r
2906 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
2907 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
2909 static double Sqr( double x )
\r
2914 static int Round( double x )
\r
2916 return (int) (x + 0.5);
\r
2919 /* Draw an arrow between two points using current settings */
\r
2920 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
2923 double dx, dy, j, k, x, y;
\r
2925 if( d_x == s_x ) {
\r
2926 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2928 arrow[0].x = s_x + A_WIDTH;
\r
2931 arrow[1].x = s_x + A_WIDTH;
\r
2932 arrow[1].y = d_y - h;
\r
2934 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
2935 arrow[2].y = d_y - h;
\r
2940 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
2941 arrow[4].y = d_y - h;
\r
2943 arrow[5].x = s_x - A_WIDTH;
\r
2944 arrow[5].y = d_y - h;
\r
2946 arrow[6].x = s_x - A_WIDTH;
\r
2949 else if( d_y == s_y ) {
\r
2950 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2953 arrow[0].y = s_y + A_WIDTH;
\r
2955 arrow[1].x = d_x - w;
\r
2956 arrow[1].y = s_y + A_WIDTH;
\r
2958 arrow[2].x = d_x - w;
\r
2959 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
2964 arrow[4].x = d_x - w;
\r
2965 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
2967 arrow[5].x = d_x - w;
\r
2968 arrow[5].y = s_y - A_WIDTH;
\r
2971 arrow[6].y = s_y - A_WIDTH;
\r
2974 /* [AS] Needed a lot of paper for this! :-) */
\r
2975 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
2976 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
2978 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
2980 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
2985 arrow[0].x = Round(x - j);
\r
2986 arrow[0].y = Round(y + j*dx);
\r
2988 arrow[1].x = Round(x + j);
\r
2989 arrow[1].y = Round(y - j*dx);
\r
2992 x = (double) d_x - k;
\r
2993 y = (double) d_y - k*dy;
\r
2996 x = (double) d_x + k;
\r
2997 y = (double) d_y + k*dy;
\r
3000 arrow[2].x = Round(x + j);
\r
3001 arrow[2].y = Round(y - j*dx);
\r
3003 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3004 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3009 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3010 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3012 arrow[6].x = Round(x - j);
\r
3013 arrow[6].y = Round(y + j*dx);
\r
3016 Polygon( hdc, arrow, 7 );
\r
3019 /* [AS] Draw an arrow between two squares */
\r
3020 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3022 int s_x, s_y, d_x, d_y;
\r
3029 if( s_col == d_col && s_row == d_row ) {
\r
3033 /* Get source and destination points */
\r
3034 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3035 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3038 d_y += squareSize / 4;
\r
3040 else if( d_y < s_y ) {
\r
3041 d_y += 3 * squareSize / 4;
\r
3044 d_y += squareSize / 2;
\r
3048 d_x += squareSize / 4;
\r
3050 else if( d_x < s_x ) {
\r
3051 d_x += 3 * squareSize / 4;
\r
3054 d_x += squareSize / 2;
\r
3057 s_x += squareSize / 2;
\r
3058 s_y += squareSize / 2;
\r
3060 /* Adjust width */
\r
3061 A_WIDTH = squareSize / 14;
\r
3064 stLB.lbStyle = BS_SOLID;
\r
3065 stLB.lbColor = appData.highlightArrowColor;
\r
3068 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3069 holdpen = SelectObject( hdc, hpen );
\r
3070 hbrush = CreateBrushIndirect( &stLB );
\r
3071 holdbrush = SelectObject( hdc, hbrush );
\r
3073 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3075 SelectObject( hdc, holdpen );
\r
3076 SelectObject( hdc, holdbrush );
\r
3077 DeleteObject( hpen );
\r
3078 DeleteObject( hbrush );
\r
3081 BOOL HasHighlightInfo()
\r
3083 BOOL result = FALSE;
\r
3085 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3086 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3094 BOOL IsDrawArrowEnabled()
\r
3096 BOOL result = FALSE;
\r
3098 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3105 VOID DrawArrowHighlight( HDC hdc )
\r
3107 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3108 DrawArrowBetweenSquares( hdc,
\r
3109 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3110 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3114 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3116 HRGN result = NULL;
\r
3118 if( HasHighlightInfo() ) {
\r
3119 int x1, y1, x2, y2;
\r
3120 int sx, sy, dx, dy;
\r
3122 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3123 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3125 sx = MIN( x1, x2 );
\r
3126 sy = MIN( y1, y2 );
\r
3127 dx = MAX( x1, x2 ) + squareSize;
\r
3128 dy = MAX( y1, y2 ) + squareSize;
\r
3130 result = CreateRectRgn( sx, sy, dx, dy );
\r
3137 Warning: this function modifies the behavior of several other functions.
\r
3139 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3140 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3141 repaint is scattered all over the place, which is not good for features such as
\r
3142 "arrow highlighting" that require a full repaint of the board.
\r
3144 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3145 user interaction, when speed is not so important) but especially to avoid errors
\r
3146 in the displayed graphics.
\r
3148 In such patched places, I always try refer to this function so there is a single
\r
3149 place to maintain knowledge.
\r
3151 To restore the original behavior, just return FALSE unconditionally.
\r
3153 BOOL IsFullRepaintPreferrable()
\r
3155 BOOL result = FALSE;
\r
3157 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3158 /* Arrow may appear on the board */
\r
3166 This function is called by DrawPosition to know whether a full repaint must
\r
3169 Only DrawPosition may directly call this function, which makes use of
\r
3170 some state information. Other function should call DrawPosition specifying
\r
3171 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3173 BOOL DrawPositionNeedsFullRepaint()
\r
3175 BOOL result = FALSE;
\r
3178 Probably a slightly better policy would be to trigger a full repaint
\r
3179 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3180 but animation is fast enough that it's difficult to notice.
\r
3182 if( animInfo.piece == EmptySquare ) {
\r
3183 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3192 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3194 int row, column, x, y, square_color, piece_color;
\r
3195 ChessSquare piece;
\r
3197 HDC texture_hdc = NULL;
\r
3199 /* [AS] Initialize background textures if needed */
\r
3200 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3201 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3202 if( backTextureSquareSize != squareSize
\r
3203 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3204 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3205 backTextureSquareSize = squareSize;
\r
3206 RebuildTextureSquareInfo();
\r
3209 texture_hdc = CreateCompatibleDC( hdc );
\r
3212 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3213 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3215 SquareToPos(row, column, &x, &y);
\r
3217 piece = board[row][column];
\r
3219 square_color = ((column + row) % 2) == 1;
\r
3220 if( gameInfo.variant == VariantXiangqi ) {
\r
3221 square_color = !InPalace(row, column);
\r
3222 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3223 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3225 piece_color = (int) piece < (int) BlackPawn;
\r
3228 /* [HGM] holdings file: light square or black */
\r
3229 if(column == BOARD_LEFT-2) {
\r
3230 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3233 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3237 if(column == BOARD_RGHT + 1 ) {
\r
3238 if( row < gameInfo.holdingsSize )
\r
3241 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3245 if(column == BOARD_LEFT-1 ) /* left align */
\r
3246 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3247 else if( column == BOARD_RGHT) /* right align */
\r
3248 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3250 if (appData.monoMode) {
\r
3251 if (piece == EmptySquare) {
\r
3252 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3253 square_color ? WHITENESS : BLACKNESS);
\r
3255 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3258 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3259 /* [AS] Draw the square using a texture bitmap */
\r
3260 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3261 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3262 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3265 squareSize, squareSize,
\r
3268 backTextureSquareInfo[r][c].mode,
\r
3269 backTextureSquareInfo[r][c].x,
\r
3270 backTextureSquareInfo[r][c].y );
\r
3272 SelectObject( texture_hdc, hbm );
\r
3274 if (piece != EmptySquare) {
\r
3275 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3279 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3281 oldBrush = SelectObject(hdc, brush );
\r
3282 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3283 SelectObject(hdc, oldBrush);
\r
3284 if (piece != EmptySquare)
\r
3285 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3290 if( texture_hdc != NULL ) {
\r
3291 DeleteDC( texture_hdc );
\r
3295 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3296 void fputDW(FILE *f, int x)
\r
3298 fputc(x & 255, f);
\r
3299 fputc(x>>8 & 255, f);
\r
3300 fputc(x>>16 & 255, f);
\r
3301 fputc(x>>24 & 255, f);
\r
3304 #define MAX_CLIPS 200 /* more than enough */
\r
3307 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3309 // HBITMAP bufferBitmap;
\r
3314 int w = 100, h = 50;
\r
3316 if(logo == NULL) return;
\r
3317 // GetClientRect(hwndMain, &Rect);
\r
3318 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3319 // Rect.bottom-Rect.top+1);
\r
3320 tmphdc = CreateCompatibleDC(hdc);
\r
3321 hbm = SelectObject(tmphdc, logo);
\r
3322 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3326 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3327 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3328 SelectObject(tmphdc, hbm);
\r
3332 static HDC hdcSeek;
\r
3334 // [HGM] seekgraph
\r
3335 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3338 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3339 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3340 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3341 SelectObject( hdcSeek, hp );
\r
3344 // front-end wrapper for drawing functions to do rectangles
\r
3345 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3350 if (hdcSeek == NULL) {
\r
3351 hdcSeek = GetDC(hwndMain);
\r
3352 if (!appData.monoMode) {
\r
3353 SelectPalette(hdcSeek, hPal, FALSE);
\r
3354 RealizePalette(hdcSeek);
\r
3357 hp = SelectObject( hdcSeek, gridPen );
\r
3358 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3359 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3360 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3361 SelectObject( hdcSeek, hp );
\r
3364 // front-end wrapper for putting text in graph
\r
3365 void DrawSeekText(char *buf, int x, int y)
\r
3368 SetBkMode( hdcSeek, TRANSPARENT );
\r
3369 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3370 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3373 void DrawSeekDot(int x, int y, int color)
\r
3375 int square = color & 0x80;
\r
3376 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3377 color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);
\r
3380 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3381 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3383 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3384 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3385 SelectObject(hdcSeek, oldBrush);
\r
3389 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3391 static Board lastReq[2], lastDrawn[2];
\r
3392 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3393 static int lastDrawnFlipView = 0;
\r
3394 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3395 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3398 HBITMAP bufferBitmap;
\r
3399 HBITMAP oldBitmap;
\r
3401 HRGN clips[MAX_CLIPS];
\r
3402 ChessSquare dragged_piece = EmptySquare;
\r
3403 int nr = twoBoards*partnerUp;
\r
3405 /* I'm undecided on this - this function figures out whether a full
\r
3406 * repaint is necessary on its own, so there's no real reason to have the
\r
3407 * caller tell it that. I think this can safely be set to FALSE - but
\r
3408 * if we trust the callers not to request full repaints unnessesarily, then
\r
3409 * we could skip some clipping work. In other words, only request a full
\r
3410 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3411 * gamestart and similar) --Hawk
\r
3413 Boolean fullrepaint = repaint;
\r
3415 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3417 if( DrawPositionNeedsFullRepaint() ) {
\r
3418 fullrepaint = TRUE;
\r
3421 if (board == NULL) {
\r
3422 if (!lastReqValid[nr]) {
\r
3425 board = lastReq[nr];
\r
3427 CopyBoard(lastReq[nr], board);
\r
3428 lastReqValid[nr] = 1;
\r
3431 if (doingSizing) {
\r
3435 if (IsIconic(hwndMain)) {
\r
3439 if (hdc == NULL) {
\r
3440 hdc = GetDC(hwndMain);
\r
3441 if (!appData.monoMode) {
\r
3442 SelectPalette(hdc, hPal, FALSE);
\r
3443 RealizePalette(hdc);
\r
3447 releaseDC = FALSE;
\r
3450 /* Create some work-DCs */
\r
3451 hdcmem = CreateCompatibleDC(hdc);
\r
3452 tmphdc = CreateCompatibleDC(hdc);
\r
3454 /* If dragging is in progress, we temporarely remove the piece */
\r
3455 /* [HGM] or temporarily decrease count if stacked */
\r
3456 /* !! Moved to before board compare !! */
\r
3457 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3458 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3459 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3460 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3461 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3463 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3464 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3465 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3467 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3470 /* Figure out which squares need updating by comparing the
\r
3471 * newest board with the last drawn board and checking if
\r
3472 * flipping has changed.
\r
3474 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3475 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3476 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3477 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3478 SquareToPos(row, column, &x, &y);
\r
3479 clips[num_clips++] =
\r
3480 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3484 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3485 for (i=0; i<2; i++) {
\r
3486 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3487 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3488 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3489 lastDrawnHighlight.sq[i].y >= 0) {
\r
3490 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3491 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3492 clips[num_clips++] =
\r
3493 CreateRectRgn(x - lineGap, y - lineGap,
\r
3494 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3496 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3497 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3498 clips[num_clips++] =
\r
3499 CreateRectRgn(x - lineGap, y - lineGap,
\r
3500 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3504 for (i=0; i<2; i++) {
\r
3505 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3506 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3507 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3508 lastDrawnPremove.sq[i].y >= 0) {
\r
3509 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3510 lastDrawnPremove.sq[i].x, &x, &y);
\r
3511 clips[num_clips++] =
\r
3512 CreateRectRgn(x - lineGap, y - lineGap,
\r
3513 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3515 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3516 premoveHighlightInfo.sq[i].y >= 0) {
\r
3517 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3518 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3519 clips[num_clips++] =
\r
3520 CreateRectRgn(x - lineGap, y - lineGap,
\r
3521 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3525 } else { // nr == 1
\r
3526 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3527 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3528 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3529 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3530 for (i=0; i<2; i++) {
\r
3531 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3532 partnerHighlightInfo.sq[i].y >= 0) {
\r
3533 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3534 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3535 clips[num_clips++] =
\r
3536 CreateRectRgn(x - lineGap, y - lineGap,
\r
3537 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3539 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3540 oldPartnerHighlight.sq[i].y >= 0) {
\r
3541 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3542 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3543 clips[num_clips++] =
\r
3544 CreateRectRgn(x - lineGap, y - lineGap,
\r
3545 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3550 fullrepaint = TRUE;
\r
3553 /* Create a buffer bitmap - this is the actual bitmap
\r
3554 * being written to. When all the work is done, we can
\r
3555 * copy it to the real DC (the screen). This avoids
\r
3556 * the problems with flickering.
\r
3558 GetClientRect(hwndMain, &Rect);
\r
3559 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3560 Rect.bottom-Rect.top+1);
\r
3561 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3562 if (!appData.monoMode) {
\r
3563 SelectPalette(hdcmem, hPal, FALSE);
\r
3566 /* Create clips for dragging */
\r
3567 if (!fullrepaint) {
\r
3568 if (dragInfo.from.x >= 0) {
\r
3569 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3570 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3572 if (dragInfo.start.x >= 0) {
\r
3573 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3574 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3576 if (dragInfo.pos.x >= 0) {
\r
3577 x = dragInfo.pos.x - squareSize / 2;
\r
3578 y = dragInfo.pos.y - squareSize / 2;
\r
3579 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3581 if (dragInfo.lastpos.x >= 0) {
\r
3582 x = dragInfo.lastpos.x - squareSize / 2;
\r
3583 y = dragInfo.lastpos.y - squareSize / 2;
\r
3584 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3588 /* Are we animating a move?
\r
3590 * - remove the piece from the board (temporarely)
\r
3591 * - calculate the clipping region
\r
3593 if (!fullrepaint) {
\r
3594 if (animInfo.piece != EmptySquare) {
\r
3595 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3596 x = boardRect.left + animInfo.lastpos.x;
\r
3597 y = boardRect.top + animInfo.lastpos.y;
\r
3598 x2 = boardRect.left + animInfo.pos.x;
\r
3599 y2 = boardRect.top + animInfo.pos.y;
\r
3600 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3601 /* Slight kludge. The real problem is that after AnimateMove is
\r
3602 done, the position on the screen does not match lastDrawn.
\r
3603 This currently causes trouble only on e.p. captures in
\r
3604 atomic, where the piece moves to an empty square and then
\r
3605 explodes. The old and new positions both had an empty square
\r
3606 at the destination, but animation has drawn a piece there and
\r
3607 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3608 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3612 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3613 if (num_clips == 0)
\r
3614 fullrepaint = TRUE;
\r
3616 /* Set clipping on the memory DC */
\r
3617 if (!fullrepaint) {
\r
3618 SelectClipRgn(hdcmem, clips[0]);
\r
3619 for (x = 1; x < num_clips; x++) {
\r
3620 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3621 abort(); // this should never ever happen!
\r
3625 /* Do all the drawing to the memory DC */
\r
3626 if(explodeInfo.radius) { // [HGM] atomic
\r
3628 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3629 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3630 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3631 x += squareSize/2;
\r
3632 y += squareSize/2;
\r
3633 if(!fullrepaint) {
\r
3634 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3635 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3637 DrawGridOnDC(hdcmem);
\r
3638 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3639 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3640 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3641 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3642 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3643 SelectObject(hdcmem, oldBrush);
\r
3645 DrawGridOnDC(hdcmem);
\r
3646 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3647 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3648 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3650 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3651 oldPartnerHighlight = partnerHighlightInfo;
\r
3653 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3655 if(nr == 0) // [HGM] dual: markers only on left board
\r
3656 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3657 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3658 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3659 HBRUSH oldBrush = SelectObject(hdcmem,
\r
3660 marker[row][column] == 2 ? markerBrush : explodeBrush);
\r
3661 SquareToPos(row, column, &x, &y);
\r
3662 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3663 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3664 SelectObject(hdcmem, oldBrush);
\r
3669 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3670 if(appData.autoLogo) {
\r
3672 switch(gameMode) { // pick logos based on game mode
\r
3673 case IcsObserving:
\r
3674 whiteLogo = second.programLogo; // ICS logo
\r
3675 blackLogo = second.programLogo;
\r
3678 case IcsPlayingWhite:
\r
3679 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3680 blackLogo = second.programLogo; // ICS logo
\r
3682 case IcsPlayingBlack:
\r
3683 whiteLogo = second.programLogo; // ICS logo
\r
3684 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3686 case TwoMachinesPlay:
\r
3687 if(first.twoMachinesColor[0] == 'b') {
\r
3688 whiteLogo = second.programLogo;
\r
3689 blackLogo = first.programLogo;
\r
3692 case MachinePlaysWhite:
\r
3693 blackLogo = userLogo;
\r
3695 case MachinePlaysBlack:
\r
3696 whiteLogo = userLogo;
\r
3697 blackLogo = first.programLogo;
\r
3700 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3701 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3704 if( appData.highlightMoveWithArrow ) {
\r
3705 DrawArrowHighlight(hdcmem);
\r
3708 DrawCoordsOnDC(hdcmem);
\r
3710 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
3711 /* to make sure lastDrawn contains what is actually drawn */
\r
3713 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3714 if (dragged_piece != EmptySquare) {
\r
3715 /* [HGM] or restack */
\r
3716 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3717 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3719 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3720 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3721 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3722 x = dragInfo.pos.x - squareSize / 2;
\r
3723 y = dragInfo.pos.y - squareSize / 2;
\r
3724 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3725 ((int) dragged_piece < (int) BlackPawn),
\r
3726 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3729 /* Put the animated piece back into place and draw it */
\r
3730 if (animInfo.piece != EmptySquare) {
\r
3731 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3732 x = boardRect.left + animInfo.pos.x;
\r
3733 y = boardRect.top + animInfo.pos.y;
\r
3734 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3735 ((int) animInfo.piece < (int) BlackPawn),
\r
3736 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3739 /* Release the bufferBitmap by selecting in the old bitmap
\r
3740 * and delete the memory DC
\r
3742 SelectObject(hdcmem, oldBitmap);
\r
3745 /* Set clipping on the target DC */
\r
3746 if (!fullrepaint) {
\r
3747 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
3749 GetRgnBox(clips[x], &rect);
\r
3750 DeleteObject(clips[x]);
\r
3751 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
3752 rect.right + wpMain.width/2, rect.bottom);
\r
3754 SelectClipRgn(hdc, clips[0]);
\r
3755 for (x = 1; x < num_clips; x++) {
\r
3756 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3757 abort(); // this should never ever happen!
\r
3761 /* Copy the new bitmap onto the screen in one go.
\r
3762 * This way we avoid any flickering
\r
3764 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3765 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
3766 boardRect.right - boardRect.left,
\r
3767 boardRect.bottom - boardRect.top,
\r
3768 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3769 if(saveDiagFlag) {
\r
3770 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
3771 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
3773 GetObject(bufferBitmap, sizeof(b), &b);
\r
3774 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
3775 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
3776 bih.biWidth = b.bmWidth;
\r
3777 bih.biHeight = b.bmHeight;
\r
3779 bih.biBitCount = b.bmBitsPixel;
\r
3780 bih.biCompression = 0;
\r
3781 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
3782 bih.biXPelsPerMeter = 0;
\r
3783 bih.biYPelsPerMeter = 0;
\r
3784 bih.biClrUsed = 0;
\r
3785 bih.biClrImportant = 0;
\r
3786 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
3787 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
3788 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
3789 // fprintf(diagFile, "%8x\n", (int) pData);
\r
3791 wb = b.bmWidthBytes;
\r
3793 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
3794 int k = ((int*) pData)[i];
\r
3795 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3796 if(j >= 16) break;
\r
3798 if(j >= nrColors) nrColors = j+1;
\r
3800 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
3802 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
3803 for(w=0; w<(wb>>2); w+=2) {
\r
3804 int k = ((int*) pData)[(wb*i>>2) + w];
\r
3805 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3806 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
3807 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
3808 pData[p++] = m | j<<4;
\r
3810 while(p&3) pData[p++] = 0;
\r
3813 wb = ((wb+31)>>5)<<2;
\r
3815 // write BITMAPFILEHEADER
\r
3816 fprintf(diagFile, "BM");
\r
3817 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
3818 fputDW(diagFile, 0);
\r
3819 fputDW(diagFile, 0x36 + (fac?64:0));
\r
3820 // write BITMAPINFOHEADER
\r
3821 fputDW(diagFile, 40);
\r
3822 fputDW(diagFile, b.bmWidth);
\r
3823 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
3824 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
3825 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
3826 fputDW(diagFile, 0);
\r
3827 fputDW(diagFile, 0);
\r
3828 fputDW(diagFile, 0);
\r
3829 fputDW(diagFile, 0);
\r
3830 fputDW(diagFile, 0);
\r
3831 fputDW(diagFile, 0);
\r
3832 // write color table
\r
3834 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
3835 // write bitmap data
\r
3836 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
3837 fputc(pData[i], diagFile);
\r
3841 SelectObject(tmphdc, oldBitmap);
\r
3843 /* Massive cleanup */
\r
3844 for (x = 0; x < num_clips; x++)
\r
3845 DeleteObject(clips[x]);
\r
3848 DeleteObject(bufferBitmap);
\r
3851 ReleaseDC(hwndMain, hdc);
\r
3853 if (lastDrawnFlipView != flipView && nr == 0) {
\r
3855 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3857 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3860 /* CopyBoard(lastDrawn, board);*/
\r
3861 lastDrawnHighlight = highlightInfo;
\r
3862 lastDrawnPremove = premoveHighlightInfo;
\r
3863 lastDrawnFlipView = flipView;
\r
3864 lastDrawnValid[nr] = 1;
\r
3867 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
3872 saveDiagFlag = 1; diagFile = f;
\r
3873 HDCDrawPosition(NULL, TRUE, NULL);
\r
3877 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
3884 /*---------------------------------------------------------------------------*\
\r
3885 | CLIENT PAINT PROCEDURE
\r
3886 | This is the main event-handler for the WM_PAINT message.
\r
3888 \*---------------------------------------------------------------------------*/
\r
3890 PaintProc(HWND hwnd)
\r
3896 if((hdc = BeginPaint(hwnd, &ps))) {
\r
3897 if (IsIconic(hwnd)) {
\r
3898 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3900 if (!appData.monoMode) {
\r
3901 SelectPalette(hdc, hPal, FALSE);
\r
3902 RealizePalette(hdc);
\r
3904 HDCDrawPosition(hdc, 1, NULL);
\r
3905 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
3906 flipView = !flipView; partnerUp = !partnerUp;
\r
3907 HDCDrawPosition(hdc, 1, NULL);
\r
3908 flipView = !flipView; partnerUp = !partnerUp;
\r
3911 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3912 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3913 ETO_CLIPPED|ETO_OPAQUE,
\r
3914 &messageRect, messageText, strlen(messageText), NULL);
\r
3915 SelectObject(hdc, oldFont);
\r
3916 DisplayBothClocks();
\r
3918 EndPaint(hwnd,&ps);
\r
3926 * If the user selects on a border boundary, return -1; if off the board,
\r
3927 * return -2. Otherwise map the event coordinate to the square.
\r
3928 * The offset boardRect.left or boardRect.top must already have been
\r
3929 * subtracted from x.
\r
3931 int EventToSquare(x, limit)
\r
3939 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3941 x /= (squareSize + lineGap);
\r
3953 DropEnable dropEnables[] = {
\r
3954 { 'P', DP_Pawn, N_("Pawn") },
\r
3955 { 'N', DP_Knight, N_("Knight") },
\r
3956 { 'B', DP_Bishop, N_("Bishop") },
\r
3957 { 'R', DP_Rook, N_("Rook") },
\r
3958 { 'Q', DP_Queen, N_("Queen") },
\r
3962 SetupDropMenu(HMENU hmenu)
\r
3964 int i, count, enable;
\r
3966 extern char white_holding[], black_holding[];
\r
3967 char item[MSG_SIZ];
\r
3969 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
3970 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
3971 dropEnables[i].piece);
\r
3973 while (p && *p++ == dropEnables[i].piece) count++;
\r
3974 sprintf(item, "%s %d", T_(dropEnables[i].name), count);
\r
3975 enable = count > 0 || !appData.testLegality
\r
3976 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
3977 && !appData.icsActive);
\r
3978 ModifyMenu(hmenu, dropEnables[i].command,
\r
3979 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
3980 dropEnables[i].command, item);
\r
3984 void DragPieceBegin(int x, int y)
\r
3986 dragInfo.lastpos.x = boardRect.left + x;
\r
3987 dragInfo.lastpos.y = boardRect.top + y;
\r
3988 dragInfo.from.x = fromX;
\r
3989 dragInfo.from.y = fromY;
\r
3990 dragInfo.start = dragInfo.from;
\r
3991 SetCapture(hwndMain);
\r
3994 void DragPieceEnd(int x, int y)
\r
3997 dragInfo.start.x = dragInfo.start.y = -1;
\r
3998 dragInfo.from = dragInfo.start;
\r
3999 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4002 /* Event handler for mouse messages */
\r
4004 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4008 static int recursive = 0;
\r
4010 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4013 if (message == WM_MBUTTONUP) {
\r
4014 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4015 to the middle button: we simulate pressing the left button too!
\r
4017 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4018 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4024 pt.x = LOWORD(lParam);
\r
4025 pt.y = HIWORD(lParam);
\r
4026 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4027 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4028 if (!flipView && y >= 0) {
\r
4029 y = BOARD_HEIGHT - 1 - y;
\r
4031 if (flipView && x >= 0) {
\r
4032 x = BOARD_WIDTH - 1 - x;
\r
4035 switch (message) {
\r
4036 case WM_LBUTTONDOWN:
\r
4037 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4038 if (gameMode == EditPosition) {
\r
4039 SetWhiteToPlayEvent();
\r
4040 } else if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) {
\r
4041 AdjustClock(flipClock, -1);
\r
4042 } else if (gameMode == IcsPlayingBlack ||
\r
4043 gameMode == MachinePlaysWhite) {
\r
4046 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4047 if (gameMode == EditPosition) {
\r
4048 SetBlackToPlayEvent();
\r
4049 } else if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) {
\r
4050 AdjustClock(!flipClock, -1);
\r
4051 } else if (gameMode == IcsPlayingWhite ||
\r
4052 gameMode == MachinePlaysBlack) {
\r
4056 dragInfo.start.x = dragInfo.start.y = -1;
\r
4057 dragInfo.from = dragInfo.start;
\r
4058 if(fromX == -1 && frozen) { // not sure where this is for
\r
4059 fromX = fromY = -1;
\r
4060 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4063 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4064 DrawPosition(TRUE, NULL);
\r
4067 case WM_LBUTTONUP:
\r
4068 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4069 DrawPosition(TRUE, NULL);
\r
4072 case WM_MOUSEMOVE:
\r
4073 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4074 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4075 if ((appData.animateDragging || appData.highlightDragging)
\r
4076 && (wParam & MK_LBUTTON)
\r
4077 && dragInfo.from.x >= 0)
\r
4079 BOOL full_repaint = FALSE;
\r
4081 if (appData.animateDragging) {
\r
4082 dragInfo.pos = pt;
\r
4084 if (appData.highlightDragging) {
\r
4085 SetHighlights(fromX, fromY, x, y);
\r
4086 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4087 full_repaint = TRUE;
\r
4091 DrawPosition( full_repaint, NULL);
\r
4093 dragInfo.lastpos = dragInfo.pos;
\r
4097 case WM_MOUSEWHEEL: // [DM]
\r
4098 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4099 /* Mouse Wheel is being rolled forward
\r
4100 * Play moves forward
\r
4102 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4103 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4104 /* Mouse Wheel is being rolled backward
\r
4105 * Play moves backward
\r
4107 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4108 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4112 case WM_MBUTTONUP:
\r
4113 case WM_RBUTTONUP:
\r
4115 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4118 case WM_MBUTTONDOWN:
\r
4119 case WM_RBUTTONDOWN:
\r
4122 fromX = fromY = -1;
\r
4123 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4124 dragInfo.start.x = dragInfo.start.y = -1;
\r
4125 dragInfo.from = dragInfo.start;
\r
4126 dragInfo.lastpos = dragInfo.pos;
\r
4127 if (appData.highlightDragging) {
\r
4128 ClearHighlights();
\r
4131 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4132 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4133 if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4134 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4135 if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4139 DrawPosition(TRUE, NULL);
\r
4141 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4144 if (message == WM_MBUTTONDOWN) {
\r
4145 buttonCount = 3; /* even if system didn't think so */
\r
4146 if (wParam & MK_SHIFT)
\r
4147 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4149 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4150 } else { /* message == WM_RBUTTONDOWN */
\r
4151 /* Just have one menu, on the right button. Windows users don't
\r
4152 think to try the middle one, and sometimes other software steals
\r
4153 it, or it doesn't really exist. */
\r
4154 if(gameInfo.variant != VariantShogi)
\r
4155 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4157 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4161 SetCapture(hwndMain);
4164 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4165 SetupDropMenu(hmenu);
\r
4166 MenuPopup(hwnd, pt, hmenu, -1);
\r
4176 /* Preprocess messages for buttons in main window */
\r
4178 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4180 int id = GetWindowLong(hwnd, GWL_ID);
\r
4183 for (i=0; i<N_BUTTONS; i++) {
\r
4184 if (buttonDesc[i].id == id) break;
\r
4186 if (i == N_BUTTONS) return 0;
\r
4187 switch (message) {
\r
4192 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4193 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4200 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4203 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4204 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4205 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4206 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4208 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4210 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4211 PopUpMoveDialog((char)wParam);
\r
4217 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4220 /* Process messages for Promotion dialog box */
\r
4222 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4226 switch (message) {
\r
4227 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4228 /* Center the dialog over the application window */
\r
4229 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4230 Translate(hDlg, DLG_PromotionKing);
\r
4231 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4232 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4233 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4234 SW_SHOW : SW_HIDE);
\r
4235 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4236 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4237 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
4238 PieceToChar(WhiteAngel) != '~') ||
\r
4239 (PieceToChar(BlackAngel) >= 'A' &&
\r
4240 PieceToChar(BlackAngel) != '~') ) ?
\r
4241 SW_SHOW : SW_HIDE);
\r
4242 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4243 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
4244 PieceToChar(WhiteMarshall) != '~') ||
\r
4245 (PieceToChar(BlackMarshall) >= 'A' &&
\r
4246 PieceToChar(BlackMarshall) != '~') ) ?
\r
4247 SW_SHOW : SW_HIDE);
\r
4248 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4249 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4250 gameInfo.variant != VariantShogi ?
\r
4251 SW_SHOW : SW_HIDE);
\r
4252 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4253 gameInfo.variant != VariantShogi ?
\r
4254 SW_SHOW : SW_HIDE);
\r
4255 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
4256 gameInfo.variant == VariantShogi ?
\r
4257 SW_SHOW : SW_HIDE);
\r
4258 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
4259 gameInfo.variant == VariantShogi ?
\r
4260 SW_SHOW : SW_HIDE);
\r
4261 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4262 gameInfo.variant == VariantSuper ?
\r
4263 SW_SHOW : SW_HIDE);
\r
4266 case WM_COMMAND: /* message: received a command */
\r
4267 switch (LOWORD(wParam)) {
\r
4269 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4270 ClearHighlights();
\r
4271 DrawPosition(FALSE, NULL);
\r
4274 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4277 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
4280 promoChar = PieceToChar(BlackRook);
\r
4283 promoChar = PieceToChar(BlackBishop);
\r
4285 case PB_Chancellor:
\r
4286 promoChar = PieceToChar(BlackMarshall);
\r
4288 case PB_Archbishop:
\r
4289 promoChar = PieceToChar(BlackAngel);
\r
4292 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
4297 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4298 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
4299 only show the popup when we are already sure the move is valid or
\r
4300 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
4301 will figure out it is a promotion from the promoChar. */
\r
4302 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4303 fromX = fromY = -1;
\r
4304 if (!appData.highlightLastMove) {
\r
4305 ClearHighlights();
\r
4306 DrawPosition(FALSE, NULL);
\r
4313 /* Pop up promotion dialog */
\r
4315 PromotionPopup(HWND hwnd)
\r
4319 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4320 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4321 hwnd, (DLGPROC)lpProc);
\r
4322 FreeProcInstance(lpProc);
\r
4328 DrawPosition(TRUE, NULL);
\r
4329 PromotionPopup(hwndMain);
\r
4332 /* Toggle ShowThinking */
\r
4334 ToggleShowThinking()
\r
4336 appData.showThinking = !appData.showThinking;
\r
4337 ShowThinkingEvent();
\r
4341 LoadGameDialog(HWND hwnd, char* title)
\r
4345 char fileTitle[MSG_SIZ];
\r
4346 f = OpenFileDialog(hwnd, "rb", "",
\r
4347 appData.oldSaveStyle ? "gam" : "pgn",
\r
4349 title, &number, fileTitle, NULL);
\r
4351 cmailMsgLoaded = FALSE;
\r
4352 if (number == 0) {
\r
4353 int error = GameListBuild(f);
\r
4355 DisplayError(_("Cannot build game list"), error);
\r
4356 } else if (!ListEmpty(&gameList) &&
\r
4357 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4358 GameListPopUp(f, fileTitle);
\r
4361 GameListDestroy();
\r
4364 LoadGame(f, number, fileTitle, FALSE);
\r
4368 int get_term_width()
\r
4373 HFONT hfont, hold_font;
\r
4378 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4382 // get the text metrics
\r
4383 hdc = GetDC(hText);
\r
4384 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4385 if (consoleCF.dwEffects & CFE_BOLD)
\r
4386 lf.lfWeight = FW_BOLD;
\r
4387 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4388 lf.lfItalic = TRUE;
\r
4389 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4390 lf.lfStrikeOut = TRUE;
\r
4391 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4392 lf.lfUnderline = TRUE;
\r
4393 hfont = CreateFontIndirect(&lf);
\r
4394 hold_font = SelectObject(hdc, hfont);
\r
4395 GetTextMetrics(hdc, &tm);
\r
4396 SelectObject(hdc, hold_font);
\r
4397 DeleteObject(hfont);
\r
4398 ReleaseDC(hText, hdc);
\r
4400 // get the rectangle
\r
4401 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4403 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4406 void UpdateICSWidth(HWND hText)
\r
4408 LONG old_width, new_width;
\r
4410 new_width = get_term_width(hText, FALSE);
\r
4411 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
4412 if (new_width != old_width)
\r
4414 ics_update_width(new_width);
\r
4415 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
4420 ChangedConsoleFont()
\r
4423 CHARRANGE tmpsel, sel;
\r
4424 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4425 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4426 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4429 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4430 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4431 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4432 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4433 * size. This was undocumented in the version of MSVC++ that I had
\r
4434 * when I wrote the code, but is apparently documented now.
\r
4436 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4437 cfmt.bCharSet = f->lf.lfCharSet;
\r
4438 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4439 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4440 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4441 /* Why are the following seemingly needed too? */
\r
4442 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4443 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4444 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4446 tmpsel.cpMax = -1; /*999999?*/
\r
4447 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4448 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4449 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4450 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4452 paraf.cbSize = sizeof(paraf);
\r
4453 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4454 paraf.dxStartIndent = 0;
\r
4455 paraf.dxOffset = WRAP_INDENT;
\r
4456 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4457 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4458 UpdateICSWidth(hText);
\r
4461 /*---------------------------------------------------------------------------*\
\r
4463 * Window Proc for main window
\r
4465 \*---------------------------------------------------------------------------*/
\r
4467 /* Process messages for main window, etc. */
\r
4469 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4472 int wmId, wmEvent;
\r
4476 char fileTitle[MSG_SIZ];
\r
4477 char buf[MSG_SIZ];
\r
4478 static SnapData sd;
\r
4480 switch (message) {
\r
4482 case WM_PAINT: /* message: repaint portion of window */
\r
4486 case WM_ERASEBKGND:
\r
4487 if (IsIconic(hwnd)) {
\r
4488 /* Cheat; change the message */
\r
4489 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4491 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4495 case WM_LBUTTONDOWN:
\r
4496 case WM_MBUTTONDOWN:
\r
4497 case WM_RBUTTONDOWN:
\r
4498 case WM_LBUTTONUP:
\r
4499 case WM_MBUTTONUP:
\r
4500 case WM_RBUTTONUP:
\r
4501 case WM_MOUSEMOVE:
\r
4502 case WM_MOUSEWHEEL:
\r
4503 MouseEvent(hwnd, message, wParam, lParam);
\r
4506 JAWS_KB_NAVIGATION
\r
4510 JAWS_ALT_INTERCEPT
\r
4512 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4513 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4514 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4515 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4517 SendMessage(h, message, wParam, lParam);
\r
4518 } else if(lParam != KF_REPEAT) {
\r
4519 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4520 PopUpMoveDialog((char)wParam);
\r
4521 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4522 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4527 case WM_PALETTECHANGED:
\r
4528 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4530 HDC hdc = GetDC(hwndMain);
\r
4531 SelectPalette(hdc, hPal, TRUE);
\r
4532 nnew = RealizePalette(hdc);
\r
4534 paletteChanged = TRUE;
\r
4535 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4537 ReleaseDC(hwnd, hdc);
\r
4541 case WM_QUERYNEWPALETTE:
\r
4542 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4544 HDC hdc = GetDC(hwndMain);
\r
4545 paletteChanged = FALSE;
\r
4546 SelectPalette(hdc, hPal, FALSE);
\r
4547 nnew = RealizePalette(hdc);
\r
4549 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4551 ReleaseDC(hwnd, hdc);
\r
4556 case WM_COMMAND: /* message: command from application menu */
\r
4557 wmId = LOWORD(wParam);
\r
4558 wmEvent = HIWORD(wParam);
\r
4563 SAY("new game enter a move to play against the computer with white");
\r
4566 case IDM_NewGameFRC:
\r
4567 if( NewGameFRC() == 0 ) {
\r
4572 case IDM_NewVariant:
\r
4573 NewVariantPopup(hwnd);
\r
4576 case IDM_LoadGame:
\r
4577 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4580 case IDM_LoadNextGame:
\r
4584 case IDM_LoadPrevGame:
\r
4588 case IDM_ReloadGame:
\r
4592 case IDM_LoadPosition:
\r
4593 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4594 Reset(FALSE, TRUE);
\r
4597 f = OpenFileDialog(hwnd, "rb", "",
\r
4598 appData.oldSaveStyle ? "pos" : "fen",
\r
4600 _("Load Position from File"), &number, fileTitle, NULL);
\r
4602 LoadPosition(f, number, fileTitle);
\r
4606 case IDM_LoadNextPosition:
\r
4607 ReloadPosition(1);
\r
4610 case IDM_LoadPrevPosition:
\r
4611 ReloadPosition(-1);
\r
4614 case IDM_ReloadPosition:
\r
4615 ReloadPosition(0);
\r
4618 case IDM_SaveGame:
\r
4619 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4620 f = OpenFileDialog(hwnd, "a", defName,
\r
4621 appData.oldSaveStyle ? "gam" : "pgn",
\r
4623 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4625 SaveGame(f, 0, "");
\r
4629 case IDM_SavePosition:
\r
4630 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4631 f = OpenFileDialog(hwnd, "a", defName,
\r
4632 appData.oldSaveStyle ? "pos" : "fen",
\r
4634 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4636 SavePosition(f, 0, "");
\r
4640 case IDM_SaveDiagram:
\r
4641 defName = "diagram";
\r
4642 f = OpenFileDialog(hwnd, "wb", defName,
\r
4645 "Save Diagram to File", NULL, fileTitle, NULL);
\r
4651 case IDM_CopyGame:
\r
4652 CopyGameToClipboard();
\r
4655 case IDM_PasteGame:
\r
4656 PasteGameFromClipboard();
\r
4659 case IDM_CopyGameListToClipboard:
\r
4660 CopyGameListToClipboard();
\r
4663 /* [AS] Autodetect FEN or PGN data */
\r
4664 case IDM_PasteAny:
\r
4665 PasteGameOrFENFromClipboard();
\r
4668 /* [AS] Move history */
\r
4669 case IDM_ShowMoveHistory:
\r
4670 if( MoveHistoryIsUp() ) {
\r
4671 MoveHistoryPopDown();
\r
4674 MoveHistoryPopUp();
\r
4678 /* [AS] Eval graph */
\r
4679 case IDM_ShowEvalGraph:
\r
4680 if( EvalGraphIsUp() ) {
\r
4681 EvalGraphPopDown();
\r
4685 SetFocus(hwndMain);
\r
4689 /* [AS] Engine output */
\r
4690 case IDM_ShowEngineOutput:
\r
4691 if( EngineOutputIsUp() ) {
\r
4692 EngineOutputPopDown();
\r
4695 EngineOutputPopUp();
\r
4699 /* [AS] User adjudication */
\r
4700 case IDM_UserAdjudication_White:
\r
4701 UserAdjudicationEvent( +1 );
\r
4704 case IDM_UserAdjudication_Black:
\r
4705 UserAdjudicationEvent( -1 );
\r
4708 case IDM_UserAdjudication_Draw:
\r
4709 UserAdjudicationEvent( 0 );
\r
4712 /* [AS] Game list options dialog */
\r
4713 case IDM_GameListOptions:
\r
4714 GameListOptions();
\r
4721 case IDM_CopyPosition:
\r
4722 CopyFENToClipboard();
\r
4725 case IDM_PastePosition:
\r
4726 PasteFENFromClipboard();
\r
4729 case IDM_MailMove:
\r
4733 case IDM_ReloadCMailMsg:
\r
4734 Reset(TRUE, TRUE);
\r
4735 ReloadCmailMsgEvent(FALSE);
\r
4738 case IDM_Minimize:
\r
4739 ShowWindow(hwnd, SW_MINIMIZE);
\r
4746 case IDM_MachineWhite:
\r
4747 MachineWhiteEvent();
\r
4749 * refresh the tags dialog only if it's visible
\r
4751 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4753 tags = PGNTags(&gameInfo);
\r
4754 TagsPopUp(tags, CmailMsg());
\r
4757 SAY("computer starts playing white");
\r
4760 case IDM_MachineBlack:
\r
4761 MachineBlackEvent();
\r
4763 * refresh the tags dialog only if it's visible
\r
4765 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4767 tags = PGNTags(&gameInfo);
\r
4768 TagsPopUp(tags, CmailMsg());
\r
4771 SAY("computer starts playing black");
\r
4774 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
4775 if(gameMode != BeginningOfGame) break; // allow menu item to remain enabled for better mode highligting
\r
4776 matchMode = 2;// distinguish from command-line-triggered case (matchMode=1)
\r
4777 appData.matchGames = appData.defaultMatchGames;
\r
4780 case IDM_TwoMachines:
\r
4781 TwoMachinesEvent();
\r
4783 * refresh the tags dialog only if it's visible
\r
4785 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4787 tags = PGNTags(&gameInfo);
\r
4788 TagsPopUp(tags, CmailMsg());
\r
4791 SAY("computer starts playing both sides");
\r
4794 case IDM_AnalysisMode:
\r
4795 if (!first.analysisSupport) {
\r
4796 sprintf(buf, _("%s does not support analysis"), first.tidy);
\r
4797 DisplayError(buf, 0);
\r
4799 SAY("analyzing current position");
\r
4800 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
4801 if (appData.icsActive) {
\r
4802 if (gameMode != IcsObserving) {
\r
4803 sprintf(buf, "You are not observing a game");
\r
4804 DisplayError(buf, 0);
\r
4805 /* secure check */
\r
4806 if (appData.icsEngineAnalyze) {
\r
4807 if (appData.debugMode)
\r
4808 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
4809 ExitAnalyzeMode();
\r
4815 /* if enable, user want disable icsEngineAnalyze */
\r
4816 if (appData.icsEngineAnalyze) {
\r
4817 ExitAnalyzeMode();
\r
4821 appData.icsEngineAnalyze = TRUE;
\r
4822 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
4825 if (!appData.showThinking) ToggleShowThinking();
\r
4826 AnalyzeModeEvent();
\r
4830 case IDM_AnalyzeFile:
\r
4831 if (!first.analysisSupport) {
\r
4832 char buf[MSG_SIZ];
\r
4833 sprintf(buf, _("%s does not support analysis"), first.tidy);
\r
4834 DisplayError(buf, 0);
\r
4836 if (!appData.showThinking) ToggleShowThinking();
\r
4837 AnalyzeFileEvent();
\r
4838 LoadGameDialog(hwnd, _("Analyze Game from File"));
\r
4839 AnalysisPeriodicEvent(1);
\r
4843 case IDM_IcsClient:
\r
4847 case IDM_EditGame:
\r
4852 case IDM_EditPosition:
\r
4853 EditPositionEvent();
\r
4854 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
4857 case IDM_Training:
\r
4861 case IDM_ShowGameList:
\r
4862 ShowGameListProc();
\r
4865 case IDM_EditTags:
\r
4869 case IDM_EditComment:
\r
4870 if (commentUp && editComment) {
\r
4873 EditCommentEvent();
\r
4893 case IDM_CallFlag:
\r
4913 case IDM_StopObserving:
\r
4914 StopObservingEvent();
\r
4917 case IDM_StopExamining:
\r
4918 StopExaminingEvent();
\r
4922 UploadGameEvent();
\r
4925 case IDM_TypeInMove:
\r
4926 PopUpMoveDialog('\000');
\r
4929 case IDM_TypeInName:
\r
4930 PopUpNameDialog('\000');
\r
4933 case IDM_Backward:
\r
4935 SetFocus(hwndMain);
\r
4942 SetFocus(hwndMain);
\r
4947 SetFocus(hwndMain);
\r
4952 SetFocus(hwndMain);
\r
4956 RevertEvent(FALSE);
\r
4959 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
4960 RevertEvent(TRUE);
\r
4963 case IDM_TruncateGame:
\r
4964 TruncateGameEvent();
\r
4971 case IDM_RetractMove:
\r
4972 RetractMoveEvent();
\r
4975 case IDM_FlipView:
\r
4976 flipView = !flipView;
\r
4977 DrawPosition(FALSE, NULL);
\r
4980 case IDM_FlipClock:
\r
4981 flipClock = !flipClock;
\r
4982 DisplayBothClocks();
\r
4983 DrawPosition(FALSE, NULL);
\r
4986 case IDM_MuteSounds:
\r
4987 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
4988 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
4989 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
4992 case IDM_GeneralOptions:
\r
4993 GeneralOptionsPopup(hwnd);
\r
4994 DrawPosition(TRUE, NULL);
\r
4997 case IDM_BoardOptions:
\r
4998 BoardOptionsPopup(hwnd);
\r
5001 case IDM_EnginePlayOptions:
\r
5002 EnginePlayOptionsPopup(hwnd);
\r
5005 case IDM_Engine1Options:
\r
5006 EngineOptionsPopup(hwnd, &first);
\r
5009 case IDM_Engine2Options:
\r
5010 EngineOptionsPopup(hwnd, &second);
\r
5013 case IDM_OptionsUCI:
\r
5014 UciOptionsPopup(hwnd);
\r
5017 case IDM_IcsOptions:
\r
5018 IcsOptionsPopup(hwnd);
\r
5022 FontsOptionsPopup(hwnd);
\r
5026 SoundOptionsPopup(hwnd);
\r
5029 case IDM_CommPort:
\r
5030 CommPortOptionsPopup(hwnd);
\r
5033 case IDM_LoadOptions:
\r
5034 LoadOptionsPopup(hwnd);
\r
5037 case IDM_SaveOptions:
\r
5038 SaveOptionsPopup(hwnd);
\r
5041 case IDM_TimeControl:
\r
5042 TimeControlOptionsPopup(hwnd);
\r
5045 case IDM_SaveSettings:
\r
5046 SaveSettings(settingsFileName);
\r
5049 case IDM_SaveSettingsOnExit:
\r
5050 saveSettingsOnExit = !saveSettingsOnExit;
\r
5051 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5052 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5053 MF_CHECKED : MF_UNCHECKED));
\r
5064 case IDM_AboutGame:
\r
5069 appData.debugMode = !appData.debugMode;
\r
5070 if (appData.debugMode) {
\r
5071 char dir[MSG_SIZ];
\r
5072 GetCurrentDirectory(MSG_SIZ, dir);
\r
5073 SetCurrentDirectory(installDir);
\r
5074 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5075 SetCurrentDirectory(dir);
\r
5076 setbuf(debugFP, NULL);
\r
5083 case IDM_HELPCONTENTS:
\r
5084 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5085 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5086 MessageBox (GetFocus(),
\r
5087 _("Unable to activate help"),
\r
5088 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5092 case IDM_HELPSEARCH:
\r
5093 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5094 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5095 MessageBox (GetFocus(),
\r
5096 _("Unable to activate help"),
\r
5097 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5101 case IDM_HELPHELP:
\r
5102 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5103 MessageBox (GetFocus(),
\r
5104 _("Unable to activate help"),
\r
5105 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5110 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5112 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5113 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5114 FreeProcInstance(lpProc);
\r
5117 case IDM_DirectCommand1:
\r
5118 AskQuestionEvent(_("Direct Command"),
\r
5119 _("Send to chess program:"), "", "1");
\r
5121 case IDM_DirectCommand2:
\r
5122 AskQuestionEvent(_("Direct Command"),
\r
5123 _("Send to second chess program:"), "", "2");
\r
5126 case EP_WhitePawn:
\r
5127 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5128 fromX = fromY = -1;
\r
5131 case EP_WhiteKnight:
\r
5132 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5133 fromX = fromY = -1;
\r
5136 case EP_WhiteBishop:
\r
5137 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5138 fromX = fromY = -1;
\r
5141 case EP_WhiteRook:
\r
5142 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5143 fromX = fromY = -1;
\r
5146 case EP_WhiteQueen:
\r
5147 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5148 fromX = fromY = -1;
\r
5151 case EP_WhiteFerz:
\r
5152 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5153 fromX = fromY = -1;
\r
5156 case EP_WhiteWazir:
\r
5157 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5158 fromX = fromY = -1;
\r
5161 case EP_WhiteAlfil:
\r
5162 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5163 fromX = fromY = -1;
\r
5166 case EP_WhiteCannon:
\r
5167 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5168 fromX = fromY = -1;
\r
5171 case EP_WhiteCardinal:
\r
5172 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5173 fromX = fromY = -1;
\r
5176 case EP_WhiteMarshall:
\r
5177 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5178 fromX = fromY = -1;
\r
5181 case EP_WhiteKing:
\r
5182 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5183 fromX = fromY = -1;
\r
5186 case EP_BlackPawn:
\r
5187 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5188 fromX = fromY = -1;
\r
5191 case EP_BlackKnight:
\r
5192 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5193 fromX = fromY = -1;
\r
5196 case EP_BlackBishop:
\r
5197 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5198 fromX = fromY = -1;
\r
5201 case EP_BlackRook:
\r
5202 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5203 fromX = fromY = -1;
\r
5206 case EP_BlackQueen:
\r
5207 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5208 fromX = fromY = -1;
\r
5211 case EP_BlackFerz:
\r
5212 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5213 fromX = fromY = -1;
\r
5216 case EP_BlackWazir:
\r
5217 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5218 fromX = fromY = -1;
\r
5221 case EP_BlackAlfil:
\r
5222 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5223 fromX = fromY = -1;
\r
5226 case EP_BlackCannon:
\r
5227 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5228 fromX = fromY = -1;
\r
5231 case EP_BlackCardinal:
\r
5232 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5233 fromX = fromY = -1;
\r
5236 case EP_BlackMarshall:
\r
5237 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5238 fromX = fromY = -1;
\r
5241 case EP_BlackKing:
\r
5242 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5243 fromX = fromY = -1;
\r
5246 case EP_EmptySquare:
\r
5247 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5248 fromX = fromY = -1;
\r
5251 case EP_ClearBoard:
\r
5252 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5253 fromX = fromY = -1;
\r
5257 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5258 fromX = fromY = -1;
\r
5262 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5263 fromX = fromY = -1;
\r
5267 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5268 fromX = fromY = -1;
\r
5272 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5273 fromX = fromY = -1;
\r
5277 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5278 fromX = fromY = -1;
\r
5282 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5283 fromX = fromY = -1;
\r
5287 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5288 fromX = fromY = -1;
\r
5292 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5293 fromX = fromY = -1;
\r
5297 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5298 fromX = fromY = -1;
\r
5302 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5308 case CLOCK_TIMER_ID:
\r
5309 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5310 clockTimerEvent = 0;
\r
5311 DecrementClocks(); /* call into back end */
\r
5313 case LOAD_GAME_TIMER_ID:
\r
5314 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5315 loadGameTimerEvent = 0;
\r
5316 AutoPlayGameLoop(); /* call into back end */
\r
5318 case ANALYSIS_TIMER_ID:
\r
5319 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5320 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5321 AnalysisPeriodicEvent(0);
\r
5323 KillTimer(hwnd, analysisTimerEvent);
\r
5324 analysisTimerEvent = 0;
\r
5327 case DELAYED_TIMER_ID:
\r
5328 KillTimer(hwnd, delayedTimerEvent);
\r
5329 delayedTimerEvent = 0;
\r
5330 delayedTimerCallback();
\r
5335 case WM_USER_Input:
\r
5336 InputEvent(hwnd, message, wParam, lParam);
\r
5339 /* [AS] Also move "attached" child windows */
\r
5340 case WM_WINDOWPOSCHANGING:
\r
5342 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5343 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5345 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5346 /* Window is moving */
\r
5349 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5350 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5351 rcMain.right = wpMain.x + wpMain.width;
\r
5352 rcMain.top = wpMain.y;
\r
5353 rcMain.bottom = wpMain.y + wpMain.height;
\r
5355 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5356 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5357 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5358 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5359 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5360 wpMain.x = lpwp->x;
\r
5361 wpMain.y = lpwp->y;
\r
5366 /* [AS] Snapping */
\r
5367 case WM_ENTERSIZEMOVE:
\r
5368 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5369 if (hwnd == hwndMain) {
\r
5370 doingSizing = TRUE;
\r
5373 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5377 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5378 if (hwnd == hwndMain) {
\r
5379 lastSizing = wParam;
\r
5384 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5385 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5387 case WM_EXITSIZEMOVE:
\r
5388 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5389 if (hwnd == hwndMain) {
\r
5391 doingSizing = FALSE;
\r
5392 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5393 GetClientRect(hwnd, &client);
\r
5394 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5396 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5398 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5401 case WM_DESTROY: /* message: window being destroyed */
\r
5402 PostQuitMessage(0);
\r
5406 if (hwnd == hwndMain) {
\r
5411 default: /* Passes it on if unprocessed */
\r
5412 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5417 /*---------------------------------------------------------------------------*\
\r
5419 * Misc utility routines
\r
5421 \*---------------------------------------------------------------------------*/
\r
5424 * Decent random number generator, at least not as bad as Windows
\r
5425 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5427 unsigned int randstate;
\r
5432 randstate = randstate * 1664525 + 1013904223;
\r
5433 return (int) randstate & 0x7fffffff;
\r
5437 mysrandom(unsigned int seed)
\r
5444 * returns TRUE if user selects a different color, FALSE otherwise
\r
5448 ChangeColor(HWND hwnd, COLORREF *which)
\r
5450 static BOOL firstTime = TRUE;
\r
5451 static DWORD customColors[16];
\r
5453 COLORREF newcolor;
\r
5458 /* Make initial colors in use available as custom colors */
\r
5459 /* Should we put the compiled-in defaults here instead? */
\r
5461 customColors[i++] = lightSquareColor & 0xffffff;
\r
5462 customColors[i++] = darkSquareColor & 0xffffff;
\r
5463 customColors[i++] = whitePieceColor & 0xffffff;
\r
5464 customColors[i++] = blackPieceColor & 0xffffff;
\r
5465 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5466 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5468 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5469 customColors[i++] = textAttribs[ccl].color;
\r
5471 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5472 firstTime = FALSE;
\r
5475 cc.lStructSize = sizeof(cc);
\r
5476 cc.hwndOwner = hwnd;
\r
5477 cc.hInstance = NULL;
\r
5478 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5479 cc.lpCustColors = (LPDWORD) customColors;
\r
5480 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5482 if (!ChooseColor(&cc)) return FALSE;
\r
5484 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5485 if (newcolor == *which) return FALSE;
\r
5486 *which = newcolor;
\r
5490 InitDrawingColors();
\r
5491 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5496 MyLoadSound(MySound *ms)
\r
5502 if (ms->data) free(ms->data);
\r
5505 switch (ms->name[0]) {
\r
5511 /* System sound from Control Panel. Don't preload here. */
\r
5515 if (ms->name[1] == NULLCHAR) {
\r
5516 /* "!" alone = silence */
\r
5519 /* Builtin wave resource. Error if not found. */
\r
5520 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5521 if (h == NULL) break;
\r
5522 ms->data = (void *)LoadResource(hInst, h);
\r
5523 if (h == NULL) break;
\r
5528 /* .wav file. Error if not found. */
\r
5529 f = fopen(ms->name, "rb");
\r
5530 if (f == NULL) break;
\r
5531 if (fstat(fileno(f), &st) < 0) break;
\r
5532 ms->data = malloc(st.st_size);
\r
5533 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5539 char buf[MSG_SIZ];
\r
5540 sprintf(buf, _("Error loading sound %s"), ms->name);
\r
5541 DisplayError(buf, GetLastError());
\r
5547 MyPlaySound(MySound *ms)
\r
5549 BOOLEAN ok = FALSE;
\r
5551 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5552 switch (ms->name[0]) {
\r
5554 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5559 /* System sound from Control Panel (deprecated feature).
\r
5560 "$" alone or an unset sound name gets default beep (still in use). */
\r
5561 if (ms->name[1]) {
\r
5562 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5564 if (!ok) ok = MessageBeep(MB_OK);
\r
5567 /* Builtin wave resource, or "!" alone for silence */
\r
5568 if (ms->name[1]) {
\r
5569 if (ms->data == NULL) return FALSE;
\r
5570 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5576 /* .wav file. Error if not found. */
\r
5577 if (ms->data == NULL) return FALSE;
\r
5578 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5581 /* Don't print an error: this can happen innocently if the sound driver
\r
5582 is busy; for instance, if another instance of WinBoard is playing
\r
5583 a sound at about the same time. */
\r
5589 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5592 OPENFILENAME *ofn;
\r
5593 static UINT *number; /* gross that this is static */
\r
5595 switch (message) {
\r
5596 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5597 /* Center the dialog over the application window */
\r
5598 ofn = (OPENFILENAME *) lParam;
\r
5599 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5600 number = (UINT *) ofn->lCustData;
\r
5601 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5605 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5606 return FALSE; /* Allow for further processing */
\r
5609 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5610 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5612 return FALSE; /* Allow for further processing */
\r
5618 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5620 static UINT *number;
\r
5621 OPENFILENAME *ofname;
\r
5624 case WM_INITDIALOG:
\r
5625 ofname = (OPENFILENAME *)lParam;
\r
5626 number = (UINT *)(ofname->lCustData);
\r
5629 ofnot = (OFNOTIFY *)lParam;
\r
5630 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5631 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5640 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5641 char *nameFilt, char *dlgTitle, UINT *number,
\r
5642 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5644 OPENFILENAME openFileName;
\r
5645 char buf1[MSG_SIZ];
\r
5648 if (fileName == NULL) fileName = buf1;
\r
5649 if (defName == NULL) {
\r
5650 strcpy(fileName, "*.");
\r
5651 strcat(fileName, defExt);
\r
5653 strcpy(fileName, defName);
\r
5655 if (fileTitle) strcpy(fileTitle, "");
\r
5656 if (number) *number = 0;
\r
5658 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5659 openFileName.hwndOwner = hwnd;
\r
5660 openFileName.hInstance = (HANDLE) hInst;
\r
5661 openFileName.lpstrFilter = nameFilt;
\r
5662 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5663 openFileName.nMaxCustFilter = 0L;
\r
5664 openFileName.nFilterIndex = 1L;
\r
5665 openFileName.lpstrFile = fileName;
\r
5666 openFileName.nMaxFile = MSG_SIZ;
\r
5667 openFileName.lpstrFileTitle = fileTitle;
\r
5668 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5669 openFileName.lpstrInitialDir = NULL;
\r
5670 openFileName.lpstrTitle = dlgTitle;
\r
5671 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5672 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5673 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5674 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5675 openFileName.nFileOffset = 0;
\r
5676 openFileName.nFileExtension = 0;
\r
5677 openFileName.lpstrDefExt = defExt;
\r
5678 openFileName.lCustData = (LONG) number;
\r
5679 openFileName.lpfnHook = oldDialog ?
\r
5680 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5681 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5683 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5684 GetOpenFileName(&openFileName)) {
\r
5685 /* open the file */
\r
5686 f = fopen(openFileName.lpstrFile, write);
\r
5688 MessageBox(hwnd, _("File open failed"), NULL,
\r
5689 MB_OK|MB_ICONEXCLAMATION);
\r
5693 int err = CommDlgExtendedError();
\r
5694 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
5703 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5705 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5708 * Get the first pop-up menu in the menu template. This is the
\r
5709 * menu that TrackPopupMenu displays.
\r
5711 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5713 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5716 * TrackPopup uses screen coordinates, so convert the
\r
5717 * coordinates of the mouse click to screen coordinates.
\r
5719 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5721 /* Draw and track the floating pop-up menu. */
\r
5722 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5723 pt.x, pt.y, 0, hwnd, NULL);
\r
5725 /* Destroy the menu.*/
\r
5726 DestroyMenu(hmenu);
\r
5731 int sizeX, sizeY, newSizeX, newSizeY;
\r
5733 } ResizeEditPlusButtonsClosure;
\r
5736 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5738 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5742 if (hChild == cl->hText) return TRUE;
\r
5743 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5744 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5745 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5746 ScreenToClient(cl->hDlg, &pt);
\r
5747 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5748 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5752 /* Resize a dialog that has a (rich) edit field filling most of
\r
5753 the top, with a row of buttons below */
\r
5755 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5758 int newTextHeight, newTextWidth;
\r
5759 ResizeEditPlusButtonsClosure cl;
\r
5761 /*if (IsIconic(hDlg)) return;*/
\r
5762 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5764 cl.hdwp = BeginDeferWindowPos(8);
\r
5766 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5767 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5768 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5769 if (newTextHeight < 0) {
\r
5770 newSizeY += -newTextHeight;
\r
5771 newTextHeight = 0;
\r
5773 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5774 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5780 cl.newSizeX = newSizeX;
\r
5781 cl.newSizeY = newSizeY;
\r
5782 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5784 EndDeferWindowPos(cl.hdwp);
\r
5787 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
5789 RECT rChild, rParent;
\r
5790 int wChild, hChild, wParent, hParent;
\r
5791 int wScreen, hScreen, xNew, yNew;
\r
5794 /* Get the Height and Width of the child window */
\r
5795 GetWindowRect (hwndChild, &rChild);
\r
5796 wChild = rChild.right - rChild.left;
\r
5797 hChild = rChild.bottom - rChild.top;
\r
5799 /* Get the Height and Width of the parent window */
\r
5800 GetWindowRect (hwndParent, &rParent);
\r
5801 wParent = rParent.right - rParent.left;
\r
5802 hParent = rParent.bottom - rParent.top;
\r
5804 /* Get the display limits */
\r
5805 hdc = GetDC (hwndChild);
\r
5806 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5807 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5808 ReleaseDC(hwndChild, hdc);
\r
5810 /* Calculate new X position, then adjust for screen */
\r
5811 xNew = rParent.left + ((wParent - wChild) /2);
\r
5814 } else if ((xNew+wChild) > wScreen) {
\r
5815 xNew = wScreen - wChild;
\r
5818 /* Calculate new Y position, then adjust for screen */
\r
5820 yNew = rParent.top + ((hParent - hChild) /2);
\r
5823 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
5828 } else if ((yNew+hChild) > hScreen) {
\r
5829 yNew = hScreen - hChild;
\r
5832 /* Set it, and return */
\r
5833 return SetWindowPos (hwndChild, NULL,
\r
5834 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5837 /* Center one window over another */
\r
5838 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
5840 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
5843 /*---------------------------------------------------------------------------*\
\r
5845 * Startup Dialog functions
\r
5847 \*---------------------------------------------------------------------------*/
\r
5849 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5851 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5853 while (*cd != NULL) {
\r
5854 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5860 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5862 char buf1[MAX_ARG_LEN];
\r
5865 if (str[0] == '@') {
\r
5866 FILE* f = fopen(str + 1, "r");
\r
5868 DisplayFatalError(str + 1, errno, 2);
\r
5871 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5873 buf1[len] = NULLCHAR;
\r
5877 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5880 char buf[MSG_SIZ];
\r
5881 char *end = strchr(str, '\n');
\r
5882 if (end == NULL) return;
\r
5883 memcpy(buf, str, end - str);
\r
5884 buf[end - str] = NULLCHAR;
\r
5885 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5891 SetStartupDialogEnables(HWND hDlg)
\r
5893 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5894 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5895 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
5896 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5897 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5898 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5899 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5900 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5901 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5902 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5903 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5904 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5905 IsDlgButtonChecked(hDlg, OPT_View));
\r
5909 QuoteForFilename(char *filename)
\r
5911 int dquote, space;
\r
5912 dquote = strchr(filename, '"') != NULL;
\r
5913 space = strchr(filename, ' ') != NULL;
\r
5914 if (dquote || space) {
\r
5926 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5928 char buf[MSG_SIZ];
\r
5931 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5932 q = QuoteForFilename(nthcp);
\r
5933 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5934 if (*nthdir != NULLCHAR) {
\r
5935 q = QuoteForFilename(nthdir);
\r
5936 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5938 if (*nthcp == NULLCHAR) {
\r
5939 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5940 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5941 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5942 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5947 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5949 char buf[MSG_SIZ];
\r
5953 switch (message) {
\r
5954 case WM_INITDIALOG:
\r
5955 /* Center the dialog */
\r
5956 CenterWindow (hDlg, GetDesktopWindow());
\r
5957 Translate(hDlg, DLG_Startup);
\r
5958 /* Initialize the dialog items */
\r
5959 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5960 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5961 firstChessProgramNames);
\r
5962 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5963 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5964 secondChessProgramNames);
\r
5965 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5966 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5967 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5968 if (*appData.icsHelper != NULLCHAR) {
\r
5969 char *q = QuoteForFilename(appData.icsHelper);
\r
5970 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5972 if (*appData.icsHost == NULLCHAR) {
\r
5973 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5974 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5975 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5976 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5977 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5980 if (appData.icsActive) {
\r
5981 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5983 else if (appData.noChessProgram) {
\r
5984 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5987 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
5990 SetStartupDialogEnables(hDlg);
\r
5994 switch (LOWORD(wParam)) {
\r
5996 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5997 strcpy(buf, "/fcp=");
\r
5998 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6000 ParseArgs(StringGet, &p);
\r
6001 strcpy(buf, "/scp=");
\r
6002 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6004 ParseArgs(StringGet, &p);
\r
6005 appData.noChessProgram = FALSE;
\r
6006 appData.icsActive = FALSE;
\r
6007 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6008 strcpy(buf, "/ics /icshost=");
\r
6009 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6011 ParseArgs(StringGet, &p);
\r
6012 if (appData.zippyPlay) {
\r
6013 strcpy(buf, "/fcp=");
\r
6014 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6016 ParseArgs(StringGet, &p);
\r
6018 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6019 appData.noChessProgram = TRUE;
\r
6020 appData.icsActive = FALSE;
\r
6022 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6023 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6026 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6027 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6029 ParseArgs(StringGet, &p);
\r
6031 EndDialog(hDlg, TRUE);
\r
6038 case IDM_HELPCONTENTS:
\r
6039 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6040 MessageBox (GetFocus(),
\r
6041 _("Unable to activate help"),
\r
6042 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6047 SetStartupDialogEnables(hDlg);
\r
6055 /*---------------------------------------------------------------------------*\
\r
6057 * About box dialog functions
\r
6059 \*---------------------------------------------------------------------------*/
\r
6061 /* Process messages for "About" dialog box */
\r
6063 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6065 switch (message) {
\r
6066 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6067 /* Center the dialog over the application window */
\r
6068 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6069 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6073 case WM_COMMAND: /* message: received a command */
\r
6074 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6075 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6076 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6084 /*---------------------------------------------------------------------------*\
\r
6086 * Comment Dialog functions
\r
6088 \*---------------------------------------------------------------------------*/
\r
6091 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6093 static HANDLE hwndText = NULL;
\r
6094 int len, newSizeX, newSizeY, flags;
\r
6095 static int sizeX, sizeY;
\r
6100 switch (message) {
\r
6101 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6102 /* Initialize the dialog items */
\r
6103 Translate(hDlg, DLG_EditComment);
\r
6104 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6105 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6106 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6107 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6108 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6109 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6110 SetWindowText(hDlg, commentTitle);
\r
6111 if (editComment) {
\r
6112 SetFocus(hwndText);
\r
6114 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6116 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6117 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6118 MAKELPARAM(FALSE, 0));
\r
6119 /* Size and position the dialog */
\r
6120 if (!commentDialog) {
\r
6121 commentDialog = hDlg;
\r
6122 flags = SWP_NOZORDER;
\r
6123 GetClientRect(hDlg, &rect);
\r
6124 sizeX = rect.right;
\r
6125 sizeY = rect.bottom;
\r
6126 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6127 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6128 WINDOWPLACEMENT wp;
\r
6129 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6130 wp.length = sizeof(WINDOWPLACEMENT);
\r
6132 wp.showCmd = SW_SHOW;
\r
6133 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6134 wp.rcNormalPosition.left = wpComment.x;
\r
6135 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6136 wp.rcNormalPosition.top = wpComment.y;
\r
6137 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6138 SetWindowPlacement(hDlg, &wp);
\r
6140 GetClientRect(hDlg, &rect);
\r
6141 newSizeX = rect.right;
\r
6142 newSizeY = rect.bottom;
\r
6143 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6144 newSizeX, newSizeY);
\r
6149 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS );
\r
6152 case WM_COMMAND: /* message: received a command */
\r
6153 switch (LOWORD(wParam)) {
\r
6155 if (editComment) {
\r
6157 /* Read changed options from the dialog box */
\r
6158 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6159 len = GetWindowTextLength(hwndText);
\r
6160 str = (char *) malloc(len + 1);
\r
6161 GetWindowText(hwndText, str, len + 1);
\r
6170 ReplaceComment(commentIndex, str);
\r
6177 case OPT_CancelComment:
\r
6181 case OPT_ClearComment:
\r
6182 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6185 case OPT_EditComment:
\r
6186 EditCommentEvent();
\r
6194 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6195 if( wParam == OPT_CommentText ) {
\r
6196 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6198 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ) {
\r
6202 pt.x = LOWORD( lpMF->lParam );
\r
6203 pt.y = HIWORD( lpMF->lParam );
\r
6205 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6207 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6208 len = GetWindowTextLength(hwndText);
\r
6209 str = (char *) malloc(len + 1);
\r
6210 GetWindowText(hwndText, str, len + 1);
\r
6211 ReplaceComment(commentIndex, str);
\r
6212 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6213 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6216 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6217 lpMF->msg = WM_USER;
\r
6225 newSizeX = LOWORD(lParam);
\r
6226 newSizeY = HIWORD(lParam);
\r
6227 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6232 case WM_GETMINMAXINFO:
\r
6233 /* Prevent resizing window too small */
\r
6234 mmi = (MINMAXINFO *) lParam;
\r
6235 mmi->ptMinTrackSize.x = 100;
\r
6236 mmi->ptMinTrackSize.y = 100;
\r
6243 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6248 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6250 if (str == NULL) str = "";
\r
6251 p = (char *) malloc(2 * strlen(str) + 2);
\r
6254 if (*str == '\n') *q++ = '\r';
\r
6258 if (commentText != NULL) free(commentText);
\r
6260 commentIndex = index;
\r
6261 commentTitle = title;
\r
6263 editComment = edit;
\r
6265 if (commentDialog) {
\r
6266 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6267 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6269 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6270 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6271 hwndMain, (DLGPROC)lpProc);
\r
6272 FreeProcInstance(lpProc);
\r
6278 /*---------------------------------------------------------------------------*\
\r
6280 * Type-in move dialog functions
\r
6282 \*---------------------------------------------------------------------------*/
\r
6285 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6287 char move[MSG_SIZ];
\r
6289 ChessMove moveType;
\r
6290 int fromX, fromY, toX, toY;
\r
6293 switch (message) {
\r
6294 case WM_INITDIALOG:
\r
6295 move[0] = (char) lParam;
\r
6296 move[1] = NULLCHAR;
\r
6297 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6298 Translate(hDlg, DLG_TypeInMove);
\r
6299 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6300 SetWindowText(hInput, move);
\r
6302 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6306 switch (LOWORD(wParam)) {
\r
6308 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6309 { int n; Board board;
\r
6311 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
6312 EditPositionPasteFEN(move);
\r
6313 EndDialog(hDlg, TRUE);
\r
6316 // [HGM] movenum: allow move number to be typed in any mode
\r
6317 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
6319 EndDialog(hDlg, TRUE);
\r
6323 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6324 gameMode != Training) {
\r
6325 DisplayMoveError(_("Displayed move is not current"));
\r
6327 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
6328 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6329 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
6330 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
6331 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6332 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6333 if (gameMode != Training)
\r
6334 forwardMostMove = currentMove;
\r
6335 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6337 DisplayMoveError(_("Could not parse move"));
\r
6340 EndDialog(hDlg, TRUE);
\r
6343 EndDialog(hDlg, FALSE);
\r
6354 PopUpMoveDialog(char firstchar)
\r
6358 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6359 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6360 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6361 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6362 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6363 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
6364 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
6365 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
6366 gameMode == Training) {
\r
6367 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6368 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6369 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6370 FreeProcInstance(lpProc);
\r
6374 /*---------------------------------------------------------------------------*\
\r
6376 * Type-in name dialog functions
\r
6378 \*---------------------------------------------------------------------------*/
\r
6381 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6383 char move[MSG_SIZ];
\r
6386 switch (message) {
\r
6387 case WM_INITDIALOG:
\r
6388 move[0] = (char) lParam;
\r
6389 move[1] = NULLCHAR;
\r
6390 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6391 Translate(hDlg, DLG_TypeInName);
\r
6392 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6393 SetWindowText(hInput, move);
\r
6395 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6399 switch (LOWORD(wParam)) {
\r
6401 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6402 appData.userName = strdup(move);
\r
6405 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6406 sprintf(move, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6407 DisplayTitle(move);
\r
6411 EndDialog(hDlg, TRUE);
\r
6414 EndDialog(hDlg, FALSE);
\r
6425 PopUpNameDialog(char firstchar)
\r
6429 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6430 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6431 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6432 FreeProcInstance(lpProc);
\r
6435 /*---------------------------------------------------------------------------*\
\r
6439 \*---------------------------------------------------------------------------*/
\r
6441 /* Nonmodal error box */
\r
6442 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6443 WPARAM wParam, LPARAM lParam);
\r
6446 ErrorPopUp(char *title, char *content)
\r
6450 BOOLEAN modal = hwndMain == NULL;
\r
6468 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6469 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6472 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6474 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6475 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6476 hwndMain, (DLGPROC)lpProc);
\r
6477 FreeProcInstance(lpProc);
\r
6484 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6485 if (errorDialog == NULL) return;
\r
6486 DestroyWindow(errorDialog);
\r
6487 errorDialog = NULL;
\r
6488 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6492 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6497 switch (message) {
\r
6498 case WM_INITDIALOG:
\r
6499 GetWindowRect(hDlg, &rChild);
\r
6502 SetWindowPos(hDlg, NULL, rChild.left,
\r
6503 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6504 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6508 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6509 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6510 and it doesn't work when you resize the dialog.
\r
6511 For now, just give it a default position.
\r
6513 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6514 Translate(hDlg, DLG_Error);
\r
6516 errorDialog = hDlg;
\r
6517 SetWindowText(hDlg, errorTitle);
\r
6518 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6519 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6523 switch (LOWORD(wParam)) {
\r
6526 if (errorDialog == hDlg) errorDialog = NULL;
\r
6527 DestroyWindow(hDlg);
\r
6539 HWND gothicDialog = NULL;
\r
6542 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6546 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6548 switch (message) {
\r
6549 case WM_INITDIALOG:
\r
6550 GetWindowRect(hDlg, &rChild);
\r
6552 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6556 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6557 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6558 and it doesn't work when you resize the dialog.
\r
6559 For now, just give it a default position.
\r
6561 gothicDialog = hDlg;
\r
6562 SetWindowText(hDlg, errorTitle);
\r
6563 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6564 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6568 switch (LOWORD(wParam)) {
\r
6571 if (errorDialog == hDlg) errorDialog = NULL;
\r
6572 DestroyWindow(hDlg);
\r
6584 GothicPopUp(char *title, VariantClass variant)
\r
6587 static char *lastTitle;
\r
6589 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6590 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6592 if(lastTitle != title && gothicDialog != NULL) {
\r
6593 DestroyWindow(gothicDialog);
\r
6594 gothicDialog = NULL;
\r
6596 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6597 title = lastTitle;
\r
6598 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6599 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6600 hwndMain, (DLGPROC)lpProc);
\r
6601 FreeProcInstance(lpProc);
\r
6606 /*---------------------------------------------------------------------------*\
\r
6608 * Ics Interaction console functions
\r
6610 \*---------------------------------------------------------------------------*/
\r
6612 #define HISTORY_SIZE 64
\r
6613 static char *history[HISTORY_SIZE];
\r
6614 int histIn = 0, histP = 0;
\r
6617 SaveInHistory(char *cmd)
\r
6619 if (history[histIn] != NULL) {
\r
6620 free(history[histIn]);
\r
6621 history[histIn] = NULL;
\r
6623 if (*cmd == NULLCHAR) return;
\r
6624 history[histIn] = StrSave(cmd);
\r
6625 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6626 if (history[histIn] != NULL) {
\r
6627 free(history[histIn]);
\r
6628 history[histIn] = NULL;
\r
6634 PrevInHistory(char *cmd)
\r
6637 if (histP == histIn) {
\r
6638 if (history[histIn] != NULL) free(history[histIn]);
\r
6639 history[histIn] = StrSave(cmd);
\r
6641 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6642 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6644 return history[histP];
\r
6650 if (histP == histIn) return NULL;
\r
6651 histP = (histP + 1) % HISTORY_SIZE;
\r
6652 return history[histP];
\r
6656 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6660 hmenu = LoadMenu(hInst, "TextMenu");
\r
6661 h = GetSubMenu(hmenu, 0);
\r
6663 if (strcmp(e->item, "-") == 0) {
\r
6664 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6665 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6666 int flags = MF_STRING, j = 0;
\r
6667 if (e->item[0] == '|') {
\r
6668 flags |= MF_MENUBARBREAK;
\r
6671 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6672 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6680 WNDPROC consoleTextWindowProc;
\r
6683 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6685 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6686 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6690 SetWindowText(hInput, command);
\r
6692 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6694 sel.cpMin = 999999;
\r
6695 sel.cpMax = 999999;
\r
6696 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6701 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6702 if (sel.cpMin == sel.cpMax) {
\r
6703 /* Expand to surrounding word */
\r
6706 tr.chrg.cpMax = sel.cpMin;
\r
6707 tr.chrg.cpMin = --sel.cpMin;
\r
6708 if (sel.cpMin < 0) break;
\r
6709 tr.lpstrText = name;
\r
6710 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6711 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6715 tr.chrg.cpMin = sel.cpMax;
\r
6716 tr.chrg.cpMax = ++sel.cpMax;
\r
6717 tr.lpstrText = name;
\r
6718 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6719 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6722 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6723 MessageBeep(MB_ICONEXCLAMATION);
\r
6727 tr.lpstrText = name;
\r
6728 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6730 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6731 MessageBeep(MB_ICONEXCLAMATION);
\r
6734 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6737 sprintf(buf, "%s %s", command, name);
\r
6738 SetWindowText(hInput, buf);
\r
6739 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6741 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
6742 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6743 SetWindowText(hInput, buf);
\r
6744 sel.cpMin = 999999;
\r
6745 sel.cpMax = 999999;
\r
6746 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6752 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6757 switch (message) {
\r
6759 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6762 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6765 sel.cpMin = 999999;
\r
6766 sel.cpMax = 999999;
\r
6767 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6768 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6773 if(wParam != '\022') {
\r
6774 if (wParam == '\t') {
\r
6775 if (GetKeyState(VK_SHIFT) < 0) {
\r
6777 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6778 if (buttonDesc[0].hwnd) {
\r
6779 SetFocus(buttonDesc[0].hwnd);
\r
6781 SetFocus(hwndMain);
\r
6785 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6788 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6789 JAWS_DELETE( SetFocus(hInput); )
\r
6790 SendMessage(hInput, message, wParam, lParam);
\r
6793 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
6794 case WM_RBUTTONDOWN:
\r
6795 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6796 /* Move selection here if it was empty */
\r
6798 pt.x = LOWORD(lParam);
\r
6799 pt.y = HIWORD(lParam);
\r
6800 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6801 if (sel.cpMin == sel.cpMax) {
\r
6802 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6803 sel.cpMax = sel.cpMin;
\r
6804 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6806 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6807 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
6809 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6810 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6811 if (sel.cpMin == sel.cpMax) {
\r
6812 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6813 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6815 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6816 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6818 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
6819 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
6820 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
6821 MenuPopup(hwnd, pt, hmenu, -1);
\r
6825 case WM_RBUTTONUP:
\r
6826 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6827 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6828 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6832 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6834 return SendMessage(hInput, message, wParam, lParam);
\r
6835 case WM_MBUTTONDOWN:
\r
6836 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6838 switch (LOWORD(wParam)) {
\r
6839 case IDM_QuickPaste:
\r
6841 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6842 if (sel.cpMin == sel.cpMax) {
\r
6843 MessageBeep(MB_ICONEXCLAMATION);
\r
6846 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6847 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6848 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6853 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6856 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6859 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6863 int i = LOWORD(wParam) - IDM_CommandX;
\r
6864 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6865 icsTextMenuEntry[i].command != NULL) {
\r
6866 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6867 icsTextMenuEntry[i].getname,
\r
6868 icsTextMenuEntry[i].immediate);
\r
6876 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6879 WNDPROC consoleInputWindowProc;
\r
6882 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6884 char buf[MSG_SIZ];
\r
6886 static BOOL sendNextChar = FALSE;
\r
6887 static BOOL quoteNextChar = FALSE;
\r
6888 InputSource *is = consoleInputSource;
\r
6892 switch (message) {
\r
6894 if (!appData.localLineEditing || sendNextChar) {
\r
6895 is->buf[0] = (CHAR) wParam;
\r
6897 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6898 sendNextChar = FALSE;
\r
6901 if (quoteNextChar) {
\r
6902 buf[0] = (char) wParam;
\r
6903 buf[1] = NULLCHAR;
\r
6904 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6905 quoteNextChar = FALSE;
\r
6909 case '\r': /* Enter key */
\r
6910 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6911 if (consoleEcho) SaveInHistory(is->buf);
\r
6912 is->buf[is->count++] = '\n';
\r
6913 is->buf[is->count] = NULLCHAR;
\r
6914 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6915 if (consoleEcho) {
\r
6916 ConsoleOutput(is->buf, is->count, TRUE);
\r
6917 } else if (appData.localLineEditing) {
\r
6918 ConsoleOutput("\n", 1, TRUE);
\r
6921 case '\033': /* Escape key */
\r
6922 SetWindowText(hwnd, "");
\r
6923 cf.cbSize = sizeof(CHARFORMAT);
\r
6924 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6925 if (consoleEcho) {
\r
6926 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6928 cf.crTextColor = COLOR_ECHOOFF;
\r
6930 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6931 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6933 case '\t': /* Tab key */
\r
6934 if (GetKeyState(VK_SHIFT) < 0) {
\r
6936 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6939 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6940 if (buttonDesc[0].hwnd) {
\r
6941 SetFocus(buttonDesc[0].hwnd);
\r
6943 SetFocus(hwndMain);
\r
6947 case '\023': /* Ctrl+S */
\r
6948 sendNextChar = TRUE;
\r
6950 case '\021': /* Ctrl+Q */
\r
6951 quoteNextChar = TRUE;
\r
6961 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6962 p = PrevInHistory(buf);
\r
6964 SetWindowText(hwnd, p);
\r
6965 sel.cpMin = 999999;
\r
6966 sel.cpMax = 999999;
\r
6967 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6972 p = NextInHistory();
\r
6974 SetWindowText(hwnd, p);
\r
6975 sel.cpMin = 999999;
\r
6976 sel.cpMax = 999999;
\r
6977 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6983 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6987 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6991 case WM_MBUTTONDOWN:
\r
6992 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6993 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6995 case WM_RBUTTONUP:
\r
6996 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6997 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6998 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7002 hmenu = LoadMenu(hInst, "InputMenu");
\r
7003 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7004 if (sel.cpMin == sel.cpMax) {
\r
7005 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7006 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7008 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7009 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7011 pt.x = LOWORD(lParam);
\r
7012 pt.y = HIWORD(lParam);
\r
7013 MenuPopup(hwnd, pt, hmenu, -1);
\r
7017 switch (LOWORD(wParam)) {
\r
7019 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7021 case IDM_SelectAll:
\r
7023 sel.cpMax = -1; /*999999?*/
\r
7024 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7027 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7030 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7033 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7038 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7041 #define CO_MAX 100000
\r
7042 #define CO_TRIM 1000
\r
7045 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7047 static SnapData sd;
\r
7048 HWND hText, hInput;
\r
7050 static int sizeX, sizeY;
\r
7051 int newSizeX, newSizeY;
\r
7055 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7056 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7058 switch (message) {
\r
7060 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7062 ENLINK *pLink = (ENLINK*)lParam;
\r
7063 if (pLink->msg == WM_LBUTTONUP)
\r
7067 tr.chrg = pLink->chrg;
\r
7068 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7069 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7070 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7071 free(tr.lpstrText);
\r
7075 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7076 hwndConsole = hDlg;
\r
7078 consoleTextWindowProc = (WNDPROC)
\r
7079 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7080 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7081 consoleInputWindowProc = (WNDPROC)
\r
7082 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7083 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7084 Colorize(ColorNormal, TRUE);
\r
7085 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7086 ChangedConsoleFont();
\r
7087 GetClientRect(hDlg, &rect);
\r
7088 sizeX = rect.right;
\r
7089 sizeY = rect.bottom;
\r
7090 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7091 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7092 WINDOWPLACEMENT wp;
\r
7093 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7094 wp.length = sizeof(WINDOWPLACEMENT);
\r
7096 wp.showCmd = SW_SHOW;
\r
7097 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7098 wp.rcNormalPosition.left = wpConsole.x;
\r
7099 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7100 wp.rcNormalPosition.top = wpConsole.y;
\r
7101 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7102 SetWindowPlacement(hDlg, &wp);
\r
7105 // [HGM] Chessknight's change 2004-07-13
\r
7106 else { /* Determine Defaults */
\r
7107 WINDOWPLACEMENT wp;
\r
7108 wpConsole.x = wpMain.width + 1;
\r
7109 wpConsole.y = wpMain.y;
\r
7110 wpConsole.width = screenWidth - wpMain.width;
\r
7111 wpConsole.height = wpMain.height;
\r
7112 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7113 wp.length = sizeof(WINDOWPLACEMENT);
\r
7115 wp.showCmd = SW_SHOW;
\r
7116 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7117 wp.rcNormalPosition.left = wpConsole.x;
\r
7118 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7119 wp.rcNormalPosition.top = wpConsole.y;
\r
7120 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7121 SetWindowPlacement(hDlg, &wp);
\r
7124 // Allow hText to highlight URLs and send notifications on them
\r
7125 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7126 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7127 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7128 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
7142 if (IsIconic(hDlg)) break;
\r
7143 newSizeX = LOWORD(lParam);
\r
7144 newSizeY = HIWORD(lParam);
\r
7145 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7146 RECT rectText, rectInput;
\r
7148 int newTextHeight, newTextWidth;
\r
7149 GetWindowRect(hText, &rectText);
\r
7150 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7151 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7152 if (newTextHeight < 0) {
\r
7153 newSizeY += -newTextHeight;
\r
7154 newTextHeight = 0;
\r
7156 SetWindowPos(hText, NULL, 0, 0,
\r
7157 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7158 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7159 pt.x = rectInput.left;
\r
7160 pt.y = rectInput.top + newSizeY - sizeY;
\r
7161 ScreenToClient(hDlg, &pt);
\r
7162 SetWindowPos(hInput, NULL,
\r
7163 pt.x, pt.y, /* needs client coords */
\r
7164 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7165 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7171 case WM_GETMINMAXINFO:
\r
7172 /* Prevent resizing window too small */
\r
7173 mmi = (MINMAXINFO *) lParam;
\r
7174 mmi->ptMinTrackSize.x = 100;
\r
7175 mmi->ptMinTrackSize.y = 100;
\r
7178 /* [AS] Snapping */
\r
7179 case WM_ENTERSIZEMOVE:
\r
7180 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7183 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7186 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7188 case WM_EXITSIZEMOVE:
\r
7189 UpdateICSWidth(hText);
\r
7190 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7193 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7201 if (hwndConsole) return;
\r
7202 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7203 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7208 ConsoleOutput(char* data, int length, int forceVisible)
\r
7213 char buf[CO_MAX+1];
\r
7216 static int delayLF = 0;
\r
7217 CHARRANGE savesel, sel;
\r
7219 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7227 while (length--) {
\r
7235 } else if (*p == '\007') {
\r
7236 MyPlaySound(&sounds[(int)SoundBell]);
\r
7243 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7244 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7245 /* Save current selection */
\r
7246 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7247 exlen = GetWindowTextLength(hText);
\r
7248 /* Find out whether current end of text is visible */
\r
7249 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7250 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7251 /* Trim existing text if it's too long */
\r
7252 if (exlen + (q - buf) > CO_MAX) {
\r
7253 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7256 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7257 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7259 savesel.cpMin -= trim;
\r
7260 savesel.cpMax -= trim;
\r
7261 if (exlen < 0) exlen = 0;
\r
7262 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7263 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7265 /* Append the new text */
\r
7266 sel.cpMin = exlen;
\r
7267 sel.cpMax = exlen;
\r
7268 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7269 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7270 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7271 if (forceVisible || exlen == 0 ||
\r
7272 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7273 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7274 /* Scroll to make new end of text visible if old end of text
\r
7275 was visible or new text is an echo of user typein */
\r
7276 sel.cpMin = 9999999;
\r
7277 sel.cpMax = 9999999;
\r
7278 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7279 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7280 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7281 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7283 if (savesel.cpMax == exlen || forceVisible) {
\r
7284 /* Move insert point to new end of text if it was at the old
\r
7285 end of text or if the new text is an echo of user typein */
\r
7286 sel.cpMin = 9999999;
\r
7287 sel.cpMax = 9999999;
\r
7288 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7290 /* Restore previous selection */
\r
7291 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7293 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7300 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7304 COLORREF oldFg, oldBg;
\r
7308 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
7310 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7311 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7312 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7315 rect.right = x + squareSize;
\r
7317 rect.bottom = y + squareSize;
\r
7320 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7321 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7322 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7323 &rect, str, strlen(str), NULL);
\r
7325 (void) SetTextColor(hdc, oldFg);
\r
7326 (void) SetBkColor(hdc, oldBg);
\r
7327 (void) SelectObject(hdc, oldFont);
\r
7331 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7332 RECT *rect, char *color, char *flagFell)
\r
7336 COLORREF oldFg, oldBg;
\r
7339 if (appData.clockMode) {
\r
7341 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7343 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7350 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7351 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7353 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7354 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7356 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7360 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7361 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7362 rect, str, strlen(str), NULL);
\r
7363 if(logoHeight > 0 && appData.clockMode) {
\r
7365 sprintf(buf, "%s %s", buf+7, flagFell);
\r
7366 r.top = rect->top + logoHeight/2;
\r
7367 r.left = rect->left;
\r
7368 r.right = rect->right;
\r
7369 r.bottom = rect->bottom;
\r
7370 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7371 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7372 &r, str, strlen(str), NULL);
\r
7374 (void) SetTextColor(hdc, oldFg);
\r
7375 (void) SetBkColor(hdc, oldBg);
\r
7376 (void) SelectObject(hdc, oldFont);
\r
7381 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7387 if( count <= 0 ) {
\r
7388 if (appData.debugMode) {
\r
7389 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7392 return ERROR_INVALID_USER_BUFFER;
\r
7395 ResetEvent(ovl->hEvent);
\r
7396 ovl->Offset = ovl->OffsetHigh = 0;
\r
7397 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7401 err = GetLastError();
\r
7402 if (err == ERROR_IO_PENDING) {
\r
7403 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7407 err = GetLastError();
\r
7414 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7419 ResetEvent(ovl->hEvent);
\r
7420 ovl->Offset = ovl->OffsetHigh = 0;
\r
7421 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7425 err = GetLastError();
\r
7426 if (err == ERROR_IO_PENDING) {
\r
7427 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7431 err = GetLastError();
\r
7437 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7438 void CheckForInputBufferFull( InputSource * is )
\r
7440 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7441 /* Look for end of line */
\r
7442 char * p = is->buf;
\r
7444 while( p < is->next && *p != '\n' ) {
\r
7448 if( p >= is->next ) {
\r
7449 if (appData.debugMode) {
\r
7450 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7453 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7454 is->count = (DWORD) -1;
\r
7455 is->next = is->buf;
\r
7461 InputThread(LPVOID arg)
\r
7466 is = (InputSource *) arg;
\r
7467 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7468 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7469 while (is->hThread != NULL) {
\r
7470 is->error = DoReadFile(is->hFile, is->next,
\r
7471 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7472 &is->count, &ovl);
\r
7473 if (is->error == NO_ERROR) {
\r
7474 is->next += is->count;
\r
7476 if (is->error == ERROR_BROKEN_PIPE) {
\r
7477 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7480 is->count = (DWORD) -1;
\r
7481 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7486 CheckForInputBufferFull( is );
\r
7488 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7490 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7492 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7495 CloseHandle(ovl.hEvent);
\r
7496 CloseHandle(is->hFile);
\r
7498 if (appData.debugMode) {
\r
7499 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7506 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7508 NonOvlInputThread(LPVOID arg)
\r
7515 is = (InputSource *) arg;
\r
7516 while (is->hThread != NULL) {
\r
7517 is->error = ReadFile(is->hFile, is->next,
\r
7518 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7519 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7520 if (is->error == NO_ERROR) {
\r
7521 /* Change CRLF to LF */
\r
7522 if (is->next > is->buf) {
\r
7524 i = is->count + 1;
\r
7532 if (prev == '\r' && *p == '\n') {
\r
7544 if (is->error == ERROR_BROKEN_PIPE) {
\r
7545 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7548 is->count = (DWORD) -1;
\r
7552 CheckForInputBufferFull( is );
\r
7554 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7556 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7558 if (is->count < 0) break; /* Quit on error */
\r
7560 CloseHandle(is->hFile);
\r
7565 SocketInputThread(LPVOID arg)
\r
7569 is = (InputSource *) arg;
\r
7570 while (is->hThread != NULL) {
\r
7571 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7572 if ((int)is->count == SOCKET_ERROR) {
\r
7573 is->count = (DWORD) -1;
\r
7574 is->error = WSAGetLastError();
\r
7576 is->error = NO_ERROR;
\r
7577 is->next += is->count;
\r
7578 if (is->count == 0 && is->second == is) {
\r
7579 /* End of file on stderr; quit with no message */
\r
7583 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7585 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7587 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7593 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7597 is = (InputSource *) lParam;
\r
7598 if (is->lineByLine) {
\r
7599 /* Feed in lines one by one */
\r
7600 char *p = is->buf;
\r
7602 while (q < is->next) {
\r
7603 if (*q++ == '\n') {
\r
7604 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7609 /* Move any partial line to the start of the buffer */
\r
7611 while (p < is->next) {
\r
7616 if (is->error != NO_ERROR || is->count == 0) {
\r
7617 /* Notify backend of the error. Note: If there was a partial
\r
7618 line at the end, it is not flushed through. */
\r
7619 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7622 /* Feed in the whole chunk of input at once */
\r
7623 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7624 is->next = is->buf;
\r
7628 /*---------------------------------------------------------------------------*\
\r
7630 * Menu enables. Used when setting various modes.
\r
7632 \*---------------------------------------------------------------------------*/
\r
7640 GreyRevert(Boolean grey)
\r
7641 { // [HGM] vari: for retracting variations in local mode
\r
7642 HMENU hmenu = GetMenu(hwndMain);
\r
7643 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7644 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7648 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7650 while (enab->item > 0) {
\r
7651 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7656 Enables gnuEnables[] = {
\r
7657 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7658 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7659 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7660 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7661 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7662 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7663 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7664 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7665 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7666 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7667 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7668 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7669 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7673 Enables icsEnables[] = {
\r
7674 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7675 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7676 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7677 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7678 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7679 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7680 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7681 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7682 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7683 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7684 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7685 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7686 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7687 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7688 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7689 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7690 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7695 Enables zippyEnables[] = {
\r
7696 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7697 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7698 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7699 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7704 Enables ncpEnables[] = {
\r
7705 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7706 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7707 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7708 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7709 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7710 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7711 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7712 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7713 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7714 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7715 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7716 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7717 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7718 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7719 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7720 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7721 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7722 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7723 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7724 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7725 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7729 Enables trainingOnEnables[] = {
\r
7730 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7731 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7732 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7733 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7734 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7735 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7736 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7737 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7741 Enables trainingOffEnables[] = {
\r
7742 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7743 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7744 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7745 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7746 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7747 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7748 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7749 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7753 /* These modify either ncpEnables or gnuEnables */
\r
7754 Enables cmailEnables[] = {
\r
7755 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7756 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7757 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7758 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7759 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7760 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7761 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7765 Enables machineThinkingEnables[] = {
\r
7766 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7767 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7768 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7769 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7770 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7771 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7772 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7773 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7774 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7775 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7776 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7777 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7778 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7779 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7780 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7781 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7785 Enables userThinkingEnables[] = {
\r
7786 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7787 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7788 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7789 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7790 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7791 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7792 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7793 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7794 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7795 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7796 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7797 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7798 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7799 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7800 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7801 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7805 /*---------------------------------------------------------------------------*\
\r
7807 * Front-end interface functions exported by XBoard.
\r
7808 * Functions appear in same order as prototypes in frontend.h.
\r
7810 \*---------------------------------------------------------------------------*/
\r
7814 static UINT prevChecked = 0;
\r
7815 static int prevPausing = 0;
\r
7818 if (pausing != prevPausing) {
\r
7819 prevPausing = pausing;
\r
7820 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7821 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7822 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7825 switch (gameMode) {
\r
7826 case BeginningOfGame:
\r
7827 if (appData.icsActive)
\r
7828 nowChecked = IDM_IcsClient;
\r
7829 else if (appData.noChessProgram)
\r
7830 nowChecked = IDM_EditGame;
\r
7832 nowChecked = IDM_MachineBlack;
\r
7834 case MachinePlaysBlack:
\r
7835 nowChecked = IDM_MachineBlack;
\r
7837 case MachinePlaysWhite:
\r
7838 nowChecked = IDM_MachineWhite;
\r
7840 case TwoMachinesPlay:
\r
7841 nowChecked = matchMode ? IDM_Match : IDM_TwoMachines; // [HGM] match
\r
7844 nowChecked = IDM_AnalysisMode;
\r
7847 nowChecked = IDM_AnalyzeFile;
\r
7850 nowChecked = IDM_EditGame;
\r
7852 case PlayFromGameFile:
\r
7853 nowChecked = IDM_LoadGame;
\r
7855 case EditPosition:
\r
7856 nowChecked = IDM_EditPosition;
\r
7859 nowChecked = IDM_Training;
\r
7861 case IcsPlayingWhite:
\r
7862 case IcsPlayingBlack:
\r
7863 case IcsObserving:
\r
7865 nowChecked = IDM_IcsClient;
\r
7872 if (prevChecked != 0)
\r
7873 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7874 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7875 if (nowChecked != 0)
\r
7876 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7877 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7879 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7880 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7881 MF_BYCOMMAND|MF_ENABLED);
\r
7883 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7884 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7887 prevChecked = nowChecked;
\r
7889 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
7890 if (appData.icsActive) {
\r
7891 if (appData.icsEngineAnalyze) {
\r
7892 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7893 MF_BYCOMMAND|MF_CHECKED);
\r
7895 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7896 MF_BYCOMMAND|MF_UNCHECKED);
\r
7904 HMENU hmenu = GetMenu(hwndMain);
\r
7905 SetMenuEnables(hmenu, icsEnables);
\r
7906 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7907 MF_BYPOSITION|MF_ENABLED);
\r
7909 if (appData.zippyPlay) {
\r
7910 SetMenuEnables(hmenu, zippyEnables);
\r
7911 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
7912 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7913 MF_BYCOMMAND|MF_ENABLED);
\r
7921 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7927 HMENU hmenu = GetMenu(hwndMain);
\r
7928 SetMenuEnables(hmenu, ncpEnables);
\r
7929 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7930 MF_BYPOSITION|MF_GRAYED);
\r
7931 DrawMenuBar(hwndMain);
\r
7937 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7941 SetTrainingModeOn()
\r
7944 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7945 for (i = 0; i < N_BUTTONS; i++) {
\r
7946 if (buttonDesc[i].hwnd != NULL)
\r
7947 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7952 VOID SetTrainingModeOff()
\r
7955 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7956 for (i = 0; i < N_BUTTONS; i++) {
\r
7957 if (buttonDesc[i].hwnd != NULL)
\r
7958 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7964 SetUserThinkingEnables()
\r
7966 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7970 SetMachineThinkingEnables()
\r
7972 HMENU hMenu = GetMenu(hwndMain);
\r
7973 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7975 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7977 if (gameMode == MachinePlaysBlack) {
\r
7978 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7979 } else if (gameMode == MachinePlaysWhite) {
\r
7980 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7981 } else if (gameMode == TwoMachinesPlay) {
\r
7982 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
7988 DisplayTitle(char *str)
\r
7990 char title[MSG_SIZ], *host;
\r
7991 if (str[0] != NULLCHAR) {
\r
7992 strcpy(title, str);
\r
7993 } else if (appData.icsActive) {
\r
7994 if (appData.icsCommPort[0] != NULLCHAR)
\r
7997 host = appData.icsHost;
\r
7998 sprintf(title, "%s: %s", szTitle, host);
\r
7999 } else if (appData.noChessProgram) {
\r
8000 strcpy(title, szTitle);
\r
8002 strcpy(title, szTitle);
\r
8003 strcat(title, ": ");
\r
8004 strcat(title, first.tidy);
\r
8006 SetWindowText(hwndMain, title);
\r
8011 DisplayMessage(char *str1, char *str2)
\r
8015 int remain = MESSAGE_TEXT_MAX - 1;
\r
8018 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8019 messageText[0] = NULLCHAR;
\r
8021 len = strlen(str1);
\r
8022 if (len > remain) len = remain;
\r
8023 strncpy(messageText, str1, len);
\r
8024 messageText[len] = NULLCHAR;
\r
8027 if (*str2 && remain >= 2) {
\r
8029 strcat(messageText, " ");
\r
8032 len = strlen(str2);
\r
8033 if (len > remain) len = remain;
\r
8034 strncat(messageText, str2, len);
\r
8036 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8038 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8042 hdc = GetDC(hwndMain);
\r
8043 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8044 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8045 &messageRect, messageText, strlen(messageText), NULL);
\r
8046 (void) SelectObject(hdc, oldFont);
\r
8047 (void) ReleaseDC(hwndMain, hdc);
\r
8051 DisplayError(char *str, int error)
\r
8053 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8059 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8060 NULL, error, LANG_NEUTRAL,
\r
8061 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8063 sprintf(buf, "%s:\n%s", str, buf2);
\r
8065 ErrorMap *em = errmap;
\r
8066 while (em->err != 0 && em->err != error) em++;
\r
8067 if (em->err != 0) {
\r
8068 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8070 sprintf(buf, "%s:\nError code %d", str, error);
\r
8075 ErrorPopUp(_("Error"), buf);
\r
8080 DisplayMoveError(char *str)
\r
8082 fromX = fromY = -1;
\r
8083 ClearHighlights();
\r
8084 DrawPosition(FALSE, NULL);
\r
8085 if (appData.popupMoveErrors) {
\r
8086 ErrorPopUp(_("Error"), str);
\r
8088 DisplayMessage(str, "");
\r
8089 moveErrorMessageUp = TRUE;
\r
8094 DisplayFatalError(char *str, int error, int exitStatus)
\r
8096 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8098 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8101 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8102 NULL, error, LANG_NEUTRAL,
\r
8103 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8105 sprintf(buf, "%s:\n%s", str, buf2);
\r
8107 ErrorMap *em = errmap;
\r
8108 while (em->err != 0 && em->err != error) em++;
\r
8109 if (em->err != 0) {
\r
8110 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8112 sprintf(buf, "%s:\nError code %d", str, error);
\r
8117 if (appData.debugMode) {
\r
8118 fprintf(debugFP, "%s: %s\n", label, str);
\r
8120 if (appData.popupExitMessage) {
\r
8121 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8122 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8124 ExitEvent(exitStatus);
\r
8129 DisplayInformation(char *str)
\r
8131 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8136 DisplayNote(char *str)
\r
8138 ErrorPopUp(_("Note"), str);
\r
8143 char *title, *question, *replyPrefix;
\r
8148 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8150 static QuestionParams *qp;
\r
8151 char reply[MSG_SIZ];
\r
8154 switch (message) {
\r
8155 case WM_INITDIALOG:
\r
8156 qp = (QuestionParams *) lParam;
\r
8157 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8158 Translate(hDlg, DLG_Question);
\r
8159 SetWindowText(hDlg, qp->title);
\r
8160 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8161 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8165 switch (LOWORD(wParam)) {
\r
8167 strcpy(reply, qp->replyPrefix);
\r
8168 if (*reply) strcat(reply, " ");
\r
8169 len = strlen(reply);
\r
8170 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8171 strcat(reply, "\n");
\r
8172 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8173 EndDialog(hDlg, TRUE);
\r
8174 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8177 EndDialog(hDlg, FALSE);
\r
8188 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8190 QuestionParams qp;
\r
8194 qp.question = question;
\r
8195 qp.replyPrefix = replyPrefix;
\r
8197 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8198 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8199 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8200 FreeProcInstance(lpProc);
\r
8203 /* [AS] Pick FRC position */
\r
8204 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8206 static int * lpIndexFRC;
\r
8212 case WM_INITDIALOG:
\r
8213 lpIndexFRC = (int *) lParam;
\r
8215 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8216 Translate(hDlg, DLG_NewGameFRC);
\r
8218 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8219 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8220 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8221 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8226 switch( LOWORD(wParam) ) {
\r
8228 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8229 EndDialog( hDlg, 0 );
\r
8230 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8233 EndDialog( hDlg, 1 );
\r
8235 case IDC_NFG_Edit:
\r
8236 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8237 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8239 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8242 case IDC_NFG_Random:
\r
8243 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8244 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8257 int index = appData.defaultFrcPosition;
\r
8258 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8260 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8262 if( result == 0 ) {
\r
8263 appData.defaultFrcPosition = index;
\r
8269 /* [AS] Game list options. Refactored by HGM */
\r
8271 HWND gameListOptionsDialog;
\r
8273 // low-level front-end: clear text edit / list widget
\r
8277 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8280 // low-level front-end: clear text edit / list widget
\r
8282 GLT_DeSelectList()
\r
8284 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8287 // low-level front-end: append line to text edit / list widget
\r
8289 GLT_AddToList( char *name )
\r
8292 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8296 // low-level front-end: get line from text edit / list widget
\r
8298 GLT_GetFromList( int index, char *name )
\r
8301 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8307 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8309 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8310 int idx2 = idx1 + delta;
\r
8311 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8313 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8316 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8317 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8318 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8319 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8323 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8327 case WM_INITDIALOG:
\r
8328 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8330 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8331 Translate(hDlg, DLG_GameListOptions);
\r
8333 /* Initialize list */
\r
8334 GLT_TagsToList( lpUserGLT );
\r
8336 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8341 switch( LOWORD(wParam) ) {
\r
8344 EndDialog( hDlg, 0 );
\r
8347 EndDialog( hDlg, 1 );
\r
8350 case IDC_GLT_Default:
\r
8351 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8354 case IDC_GLT_Restore:
\r
8355 GLT_TagsToList( appData.gameListTags );
\r
8359 GLT_MoveSelection( hDlg, -1 );
\r
8362 case IDC_GLT_Down:
\r
8363 GLT_MoveSelection( hDlg, +1 );
\r
8373 int GameListOptions()
\r
8376 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8378 strcpy( lpUserGLT, appData.gameListTags );
\r
8380 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8382 if( result == 0 ) {
\r
8383 /* [AS] Memory leak here! */
\r
8384 appData.gameListTags = strdup( lpUserGLT );
\r
8391 DisplayIcsInteractionTitle(char *str)
\r
8393 char consoleTitle[MSG_SIZ];
\r
8395 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8396 SetWindowText(hwndConsole, consoleTitle);
\r
8400 DrawPosition(int fullRedraw, Board board)
\r
8402 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8405 void NotifyFrontendLogin()
\r
8408 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8414 fromX = fromY = -1;
\r
8415 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8416 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8417 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8418 dragInfo.lastpos = dragInfo.pos;
\r
8419 dragInfo.start.x = dragInfo.start.y = -1;
\r
8420 dragInfo.from = dragInfo.start;
\r
8422 DrawPosition(TRUE, NULL);
\r
8429 CommentPopUp(char *title, char *str)
\r
8431 HWND hwnd = GetActiveWindow();
\r
8432 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8434 SetActiveWindow(hwnd);
\r
8438 CommentPopDown(void)
\r
8440 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8441 if (commentDialog) {
\r
8442 ShowWindow(commentDialog, SW_HIDE);
\r
8444 commentUp = FALSE;
\r
8448 EditCommentPopUp(int index, char *title, char *str)
\r
8450 EitherCommentPopUp(index, title, str, TRUE);
\r
8457 MyPlaySound(&sounds[(int)SoundMove]);
\r
8460 VOID PlayIcsWinSound()
\r
8462 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8465 VOID PlayIcsLossSound()
\r
8467 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8470 VOID PlayIcsDrawSound()
\r
8472 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8475 VOID PlayIcsUnfinishedSound()
\r
8477 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8483 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8491 consoleEcho = TRUE;
\r
8492 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8493 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8494 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8503 consoleEcho = FALSE;
\r
8504 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8505 /* This works OK: set text and background both to the same color */
\r
8507 cf.crTextColor = COLOR_ECHOOFF;
\r
8508 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8509 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8512 /* No Raw()...? */
\r
8514 void Colorize(ColorClass cc, int continuation)
\r
8516 currentColorClass = cc;
\r
8517 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8518 consoleCF.crTextColor = textAttribs[cc].color;
\r
8519 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8520 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8526 static char buf[MSG_SIZ];
\r
8527 DWORD bufsiz = MSG_SIZ;
\r
8529 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8530 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8532 if (!GetUserName(buf, &bufsiz)) {
\r
8533 /*DisplayError("Error getting user name", GetLastError());*/
\r
8534 strcpy(buf, _("User"));
\r
8542 static char buf[MSG_SIZ];
\r
8543 DWORD bufsiz = MSG_SIZ;
\r
8545 if (!GetComputerName(buf, &bufsiz)) {
\r
8546 /*DisplayError("Error getting host name", GetLastError());*/
\r
8547 strcpy(buf, _("Unknown"));
\r
8554 ClockTimerRunning()
\r
8556 return clockTimerEvent != 0;
\r
8562 if (clockTimerEvent == 0) return FALSE;
\r
8563 KillTimer(hwndMain, clockTimerEvent);
\r
8564 clockTimerEvent = 0;
\r
8569 StartClockTimer(long millisec)
\r
8571 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8572 (UINT) millisec, NULL);
\r
8576 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8579 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8581 if(appData.noGUI) return;
\r
8582 hdc = GetDC(hwndMain);
\r
8583 if (!IsIconic(hwndMain)) {
\r
8584 DisplayAClock(hdc, timeRemaining, highlight,
\r
8585 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8587 if (highlight && iconCurrent == iconBlack) {
\r
8588 iconCurrent = iconWhite;
\r
8589 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8590 if (IsIconic(hwndMain)) {
\r
8591 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8594 (void) ReleaseDC(hwndMain, hdc);
\r
8596 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8600 DisplayBlackClock(long timeRemaining, int highlight)
\r
8603 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8605 if(appData.noGUI) return;
\r
8606 hdc = GetDC(hwndMain);
\r
8607 if (!IsIconic(hwndMain)) {
\r
8608 DisplayAClock(hdc, timeRemaining, highlight,
\r
8609 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8611 if (highlight && iconCurrent == iconWhite) {
\r
8612 iconCurrent = iconBlack;
\r
8613 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8614 if (IsIconic(hwndMain)) {
\r
8615 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8618 (void) ReleaseDC(hwndMain, hdc);
\r
8620 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8625 LoadGameTimerRunning()
\r
8627 return loadGameTimerEvent != 0;
\r
8631 StopLoadGameTimer()
\r
8633 if (loadGameTimerEvent == 0) return FALSE;
\r
8634 KillTimer(hwndMain, loadGameTimerEvent);
\r
8635 loadGameTimerEvent = 0;
\r
8640 StartLoadGameTimer(long millisec)
\r
8642 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8643 (UINT) millisec, NULL);
\r
8651 char fileTitle[MSG_SIZ];
\r
8653 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8654 f = OpenFileDialog(hwndMain, "a", defName,
\r
8655 appData.oldSaveStyle ? "gam" : "pgn",
\r
8657 _("Save Game to File"), NULL, fileTitle, NULL);
\r
8659 SaveGame(f, 0, "");
\r
8666 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8668 if (delayedTimerEvent != 0) {
\r
8669 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8670 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8672 KillTimer(hwndMain, delayedTimerEvent);
\r
8673 delayedTimerEvent = 0;
\r
8674 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8675 delayedTimerCallback();
\r
8677 delayedTimerCallback = cb;
\r
8678 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8679 (UINT) millisec, NULL);
\r
8682 DelayedEventCallback
\r
8685 if (delayedTimerEvent) {
\r
8686 return delayedTimerCallback;
\r
8693 CancelDelayedEvent()
\r
8695 if (delayedTimerEvent) {
\r
8696 KillTimer(hwndMain, delayedTimerEvent);
\r
8697 delayedTimerEvent = 0;
\r
8701 DWORD GetWin32Priority(int nice)
\r
8702 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8704 REALTIME_PRIORITY_CLASS 0x00000100
\r
8705 HIGH_PRIORITY_CLASS 0x00000080
\r
8706 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8707 NORMAL_PRIORITY_CLASS 0x00000020
\r
8708 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8709 IDLE_PRIORITY_CLASS 0x00000040
\r
8711 if (nice < -15) return 0x00000080;
\r
8712 if (nice < 0) return 0x00008000;
\r
8713 if (nice == 0) return 0x00000020;
\r
8714 if (nice < 15) return 0x00004000;
\r
8715 return 0x00000040;
\r
8718 /* Start a child process running the given program.
\r
8719 The process's standard output can be read from "from", and its
\r
8720 standard input can be written to "to".
\r
8721 Exit with fatal error if anything goes wrong.
\r
8722 Returns an opaque pointer that can be used to destroy the process
\r
8726 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8728 #define BUFSIZE 4096
\r
8730 HANDLE hChildStdinRd, hChildStdinWr,
\r
8731 hChildStdoutRd, hChildStdoutWr;
\r
8732 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8733 SECURITY_ATTRIBUTES saAttr;
\r
8735 PROCESS_INFORMATION piProcInfo;
\r
8736 STARTUPINFO siStartInfo;
\r
8738 char buf[MSG_SIZ];
\r
8741 if (appData.debugMode) {
\r
8742 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8747 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8748 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8749 saAttr.bInheritHandle = TRUE;
\r
8750 saAttr.lpSecurityDescriptor = NULL;
\r
8753 * The steps for redirecting child's STDOUT:
\r
8754 * 1. Create anonymous pipe to be STDOUT for child.
\r
8755 * 2. Create a noninheritable duplicate of read handle,
\r
8756 * and close the inheritable read handle.
\r
8759 /* Create a pipe for the child's STDOUT. */
\r
8760 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8761 return GetLastError();
\r
8764 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8765 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8766 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8767 FALSE, /* not inherited */
\r
8768 DUPLICATE_SAME_ACCESS);
\r
8770 return GetLastError();
\r
8772 CloseHandle(hChildStdoutRd);
\r
8775 * The steps for redirecting child's STDIN:
\r
8776 * 1. Create anonymous pipe to be STDIN for child.
\r
8777 * 2. Create a noninheritable duplicate of write handle,
\r
8778 * and close the inheritable write handle.
\r
8781 /* Create a pipe for the child's STDIN. */
\r
8782 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8783 return GetLastError();
\r
8786 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8787 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8788 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8789 FALSE, /* not inherited */
\r
8790 DUPLICATE_SAME_ACCESS);
\r
8792 return GetLastError();
\r
8794 CloseHandle(hChildStdinWr);
\r
8796 /* Arrange to (1) look in dir for the child .exe file, and
\r
8797 * (2) have dir be the child's working directory. Interpret
\r
8798 * dir relative to the directory WinBoard loaded from. */
\r
8799 GetCurrentDirectory(MSG_SIZ, buf);
\r
8800 SetCurrentDirectory(installDir);
\r
8801 SetCurrentDirectory(dir);
\r
8803 /* Now create the child process. */
\r
8805 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8806 siStartInfo.lpReserved = NULL;
\r
8807 siStartInfo.lpDesktop = NULL;
\r
8808 siStartInfo.lpTitle = NULL;
\r
8809 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8810 siStartInfo.cbReserved2 = 0;
\r
8811 siStartInfo.lpReserved2 = NULL;
\r
8812 siStartInfo.hStdInput = hChildStdinRd;
\r
8813 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8814 siStartInfo.hStdError = hChildStdoutWr;
\r
8816 fSuccess = CreateProcess(NULL,
\r
8817 cmdLine, /* command line */
\r
8818 NULL, /* process security attributes */
\r
8819 NULL, /* primary thread security attrs */
\r
8820 TRUE, /* handles are inherited */
\r
8821 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8822 NULL, /* use parent's environment */
\r
8824 &siStartInfo, /* STARTUPINFO pointer */
\r
8825 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8827 err = GetLastError();
\r
8828 SetCurrentDirectory(buf); /* return to prev directory */
\r
8833 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
8834 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
8835 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
8838 /* Close the handles we don't need in the parent */
\r
8839 CloseHandle(piProcInfo.hThread);
\r
8840 CloseHandle(hChildStdinRd);
\r
8841 CloseHandle(hChildStdoutWr);
\r
8843 /* Prepare return value */
\r
8844 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8845 cp->kind = CPReal;
\r
8846 cp->hProcess = piProcInfo.hProcess;
\r
8847 cp->pid = piProcInfo.dwProcessId;
\r
8848 cp->hFrom = hChildStdoutRdDup;
\r
8849 cp->hTo = hChildStdinWrDup;
\r
8851 *pr = (void *) cp;
\r
8853 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8854 2000 where engines sometimes don't see the initial command(s)
\r
8855 from WinBoard and hang. I don't understand how that can happen,
\r
8856 but the Sleep is harmless, so I've put it in. Others have also
\r
8857 reported what may be the same problem, so hopefully this will fix
\r
8858 it for them too. */
\r
8866 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8868 ChildProc *cp; int result;
\r
8870 cp = (ChildProc *) pr;
\r
8871 if (cp == NULL) return;
\r
8873 switch (cp->kind) {
\r
8875 /* TerminateProcess is considered harmful, so... */
\r
8876 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8877 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8878 /* The following doesn't work because the chess program
\r
8879 doesn't "have the same console" as WinBoard. Maybe
\r
8880 we could arrange for this even though neither WinBoard
\r
8881 nor the chess program uses a console for stdio? */
\r
8882 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8884 /* [AS] Special termination modes for misbehaving programs... */
\r
8885 if( signal == 9 ) {
\r
8886 result = TerminateProcess( cp->hProcess, 0 );
\r
8888 if ( appData.debugMode) {
\r
8889 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
8892 else if( signal == 10 ) {
\r
8893 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8895 if( dw != WAIT_OBJECT_0 ) {
\r
8896 result = TerminateProcess( cp->hProcess, 0 );
\r
8898 if ( appData.debugMode) {
\r
8899 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
8905 CloseHandle(cp->hProcess);
\r
8909 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8913 closesocket(cp->sock);
\r
8918 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8919 closesocket(cp->sock);
\r
8920 closesocket(cp->sock2);
\r
8928 InterruptChildProcess(ProcRef pr)
\r
8932 cp = (ChildProc *) pr;
\r
8933 if (cp == NULL) return;
\r
8934 switch (cp->kind) {
\r
8936 /* The following doesn't work because the chess program
\r
8937 doesn't "have the same console" as WinBoard. Maybe
\r
8938 we could arrange for this even though neither WinBoard
\r
8939 nor the chess program uses a console for stdio */
\r
8940 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8945 /* Can't interrupt */
\r
8949 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8956 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8958 char cmdLine[MSG_SIZ];
\r
8960 if (port[0] == NULLCHAR) {
\r
8961 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8963 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8965 return StartChildProcess(cmdLine, "", pr);
\r
8969 /* Code to open TCP sockets */
\r
8972 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8977 struct sockaddr_in sa, mysa;
\r
8978 struct hostent FAR *hp;
\r
8979 unsigned short uport;
\r
8980 WORD wVersionRequested;
\r
8983 /* Initialize socket DLL */
\r
8984 wVersionRequested = MAKEWORD(1, 1);
\r
8985 err = WSAStartup(wVersionRequested, &wsaData);
\r
8986 if (err != 0) return err;
\r
8989 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8990 err = WSAGetLastError();
\r
8995 /* Bind local address using (mostly) don't-care values.
\r
8997 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8998 mysa.sin_family = AF_INET;
\r
8999 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9000 uport = (unsigned short) 0;
\r
9001 mysa.sin_port = htons(uport);
\r
9002 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9003 == SOCKET_ERROR) {
\r
9004 err = WSAGetLastError();
\r
9009 /* Resolve remote host name */
\r
9010 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9011 if (!(hp = gethostbyname(host))) {
\r
9012 unsigned int b0, b1, b2, b3;
\r
9014 err = WSAGetLastError();
\r
9016 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9017 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9018 hp->h_addrtype = AF_INET;
\r
9020 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9021 hp->h_addr_list[0] = (char *) malloc(4);
\r
9022 hp->h_addr_list[0][0] = (char) b0;
\r
9023 hp->h_addr_list[0][1] = (char) b1;
\r
9024 hp->h_addr_list[0][2] = (char) b2;
\r
9025 hp->h_addr_list[0][3] = (char) b3;
\r
9031 sa.sin_family = hp->h_addrtype;
\r
9032 uport = (unsigned short) atoi(port);
\r
9033 sa.sin_port = htons(uport);
\r
9034 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9036 /* Make connection */
\r
9037 if (connect(s, (struct sockaddr *) &sa,
\r
9038 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9039 err = WSAGetLastError();
\r
9044 /* Prepare return value */
\r
9045 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9046 cp->kind = CPSock;
\r
9048 *pr = (ProcRef *) cp;
\r
9054 OpenCommPort(char *name, ProcRef *pr)
\r
9059 char fullname[MSG_SIZ];
\r
9061 if (*name != '\\')
\r
9062 sprintf(fullname, "\\\\.\\%s", name);
\r
9064 strcpy(fullname, name);
\r
9066 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9067 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9068 if (h == (HANDLE) -1) {
\r
9069 return GetLastError();
\r
9073 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9075 /* Accumulate characters until a 100ms pause, then parse */
\r
9076 ct.ReadIntervalTimeout = 100;
\r
9077 ct.ReadTotalTimeoutMultiplier = 0;
\r
9078 ct.ReadTotalTimeoutConstant = 0;
\r
9079 ct.WriteTotalTimeoutMultiplier = 0;
\r
9080 ct.WriteTotalTimeoutConstant = 0;
\r
9081 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9083 /* Prepare return value */
\r
9084 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9085 cp->kind = CPComm;
\r
9088 *pr = (ProcRef *) cp;
\r
9094 OpenLoopback(ProcRef *pr)
\r
9096 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9102 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9107 struct sockaddr_in sa, mysa;
\r
9108 struct hostent FAR *hp;
\r
9109 unsigned short uport;
\r
9110 WORD wVersionRequested;
\r
9113 char stderrPortStr[MSG_SIZ];
\r
9115 /* Initialize socket DLL */
\r
9116 wVersionRequested = MAKEWORD(1, 1);
\r
9117 err = WSAStartup(wVersionRequested, &wsaData);
\r
9118 if (err != 0) return err;
\r
9120 /* Resolve remote host name */
\r
9121 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9122 if (!(hp = gethostbyname(host))) {
\r
9123 unsigned int b0, b1, b2, b3;
\r
9125 err = WSAGetLastError();
\r
9127 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9128 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9129 hp->h_addrtype = AF_INET;
\r
9131 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9132 hp->h_addr_list[0] = (char *) malloc(4);
\r
9133 hp->h_addr_list[0][0] = (char) b0;
\r
9134 hp->h_addr_list[0][1] = (char) b1;
\r
9135 hp->h_addr_list[0][2] = (char) b2;
\r
9136 hp->h_addr_list[0][3] = (char) b3;
\r
9142 sa.sin_family = hp->h_addrtype;
\r
9143 uport = (unsigned short) 514;
\r
9144 sa.sin_port = htons(uport);
\r
9145 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9147 /* Bind local socket to unused "privileged" port address
\r
9149 s = INVALID_SOCKET;
\r
9150 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9151 mysa.sin_family = AF_INET;
\r
9152 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9153 for (fromPort = 1023;; fromPort--) {
\r
9154 if (fromPort < 0) {
\r
9156 return WSAEADDRINUSE;
\r
9158 if (s == INVALID_SOCKET) {
\r
9159 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9160 err = WSAGetLastError();
\r
9165 uport = (unsigned short) fromPort;
\r
9166 mysa.sin_port = htons(uport);
\r
9167 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9168 == SOCKET_ERROR) {
\r
9169 err = WSAGetLastError();
\r
9170 if (err == WSAEADDRINUSE) continue;
\r
9174 if (connect(s, (struct sockaddr *) &sa,
\r
9175 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9176 err = WSAGetLastError();
\r
9177 if (err == WSAEADDRINUSE) {
\r
9188 /* Bind stderr local socket to unused "privileged" port address
\r
9190 s2 = INVALID_SOCKET;
\r
9191 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9192 mysa.sin_family = AF_INET;
\r
9193 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9194 for (fromPort = 1023;; fromPort--) {
\r
9195 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9196 if (fromPort < 0) {
\r
9197 (void) closesocket(s);
\r
9199 return WSAEADDRINUSE;
\r
9201 if (s2 == INVALID_SOCKET) {
\r
9202 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9203 err = WSAGetLastError();
\r
9209 uport = (unsigned short) fromPort;
\r
9210 mysa.sin_port = htons(uport);
\r
9211 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9212 == SOCKET_ERROR) {
\r
9213 err = WSAGetLastError();
\r
9214 if (err == WSAEADDRINUSE) continue;
\r
9215 (void) closesocket(s);
\r
9219 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9220 err = WSAGetLastError();
\r
9221 if (err == WSAEADDRINUSE) {
\r
9223 s2 = INVALID_SOCKET;
\r
9226 (void) closesocket(s);
\r
9227 (void) closesocket(s2);
\r
9233 prevStderrPort = fromPort; // remember port used
\r
9234 sprintf(stderrPortStr, "%d", fromPort);
\r
9236 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9237 err = WSAGetLastError();
\r
9238 (void) closesocket(s);
\r
9239 (void) closesocket(s2);
\r
9244 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9245 err = WSAGetLastError();
\r
9246 (void) closesocket(s);
\r
9247 (void) closesocket(s2);
\r
9251 if (*user == NULLCHAR) user = UserName();
\r
9252 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9253 err = WSAGetLastError();
\r
9254 (void) closesocket(s);
\r
9255 (void) closesocket(s2);
\r
9259 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9260 err = WSAGetLastError();
\r
9261 (void) closesocket(s);
\r
9262 (void) closesocket(s2);
\r
9267 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9268 err = WSAGetLastError();
\r
9269 (void) closesocket(s);
\r
9270 (void) closesocket(s2);
\r
9274 (void) closesocket(s2); /* Stop listening */
\r
9276 /* Prepare return value */
\r
9277 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9278 cp->kind = CPRcmd;
\r
9281 *pr = (ProcRef *) cp;
\r
9288 AddInputSource(ProcRef pr, int lineByLine,
\r
9289 InputCallback func, VOIDSTAR closure)
\r
9291 InputSource *is, *is2 = NULL;
\r
9292 ChildProc *cp = (ChildProc *) pr;
\r
9294 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9295 is->lineByLine = lineByLine;
\r
9297 is->closure = closure;
\r
9298 is->second = NULL;
\r
9299 is->next = is->buf;
\r
9300 if (pr == NoProc) {
\r
9301 is->kind = CPReal;
\r
9302 consoleInputSource = is;
\r
9304 is->kind = cp->kind;
\r
9306 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9307 we create all threads suspended so that the is->hThread variable can be
\r
9308 safely assigned, then let the threads start with ResumeThread.
\r
9310 switch (cp->kind) {
\r
9312 is->hFile = cp->hFrom;
\r
9313 cp->hFrom = NULL; /* now owned by InputThread */
\r
9315 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9316 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9320 is->hFile = cp->hFrom;
\r
9321 cp->hFrom = NULL; /* now owned by InputThread */
\r
9323 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9324 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9328 is->sock = cp->sock;
\r
9330 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9331 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9335 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9337 is->sock = cp->sock;
\r
9339 is2->sock = cp->sock2;
\r
9340 is2->second = is2;
\r
9342 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9343 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9345 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9346 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9350 if( is->hThread != NULL ) {
\r
9351 ResumeThread( is->hThread );
\r
9354 if( is2 != NULL && is2->hThread != NULL ) {
\r
9355 ResumeThread( is2->hThread );
\r
9359 return (InputSourceRef) is;
\r
9363 RemoveInputSource(InputSourceRef isr)
\r
9367 is = (InputSource *) isr;
\r
9368 is->hThread = NULL; /* tell thread to stop */
\r
9369 CloseHandle(is->hThread);
\r
9370 if (is->second != NULL) {
\r
9371 is->second->hThread = NULL;
\r
9372 CloseHandle(is->second->hThread);
\r
9376 int no_wrap(char *message, int count)
\r
9378 ConsoleOutput(message, count, FALSE);
\r
9383 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9386 int outCount = SOCKET_ERROR;
\r
9387 ChildProc *cp = (ChildProc *) pr;
\r
9388 static OVERLAPPED ovl;
\r
9389 static int line = 0;
\r
9393 if (appData.noJoin || !appData.useInternalWrap)
\r
9394 return no_wrap(message, count);
\r
9397 int width = get_term_width();
\r
9398 int len = wrap(NULL, message, count, width, &line);
\r
9399 char *msg = malloc(len);
\r
9403 return no_wrap(message, count);
\r
9406 dbgchk = wrap(msg, message, count, width, &line);
\r
9407 if (dbgchk != len && appData.debugMode)
\r
9408 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9409 ConsoleOutput(msg, len, FALSE);
\r
9416 if (ovl.hEvent == NULL) {
\r
9417 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9419 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9421 switch (cp->kind) {
\r
9424 outCount = send(cp->sock, message, count, 0);
\r
9425 if (outCount == SOCKET_ERROR) {
\r
9426 *outError = WSAGetLastError();
\r
9428 *outError = NO_ERROR;
\r
9433 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9434 &dOutCount, NULL)) {
\r
9435 *outError = NO_ERROR;
\r
9436 outCount = (int) dOutCount;
\r
9438 *outError = GetLastError();
\r
9443 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9444 &dOutCount, &ovl);
\r
9445 if (*outError == NO_ERROR) {
\r
9446 outCount = (int) dOutCount;
\r
9454 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9457 /* Ignore delay, not implemented for WinBoard */
\r
9458 return OutputToProcess(pr, message, count, outError);
\r
9463 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9464 char *buf, int count, int error)
\r
9466 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9469 /* see wgamelist.c for Game List functions */
\r
9470 /* see wedittags.c for Edit Tags functions */
\r
9477 char buf[MSG_SIZ];
\r
9480 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9481 f = fopen(buf, "r");
\r
9483 ProcessICSInitScript(f);
\r
9491 StartAnalysisClock()
\r
9493 if (analysisTimerEvent) return;
\r
9494 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9495 (UINT) 2000, NULL);
\r
9499 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9501 highlightInfo.sq[0].x = fromX;
\r
9502 highlightInfo.sq[0].y = fromY;
\r
9503 highlightInfo.sq[1].x = toX;
\r
9504 highlightInfo.sq[1].y = toY;
\r
9510 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9511 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9515 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9517 premoveHighlightInfo.sq[0].x = fromX;
\r
9518 premoveHighlightInfo.sq[0].y = fromY;
\r
9519 premoveHighlightInfo.sq[1].x = toX;
\r
9520 premoveHighlightInfo.sq[1].y = toY;
\r
9524 ClearPremoveHighlights()
\r
9526 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9527 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9531 ShutDownFrontEnd()
\r
9533 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9534 DeleteClipboardTempFiles();
\r
9540 if (IsIconic(hwndMain))
\r
9541 ShowWindow(hwndMain, SW_RESTORE);
\r
9543 SetActiveWindow(hwndMain);
\r
9547 * Prototypes for animation support routines
\r
9549 static void ScreenSquare(int column, int row, POINT * pt);
\r
9550 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9551 POINT frames[], int * nFrames);
\r
9555 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
9556 { // [HGM] atomic: animate blast wave
\r
9558 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
9559 explodeInfo.fromX = fromX;
\r
9560 explodeInfo.fromY = fromY;
\r
9561 explodeInfo.toX = toX;
\r
9562 explodeInfo.toY = toY;
\r
9563 for(i=1; i<nFrames; i++) {
\r
9564 explodeInfo.radius = (i*180)/(nFrames-1);
\r
9565 DrawPosition(FALSE, NULL);
\r
9566 Sleep(appData.animSpeed);
\r
9568 explodeInfo.radius = 0;
\r
9569 DrawPosition(TRUE, NULL);
\r
9575 AnimateMove(board, fromX, fromY, toX, toY)
\r
9582 ChessSquare piece;
\r
9583 POINT start, finish, mid;
\r
9584 POINT frames[kFactor * 2 + 1];
\r
9587 if (!appData.animate) return;
\r
9588 if (doingSizing) return;
\r
9589 if (fromY < 0 || fromX < 0) return;
\r
9590 piece = board[fromY][fromX];
\r
9591 if (piece >= EmptySquare) return;
\r
9593 ScreenSquare(fromX, fromY, &start);
\r
9594 ScreenSquare(toX, toY, &finish);
\r
9596 /* All pieces except knights move in straight line */
\r
9597 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9598 mid.x = start.x + (finish.x - start.x) / 2;
\r
9599 mid.y = start.y + (finish.y - start.y) / 2;
\r
9601 /* Knight: make diagonal movement then straight */
\r
9602 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9603 mid.x = start.x + (finish.x - start.x) / 2;
\r
9607 mid.y = start.y + (finish.y - start.y) / 2;
\r
9611 /* Don't use as many frames for very short moves */
\r
9612 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9613 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9615 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9617 animInfo.from.x = fromX;
\r
9618 animInfo.from.y = fromY;
\r
9619 animInfo.to.x = toX;
\r
9620 animInfo.to.y = toY;
\r
9621 animInfo.lastpos = start;
\r
9622 animInfo.piece = piece;
\r
9623 for (n = 0; n < nFrames; n++) {
\r
9624 animInfo.pos = frames[n];
\r
9625 DrawPosition(FALSE, NULL);
\r
9626 animInfo.lastpos = animInfo.pos;
\r
9627 Sleep(appData.animSpeed);
\r
9629 animInfo.pos = finish;
\r
9630 DrawPosition(FALSE, NULL);
\r
9631 animInfo.piece = EmptySquare;
\r
9632 if(gameInfo.variant == VariantAtomic &&
\r
9633 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
9634 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
9637 /* Convert board position to corner of screen rect and color */
\r
9640 ScreenSquare(column, row, pt)
\r
9641 int column; int row; POINT * pt;
\r
9644 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9645 pt->y = lineGap + row * (squareSize + lineGap);
\r
9647 pt->x = lineGap + column * (squareSize + lineGap);
\r
9648 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9652 /* Generate a series of frame coords from start->mid->finish.
\r
9653 The movement rate doubles until the half way point is
\r
9654 reached, then halves back down to the final destination,
\r
9655 which gives a nice slow in/out effect. The algorithmn
\r
9656 may seem to generate too many intermediates for short
\r
9657 moves, but remember that the purpose is to attract the
\r
9658 viewers attention to the piece about to be moved and
\r
9659 then to where it ends up. Too few frames would be less
\r
9663 Tween(start, mid, finish, factor, frames, nFrames)
\r
9664 POINT * start; POINT * mid;
\r
9665 POINT * finish; int factor;
\r
9666 POINT frames[]; int * nFrames;
\r
9668 int n, fraction = 1, count = 0;
\r
9670 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9671 for (n = 0; n < factor; n++)
\r
9673 for (n = 0; n < factor; n++) {
\r
9674 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9675 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9677 fraction = fraction / 2;
\r
9681 frames[count] = *mid;
\r
9684 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9686 for (n = 0; n < factor; n++) {
\r
9687 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9688 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9690 fraction = fraction * 2;
\r
9696 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9698 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9700 EvalGraphSet( first, last, current, pvInfoList );
\r